sl@0: /* sl@0: * Copyright (c) 1997-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "pkixchainbuilder.h" sl@0: sl@0: CPKIXChainBuilder* CPKIXChainBuilder::NewL() sl@0: { sl@0: CPKIXChainBuilder* s = CPKIXChainBuilder::NewLC(); sl@0: CleanupStack::Pop(s); sl@0: return s; sl@0: } sl@0: sl@0: CPKIXChainBuilder* CPKIXChainBuilder::NewLC() sl@0: { sl@0: CPKIXChainBuilder* s = new (ELeave) CPKIXChainBuilder; sl@0: CleanupStack::PushL(s); sl@0: s->ConstructL(); sl@0: return s; sl@0: } sl@0: sl@0: CPKIXChainBuilder::~CPKIXChainBuilder() sl@0: { sl@0: Cancel(); sl@0: iSources.Close(); sl@0: iCandidates.ResetAndDestroy(); sl@0: iCandidates.Close(); sl@0: } sl@0: sl@0: void CPKIXChainBuilder::AddSourceL(MPKIXCertSource* aSource) sl@0: { sl@0: User::LeaveIfError(iSources.Append(aSource)); sl@0: } sl@0: sl@0: void CPKIXChainBuilder::AddIssuer(TInt& aNumberOfCertsAdded, sl@0: TBool& aResult, sl@0: CArrayPtrFlat& aChain, sl@0: TRequestStatus& aStatus) sl@0: { sl@0: iOriginalRequestStatus = &aStatus; sl@0: aStatus = KRequestPending; sl@0: iResult = &aResult; sl@0: iChain = &aChain; sl@0: iNumberOfCertsAdded = &aNumberOfCertsAdded; sl@0: sl@0: iSubject = aChain[aChain.Count()-1]; sl@0: __ASSERT_DEBUG(iSubject, User::Panic(_L("CPKICCertChainAO"), 1)); sl@0: __ASSERT_DEBUG(!iCandidates.Count(), User::Panic(_L("CPKICCertChainAO"), 1)); sl@0: sl@0: iIndex = -1; sl@0: iState = EAddCandidate; sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: } sl@0: sl@0: CPKIXChainBuilder::CPKIXChainBuilder() sl@0: : CActive(EPriorityNormal) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: void CPKIXChainBuilder::ConstructL() sl@0: { sl@0: } sl@0: sl@0: TBool CPKIXChainBuilder::ResolveIssuersL(CArrayPtr& aChain, sl@0: const RPointerArray& aCandidates) const sl@0: { sl@0: //*this function attempts to figure out which certificate in aCandidates is the issuer of sl@0: //the last cert in the aChain, and adds a *copy* of the best guess to aChain sl@0: //*it assumes that the names match already sl@0: //*if it establishes that none are any good it returns EFalse sl@0: TInt count = aCandidates.Count(); sl@0: if (count == 0) sl@0: { sl@0: return EFalse; sl@0: } sl@0: if (count == 1) sl@0: { sl@0: CX509Certificate* cert = CX509Certificate::NewLC(*aCandidates[0]); sl@0: aChain.AppendL(cert); sl@0: (*iNumberOfCertsAdded)++; sl@0: CleanupStack::Pop(cert); sl@0: return ETrue; sl@0: } sl@0: sl@0: const CX509Certificate* current = aChain[aChain.Count() - 1]; sl@0: //1) look for SKI/AKI to distinguish sl@0: const CX509CertExtension* akiExt = current->Extension(KAuthorityKeyId); sl@0: if (akiExt) sl@0: { sl@0: const CX509AuthorityKeyIdExt* aki = CX509AuthorityKeyIdExt::NewLC(akiExt->Data()); sl@0: TPtrC8 authorityKeyId = aki->KeyId(); sl@0: if (authorityKeyId != KNullDesC8) sl@0: { sl@0: for (TInt i = 0; i < count; i++) sl@0: { sl@0: const CX509CertExtension* skiExt = (aCandidates[i])->Extension(KSubjectKeyId); sl@0: if (skiExt) sl@0: { sl@0: const CX509SubjectKeyIdExt* ski = CX509SubjectKeyIdExt::NewLC(skiExt->Data()); sl@0: if (authorityKeyId == ski->KeyId()) sl@0: { sl@0: CX509Certificate* issuer = CX509Certificate::NewLC(*aCandidates[i]); sl@0: aChain.AppendL(issuer); sl@0: (*iNumberOfCertsAdded)++; sl@0: CleanupStack::Pop();//issuer sl@0: CleanupStack::PopAndDestroy(2);//aki, ski sl@0: return ETrue; sl@0: } sl@0: else sl@0: { sl@0: CleanupStack::PopAndDestroy();//ski sl@0: } sl@0: } sl@0: } sl@0: } sl@0: //ok, we haven't got a key ID for the issuer, so try for a serial number instead... sl@0: else sl@0: { sl@0: TPtrC8 authoritySerialNo = aki->AuthorityCertSerialNumber(); sl@0: for (TInt i = 0; i < count; i++) sl@0: { sl@0: const CX509Certificate* candidate = aCandidates[i]; sl@0: if (authoritySerialNo == candidate->SerialNumber()) sl@0: { sl@0: CX509Certificate* issuer = CX509Certificate::NewLC(*candidate); sl@0: aChain.AppendL(issuer); sl@0: (*iNumberOfCertsAdded)++; sl@0: CleanupStack::Pop();//issuer sl@0: CleanupStack::PopAndDestroy();//aki sl@0: return ETrue; sl@0: } sl@0: } sl@0: } sl@0: CleanupStack::PopAndDestroy();//aki sl@0: } sl@0: sl@0: // If more then one subject matching candidates are found and they doesn't contain SKI/AKI, sl@0: // consider the most recently imported/added candidate as the issuer. sl@0: for(TInt index = count - 1; index >= 0; --index) sl@0: { sl@0: TTime currentTime; sl@0: // if secure time is not available then fall back to the insecure version. sl@0: if(currentTime.UniversalTimeSecure() == KErrNoSecureTime) sl@0: { sl@0: currentTime.UniversalTime(); sl@0: } sl@0: sl@0: CX509Certificate* cert = CX509Certificate::NewLC(*aCandidates[index]); sl@0: // SKI/AKI are optional in versions lower than 3. So, relax the candidate selection rules only for version 1 & 2 sl@0: // If the recent candidate is not valid enough(cert expired), consider it's previous valid candidate. sl@0: if((cert->Version() < 3) && (cert->ValidityPeriod().Valid(currentTime))) sl@0: { sl@0: aChain.AppendL(cert); sl@0: ++(*iNumberOfCertsAdded); sl@0: CleanupStack::Pop(cert); sl@0: return ETrue; sl@0: } sl@0: else sl@0: { sl@0: CleanupStack::PopAndDestroy(cert); sl@0: continue; sl@0: } sl@0: } sl@0: sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: void CPKIXChainBuilder::RunL() sl@0: { sl@0: User::LeaveIfError(iStatus.Int()); sl@0: sl@0: switch (iState) sl@0: { sl@0: case EAddCandidate: sl@0: iIndex++; sl@0: if (iIndex < iSources.Count()) sl@0: { sl@0: iSources[iIndex]->CandidatesL(*iSubject, iCandidates, iStatus); sl@0: } sl@0: else sl@0: { sl@0: iState = EFinished; sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: } sl@0: SetActive(); sl@0: break; sl@0: sl@0: case EFinished: sl@0: iState = EIdle; sl@0: *iResult = ResolveIssuersL(*iChain, iCandidates); sl@0: iCandidates.ResetAndDestroy(); sl@0: User::RequestComplete(iOriginalRequestStatus, KErrNone); sl@0: break; sl@0: sl@0: default: sl@0: User::Panic(_L("CPKIXChainBuilder"), 1); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: void CPKIXChainBuilder::DoCancel() sl@0: { sl@0: int i = 0; sl@0: int end = iSources.Count(); sl@0: while (i < end) sl@0: { sl@0: iSources[i]->CancelCandidates(); sl@0: i++; sl@0: } sl@0: iCandidates.ResetAndDestroy(); sl@0: sl@0: User::RequestComplete(iOriginalRequestStatus, KErrCancel); sl@0: sl@0: iState = EIdle; sl@0: } sl@0: sl@0: TInt CPKIXChainBuilder::RunError(TInt aError) sl@0: { sl@0: iState = EIdle; sl@0: iCandidates.ResetAndDestroy(); sl@0: User::RequestComplete(iOriginalRequestStatus, aError); sl@0: return KErrNone; sl@0: }