--- /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 <secdlgimpldefs.h>
+#include <certificateapps.h>
+#include <x509cert.h>
+
+
+// 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<MNotifierBase2>* NotifierArray()
+#else
+CArrayPtr<MNotifierBase2>* NotifierArray()
+#endif
+ {
+ //The notifierArray function CAN leave, despite no trailing L
+ CArrayPtrFlat<MNotifierBase2>* subjects = new (ELeave) CArrayPtrFlat<MNotifierBase2>( 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<TSecurityDialogOperation>(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<const TPINInput&>(*aBuffer.Ptr());
+
+ if (pinInput.iPIN.iPINLabel.Find(aSpec.LabelSpec()) == KErrNotFound)
+ {
+ User::Leave(KErrLabelMismatch);
+ }
+
+ TPINValue pinValue = aSpec.Response1();
+ TPckg<TPINValue> 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<const TPINInput&>(*aBuffer.Ptr());
+
+ if (input.iPIN.iPINLabel.Find(aSpec.LabelSpec()) == KErrNotFound)
+ {
+ User::Leave(KErrLabelMismatch);
+ }
+
+ TTwoPINOutput output;
+ output.iPINValueToCheck = aSpec.Response1();
+ output.iNewPINValue = aSpec.Response2();
+ TPckg<TTwoPINOutput> 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<const TInt *>(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<TPINValue> 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<const TSignInput*>( 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<TCTTokenObjectHandle> 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;
+ }