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