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