cryptoservices/certificateandkeymgmt/pkcs10/pkcs10.cpp
changeset 0 2c201484c85f
child 8 35751d3474b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptoservices/certificateandkeymgmt/pkcs10/pkcs10.cpp	Wed Jul 08 11:25:26 2009 +0100
@@ -0,0 +1,354 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* Implements PKCS#10 certificate request class.
+*
+*/
+
+
+#include <pkcs10.h>
+#include <asn1enc.h>
+#include <e32std.h>
+#include <e32def.h>
+#include <x500dn.h>
+#include <x509keys.h>
+#include <hash.h>
+#include <pkcs10attr.h>
+#include "keyhelper.h"
+
+void Panic(TInt aError)
+	{
+	_LIT(KCategory, "PKCS10");
+	User::Panic(KCategory, aError);
+	}
+
+// CPKCS10Request Class Implementation
+
+CPKCS10Request::CPKCS10Request(const CX500DistinguishedName* aDN,
+							   const CCTKeyInfo* aKeyInfo,
+							   CPKCS10Attributes* aAttr) :
+	CActive(EPriorityNormal),
+	iDN(aDN),
+	iKeyInfo(aKeyInfo),
+	iAttributes(aAttr),
+	iDigestId(ESHA1)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+EXPORT_C CPKCS10Request* CPKCS10Request::NewLC(const CX500DistinguishedName& aDN,
+											   const CCTKeyInfo& aKeyInfo,
+											   CPKCS10Attributes* aAttr/* = NULL*/)
+	{
+	// Sanity Check the input parameters
+	if (&aDN == NULL)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	if (&aKeyInfo == NULL)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	CPKCS10Request* self = new (ELeave) CPKCS10Request(&aDN, &aKeyInfo, aAttr);
+	CleanupStack::PushL(self);
+	return self;
+	}
+
+EXPORT_C CPKCS10Request* CPKCS10Request::NewL(const CX500DistinguishedName& aDN,
+											  const CCTKeyInfo& aKeyInfo,
+											  CPKCS10Attributes* aAttr/* = NULL*/)
+	{
+	CPKCS10Request* self = NewLC(aDN, aKeyInfo, aAttr);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+EXPORT_C CPKCS10Request::~CPKCS10Request()
+	{
+	Cancel();
+	delete iAttributes;
+	Reset();
+	}
+
+void CPKCS10Request::Reset()
+	{
+	delete iExportedKey;
+	iExportedKey = NULL;
+	delete iTBSData;
+	iTBSData = NULL;
+	delete iKeyHelper;
+	iKeyHelper = NULL;
+	if (iKeyStore)
+		{
+		iKeyStore->Release();
+		iKeyStore = NULL;
+		}
+	iState = EIdle;
+	}
+
+EXPORT_C void CPKCS10Request::SetDistinguishedNameL(const CX500DistinguishedName& aDN)
+	{
+	// Sanity check
+	if (&aDN == NULL)
+		{
+		User::Leave(KErrArgument);
+		}
+	iDN = &aDN;
+	}
+
+EXPORT_C void CPKCS10Request::SetKeyInfoL(const CCTKeyInfo& aKeyInfo)
+	{
+	// Sanity check
+	if (&aKeyInfo == NULL)
+		{
+		User::Leave(KErrArgument);
+		}
+	iKeyInfo = &aKeyInfo;
+	}
+
+EXPORT_C void CPKCS10Request::SetAttributes(CPKCS10Attributes* aAttr)
+	{
+	delete iAttributes;
+	iAttributes = aAttr;
+	}
+
+EXPORT_C void CPKCS10Request::SetDigestAlgL(TAlgorithmId aDigestId)
+	{
+	if (aDigestId != EMD2 && aDigestId != EMD5 && aDigestId != ESHA1)
+		{
+		User::Leave(KErrArgument);
+		}
+	if (iKeyInfo->Algorithm() == CCTKeyInfo::EDSA && aDigestId != ESHA1)
+		{
+		User::Leave(KErrArgument);
+		}
+	iDigestId = aDigestId;
+	}
+
+EXPORT_C void CPKCS10Request::CreateEncoding(HBufC8*& aResult, TRequestStatus& aStatus)
+	{
+	ASSERT(iState == EIdle);	
+	iClientStatus = &aStatus;
+	iResult = &aResult;
+	aResult = NULL;	
+	aStatus = KRequestPending;
+	iState = EInitialize;
+	SetActive();
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	}
+
+TInt CPKCS10Request::RunError(TInt aErr)
+	{
+    User::RequestComplete(iClientStatus, aErr);
+	iState = EIdle;
+    return KErrNone;
+	}
+
+void CPKCS10Request::DoCancel()
+	{
+	switch (iState)
+		{
+		case EGetKeyStore:
+			iKeyInfo->Token().CancelGetInterface();
+			break;
+
+		case EGetPublicKey:
+			iKeyStore->CancelExportPublic();
+			break;
+
+		case EOpenSigner:
+			iKeyHelper->CancelOpenSigner();
+			break;
+
+		case ESign:
+			iKeyHelper->CancelSignDigest();
+			break;
+
+		default:
+			// do nothing, keep compiler happy
+			break;			
+		}
+	
+	if (iClientStatus)
+		User::RequestComplete(iClientStatus, KErrCancel);
+
+	iState = EIdle;
+	}	
+
+void CPKCS10Request::RunL()
+	{
+	User::LeaveIfError(iStatus.Int());
+
+	switch (iState)
+		{
+		case EInitialize:
+			// Get keystore interface
+			if (iKeyStore)
+				{
+				iKeyStore->Release();
+				iKeyStore = NULL;
+				}
+			iKeyInfo->Token().GetInterface(TUid::Uid(KInterfaceKeyStore),
+										  *reinterpret_cast<MCTTokenInterface**>(&iKeyStore),
+										  iStatus);
+			iState = EGetKeyStore;
+			SetActive();
+			break;
+
+		case EGetKeyStore:
+			// Fetch the public key
+			delete iExportedKey;
+			iKeyStore->ExportPublic(*iKeyInfo, iExportedKey, iStatus);
+			iState = EGetPublicKey;
+			SetActive();
+			break;
+
+		case EGetPublicKey:
+			// Create key helper object
+			delete iKeyHelper;
+			iKeyHelper = CPKCS10KeyHelper::CreateKeyHelperL(*iKeyStore, *iKeyInfo, *iExportedKey, iDigestId);
+			EncodeTBSDataL();
+
+			// Open signing object
+			iKeyHelper->OpenSigner(iStatus);
+			iState = EOpenSigner;
+			SetActive();
+			break;
+
+		case EOpenSigner:
+			// Create digest
+			{
+			CMessageDigest* digest = NULL;
+			switch (iDigestId)
+				{
+				case EMD2:
+					digest = CMD2::NewL();
+					break;
+				case EMD5:
+					digest = CMD5::NewL();
+					break;
+				case ESHA1:
+					digest = CSHA1::NewL();
+					break;
+				default:
+					User::Invariant();
+				}
+			CleanupStack::PushL(digest);
+
+			// Hash data and sign
+			digest->Update(*iTBSData);
+			
+			iKeyHelper->SignDigestL(digest->Final(), iStatus);
+			CleanupStack::PopAndDestroy(digest); // keystore copies data to be signed
+			iState = ESign;
+			SetActive();
+			}
+			break;
+
+		case ESign:
+			CreateFinalEncodingL();
+			Reset();
+			break;
+		
+		default:
+			User::Invariant();
+		}
+	}
+
+CASN1EncBase* CPKCS10Request::MakeAttrEncLC() 
+	{
+	if (iAttributes)
+		{
+		CASN1EncBase* result = iAttributes->TakeEncodingLC();
+		delete iAttributes;
+		iAttributes = NULL;
+		return result;
+		}
+	else
+		{
+		CASN1EncSequence* contextSpecific = CASN1EncSequence::NewLC();
+		contextSpecific->SetTag(0);
+		return contextSpecific;
+		}
+	}
+
+CASN1EncSequence* CPKCS10Request::MakeCertRequestInfoEncLC()
+	{
+	// Top-level sequence contains distinguished name and other 
+	// stuff. This is what gets signed with the entity's private key.
+	CASN1EncSequence* certRequestInfo = CASN1EncSequence::NewLC();
+
+	// Encode version number, which is 0.
+	CASN1EncInt* version = CASN1EncInt::NewLC(0);
+	certRequestInfo->AddAndPopChildL(version);
+
+	// Encode distinguished name.
+	CASN1EncBase* distinguishedName = iDN->EncodeASN1LC();
+	certRequestInfo->AddAndPopChildL(distinguishedName);
+
+	// Encode SubjectPublicKeyInfo.
+	CASN1EncBase* subjectPubKeyInfo = iKeyHelper->EncodeKeyLC();
+	certRequestInfo->AddAndPopChildL(subjectPubKeyInfo);
+
+	// Encode attributes, if any.
+	CASN1EncBase* attr = MakeAttrEncLC();
+	certRequestInfo->AddAndPopChildL(attr);
+
+	return certRequestInfo;
+	}
+
+void CPKCS10Request::EncodeTBSDataL() 
+	{
+	// The data we provide for signing is the certRequestInfo object.
+	CASN1EncBase* certRequestInfo = MakeCertRequestInfoEncLC();
+	// Write DER of it to the buffer.
+	delete iTBSData;
+	iTBSData = HBufC8::NewMaxL(certRequestInfo->LengthDER());
+	TPtr8 dataPtr = iTBSData->Des();
+	TUint pos = 0;
+	certRequestInfo->WriteDERL(dataPtr, pos);
+	CleanupStack::PopAndDestroy(certRequestInfo);
+	}
+
+void CPKCS10Request::CreateFinalEncodingL()
+	{
+	// the root sequence contains all other components of a X509 signed object
+	CASN1EncSequence* root = CASN1EncSequence::NewLC();
+
+	// wrap data to be signed in a sequence and add it to the root
+	CASN1EncEncoding* encenc = CASN1EncEncoding::NewLC(*iTBSData);
+	root->AddAndPopChildL(encenc);
+
+	// encode signature algorithm and  parameters and add them to the root
+	CASN1EncSequence* sigalg = iKeyHelper->EncodeSignatureAlgorithmLC();
+	root->AddAndPopChildL(sigalg);
+
+	// Create ASN.1 bit string from the signature 
+	CASN1EncBitString* encSig = iKeyHelper->EncodeSignatureLC();
+	root->AddAndPopChildL(encSig);
+
+	// encode the object in a DER encoding
+	HBufC8* der = HBufC8::NewMaxLC(root->LengthDER());
+	TPtr8 pder(der->Des());
+	TUint pos = 0;
+	root->WriteDERL(pder, pos);
+	CleanupStack::Pop(der);
+	CleanupStack::PopAndDestroy(root);
+
+	*iResult = der;
+	User::RequestComplete(iClientStatus, KErrNone);
+	}