os/security/cryptoservices/certificateandkeymgmt/pkixcertbase/Pkixchainbuilder.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/security/cryptoservices/certificateandkeymgmt/pkixcertbase/Pkixchainbuilder.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,242 @@
1.4 +/*
1.5 +* Copyright (c) 1997-2010 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of the License "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include "pkixchainbuilder.h"
1.23 +
1.24 +CPKIXChainBuilder* CPKIXChainBuilder::NewL()
1.25 + {
1.26 + CPKIXChainBuilder* s = CPKIXChainBuilder::NewLC();
1.27 + CleanupStack::Pop(s);
1.28 + return s;
1.29 + }
1.30 +
1.31 +CPKIXChainBuilder* CPKIXChainBuilder::NewLC()
1.32 + {
1.33 + CPKIXChainBuilder* s = new (ELeave) CPKIXChainBuilder;
1.34 + CleanupStack::PushL(s);
1.35 + s->ConstructL();
1.36 + return s;
1.37 + }
1.38 +
1.39 +CPKIXChainBuilder::~CPKIXChainBuilder()
1.40 + {
1.41 + Cancel();
1.42 + iSources.Close();
1.43 + iCandidates.ResetAndDestroy();
1.44 + iCandidates.Close();
1.45 + }
1.46 +
1.47 +void CPKIXChainBuilder::AddSourceL(MPKIXCertSource* aSource)
1.48 + {
1.49 + User::LeaveIfError(iSources.Append(aSource));
1.50 + }
1.51 +
1.52 +void CPKIXChainBuilder::AddIssuer(TInt& aNumberOfCertsAdded,
1.53 + TBool& aResult,
1.54 + CArrayPtrFlat<CX509Certificate>& aChain,
1.55 + TRequestStatus& aStatus)
1.56 + {
1.57 + iOriginalRequestStatus = &aStatus;
1.58 + aStatus = KRequestPending;
1.59 + iResult = &aResult;
1.60 + iChain = &aChain;
1.61 + iNumberOfCertsAdded = &aNumberOfCertsAdded;
1.62 +
1.63 + iSubject = aChain[aChain.Count()-1];
1.64 + __ASSERT_DEBUG(iSubject, User::Panic(_L("CPKICCertChainAO"), 1));
1.65 + __ASSERT_DEBUG(!iCandidates.Count(), User::Panic(_L("CPKICCertChainAO"), 1));
1.66 +
1.67 + iIndex = -1;
1.68 + iState = EAddCandidate;
1.69 + TRequestStatus* status = &iStatus;
1.70 + User::RequestComplete(status, KErrNone);
1.71 + SetActive();
1.72 + }
1.73 +
1.74 +CPKIXChainBuilder::CPKIXChainBuilder()
1.75 +: CActive(EPriorityNormal)
1.76 + {
1.77 + CActiveScheduler::Add(this);
1.78 + }
1.79 +
1.80 +void CPKIXChainBuilder::ConstructL()
1.81 + {
1.82 + }
1.83 +
1.84 +TBool CPKIXChainBuilder::ResolveIssuersL(CArrayPtr<CX509Certificate>& aChain,
1.85 + const RPointerArray<CX509Certificate>& aCandidates) const
1.86 + {
1.87 + //*this function attempts to figure out which certificate in aCandidates is the issuer of
1.88 + //the last cert in the aChain, and adds a *copy* of the best guess to aChain
1.89 + //*it assumes that the names match already
1.90 + //*if it establishes that none are any good it returns EFalse
1.91 + TInt count = aCandidates.Count();
1.92 + if (count == 0)
1.93 + {
1.94 + return EFalse;
1.95 + }
1.96 + if (count == 1)
1.97 + {
1.98 + CX509Certificate* cert = CX509Certificate::NewLC(*aCandidates[0]);
1.99 + aChain.AppendL(cert);
1.100 + (*iNumberOfCertsAdded)++;
1.101 + CleanupStack::Pop(cert);
1.102 + return ETrue;
1.103 + }
1.104 +
1.105 + const CX509Certificate* current = aChain[aChain.Count() - 1];
1.106 + //1) look for SKI/AKI to distinguish
1.107 + const CX509CertExtension* akiExt = current->Extension(KAuthorityKeyId);
1.108 + if (akiExt)
1.109 + {
1.110 + const CX509AuthorityKeyIdExt* aki = CX509AuthorityKeyIdExt::NewLC(akiExt->Data());
1.111 + TPtrC8 authorityKeyId = aki->KeyId();
1.112 + if (authorityKeyId != KNullDesC8)
1.113 + {
1.114 + for (TInt i = 0; i < count; i++)
1.115 + {
1.116 + const CX509CertExtension* skiExt = (aCandidates[i])->Extension(KSubjectKeyId);
1.117 + if (skiExt)
1.118 + {
1.119 + const CX509SubjectKeyIdExt* ski = CX509SubjectKeyIdExt::NewLC(skiExt->Data());
1.120 + if (authorityKeyId == ski->KeyId())
1.121 + {
1.122 + CX509Certificate* issuer = CX509Certificate::NewLC(*aCandidates[i]);
1.123 + aChain.AppendL(issuer);
1.124 + (*iNumberOfCertsAdded)++;
1.125 + CleanupStack::Pop();//issuer
1.126 + CleanupStack::PopAndDestroy(2);//aki, ski
1.127 + return ETrue;
1.128 + }
1.129 + else
1.130 + {
1.131 + CleanupStack::PopAndDestroy();//ski
1.132 + }
1.133 + }
1.134 + }
1.135 + }
1.136 + //ok, we haven't got a key ID for the issuer, so try for a serial number instead...
1.137 + else
1.138 + {
1.139 + TPtrC8 authoritySerialNo = aki->AuthorityCertSerialNumber();
1.140 + for (TInt i = 0; i < count; i++)
1.141 + {
1.142 + const CX509Certificate* candidate = aCandidates[i];
1.143 + if (authoritySerialNo == candidate->SerialNumber())
1.144 + {
1.145 + CX509Certificate* issuer = CX509Certificate::NewLC(*candidate);
1.146 + aChain.AppendL(issuer);
1.147 + (*iNumberOfCertsAdded)++;
1.148 + CleanupStack::Pop();//issuer
1.149 + CleanupStack::PopAndDestroy();//aki
1.150 + return ETrue;
1.151 + }
1.152 + }
1.153 + }
1.154 + CleanupStack::PopAndDestroy();//aki
1.155 + }
1.156 +
1.157 + // If more then one subject matching candidates are found and they doesn't contain SKI/AKI,
1.158 + // consider the most recently imported/added candidate as the issuer.
1.159 + for(TInt index = count - 1; index >= 0; --index)
1.160 + {
1.161 + TTime currentTime;
1.162 + // if secure time is not available then fall back to the insecure version.
1.163 + if(currentTime.UniversalTimeSecure() == KErrNoSecureTime)
1.164 + {
1.165 + currentTime.UniversalTime();
1.166 + }
1.167 +
1.168 + CX509Certificate* cert = CX509Certificate::NewLC(*aCandidates[index]);
1.169 + // SKI/AKI are optional in versions lower than 3. So, relax the candidate selection rules only for version 1 & 2
1.170 + // If the recent candidate is not valid enough(cert expired), consider it's previous valid candidate.
1.171 + if((cert->Version() < 3) && (cert->ValidityPeriod().Valid(currentTime)))
1.172 + {
1.173 + aChain.AppendL(cert);
1.174 + ++(*iNumberOfCertsAdded);
1.175 + CleanupStack::Pop(cert);
1.176 + return ETrue;
1.177 + }
1.178 + else
1.179 + {
1.180 + CleanupStack::PopAndDestroy(cert);
1.181 + continue;
1.182 + }
1.183 + }
1.184 +
1.185 + return EFalse;
1.186 + }
1.187 +
1.188 +
1.189 +void CPKIXChainBuilder::RunL()
1.190 + {
1.191 + User::LeaveIfError(iStatus.Int());
1.192 +
1.193 + switch (iState)
1.194 + {
1.195 + case EAddCandidate:
1.196 + iIndex++;
1.197 + if (iIndex < iSources.Count())
1.198 + {
1.199 + iSources[iIndex]->CandidatesL(*iSubject, iCandidates, iStatus);
1.200 + }
1.201 + else
1.202 + {
1.203 + iState = EFinished;
1.204 + TRequestStatus* status = &iStatus;
1.205 + User::RequestComplete(status, KErrNone);
1.206 + }
1.207 + SetActive();
1.208 + break;
1.209 +
1.210 + case EFinished:
1.211 + iState = EIdle;
1.212 + *iResult = ResolveIssuersL(*iChain, iCandidates);
1.213 + iCandidates.ResetAndDestroy();
1.214 + User::RequestComplete(iOriginalRequestStatus, KErrNone);
1.215 + break;
1.216 +
1.217 + default:
1.218 + User::Panic(_L("CPKIXChainBuilder"), 1);
1.219 + break;
1.220 + }
1.221 + }
1.222 +
1.223 +void CPKIXChainBuilder::DoCancel()
1.224 + {
1.225 + int i = 0;
1.226 + int end = iSources.Count();
1.227 + while (i < end)
1.228 + {
1.229 + iSources[i]->CancelCandidates();
1.230 + i++;
1.231 + }
1.232 + iCandidates.ResetAndDestroy();
1.233 +
1.234 + User::RequestComplete(iOriginalRequestStatus, KErrCancel);
1.235 +
1.236 + iState = EIdle;
1.237 + }
1.238 +
1.239 +TInt CPKIXChainBuilder::RunError(TInt aError)
1.240 + {
1.241 + iState = EIdle;
1.242 + iCandidates.ResetAndDestroy();
1.243 + User::RequestComplete(iOriginalRequestStatus, aError);
1.244 + return KErrNone;
1.245 + }