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