diff -r 000000000000 -r 2c201484c85f cryptomgmtlibs/cryptotokenfw/tsecdlg/Tsecdlg.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cryptomgmtlibs/cryptotokenfw/tsecdlg/Tsecdlg.cpp Wed Jul 08 11:25:26 2009 +0100 @@ -0,0 +1,449 @@ +/* +* Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* secdlgImpl.cpp +* +*/ + + +#include "Tsecdlg.h" +#include +#include +#include + + +// These are not really allocated to us, but this is only for finding errors +// while debugging, so it doesn't really matter +const TInt KErrTooManyDialogs = -12000; +const TInt KErrLabelMismatch = -12001; +const TInt KErrOperationMismatch = -12002; +const TInt KErrOperationNotSupported = -12003; + +_LIT(KpinValue,"pinkcloud"); +_LIT(KYes,"Yes"); + +// ---------------------------------------------------------------------------- +// Lib main entry point. +// This can leave and should leave (if failure occurs) despite the lack of trailing L. +// + +#ifdef _T_SECDLG_TEXTSHELL +EXPORT_C CArrayPtr* NotifierArray() +#else +CArrayPtr* NotifierArray() +#endif + { + //The notifierArray function CAN leave, despite no trailing L + CArrayPtrFlat* subjects = new (ELeave) CArrayPtrFlat( 1 ); + CleanupStack::PushL(subjects); + CTestSecDlgNotifier* notifier = CTestSecDlgNotifier::NewL(); + CleanupStack::PushL( notifier ); + subjects->AppendL( notifier ); + CleanupStack::Pop( 2,subjects); //notifier, subjects + return subjects; + } + +// ---------------------------------------------------------------------------- +// Ecom plugin implementation for UI notifier +// + +#ifndef _T_SECDLG_TEXTSHELL + +const TImplementationProxy ImplementationTable[] = + { + IMPLEMENTATION_PROXY_ENTRY(KTSecDlgNotiferUid, NotifierArray) + }; + +EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount) + { + aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); + return (ImplementationTable); + } + +#endif + +// ---------------------------------------------------------------------------- +// CInputSpec +// + +CInputSpec::CInputSpec(TSecurityDialogOperation aOp, HBufC* aLabelSpec, HBufC* aResponse1, HBufC* aResponse2) : + iOp(aOp), iLabelSpec(aLabelSpec), iResponse1(aResponse1), iResponse2(aResponse2) + { + } + +CInputSpec::~CInputSpec() + { + delete iLabelSpec; + delete iResponse1; + delete iResponse2; + } + + +// ---------------------------------------------------------------------------- +// CTestSecDlgNotifier +// + +_LIT(KInputFile, "\\t_secdlg_in.dat"); +_LIT(KOutputFile, "\\t_secdlg_out.dat"); + +CTestSecDlgNotifier* CTestSecDlgNotifier::NewL() + { + CTestSecDlgNotifier* self=new (ELeave) CTestSecDlgNotifier(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CTestSecDlgNotifier::CTestSecDlgNotifier() + { + iInfo.iUid = KUidSecurityDialogNotifier; + iInfo.iChannel = TUid::Uid(0x00001234); // dummy + iInfo.iPriority = ENotifierPriorityHigh; + } + +void CTestSecDlgNotifier::ConstructL() + { + User::LeaveIfError(iFs.Connect()); + } + + +TInt CTestSecDlgNotifier::GetInputIndexL() + { + RFileReadStream stream; + TDriveUnit sysDrive (RFs::GetSystemDrive()); + TDriveName driveName(sysDrive.Name()); + TBuf<128> outputFile (driveName); + outputFile.Append(KOutputFile); + + TInt err = stream.Open(iFs, outputFile, EFileRead | EFileShareExclusive); + // If the file doesn't exist yet just return zero + if (err == KErrNotFound) + { + return 0; + } + User::LeaveIfError(err); + stream.PushL(); + TInt index = stream.ReadInt32L(); + CleanupStack::PopAndDestroy(); // stream + return index; + } + +void CTestSecDlgNotifier::WriteDialogCountL(TInt aCount) + { + RFileWriteStream stream; + TDriveUnit sysDrive (RFs::GetSystemDrive()); + TDriveName driveName(sysDrive.Name()); + TBuf<128> outputFile (driveName); + outputFile.Append(KOutputFile); + + TInt err = stream.Replace(iFs, outputFile, EFileWrite | EFileShareExclusive); + if (err == KErrNotFound) + { + err = stream.Create(iFs, outputFile, EFileWrite | EFileShareExclusive); + } + User::LeaveIfError(err); + stream.PushL(); + stream.WriteInt32L(aCount); + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + } + +CInputSpec* CTestSecDlgNotifier::ReadInputSpecL(TInt aIndex) + { + RFileReadStream stream; + TDriveUnit sysDrive (RFs::GetSystemDrive()); + TDriveName driveName(sysDrive.Name()); + TBuf<128> inputFile (driveName); + inputFile.Append(KInputFile); + User::LeaveIfError(stream.Open(iFs, inputFile, EFileRead | EFileShareExclusive)); + stream.PushL(); + + // Update dialog count here so test code can see how many dialogs were + // requested if there were more than expected + WriteDialogCountL(aIndex + 1); + + MStreamBuf* streamBuf = stream.Source(); + TInt labelSize, response1Size, response2Size; + + // Skip records until we reach the one we want + for (TInt i = 0 ; i < aIndex ; ++i) + { + stream.ReadInt32L(); + labelSize = stream.ReadInt32L(); + streamBuf->SeekL(MStreamBuf::ERead, EStreamMark, labelSize * 2); + response1Size = stream.ReadInt32L(); + streamBuf->SeekL(MStreamBuf::ERead, EStreamMark, response1Size * 2); + response2Size = stream.ReadInt32L(); + streamBuf->SeekL(MStreamBuf::ERead, EStreamMark, response2Size * 2); + } + + TSecurityDialogOperation op = static_cast(stream.ReadInt32L()); + + labelSize = stream.ReadInt32L(); + HBufC* labelSpec = HBufC::NewMaxLC(labelSize); + TPtr labelPtr(labelSpec->Des()); + stream.ReadL(labelPtr, labelSize); + + response1Size = stream.ReadInt32L(); + HBufC* response1 = HBufC::NewMaxLC(response1Size); + TPtr response1Ptr(response1->Des()); + stream.ReadL(response1Ptr, response1Size); + + response2Size = stream.ReadInt32L(); + HBufC* response2 = HBufC::NewMaxLC(response2Size); + TPtr response2Ptr(response2->Des()); + stream.ReadL(response2Ptr, response2Size); + + CInputSpec* inputSpec = new (ELeave) CInputSpec(op, labelSpec, response1, response2); + CleanupStack::Pop(3, labelSpec); + CleanupStack::PopAndDestroy(); // stream + + return inputSpec; + } + + +void CTestSecDlgNotifier::DoEnterPINL(const CInputSpec& aSpec, const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage) + { + const TPINInput& pinInput = reinterpret_cast(*aBuffer.Ptr()); + + if (pinInput.iPIN.iPINLabel.Find(aSpec.LabelSpec()) == KErrNotFound) + { + User::Leave(KErrLabelMismatch); + } + + TPINValue pinValue = aSpec.Response1(); + TPckg pinValueBufPtr(pinValue); + aMessage.WriteL(aReplySlot, pinValueBufPtr); + } + +void CTestSecDlgNotifier::DoChangePINL(const CInputSpec& aSpec, const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage) + { + const TPINInput& input = reinterpret_cast(*aBuffer.Ptr()); + + if (input.iPIN.iPINLabel.Find(aSpec.LabelSpec()) == KErrNotFound) + { + User::Leave(KErrLabelMismatch); + } + + TTwoPINOutput output; + output.iPINValueToCheck = aSpec.Response1(); + output.iNewPINValue = aSpec.Response2(); + TPckg outputPckg(output); + aMessage.WriteL(aReplySlot, outputPckg); + } + + +void CTestSecDlgNotifier::Release() + { + delete this; + } + + + +CTestSecDlgNotifier::TNotifierInfo CTestSecDlgNotifier::RegisterL() + { + return iInfo; + } + + + +CTestSecDlgNotifier::TNotifierInfo CTestSecDlgNotifier::Info() const + { + return iInfo; + } + + + +void CTestSecDlgNotifier::StartL(const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage) + { + TRAPD(err, DoStartL(aBuffer, aReplySlot, aMessage)); + aMessage.Complete(err); + } + + +void CTestSecDlgNotifier::DoStartL(const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage) + { + // Minimum length is 4 + __ASSERT_DEBUG( aBuffer.Length() >= 4, User::Panic(_L("CTestSecDlgNotifier"), 0)); + + TUint operation = *reinterpret_cast(aBuffer.Ptr()) & KSecurityDialogOperationMask; + + TInt index = GetInputIndexL(); + CInputSpec* spec = NULL; + + TRAPD(err, spec = ReadInputSpecL(index)); + + // If the input file doesn't exist then we will answer PIN requests with the + // "pinkcloud" passphrase - this is so the certstore tests work independantly + // from keystore + if (err == KErrNotFound) + { + switch(operation) + { + case EEnterPIN: + { + TPINValue pinValue(KpinValue); + TPckg pinValueBufPtr(pinValue); + aMessage.WriteL(aReplySlot, pinValueBufPtr); + break; + } + case EServerAuthenticationFailure: + { + TServerAuthenticationFailureDialogResult output; + output = EStop; + TServerAuthenticationFailureOutputBuf outputPckg(output); + aMessage.WriteL(aReplySlot, outputPckg); + break; + } + default: + { + User::Leave(KErrOperationMismatch); + break; + } + } + return; + } + + if (err == KErrEof) + { + User::Leave(KErrTooManyDialogs); + } + + User::LeaveIfError(err); + + CleanupStack::PushL(spec); + + if (operation != spec->Operation()) + { + User::Leave(KErrOperationMismatch); + } + + switch (operation) + { + case EEnterPIN: + DoEnterPINL(*spec, aBuffer, aReplySlot, aMessage); + break; + + case EChangePIN: + DoChangePINL(*spec, aBuffer, aReplySlot, aMessage); + break; + + case ESecureConnection: + DoSecureConnectionL(*spec, aBuffer, aReplySlot, aMessage); + break; + + case ESignText: + case EEnablePIN: + case EDisablePIN: + case EUnblockPIN: + case EUnblockPINInClear: + case EPINBlocked: + // these operations are not yet implemented in this test harness + User::Leave(KErrOperationNotSupported); + break; + + case EServerAuthenticationFailure: + DoServerAuthenticationFailureL(*spec, aBuffer, aReplySlot, aMessage); + break; + + default: + User::Panic(_L("CTestSecDlgNotifier"), 0); + } + CleanupStack::PopAndDestroy(spec); + } + +void CTestSecDlgNotifier::DoServerAuthenticationFailureL(const CInputSpec& aSpec, const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage ) + { + // Test for valid packing of dialog data by extracting the encoded certificate + // and attempting to construct an X509 certificate from it. + CServerAuthenticationFailureInput* srvAuthFail = CServerAuthenticationFailureInput::NewLC(aBuffer); + TPtrC8 encodedCert; + srvAuthFail->GetEncodedCert(encodedCert); + + // If CX509Certificate::NewL leaves the encoded cert buffer must not be valid. + const CX509Certificate* cert = CX509Certificate::NewL(encodedCert); + + // There is no further need for the cert, so it can be deleted immediately. + delete cert; + + CleanupStack::PopAndDestroy(srvAuthFail); + + TServerAuthenticationFailureDialogResult output; + output = EStop; + if( (aSpec.Response1()).CompareF(KYes) == KErrNone ) + { + output = EContinue; + } + TServerAuthenticationFailureOutputBuf outputPckg(output); + aMessage.WriteL(aReplySlot, outputPckg); + } + +void CTestSecDlgNotifier::DoSecureConnectionL(const CInputSpec& aSpec, const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage ) + { + // If the client does not want to continue + if( (aSpec.Response1()).CompareF(KYes) != KErrNone ) + { + User::Leave(KErrCancel); + } + else + { + const TSignInput* secureConnectionInput = + reinterpret_cast( aBuffer.Ptr() ); + // if the client certificate is requested + if (secureConnectionInput->iDoClientAuthentication) + { + TLex lexi(aSpec.Response2()); + TInt32 selectionId=0; + TInt err=lexi.Val(selectionId); + + TInt certHandleTotal = secureConnectionInput->iCertHandleArrayTotal; + if (selectionId>certHandleTotal) + { + User::Leave(KErrNotFound); + } + + // Get index at start of list of TCTTokenObjectHandle objects + TInt bufferIndex = sizeof( TSignInput ); + TInt certHandleSize = sizeof( TCTTokenObjectHandle ); + TPckgBuf certHandleBuf; + TPtrC8 certHandleData( aBuffer.Mid( bufferIndex+(selectionId-1)*certHandleSize, certHandleSize ) ); + certHandleBuf.Copy( certHandleData ); + aMessage.WriteL( aReplySlot, certHandleBuf ); + } + } + } + + +TPtrC8 CTestSecDlgNotifier::StartL( const TDesC8& /*aBuffer*/ ) + { + User::Panic(_L("CTestSecDlgNotifier"), 0); + return TPtrC8(KNullDesC8); + } + + +void CTestSecDlgNotifier::Cancel() + { + // Don't think there is much we can do here. If a client deletes the + // client-side security dialog instance, after calling a method that + // displays a dialog, this will not get called until the user dismisses + // the dialog. We can't do anything then. + } + + +TPtrC8 CTestSecDlgNotifier::UpdateL( const TDesC8& /*aBuffer*/ ) + { + User::Panic(_L("CTestSecDlgNotifier"), 0); + return NULL; + }