cryptoservices/certificateandkeymgmt/wtlscert/wtlscertchainao.cpp
changeset 8 35751d3474b7
parent 0 2c201484c85f
--- a/cryptoservices/certificateandkeymgmt/wtlscert/wtlscertchainao.cpp	Tue Jul 21 01:04:32 2009 +0100
+++ b/cryptoservices/certificateandkeymgmt/wtlscert/wtlscertchainao.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -1,534 +1,535 @@
-/*
-* Copyright (c) 1998-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: 
-*
-*/
-
-
-#include "wtlscertchainao.h"
-#include <asymmetric.h>
-#include <bigint.h>
-#include <ccertattributefilter.h>
-#include <cctcertinfo.h>
-
-CWTLSCertChainAO* CWTLSCertChainAO::NewL(RFs& aFs, 
-										 CWTLSCertChain& aWTLSCertChain,
-										 const CArrayPtr<CWTLSCertificate>& aRootCerts)
-	{
-	CWTLSCertChainAO* self = new(ELeave) CWTLSCertChainAO(aFs, aWTLSCertChain);
-	CleanupStack::PushL(self);
-	self->ConstructL(aRootCerts);
-	CleanupStack::Pop(self);
-	return self;
-	}
-
-CWTLSCertChainAO* CWTLSCertChainAO::NewL(RFs& aFs, 
-										 CWTLSCertChain& aWTLSCertChain,
-										 const TUid aClient)
-	{
-	return new(ELeave) CWTLSCertChainAO(aFs, aWTLSCertChain, aClient);
-	}
-
-CWTLSCertChainAO::~CWTLSCertChainAO()
-	{
-	Cancel();
-	delete iCertStoreManager;
-	delete iFilter;
-	delete iEncodedCertTemp;
-	iRootSubjectClientHashList.ResetAndDestroy();
-	iRootSubjectStoreHashList.Close();
-	iCertInfos.Close(); //In an RMPointerArray Close deletes all elements as 
-						//well as any personal allocated space
-	iRootsFromStore.ResetAndDestroy();
-	iRootsFromStore.Close();
-	iRootsFromClient.ResetAndDestroy();
-	}
-
-CWTLSCertChainAO::CWTLSCertChainAO(RFs& aFs, 
-								   CWTLSCertChain& aWTLSCertChain)
-	: CActive(EPriorityNormal), iFs(aFs), iWTLSCertChain(aWTLSCertChain), iEncodedCert(NULL, 0)
-	{
-	CActiveScheduler::Add(this);
-	}
-
-CWTLSCertChainAO::CWTLSCertChainAO(RFs& aFs, 
-								   CWTLSCertChain& aWTLSCertChain,
-								   const TUid aClient)
-	: CActive(0), iFs(aFs), iWTLSCertChain(aWTLSCertChain), iClient(aClient),
-		iEncodedCert(NULL, 0)
-	{
-	CActiveScheduler::Add(this);
-	}
-
-void CWTLSCertChainAO::ConstructL(const CArrayPtr<CWTLSCertificate>& aRootCerts)
-	{
-	for(TInt i=0; i< aRootCerts.Count(); i++)
-		{
-		CWTLSCertificate* root = CWTLSCertificate::NewLC(*(aRootCerts[i]));
-		User::LeaveIfError( iRootsFromClient.Append(root) );
-		CleanupStack::Pop(); //root
-		}
-	}
-
-void CWTLSCertChainAO::RunL()
-	{
-	//If any of my active objects complete with errors then we don't
-	//want to proceed
-	User::LeaveIfError(iStatus.Int());
-
-	switch (iState)
-		{
-		case EStoreManagerInitialization:
-			HandleEStoreManagerInitializationL();
-			break;
-
-		case EStoreManagerInitialized:
-			HandleEStoreManagerInitializedL();
-			break;
-
-		case EGetCertHashes:
-			HandleEGetCertHashesL();
-			break;
-
-		case EPruneList:
-			HandleEPruneListL();
-			break;
-
-		case EPruneListDone:
-			HandleEPruneListDoneL();
-			break;
-
-		case ECheckTCA:
-			HandleECheckTCAL();
-			break;
-
-		case EIsChainSelfSigned:
-			HandleEIsChainSelfSignedL();
-			break;
-
-		case ERetrieveRoots:
-			HandleERetrieveRootsL();
-			break;
-
-		case EAddRootToList:
-			HandleEAddRootToListL();
-			break;
-
-		case EFindRoot:
-			HandleEFindRootL();
-			break;
-
-		case EValidateEnd:
-			HandleEValidateEndL();
-			break;
-		
-		default:
-			__ASSERT_DEBUG(EFalse, User::Panic(_L("CWTLSCertChainAO"), 1));
-			User::Leave(KErrArgument);
-			break;
-		}
-	}
-
-TInt CWTLSCertChainAO::RunError(TInt aError)
-	{
-	User::RequestComplete(iOriginalRequestStatus, aError);
-
-	delete iCertStoreManager;
-	iCertStoreManager = 0;
-
-	return 0;
-	}
-
-void CWTLSCertChainAO::DoCancel()
-	{
-	TRequestStatus* status = &iStatus;
-	User::RequestComplete(status, KErrCancel);
-	if (iOriginalRequestStatus)
-		{
-		User::RequestComplete(iOriginalRequestStatus, KErrCancel);
-		}
-	}
-
-void CWTLSCertChainAO::Validate(CWTLSValidationResult& aValidationResult,
-								const TTime& aValidationTime,								 
-								TRequestStatus& aStatus)
-	{
-	iValidationResult = &aValidationResult;
-	iValidationResult->Reset();
-	iValidationTime = &aValidationTime;
-	iOriginalRequestStatus = &aStatus;
-	aStatus = KRequestPending;
-
-	__ASSERT_DEBUG(!IsActive(), User::Panic(_L("CWTLSCertChainAO"), 1));
-	__ASSERT_DEBUG(!iCertStoreManager, User::Panic(_L("CWTLSCertChainAO"), 1));
-	
-	iState = EStoreManagerInitialization;
-	TRequestStatus *status = &iStatus;
-	User::RequestComplete(status, KErrNone);
-	SetActive();
-	}
-
-TBool CWTLSCertChainAO::CheckSignatureAndNameL(const CWTLSCertificate& aCert, 
-											   CWTLSValidationResult& aResult,
-											   TInt aPos) const
-	{
-	TInt issuerPos = aPos + 1;
-	TBool res = EFalse;
-	if (issuerPos == iWTLSCertChain.iChain->Count())
-		//then it's the root
-		{
-		if (aCert.IssuerName().ExactMatchL(aCert.SubjectName()))
-			//then it claims to be self signed, sig must verify
-			{
-			if (aCert.VerifySignatureL(aCert.PublicKey().KeyData()))
-				{
-				res = ETrue;
-				}
-			else 
-				{
-				aResult.SetError(ESignatureInvalid, aPos);
-				}
-			}
-		else
-			{
-			aResult.AppendWarningL(TWTLSValidationStatus(ERootCertNotSelfSigned, aPos));
-			res = ETrue; //if its a warning we continue the validation process with the 
-						//warning duly noted so we can check for further warn/errors
-			}
-		}
-	else
-		//then it isn't the root: so names must chain & sigs must verify
-		{
-		const CWTLSCertificate* issuer = iWTLSCertChain.iChain->At(issuerPos);
-		TBool subject = EFalse;
-		TBool signature = EFalse;
-		subject = aCert.IssuerName().ExactMatchL(issuer->SubjectName());
-		if( !subject ) 
-			{
-			aResult.SetError(ENamesDontChain, aPos);
-			return EFalse;
-			}
-		signature = aCert.VerifySignatureL(issuer->PublicKey().KeyData());
-		if( !signature )
-			{
-			aResult.SetError(ESignatureInvalid, aPos);
-			return EFalse;
-			}
-		res = subject && signature;
-		}
-	return res;
-	}
-
-TBool CWTLSCertChainAO::CheckValidityPeriod(const CWTLSCertificate& aCert,
-											CWTLSValidationResult& aResult, 
-											const TTime aTime,
-											TInt aPos) const
-	{
-	if (aCert.ValidityPeriod().Valid(aTime))
-		{
-		return ETrue;
-		}
-	aResult.SetError(EDateOutOfRange, aPos);
-	return EFalse;
-	}
-
-void CWTLSCertChainAO::HandleEStoreManagerInitializationL()
-	{
-	iFilter = CCertAttributeFilter::NewL();
-	iFilter->SetFormat(EWTLSCertificate);
-	iFilter->SetUid(iClient);
-	iFilter->SetOwnerType(ECACertificate);
-
-	iCertStoreManager = CUnifiedCertStore::NewL(iFs, EFalse);
-	iCertStoreManager->Initialize(iStatus);
-
-	iState = EStoreManagerInitialized;
-	SetActive();
-	}
-
-void CWTLSCertChainAO::HandleEStoreManagerInitializedL()
-	{
-	iCertStoreManager->List(iCertInfos, *iFilter, iStatus);
-
-	iState = EGetCertHashes;
-	SetActive();
-	}
-
-void CWTLSCertChainAO::HandleEGetCertHashesL()
-	{
-	for(TInt i=0; i<iRootsFromClient.Count(); i++)
-		{
-		HBufC8* hash = &GeneratePublicKeyHashL( *(iRootsFromClient[i]));
-		CleanupStack::PushL(hash);
-		User::LeaveIfError( iRootSubjectClientHashList.Append(hash) );
-		CleanupStack::Pop(); //hash
-		}
-	for(TInt j=0; j < iCertInfos.Count(); j++ )
-		{
-		User::LeaveIfError( iRootSubjectStoreHashList.Append( &((iCertInfos[j])->SubjectKeyId()) ) );
-		}
-
-	iPruned = EFalse;	
-	iPrunedChainLength = iWTLSCertChain.iChain->Count();
-	iIndex = -1;
-
-	iState = EPruneList;
-	TRequestStatus* status = &iStatus;
-	User::RequestComplete(status, KErrNone);
-	SetActive();
-	}
-
-/* Walk through the canadiate list and compare the hash of the subjects with the previously
- * computed subject hash of certs from the CertStore and certs supplied by the client
- */
-void CWTLSCertChainAO::HandleEPruneListL()
-	{
-	iIndex++;
-	if(iIndex < iWTLSCertChain.iChain->Count() )
-		{
-		CWTLSCertificate* cert = iWTLSCertChain.iChain->At(iIndex);
-		HBufC8* hash = &GeneratePublicKeyHashL(*cert);
-		CleanupStack::PushL(hash);
-
-		for(TInt i=0; i < iRootSubjectClientHashList.Count(); i++)
-			{
-			if( (iRootSubjectClientHashList[i])->Compare(*hash) == 0 )
-				{
-				iPrunedChainLength = iIndex;
-				iPruned = ETrue;
-				break;
-				}
-			}
-		if(!iPruned)
-			{
-			for(TInt j=0; j<iRootSubjectStoreHashList.Count(); j++) 
-				{
-				if( (iRootSubjectStoreHashList[j])->Compare(*hash) == 0 )
-					{
-					iPrunedChainLength = iIndex;
-					iPruned = ETrue;
-					break;
-					}
-				}
-			}
-		CleanupStack::PopAndDestroy(hash);
-		if(iPruned)
-			{
-			iState = EPruneListDone;
-			}
-		else 
-			{
-			iState = EPruneList;
-			}
-		}
-	else
-		{
-		iState = EPruneListDone;
-		}
-	TRequestStatus* status = &iStatus;
-	User::RequestComplete(status, KErrNone);
-	SetActive();
-	}
-
-void CWTLSCertChainAO::HandleEPruneListDoneL()
-	{
-	if(iPruned) 
-		{
-		TInt count = iWTLSCertChain.iChain->Count();
-		for( TInt i=count - 1; i > iPrunedChainLength; i-- )
-			{
-			delete iWTLSCertChain.iChain->At(i);
-			iWTLSCertChain.iChain->Delete(i);
-			}
-		iWTLSCertChain.iChain->Compress();
-		}
-	iState = ECheckTCA;
-	TRequestStatus* status = &iStatus;
-	User::RequestComplete(status, KErrNone);
-	SetActive();
-	}
-
-//checks to see if each certificate in a chain has the authority to sign other certificates
-void CWTLSCertChainAO::HandleECheckTCAL()
-	{
-	TBool validChain = ETrue;
-	for( TInt i = 1; i < iWTLSCertChain.iChain->Count(); i++ ) 
-		//all intermediate certs (ie not EE certs and not self signed) need
-		// to have a field T=ca indicating that they can sign other certs
-		{
-		if( (iWTLSCertChain.iChain)->At(i)->IsTCAL() == EFalse && 
-			(iWTLSCertChain.iChain)->At(i)->IsSelfSignedL() == EFalse ) 
-			{
-			iValidationResult->SetError(ENotCACert, i);
-			User::RequestComplete(iOriginalRequestStatus, KErrNone);
-			validChain = EFalse;
-			break;
-			}
-		}
-	if(validChain && iPruned) 
-		{
-		//if we've pruned the list and the chain we have is valid,
-		//then our chain already has a root that we trust.
-		//therefore there is no need to retrieve one :)
-		//therefore goto validation
-		iState = EValidateEnd;
-		TRequestStatus *status = &iStatus;
-		User::RequestComplete(status, KErrNone);
-		SetActive();
-		}
-	else if(validChain) // ie && !iPruned
-		{
-		//if we haven't pruned but chain is valid then we're back a square one.
-		iState = EIsChainSelfSigned;
-		TRequestStatus *status = &iStatus;
-		User::RequestComplete(status, KErrNone);
-		SetActive();
-		}
-	}
-
-void CWTLSCertChainAO::HandleEIsChainSelfSignedL()
-	{
-
-	TInt last = iWTLSCertChain.iChain->Count() - 1;
-	if( iWTLSCertChain.iChain->At(last)->IsSelfSignedL() )
-		{
-		//if chained is self signed, and no earlier cert in the sequence was trusted
-		//then this is going to fail validation
-		//This is just an optimisation to avoid retrieving all the roots from the store
-
-		iValidationResult->SetError(EChainHasNoRoot, last);
-		User::RequestComplete(iOriginalRequestStatus, KErrNone);
-		}
-	else 
-		{
-		//standard chain -> need to find the appropriate trusted root for chain if it exists
-		iState = ERetrieveRoots;
-		iIndex = -1;
-		TRequestStatus* status = &iStatus;
-		User::RequestComplete(status, KErrNone);
-		SetActive();
-		}
-	}
-
-void CWTLSCertChainAO::HandleERetrieveRootsL()
-	{
-	iIndex++;	
-	if(iIndex < iCertInfos.Count() )
-		{
-		if( iEncodedCertTemp != NULL ) 
-			{
-			delete iEncodedCertTemp;
-			}
-		iEncodedCertTemp = HBufC8::NewMaxL( (iCertInfos[iIndex])->Size() );
-		iEncodedCert.Set( iEncodedCertTemp->Des() );
-		iCertStoreManager->Retrieve( *(iCertInfos[iIndex]), iEncodedCert, iStatus );
-		iState = EAddRootToList;
-		}
-	else 
-		{
-		iState = EFindRoot;
-		TRequestStatus* status = &iStatus;
-		User::RequestComplete(status, KErrNone);
-		}	
-	SetActive();
-	}
-
-void CWTLSCertChainAO::HandleEAddRootToListL()
-	{
-	//are we guarenteed that a cert from the store is a valid WTLScert?
-	//ie is this going to leave for reasons other than OOM?
-	CWTLSCertificate *cert = CWTLSCertificate::NewL( iEncodedCert );
-	User::LeaveIfError( iRootsFromStore.Append(cert) );
-
-	iState = ERetrieveRoots;
-	TRequestStatus* status = &iStatus;
-	User::RequestComplete(status, KErrNone);
-	SetActive();
-	}
-
-void CWTLSCertChainAO::HandleEFindRootL()
-	{
-	TInt last = iWTLSCertChain.iChain->Count() - 1;
-	const CWTLSName* issuerName = &(iWTLSCertChain.iChain->At(last)->IssuerName());
-
-	iFoundRoot = EFalse;
-	for(TInt i=0; i<iRootsFromClient.Count(); i++) 
-		{
-		if( issuerName->ExactMatchL( (iRootsFromClient[i])->SubjectName() ) )
-			{
-			iFoundRoot = ETrue;
-			CWTLSCertificate* cert = CWTLSCertificate::NewLC( *(iRootsFromClient[i]) );
-			iWTLSCertChain.iChain->AppendL( cert ); 
-			CleanupStack::Pop(cert);
-			break;
-			}
-		}
-	if(!iFoundRoot) 
-		{
-		for(TInt j=0; j<iRootsFromStore.Count(); j++)
-			{
-			if( issuerName->ExactMatchL( (iRootsFromStore[j])->SubjectName() ) )
-				{
-				iFoundRoot = ETrue;
-				CWTLSCertificate* cert = CWTLSCertificate::NewLC( *(iRootsFromStore[j]) );
-				iWTLSCertChain.iChain->AppendL( cert );
-				CleanupStack::Pop(cert);
-				break;
-				}
-			}
-		}
-	if(!iFoundRoot)
-		{
-		iValidationResult->SetError(EChainHasNoRoot, last);
-		User::RequestComplete(iOriginalRequestStatus, KErrNone);
-		}
-	else
-		{
-		iState = EValidateEnd;
-		TRequestStatus* status = &iStatus;
-		User::RequestComplete(status, KErrNone);
-		SetActive();
-		}
-	}
-
-void CWTLSCertChainAO::HandleEValidateEndL()
-	{
-	TInt i = iWTLSCertChain.iChain->Count() -1;//we can guarantee that chain has at least 1 cert
-	for (; i >= 0; i--)
-		{
-		const CWTLSCertificate* current = iWTLSCertChain.iChain->At(i);
-		if ((!CheckSignatureAndNameL(*current, *iValidationResult, i))	||
-			(!CheckValidityPeriod(*current, *iValidationResult, *iValidationTime, i)))
-			{
-			//these functions set the error internally if there is one
-			break;
-			}
-		}		
-
-	User::RequestComplete(iOriginalRequestStatus, KErrNone);
-	}
-
-HBufC8& CWTLSCertChainAO::GeneratePublicKeyHashL(const CWTLSCertificate& aCert) const
-	{
-	TWTLSKeyFactory keyFactory;
-	CRSAPublicKey* key = keyFactory.RSAPublicKeyL( aCert.PublicKey().KeyData() );
-	CleanupStack::PushL(key);
-	HBufC8* modulusBuffer = key->N().BufferLC();
-	CSHA1* sha1 = CSHA1::NewL();
-	CleanupStack::PushL(sha1);
-	TPtrC8 hash = sha1->Final(*modulusBuffer);
-	HBufC8* permHash = hash.AllocL();
-	CleanupStack::PopAndDestroy(3); //sha1, modulusBuffer, key
-	return *permHash;
-	}
+/*
+* Copyright (c) 1998-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: 
+*
+*/
+
+
+#include "wtlscertchainao.h"
+#include <asymmetric.h>
+#include <bigint.h>
+#include <ccertattributefilter.h>
+#include <cctcertinfo.h>
+
+CWTLSCertChainAO* CWTLSCertChainAO::NewL(RFs& aFs, 
+										 CWTLSCertChain& aWTLSCertChain,
+										 const CArrayPtr<CWTLSCertificate>& aRootCerts)
+	{
+	CWTLSCertChainAO* self = new(ELeave) CWTLSCertChainAO(aFs, aWTLSCertChain);
+	CleanupStack::PushL(self);
+	self->ConstructL(aRootCerts);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CWTLSCertChainAO* CWTLSCertChainAO::NewL(RFs& aFs, 
+										 CWTLSCertChain& aWTLSCertChain,
+										 const TUid aClient)
+	{
+	return new(ELeave) CWTLSCertChainAO(aFs, aWTLSCertChain, aClient);
+	}
+
+CWTLSCertChainAO::~CWTLSCertChainAO()
+	{
+	Cancel();
+	delete iCertStoreManager;
+	delete iFilter;
+	delete iEncodedCertTemp;
+	iRootSubjectClientHashList.ResetAndDestroy();
+	iRootSubjectStoreHashList.Close();
+	iCertInfos.Close(); //In an RMPointerArray Close deletes all elements as 
+						//well as any personal allocated space
+	iRootsFromStore.ResetAndDestroy();
+	iRootsFromStore.Close();
+	iRootsFromClient.ResetAndDestroy();
+	}
+
+CWTLSCertChainAO::CWTLSCertChainAO(RFs& aFs, 
+								   CWTLSCertChain& aWTLSCertChain)
+	: CActive(EPriorityNormal), iFs(aFs), iWTLSCertChain(aWTLSCertChain), iEncodedCert(NULL, 0)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CWTLSCertChainAO::CWTLSCertChainAO(RFs& aFs, 
+								   CWTLSCertChain& aWTLSCertChain,
+								   const TUid aClient)
+	: CActive(0), iFs(aFs), iWTLSCertChain(aWTLSCertChain), iClient(aClient),
+		iEncodedCert(NULL, 0)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CWTLSCertChainAO::ConstructL(const CArrayPtr<CWTLSCertificate>& aRootCerts)
+	{
+	for(TInt i=0; i< aRootCerts.Count(); i++)
+		{
+		CWTLSCertificate* root = CWTLSCertificate::NewLC(*(aRootCerts[i]));
+		User::LeaveIfError( iRootsFromClient.Append(root) );
+		CleanupStack::Pop(); //root
+		}
+	}
+
+void CWTLSCertChainAO::RunL()
+	{
+	//If any of my active objects complete with errors then we don't
+	//want to proceed
+	User::LeaveIfError(iStatus.Int());
+
+	switch (iState)
+		{
+		case EStoreManagerInitialization:
+			HandleEStoreManagerInitializationL();
+			break;
+
+		case EStoreManagerInitialized:
+			HandleEStoreManagerInitializedL();
+			break;
+
+		case EGetCertHashes:
+			HandleEGetCertHashesL();
+			break;
+
+		case EPruneList:
+			HandleEPruneListL();
+			break;
+
+		case EPruneListDone:
+			HandleEPruneListDoneL();
+			break;
+
+		case ECheckTCA:
+			HandleECheckTCAL();
+			break;
+
+		case EIsChainSelfSigned:
+			HandleEIsChainSelfSignedL();
+			break;
+
+		case ERetrieveRoots:
+			HandleERetrieveRootsL();
+			break;
+
+		case EAddRootToList:
+			HandleEAddRootToListL();
+			break;
+
+		case EFindRoot:
+			HandleEFindRootL();
+			break;
+
+		case EValidateEnd:
+			HandleEValidateEndL();
+			break;
+		
+		default:
+			__ASSERT_DEBUG(EFalse, User::Panic(_L("CWTLSCertChainAO"), 1));
+			User::Leave(KErrArgument);
+			break;
+		}
+	}
+
+TInt CWTLSCertChainAO::RunError(TInt aError)
+	{
+	User::RequestComplete(iOriginalRequestStatus, aError);
+
+	delete iCertStoreManager;
+	iCertStoreManager = 0;
+
+	return 0;
+	}
+
+void CWTLSCertChainAO::DoCancel()
+	{
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrCancel);
+	if (iOriginalRequestStatus)
+		{
+		User::RequestComplete(iOriginalRequestStatus, KErrCancel);
+		}
+	}
+
+void CWTLSCertChainAO::Validate(CWTLSValidationResult& aValidationResult,
+								const TTime& aValidationTime,								 
+								TRequestStatus& aStatus)
+	{
+	iValidationResult = &aValidationResult;
+	iValidationResult->Reset();
+	iValidationTime = &aValidationTime;
+	iOriginalRequestStatus = &aStatus;
+	aStatus = KRequestPending;
+
+	__ASSERT_DEBUG(!IsActive(), User::Panic(_L("CWTLSCertChainAO"), 1));
+	__ASSERT_DEBUG(!iCertStoreManager, User::Panic(_L("CWTLSCertChainAO"), 1));
+	
+	iState = EStoreManagerInitialization;
+	TRequestStatus *status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+TBool CWTLSCertChainAO::CheckSignatureAndNameL(const CWTLSCertificate& aCert, 
+											   CWTLSValidationResult& aResult,
+											   TInt aPos) const
+	{
+	TInt issuerPos = aPos + 1;
+	TBool res = EFalse;
+	if (issuerPos == iWTLSCertChain.iChain->Count())
+		//then it's the root
+		{
+		if (aCert.IssuerName().ExactMatchL(aCert.SubjectName()))
+			//then it claims to be self signed, sig must verify
+			{
+			if (aCert.VerifySignatureL(aCert.PublicKey().KeyData()))
+				{
+				res = ETrue;
+				}
+			else 
+				{
+				aResult.SetError(ESignatureInvalid, aPos);
+				}
+			}
+		else
+			{
+			aResult.AppendWarningL(TWTLSValidationStatus(ERootCertNotSelfSigned, aPos));
+			res = ETrue; //if its a warning we continue the validation process with the 
+						//warning duly noted so we can check for further warn/errors
+			}
+		}
+	else
+		//then it isn't the root: so names must chain & sigs must verify
+		{
+		const CWTLSCertificate* issuer = iWTLSCertChain.iChain->At(issuerPos);
+		TBool subject = EFalse;
+		TBool signature = EFalse;
+		subject = aCert.IssuerName().ExactMatchL(issuer->SubjectName());
+		if( !subject ) 
+			{
+			aResult.SetError(ENamesDontChain, aPos);
+			return EFalse;
+			}
+		signature = aCert.VerifySignatureL(issuer->PublicKey().KeyData());
+		if( !signature )
+			{
+			aResult.SetError(ESignatureInvalid, aPos);
+			return EFalse;
+			}
+		res = subject && signature;
+		}
+	return res;
+	}
+
+TBool CWTLSCertChainAO::CheckValidityPeriod(const CWTLSCertificate& aCert,
+											CWTLSValidationResult& aResult, 
+											const TTime aTime,
+											TInt aPos) const
+	{
+	if (aCert.ValidityPeriod().Valid(aTime))
+		{
+		return ETrue;
+		}
+	aResult.SetError(EDateOutOfRange, aPos);
+	return EFalse;
+	}
+
+void CWTLSCertChainAO::HandleEStoreManagerInitializationL()
+	{
+	iFilter = CCertAttributeFilter::NewL();
+	iFilter->SetFormat(EWTLSCertificate);
+	iFilter->SetUid(iClient);
+	iFilter->SetOwnerType(ECACertificate);
+
+	iCertStoreManager = CUnifiedCertStore::NewL(iFs, EFalse);
+	iCertStoreManager->Initialize(iStatus);
+
+	iState = EStoreManagerInitialized;
+	SetActive();
+	}
+
+void CWTLSCertChainAO::HandleEStoreManagerInitializedL()
+	{
+	iCertStoreManager->List(iCertInfos, *iFilter, iStatus);
+
+	iState = EGetCertHashes;
+	SetActive();
+	}
+
+void CWTLSCertChainAO::HandleEGetCertHashesL()
+	{
+	for(TInt i=0; i<iRootsFromClient.Count(); i++)
+		{
+		HBufC8* hash = &GeneratePublicKeyHashL( *(iRootsFromClient[i]));
+		CleanupStack::PushL(hash);
+		User::LeaveIfError( iRootSubjectClientHashList.Append(hash) );
+		CleanupStack::Pop(); //hash
+		}
+	for(TInt j=0; j < iCertInfos.Count(); j++ )
+		{
+		User::LeaveIfError( iRootSubjectStoreHashList.Append( &((iCertInfos[j])->SubjectKeyId()) ) );
+		}
+
+	iPruned = EFalse;	
+	iPrunedChainLength = iWTLSCertChain.iChain->Count();
+	iIndex = -1;
+
+	iState = EPruneList;
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+/* Walk through the canadiate list and compare the hash of the subjects with the previously
+ * computed subject hash of certs from the CertStore and certs supplied by the client
+ */
+void CWTLSCertChainAO::HandleEPruneListL()
+	{
+	iIndex++;
+	if(iIndex < iWTLSCertChain.iChain->Count() )
+		{
+		CWTLSCertificate* cert = iWTLSCertChain.iChain->At(iIndex);
+		HBufC8* hash = &GeneratePublicKeyHashL(*cert);
+		CleanupStack::PushL(hash);
+
+		for(TInt i=0; i < iRootSubjectClientHashList.Count(); i++)
+			{
+			if( (iRootSubjectClientHashList[i])->Compare(*hash) == 0 )
+				{
+				iPrunedChainLength = iIndex;
+				iPruned = ETrue;
+				break;
+				}
+			}
+		if(!iPruned)
+			{
+			for(TInt j=0; j<iRootSubjectStoreHashList.Count(); j++) 
+				{
+				if( (iRootSubjectStoreHashList[j])->Compare(*hash) == 0 )
+					{
+					iPrunedChainLength = iIndex;
+					iPruned = ETrue;
+					break;
+					}
+				}
+			}
+		CleanupStack::PopAndDestroy(hash);
+		if(iPruned)
+			{
+			iState = EPruneListDone;
+			}
+		else 
+			{
+			iState = EPruneList;
+			}
+		}
+	else
+		{
+		iState = EPruneListDone;
+		}
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+void CWTLSCertChainAO::HandleEPruneListDoneL()
+	{
+	if(iPruned) 
+		{
+		TInt count = iWTLSCertChain.iChain->Count();
+		for( TInt i=count - 1; i > iPrunedChainLength; i-- )
+			{
+			delete iWTLSCertChain.iChain->At(i);
+			iWTLSCertChain.iChain->Delete(i);
+			}
+		iWTLSCertChain.iChain->Compress();
+		}
+	iState = ECheckTCA;
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+//checks to see if each certificate in a chain has the authority to sign other certificates
+void CWTLSCertChainAO::HandleECheckTCAL()
+	{
+	TBool validChain = ETrue;
+	for( TInt i = 1; i < iWTLSCertChain.iChain->Count(); i++ ) 
+		//all intermediate certs (ie not EE certs and not self signed) need
+		// to have a field T=ca indicating that they can sign other certs
+		{
+		if( (iWTLSCertChain.iChain)->At(i)->IsTCAL() == EFalse && 
+			(iWTLSCertChain.iChain)->At(i)->IsSelfSignedL() == EFalse ) 
+			{
+			iValidationResult->SetError(ENotCACert, i);
+			User::RequestComplete(iOriginalRequestStatus, KErrNone);
+			validChain = EFalse;
+			break;
+			}
+		}
+	if(validChain && iPruned) 
+		{
+		//if we've pruned the list and the chain we have is valid,
+		//then our chain already has a root that we trust.
+		//therefore there is no need to retrieve one :)
+		//therefore goto validation
+		iState = EValidateEnd;
+		TRequestStatus *status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		SetActive();
+		}
+	else if(validChain) // ie && !iPruned
+		{
+		//if we haven't pruned but chain is valid then we're back a square one.
+		iState = EIsChainSelfSigned;
+		TRequestStatus *status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		SetActive();
+		}
+	}
+
+void CWTLSCertChainAO::HandleEIsChainSelfSignedL()
+	{
+
+	TInt last = iWTLSCertChain.iChain->Count() - 1;
+	if( iWTLSCertChain.iChain->At(last)->IsSelfSignedL() )
+		{
+		//if chained is self signed, and no earlier cert in the sequence was trusted
+		//then this is going to fail validation
+		//This is just an optimisation to avoid retrieving all the roots from the store
+
+		iValidationResult->SetError(EChainHasNoRoot, last);
+		User::RequestComplete(iOriginalRequestStatus, KErrNone);
+		}
+	else 
+		{
+		//standard chain -> need to find the appropriate trusted root for chain if it exists
+		iState = ERetrieveRoots;
+		iIndex = -1;
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		SetActive();
+		}
+	}
+
+void CWTLSCertChainAO::HandleERetrieveRootsL()
+	{
+	iIndex++;	
+	if(iIndex < iCertInfos.Count() )
+		{
+		if( iEncodedCertTemp != NULL ) 
+			{
+			delete iEncodedCertTemp;
+			}
+		iEncodedCertTemp = HBufC8::NewMaxL( (iCertInfos[iIndex])->Size() );
+		iEncodedCert.Set( iEncodedCertTemp->Des() );
+		iCertStoreManager->Retrieve( *(iCertInfos[iIndex]), iEncodedCert, iStatus );
+		iState = EAddRootToList;
+		}
+	else 
+		{
+		iState = EFindRoot;
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		}	
+	SetActive();
+	}
+
+void CWTLSCertChainAO::HandleEAddRootToListL()
+	{
+	//are we guarenteed that a cert from the store is a valid WTLScert?
+	//ie is this going to leave for reasons other than OOM?
+	CWTLSCertificate *cert = CWTLSCertificate::NewL( iEncodedCert );
+	User::LeaveIfError( iRootsFromStore.Append(cert) );
+
+	iState = ERetrieveRoots;
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+void CWTLSCertChainAO::HandleEFindRootL()
+	{
+	TInt last = iWTLSCertChain.iChain->Count() - 1;
+	const CWTLSName* issuerName = &(iWTLSCertChain.iChain->At(last)->IssuerName());
+
+	iFoundRoot = EFalse;
+	for(TInt i=0; i<iRootsFromClient.Count(); i++) 
+		{
+		if( issuerName->ExactMatchL( (iRootsFromClient[i])->SubjectName() ) )
+			{
+			iFoundRoot = ETrue;
+			CWTLSCertificate* cert = CWTLSCertificate::NewLC( *(iRootsFromClient[i]) );
+			iWTLSCertChain.iChain->AppendL( cert ); 
+			CleanupStack::Pop(cert);
+			break;
+			}
+		}
+	if(!iFoundRoot) 
+		{
+		for(TInt j=0; j<iRootsFromStore.Count(); j++)
+			{
+			if( issuerName->ExactMatchL( (iRootsFromStore[j])->SubjectName() ) )
+				{
+				iFoundRoot = ETrue;
+				CWTLSCertificate* cert = CWTLSCertificate::NewLC( *(iRootsFromStore[j]) );
+				iWTLSCertChain.iChain->AppendL( cert );
+				CleanupStack::Pop(cert);
+				break;
+				}
+			}
+		}
+	if(!iFoundRoot)
+		{
+		iValidationResult->SetError(EChainHasNoRoot, last);
+		User::RequestComplete(iOriginalRequestStatus, KErrNone);
+		}
+	else
+		{
+		iState = EValidateEnd;
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		SetActive();
+		}
+	}
+
+void CWTLSCertChainAO::HandleEValidateEndL()
+	{
+	TInt i = iWTLSCertChain.iChain->Count() -1;//we can guarantee that chain has at least 1 cert
+	for (; i >= 0; i--)
+		{
+		const CWTLSCertificate* current = iWTLSCertChain.iChain->At(i);
+		if ((!CheckSignatureAndNameL(*current, *iValidationResult, i))	||
+			(!CheckValidityPeriod(*current, *iValidationResult, *iValidationTime, i)))
+			{
+			//these functions set the error internally if there is one
+			break;
+			}
+		}		
+
+	User::RequestComplete(iOriginalRequestStatus, KErrNone);
+	}
+
+HBufC8& CWTLSCertChainAO::GeneratePublicKeyHashL(const CWTLSCertificate& aCert) const
+	{
+	TWTLSKeyFactory keyFactory;
+	CRSAPublicKey* key = keyFactory.RSAPublicKeyL( aCert.PublicKey().KeyData() );
+	CleanupStack::PushL(key);
+	HBufC8* modulusBuffer = key->N().BufferLC();
+	CSHA1* sha1 = CSHA1::NewL();
+	CleanupStack::PushL(sha1);
+	TPtrC8 hash = sha1->Final(*modulusBuffer);
+	HBufC8* permHash = hash.AllocL();
+	CleanupStack::PopAndDestroy(3); //sha1, modulusBuffer, key
+	return *permHash;
+	}
+