diff -r 675a964f4eb5 -r 35751d3474b7 cryptoservices/certificateandkeymgmt/wtlscert/wtlscertchainao.cpp --- 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 -#include -#include -#include - -CWTLSCertChainAO* CWTLSCertChainAO::NewL(RFs& aFs, - CWTLSCertChain& aWTLSCertChain, - const CArrayPtr& 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& 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; iSubjectKeyId()) ) ); - } - - 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; jCompare(*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; iExactMatchL( (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; jExactMatchL( (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 +#include +#include +#include + +CWTLSCertChainAO* CWTLSCertChainAO::NewL(RFs& aFs, + CWTLSCertChain& aWTLSCertChain, + const CArrayPtr& 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& 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; iSubjectKeyId()) ) ); + } + + 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; jCompare(*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; iExactMatchL( (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; jExactMatchL( (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; + } +