cryptomgmtlibs/cryptotokenfw/tsecdlg/Tsecdlg.cpp
changeset 0 2c201484c85f
child 8 35751d3474b7
--- /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;
+	}