--- 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;
+ }
+