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