os/security/cryptoservices/certificateandkeymgmt/pkixcertbase/Pkixchainbuilder.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 1997-2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 
    19 #include "pkixchainbuilder.h"
    20 
    21 CPKIXChainBuilder* CPKIXChainBuilder::NewL()
    22 	{
    23 	CPKIXChainBuilder* s = CPKIXChainBuilder::NewLC();
    24 	CleanupStack::Pop(s);
    25 	return s;
    26 	}
    27 
    28 CPKIXChainBuilder* CPKIXChainBuilder::NewLC()
    29 	{
    30 	CPKIXChainBuilder* s = new (ELeave) CPKIXChainBuilder;
    31 	CleanupStack::PushL(s);
    32 	s->ConstructL();
    33 	return s;
    34 	}
    35 
    36 CPKIXChainBuilder::~CPKIXChainBuilder()
    37 	{
    38 	Cancel();
    39 	iSources.Close();
    40 	iCandidates.ResetAndDestroy();
    41 	iCandidates.Close();
    42 	}
    43 
    44 void CPKIXChainBuilder::AddSourceL(MPKIXCertSource* aSource)
    45 	{
    46 	User::LeaveIfError(iSources.Append(aSource));
    47 	}
    48 
    49 void CPKIXChainBuilder::AddIssuer(TInt& aNumberOfCertsAdded,
    50 								  TBool& aResult, 
    51 								  CArrayPtrFlat<CX509Certificate>& aChain, 
    52 								  TRequestStatus& aStatus)
    53 	{
    54 	iOriginalRequestStatus = &aStatus;
    55 	aStatus = KRequestPending;
    56 	iResult = &aResult;
    57 	iChain = &aChain;
    58 	iNumberOfCertsAdded = &aNumberOfCertsAdded;
    59 
    60 	iSubject = aChain[aChain.Count()-1];
    61 	__ASSERT_DEBUG(iSubject, User::Panic(_L("CPKICCertChainAO"), 1));
    62 	__ASSERT_DEBUG(!iCandidates.Count(), User::Panic(_L("CPKICCertChainAO"), 1));
    63 
    64 	iIndex = -1;
    65 	iState = EAddCandidate;
    66 	TRequestStatus* status = &iStatus;
    67 	User::RequestComplete(status, KErrNone);
    68 	SetActive();
    69 	}
    70 
    71 CPKIXChainBuilder::CPKIXChainBuilder()
    72 : CActive(EPriorityNormal)
    73 	{
    74 	CActiveScheduler::Add(this);
    75 	}
    76 
    77 void CPKIXChainBuilder::ConstructL()
    78 	{
    79 	}
    80 
    81 TBool CPKIXChainBuilder::ResolveIssuersL(CArrayPtr<CX509Certificate>& aChain,
    82 										 const RPointerArray<CX509Certificate>& aCandidates) const
    83 	{
    84 	//*this function attempts to figure out which certificate in aCandidates is the issuer of
    85 	//the last cert in the aChain, and adds a *copy* of the best guess to aChain
    86 	//*it assumes that the names match already
    87 	//*if it establishes that none are any good it returns EFalse
    88 	TInt count = aCandidates.Count();
    89 	if (count == 0)
    90 		{
    91 		return EFalse;
    92 		}
    93 	if (count == 1)
    94 		{
    95 		CX509Certificate* cert = CX509Certificate::NewLC(*aCandidates[0]);
    96 		aChain.AppendL(cert);
    97 		(*iNumberOfCertsAdded)++;
    98 		CleanupStack::Pop(cert);
    99 		return ETrue;
   100 		}
   101 
   102 	const CX509Certificate* current = aChain[aChain.Count() - 1];
   103 			//1)  look for SKI/AKI to distinguish
   104 	const CX509CertExtension* akiExt = current->Extension(KAuthorityKeyId);
   105 	if (akiExt)
   106 		{
   107 		const CX509AuthorityKeyIdExt* aki = CX509AuthorityKeyIdExt::NewLC(akiExt->Data());
   108 		TPtrC8 authorityKeyId = aki->KeyId();
   109 		if (authorityKeyId != KNullDesC8)
   110 			{
   111 			for (TInt i = 0; i < count; i++)
   112 				{
   113 				const CX509CertExtension* skiExt = (aCandidates[i])->Extension(KSubjectKeyId);
   114 				if (skiExt)
   115 					{
   116 					const CX509SubjectKeyIdExt* ski = CX509SubjectKeyIdExt::NewLC(skiExt->Data());
   117 					if (authorityKeyId == ski->KeyId())
   118 						{
   119 						CX509Certificate* issuer = CX509Certificate::NewLC(*aCandidates[i]);
   120 						aChain.AppendL(issuer);
   121 						(*iNumberOfCertsAdded)++;
   122 						CleanupStack::Pop();//issuer
   123 						CleanupStack::PopAndDestroy(2);//aki, ski
   124 						return ETrue;
   125 						}
   126 					else
   127 						{
   128 						CleanupStack::PopAndDestroy();//ski
   129 						}
   130 					}
   131 				}
   132 			}
   133 		//ok, we haven't got a key ID for the issuer, so try for a serial number instead...
   134 		else
   135 			{
   136 			TPtrC8 authoritySerialNo = aki->AuthorityCertSerialNumber();
   137 			for (TInt i = 0; i < count; i++)
   138 				{
   139 				const CX509Certificate* candidate = aCandidates[i];
   140 				if (authoritySerialNo == candidate->SerialNumber())
   141 					{
   142 					CX509Certificate* issuer = CX509Certificate::NewLC(*candidate);
   143 					aChain.AppendL(issuer);
   144 					(*iNumberOfCertsAdded)++;
   145 					CleanupStack::Pop();//issuer
   146 					CleanupStack::PopAndDestroy();//aki
   147 					return ETrue;
   148 					}
   149 				}
   150 			}
   151 		CleanupStack::PopAndDestroy();//aki
   152 		}
   153 	
   154 	// If more then one subject matching candidates are found and they doesn't contain SKI/AKI,
   155 	// consider the most recently imported/added candidate as the issuer.
   156 	for(TInt index = count - 1; index >= 0; --index)
   157 		{
   158 		TTime currentTime;
   159 		// if secure time is not available then fall back to the insecure version.
   160 		if(currentTime.UniversalTimeSecure() == KErrNoSecureTime)
   161 			{
   162 			currentTime.UniversalTime();
   163 			}
   164 
   165 		CX509Certificate* cert = CX509Certificate::NewLC(*aCandidates[index]);
   166 		// SKI/AKI are optional in versions lower than 3. So, relax the candidate selection rules only for version 1 & 2
   167 		// If the recent candidate is not valid enough(cert expired), consider it's previous valid candidate.
   168 		if((cert->Version() < 3) && (cert->ValidityPeriod().Valid(currentTime)))
   169 			{				
   170 			aChain.AppendL(cert);
   171 			++(*iNumberOfCertsAdded);
   172 			CleanupStack::Pop(cert);
   173 			return ETrue;				
   174 			}
   175 		else
   176 			{
   177 			CleanupStack::PopAndDestroy(cert);
   178 			continue;
   179 			}			
   180 		}
   181 
   182 	return EFalse;
   183 	}
   184 
   185 
   186 void CPKIXChainBuilder::RunL()
   187 	{
   188 	User::LeaveIfError(iStatus.Int());
   189 
   190 	switch (iState)
   191 		{
   192 	case EAddCandidate:
   193 		iIndex++;
   194 		if (iIndex < iSources.Count())
   195 			{
   196 			iSources[iIndex]->CandidatesL(*iSubject, iCandidates, iStatus);
   197 			}
   198 		else
   199 			{
   200 			iState = EFinished;
   201 			TRequestStatus* status = &iStatus;
   202 			User::RequestComplete(status, KErrNone);
   203 			}
   204 		SetActive();
   205 		break;
   206 
   207 	case EFinished:
   208 		iState = EIdle;
   209 		*iResult = ResolveIssuersL(*iChain, iCandidates);
   210 		iCandidates.ResetAndDestroy();
   211 		User::RequestComplete(iOriginalRequestStatus, KErrNone);
   212 		break;
   213 
   214 	default:
   215 		User::Panic(_L("CPKIXChainBuilder"), 1);
   216 		break;
   217 		}
   218 	}
   219 
   220 void CPKIXChainBuilder::DoCancel()
   221 	{
   222 	int i = 0;
   223 	int end = iSources.Count();
   224 	while (i < end)
   225 		{
   226 		iSources[i]->CancelCandidates();
   227 		i++;
   228 		}
   229 	iCandidates.ResetAndDestroy();
   230 
   231 	User::RequestComplete(iOriginalRequestStatus, KErrCancel);
   232 
   233 	iState = EIdle;
   234 	}
   235 
   236 TInt CPKIXChainBuilder::RunError(TInt aError)
   237 	{
   238 	iState = EIdle;
   239 	iCandidates.ResetAndDestroy();
   240 	User::RequestComplete(iOriginalRequestStatus, aError);
   241 	return KErrNone;
   242 	}