os/security/cryptoservices/certificateandkeymgmt/pkcs10/pkcs10.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) 2002-2009 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
* Implements PKCS#10 certificate request class.
sl@0
    16
*
sl@0
    17
*/
sl@0
    18
sl@0
    19
sl@0
    20
#include <pkcs10.h>
sl@0
    21
#include <asn1enc.h>
sl@0
    22
#include <e32std.h>
sl@0
    23
#include <e32def.h>
sl@0
    24
#include <x500dn.h>
sl@0
    25
#include <x509keys.h>
sl@0
    26
#include <hash.h>
sl@0
    27
#include <pkcs10attr.h>
sl@0
    28
#include "keyhelper.h"
sl@0
    29
#include <mctkeystoreuids.h>
sl@0
    30
sl@0
    31
void Panic(TInt aError)
sl@0
    32
	{
sl@0
    33
	_LIT(KCategory, "PKCS10");
sl@0
    34
	User::Panic(KCategory, aError);
sl@0
    35
	}
sl@0
    36
sl@0
    37
// CPKCS10Request Class Implementation
sl@0
    38
sl@0
    39
CPKCS10Request::CPKCS10Request(const CX500DistinguishedName* aDN,
sl@0
    40
							   const CCTKeyInfo* aKeyInfo,
sl@0
    41
							   CPKCS10Attributes* aAttr) :
sl@0
    42
	CActive(EPriorityNormal),
sl@0
    43
	iDN(aDN),
sl@0
    44
	iKeyInfo(aKeyInfo),
sl@0
    45
	iAttributes(aAttr),
sl@0
    46
	iDigestId(ESHA1)
sl@0
    47
	{
sl@0
    48
	CActiveScheduler::Add(this);
sl@0
    49
	}
sl@0
    50
sl@0
    51
EXPORT_C CPKCS10Request* CPKCS10Request::NewLC(const CX500DistinguishedName& aDN,
sl@0
    52
											   const CCTKeyInfo& aKeyInfo,
sl@0
    53
											   CPKCS10Attributes* aAttr/* = NULL*/)
sl@0
    54
	{
sl@0
    55
	// Sanity Check the input parameters
sl@0
    56
	if (&aDN == NULL)
sl@0
    57
		{
sl@0
    58
		User::Leave(KErrArgument);
sl@0
    59
		}
sl@0
    60
sl@0
    61
	if (&aKeyInfo == NULL)
sl@0
    62
		{
sl@0
    63
		User::Leave(KErrArgument);
sl@0
    64
		}
sl@0
    65
sl@0
    66
	CPKCS10Request* self = new (ELeave) CPKCS10Request(&aDN, &aKeyInfo, aAttr);
sl@0
    67
	CleanupStack::PushL(self);
sl@0
    68
	return self;
sl@0
    69
	}
sl@0
    70
sl@0
    71
EXPORT_C CPKCS10Request* CPKCS10Request::NewL(const CX500DistinguishedName& aDN,
sl@0
    72
											  const CCTKeyInfo& aKeyInfo,
sl@0
    73
											  CPKCS10Attributes* aAttr/* = NULL*/)
sl@0
    74
	{
sl@0
    75
	CPKCS10Request* self = NewLC(aDN, aKeyInfo, aAttr);
sl@0
    76
	CleanupStack::Pop(self);
sl@0
    77
	return self;
sl@0
    78
	}
sl@0
    79
sl@0
    80
EXPORT_C CPKCS10Request::~CPKCS10Request()
sl@0
    81
	{
sl@0
    82
	Cancel();
sl@0
    83
	delete iAttributes;
sl@0
    84
	Reset();
sl@0
    85
	}
sl@0
    86
sl@0
    87
void CPKCS10Request::Reset()
sl@0
    88
	{
sl@0
    89
	delete iExportedKey;
sl@0
    90
	iExportedKey = NULL;
sl@0
    91
	delete iTBSData;
sl@0
    92
	iTBSData = NULL;
sl@0
    93
	delete iKeyHelper;
sl@0
    94
	iKeyHelper = NULL;
sl@0
    95
	if (iKeyStore)
sl@0
    96
		{
sl@0
    97
		iKeyStore->Release();
sl@0
    98
		iKeyStore = NULL;
sl@0
    99
		}
sl@0
   100
	iState = EIdle;
sl@0
   101
	}
sl@0
   102
sl@0
   103
EXPORT_C void CPKCS10Request::SetDistinguishedNameL(const CX500DistinguishedName& aDN)
sl@0
   104
	{
sl@0
   105
	// Sanity check
sl@0
   106
	if (&aDN == NULL)
sl@0
   107
		{
sl@0
   108
		User::Leave(KErrArgument);
sl@0
   109
		}
sl@0
   110
	iDN = &aDN;
sl@0
   111
	}
sl@0
   112
sl@0
   113
EXPORT_C void CPKCS10Request::SetKeyInfoL(const CCTKeyInfo& aKeyInfo)
sl@0
   114
	{
sl@0
   115
	// Sanity check
sl@0
   116
	if (&aKeyInfo == NULL)
sl@0
   117
		{
sl@0
   118
		User::Leave(KErrArgument);
sl@0
   119
		}
sl@0
   120
	iKeyInfo = &aKeyInfo;
sl@0
   121
	}
sl@0
   122
sl@0
   123
EXPORT_C void CPKCS10Request::SetAttributes(CPKCS10Attributes* aAttr)
sl@0
   124
	{
sl@0
   125
	delete iAttributes;
sl@0
   126
	iAttributes = aAttr;
sl@0
   127
	}
sl@0
   128
sl@0
   129
EXPORT_C void CPKCS10Request::SetDigestAlgL(TAlgorithmId aDigestId)
sl@0
   130
	{
sl@0
   131
	if (aDigestId != EMD2 && aDigestId != EMD5 && aDigestId != ESHA1)
sl@0
   132
		{
sl@0
   133
		User::Leave(KErrArgument);
sl@0
   134
		}
sl@0
   135
	if (iKeyInfo->Algorithm() == CCTKeyInfo::EDSA && aDigestId != ESHA1)
sl@0
   136
		{
sl@0
   137
		User::Leave(KErrArgument);
sl@0
   138
		}
sl@0
   139
	iDigestId = aDigestId;
sl@0
   140
	}
sl@0
   141
sl@0
   142
EXPORT_C void CPKCS10Request::CreateEncoding(HBufC8*& aResult, TRequestStatus& aStatus)
sl@0
   143
	{
sl@0
   144
	ASSERT(iState == EIdle);	
sl@0
   145
	iClientStatus = &aStatus;
sl@0
   146
	iResult = &aResult;
sl@0
   147
	aResult = NULL;	
sl@0
   148
	aStatus = KRequestPending;
sl@0
   149
	iState = EInitialize;
sl@0
   150
	SetActive();
sl@0
   151
	TRequestStatus* status = &iStatus;
sl@0
   152
	User::RequestComplete(status, KErrNone);
sl@0
   153
	}
sl@0
   154
sl@0
   155
TInt CPKCS10Request::RunError(TInt aErr)
sl@0
   156
	{
sl@0
   157
    User::RequestComplete(iClientStatus, aErr);
sl@0
   158
	iState = EIdle;
sl@0
   159
    return KErrNone;
sl@0
   160
	}
sl@0
   161
sl@0
   162
void CPKCS10Request::DoCancel()
sl@0
   163
	{
sl@0
   164
	switch (iState)
sl@0
   165
		{
sl@0
   166
		case EGetKeyStore:
sl@0
   167
			iKeyInfo->Token().CancelGetInterface();
sl@0
   168
			break;
sl@0
   169
sl@0
   170
		case EGetPublicKey:
sl@0
   171
			iKeyStore->CancelExportPublic();
sl@0
   172
			break;
sl@0
   173
sl@0
   174
		case EOpenSigner:
sl@0
   175
			iKeyHelper->CancelOpenSigner();
sl@0
   176
			break;
sl@0
   177
sl@0
   178
		case ESign:
sl@0
   179
			iKeyHelper->CancelSignDigest();
sl@0
   180
			break;
sl@0
   181
sl@0
   182
		default:
sl@0
   183
			// do nothing, keep compiler happy
sl@0
   184
			break;			
sl@0
   185
		}
sl@0
   186
	
sl@0
   187
	if (iClientStatus)
sl@0
   188
		User::RequestComplete(iClientStatus, KErrCancel);
sl@0
   189
sl@0
   190
	iState = EIdle;
sl@0
   191
	}	
sl@0
   192
sl@0
   193
void CPKCS10Request::RunL()
sl@0
   194
	{
sl@0
   195
	User::LeaveIfError(iStatus.Int());
sl@0
   196
sl@0
   197
	switch (iState)
sl@0
   198
		{
sl@0
   199
		case EInitialize:
sl@0
   200
			// Get keystore interface
sl@0
   201
			if (iKeyStore)
sl@0
   202
				{
sl@0
   203
				iKeyStore->Release();
sl@0
   204
				iKeyStore = NULL;
sl@0
   205
				}
sl@0
   206
			iKeyInfo->Token().GetInterface(TUid::Uid(KInterfaceKeyStore),
sl@0
   207
										  *reinterpret_cast<MCTTokenInterface**>(&iKeyStore),
sl@0
   208
										  iStatus);
sl@0
   209
			iState = EGetKeyStore;
sl@0
   210
			SetActive();
sl@0
   211
			break;
sl@0
   212
sl@0
   213
		case EGetKeyStore:
sl@0
   214
			// Fetch the public key
sl@0
   215
			delete iExportedKey;
sl@0
   216
			iKeyStore->ExportPublic(*iKeyInfo, iExportedKey, iStatus);
sl@0
   217
			iState = EGetPublicKey;
sl@0
   218
			SetActive();
sl@0
   219
			break;
sl@0
   220
sl@0
   221
		case EGetPublicKey:
sl@0
   222
			// Create key helper object
sl@0
   223
			delete iKeyHelper;
sl@0
   224
			iKeyHelper = CPKCS10KeyHelper::CreateKeyHelperL(*iKeyStore, *iKeyInfo, *iExportedKey, iDigestId);
sl@0
   225
			EncodeTBSDataL();
sl@0
   226
sl@0
   227
			// Open signing object
sl@0
   228
			iKeyHelper->OpenSigner(iStatus);
sl@0
   229
			iState = EOpenSigner;
sl@0
   230
			SetActive();
sl@0
   231
			break;
sl@0
   232
sl@0
   233
		case EOpenSigner:
sl@0
   234
			// Create digest
sl@0
   235
			{
sl@0
   236
			CMessageDigest* digest = NULL;
sl@0
   237
			switch (iDigestId)
sl@0
   238
				{
sl@0
   239
				case EMD2:
sl@0
   240
					digest = CMD2::NewL();
sl@0
   241
					break;
sl@0
   242
				case EMD5:
sl@0
   243
					digest = CMD5::NewL();
sl@0
   244
					break;
sl@0
   245
				case ESHA1:
sl@0
   246
					digest = CSHA1::NewL();
sl@0
   247
					break;
sl@0
   248
				default:
sl@0
   249
					User::Invariant();
sl@0
   250
				}
sl@0
   251
			CleanupStack::PushL(digest);
sl@0
   252
sl@0
   253
			// Hash data and sign
sl@0
   254
			digest->Update(*iTBSData);
sl@0
   255
			
sl@0
   256
			iKeyHelper->SignDigestL(digest->Final(), iStatus);
sl@0
   257
			CleanupStack::PopAndDestroy(digest); // keystore copies data to be signed
sl@0
   258
			iState = ESign;
sl@0
   259
			SetActive();
sl@0
   260
			}
sl@0
   261
			break;
sl@0
   262
sl@0
   263
		case ESign:
sl@0
   264
			CreateFinalEncodingL();
sl@0
   265
			Reset();
sl@0
   266
			break;
sl@0
   267
		
sl@0
   268
		default:
sl@0
   269
			User::Invariant();
sl@0
   270
		}
sl@0
   271
	}
sl@0
   272
sl@0
   273
CASN1EncBase* CPKCS10Request::MakeAttrEncLC() 
sl@0
   274
	{
sl@0
   275
	if (iAttributes)
sl@0
   276
		{
sl@0
   277
		CASN1EncBase* result = iAttributes->TakeEncodingLC();
sl@0
   278
		delete iAttributes;
sl@0
   279
		iAttributes = NULL;
sl@0
   280
		return result;
sl@0
   281
		}
sl@0
   282
	else
sl@0
   283
		{
sl@0
   284
		CASN1EncSequence* contextSpecific = CASN1EncSequence::NewLC();
sl@0
   285
		contextSpecific->SetTag(0);
sl@0
   286
		return contextSpecific;
sl@0
   287
		}
sl@0
   288
	}
sl@0
   289
sl@0
   290
CASN1EncSequence* CPKCS10Request::MakeCertRequestInfoEncLC()
sl@0
   291
	{
sl@0
   292
	// Top-level sequence contains distinguished name and other 
sl@0
   293
	// stuff. This is what gets signed with the entity's private key.
sl@0
   294
	CASN1EncSequence* certRequestInfo = CASN1EncSequence::NewLC();
sl@0
   295
sl@0
   296
	// Encode version number, which is 0.
sl@0
   297
	CASN1EncInt* version = CASN1EncInt::NewLC(0);
sl@0
   298
	certRequestInfo->AddAndPopChildL(version);
sl@0
   299
sl@0
   300
	// Encode distinguished name.
sl@0
   301
	CASN1EncBase* distinguishedName = iDN->EncodeASN1LC();
sl@0
   302
	certRequestInfo->AddAndPopChildL(distinguishedName);
sl@0
   303
sl@0
   304
	// Encode SubjectPublicKeyInfo.
sl@0
   305
	CASN1EncBase* subjectPubKeyInfo = iKeyHelper->EncodeKeyLC();
sl@0
   306
	certRequestInfo->AddAndPopChildL(subjectPubKeyInfo);
sl@0
   307
sl@0
   308
	// Encode attributes, if any.
sl@0
   309
	CASN1EncBase* attr = MakeAttrEncLC();
sl@0
   310
	certRequestInfo->AddAndPopChildL(attr);
sl@0
   311
sl@0
   312
	return certRequestInfo;
sl@0
   313
	}
sl@0
   314
sl@0
   315
void CPKCS10Request::EncodeTBSDataL() 
sl@0
   316
	{
sl@0
   317
	// The data we provide for signing is the certRequestInfo object.
sl@0
   318
	CASN1EncBase* certRequestInfo = MakeCertRequestInfoEncLC();
sl@0
   319
	// Write DER of it to the buffer.
sl@0
   320
	delete iTBSData;
sl@0
   321
	iTBSData = HBufC8::NewMaxL(certRequestInfo->LengthDER());
sl@0
   322
	TPtr8 dataPtr = iTBSData->Des();
sl@0
   323
	TUint pos = 0;
sl@0
   324
	certRequestInfo->WriteDERL(dataPtr, pos);
sl@0
   325
	CleanupStack::PopAndDestroy(certRequestInfo);
sl@0
   326
	}
sl@0
   327
sl@0
   328
void CPKCS10Request::CreateFinalEncodingL()
sl@0
   329
	{
sl@0
   330
	// the root sequence contains all other components of a X509 signed object
sl@0
   331
	CASN1EncSequence* root = CASN1EncSequence::NewLC();
sl@0
   332
sl@0
   333
	// wrap data to be signed in a sequence and add it to the root
sl@0
   334
	CASN1EncEncoding* encenc = CASN1EncEncoding::NewLC(*iTBSData);
sl@0
   335
	root->AddAndPopChildL(encenc);
sl@0
   336
sl@0
   337
	// encode signature algorithm and  parameters and add them to the root
sl@0
   338
	CASN1EncSequence* sigalg = iKeyHelper->EncodeSignatureAlgorithmLC();
sl@0
   339
	root->AddAndPopChildL(sigalg);
sl@0
   340
sl@0
   341
	// Create ASN.1 bit string from the signature 
sl@0
   342
	CASN1EncBitString* encSig = iKeyHelper->EncodeSignatureLC();
sl@0
   343
	root->AddAndPopChildL(encSig);
sl@0
   344
sl@0
   345
	// encode the object in a DER encoding
sl@0
   346
	HBufC8* der = HBufC8::NewMaxLC(root->LengthDER());
sl@0
   347
	TPtr8 pder(der->Des());
sl@0
   348
	TUint pos = 0;
sl@0
   349
	root->WriteDERL(pder, pos);
sl@0
   350
	CleanupStack::Pop(der);
sl@0
   351
	CleanupStack::PopAndDestroy(root);
sl@0
   352
sl@0
   353
	*iResult = der;
sl@0
   354
	User::RequestComplete(iClientStatus, KErrNone);
sl@0
   355
	}
sl@0
   356