1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/security/cryptoservices/certificateandkeymgmt/pkcs10/pkcs10.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,356 @@
1.4 +/*
1.5 +* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of the License "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +* Implements PKCS#10 certificate request class.
1.19 +*
1.20 +*/
1.21 +
1.22 +
1.23 +#include <pkcs10.h>
1.24 +#include <asn1enc.h>
1.25 +#include <e32std.h>
1.26 +#include <e32def.h>
1.27 +#include <x500dn.h>
1.28 +#include <x509keys.h>
1.29 +#include <hash.h>
1.30 +#include <pkcs10attr.h>
1.31 +#include "keyhelper.h"
1.32 +#include <mctkeystoreuids.h>
1.33 +
1.34 +void Panic(TInt aError)
1.35 + {
1.36 + _LIT(KCategory, "PKCS10");
1.37 + User::Panic(KCategory, aError);
1.38 + }
1.39 +
1.40 +// CPKCS10Request Class Implementation
1.41 +
1.42 +CPKCS10Request::CPKCS10Request(const CX500DistinguishedName* aDN,
1.43 + const CCTKeyInfo* aKeyInfo,
1.44 + CPKCS10Attributes* aAttr) :
1.45 + CActive(EPriorityNormal),
1.46 + iDN(aDN),
1.47 + iKeyInfo(aKeyInfo),
1.48 + iAttributes(aAttr),
1.49 + iDigestId(ESHA1)
1.50 + {
1.51 + CActiveScheduler::Add(this);
1.52 + }
1.53 +
1.54 +EXPORT_C CPKCS10Request* CPKCS10Request::NewLC(const CX500DistinguishedName& aDN,
1.55 + const CCTKeyInfo& aKeyInfo,
1.56 + CPKCS10Attributes* aAttr/* = NULL*/)
1.57 + {
1.58 + // Sanity Check the input parameters
1.59 + if (&aDN == NULL)
1.60 + {
1.61 + User::Leave(KErrArgument);
1.62 + }
1.63 +
1.64 + if (&aKeyInfo == NULL)
1.65 + {
1.66 + User::Leave(KErrArgument);
1.67 + }
1.68 +
1.69 + CPKCS10Request* self = new (ELeave) CPKCS10Request(&aDN, &aKeyInfo, aAttr);
1.70 + CleanupStack::PushL(self);
1.71 + return self;
1.72 + }
1.73 +
1.74 +EXPORT_C CPKCS10Request* CPKCS10Request::NewL(const CX500DistinguishedName& aDN,
1.75 + const CCTKeyInfo& aKeyInfo,
1.76 + CPKCS10Attributes* aAttr/* = NULL*/)
1.77 + {
1.78 + CPKCS10Request* self = NewLC(aDN, aKeyInfo, aAttr);
1.79 + CleanupStack::Pop(self);
1.80 + return self;
1.81 + }
1.82 +
1.83 +EXPORT_C CPKCS10Request::~CPKCS10Request()
1.84 + {
1.85 + Cancel();
1.86 + delete iAttributes;
1.87 + Reset();
1.88 + }
1.89 +
1.90 +void CPKCS10Request::Reset()
1.91 + {
1.92 + delete iExportedKey;
1.93 + iExportedKey = NULL;
1.94 + delete iTBSData;
1.95 + iTBSData = NULL;
1.96 + delete iKeyHelper;
1.97 + iKeyHelper = NULL;
1.98 + if (iKeyStore)
1.99 + {
1.100 + iKeyStore->Release();
1.101 + iKeyStore = NULL;
1.102 + }
1.103 + iState = EIdle;
1.104 + }
1.105 +
1.106 +EXPORT_C void CPKCS10Request::SetDistinguishedNameL(const CX500DistinguishedName& aDN)
1.107 + {
1.108 + // Sanity check
1.109 + if (&aDN == NULL)
1.110 + {
1.111 + User::Leave(KErrArgument);
1.112 + }
1.113 + iDN = &aDN;
1.114 + }
1.115 +
1.116 +EXPORT_C void CPKCS10Request::SetKeyInfoL(const CCTKeyInfo& aKeyInfo)
1.117 + {
1.118 + // Sanity check
1.119 + if (&aKeyInfo == NULL)
1.120 + {
1.121 + User::Leave(KErrArgument);
1.122 + }
1.123 + iKeyInfo = &aKeyInfo;
1.124 + }
1.125 +
1.126 +EXPORT_C void CPKCS10Request::SetAttributes(CPKCS10Attributes* aAttr)
1.127 + {
1.128 + delete iAttributes;
1.129 + iAttributes = aAttr;
1.130 + }
1.131 +
1.132 +EXPORT_C void CPKCS10Request::SetDigestAlgL(TAlgorithmId aDigestId)
1.133 + {
1.134 + if (aDigestId != EMD2 && aDigestId != EMD5 && aDigestId != ESHA1)
1.135 + {
1.136 + User::Leave(KErrArgument);
1.137 + }
1.138 + if (iKeyInfo->Algorithm() == CCTKeyInfo::EDSA && aDigestId != ESHA1)
1.139 + {
1.140 + User::Leave(KErrArgument);
1.141 + }
1.142 + iDigestId = aDigestId;
1.143 + }
1.144 +
1.145 +EXPORT_C void CPKCS10Request::CreateEncoding(HBufC8*& aResult, TRequestStatus& aStatus)
1.146 + {
1.147 + ASSERT(iState == EIdle);
1.148 + iClientStatus = &aStatus;
1.149 + iResult = &aResult;
1.150 + aResult = NULL;
1.151 + aStatus = KRequestPending;
1.152 + iState = EInitialize;
1.153 + SetActive();
1.154 + TRequestStatus* status = &iStatus;
1.155 + User::RequestComplete(status, KErrNone);
1.156 + }
1.157 +
1.158 +TInt CPKCS10Request::RunError(TInt aErr)
1.159 + {
1.160 + User::RequestComplete(iClientStatus, aErr);
1.161 + iState = EIdle;
1.162 + return KErrNone;
1.163 + }
1.164 +
1.165 +void CPKCS10Request::DoCancel()
1.166 + {
1.167 + switch (iState)
1.168 + {
1.169 + case EGetKeyStore:
1.170 + iKeyInfo->Token().CancelGetInterface();
1.171 + break;
1.172 +
1.173 + case EGetPublicKey:
1.174 + iKeyStore->CancelExportPublic();
1.175 + break;
1.176 +
1.177 + case EOpenSigner:
1.178 + iKeyHelper->CancelOpenSigner();
1.179 + break;
1.180 +
1.181 + case ESign:
1.182 + iKeyHelper->CancelSignDigest();
1.183 + break;
1.184 +
1.185 + default:
1.186 + // do nothing, keep compiler happy
1.187 + break;
1.188 + }
1.189 +
1.190 + if (iClientStatus)
1.191 + User::RequestComplete(iClientStatus, KErrCancel);
1.192 +
1.193 + iState = EIdle;
1.194 + }
1.195 +
1.196 +void CPKCS10Request::RunL()
1.197 + {
1.198 + User::LeaveIfError(iStatus.Int());
1.199 +
1.200 + switch (iState)
1.201 + {
1.202 + case EInitialize:
1.203 + // Get keystore interface
1.204 + if (iKeyStore)
1.205 + {
1.206 + iKeyStore->Release();
1.207 + iKeyStore = NULL;
1.208 + }
1.209 + iKeyInfo->Token().GetInterface(TUid::Uid(KInterfaceKeyStore),
1.210 + *reinterpret_cast<MCTTokenInterface**>(&iKeyStore),
1.211 + iStatus);
1.212 + iState = EGetKeyStore;
1.213 + SetActive();
1.214 + break;
1.215 +
1.216 + case EGetKeyStore:
1.217 + // Fetch the public key
1.218 + delete iExportedKey;
1.219 + iKeyStore->ExportPublic(*iKeyInfo, iExportedKey, iStatus);
1.220 + iState = EGetPublicKey;
1.221 + SetActive();
1.222 + break;
1.223 +
1.224 + case EGetPublicKey:
1.225 + // Create key helper object
1.226 + delete iKeyHelper;
1.227 + iKeyHelper = CPKCS10KeyHelper::CreateKeyHelperL(*iKeyStore, *iKeyInfo, *iExportedKey, iDigestId);
1.228 + EncodeTBSDataL();
1.229 +
1.230 + // Open signing object
1.231 + iKeyHelper->OpenSigner(iStatus);
1.232 + iState = EOpenSigner;
1.233 + SetActive();
1.234 + break;
1.235 +
1.236 + case EOpenSigner:
1.237 + // Create digest
1.238 + {
1.239 + CMessageDigest* digest = NULL;
1.240 + switch (iDigestId)
1.241 + {
1.242 + case EMD2:
1.243 + digest = CMD2::NewL();
1.244 + break;
1.245 + case EMD5:
1.246 + digest = CMD5::NewL();
1.247 + break;
1.248 + case ESHA1:
1.249 + digest = CSHA1::NewL();
1.250 + break;
1.251 + default:
1.252 + User::Invariant();
1.253 + }
1.254 + CleanupStack::PushL(digest);
1.255 +
1.256 + // Hash data and sign
1.257 + digest->Update(*iTBSData);
1.258 +
1.259 + iKeyHelper->SignDigestL(digest->Final(), iStatus);
1.260 + CleanupStack::PopAndDestroy(digest); // keystore copies data to be signed
1.261 + iState = ESign;
1.262 + SetActive();
1.263 + }
1.264 + break;
1.265 +
1.266 + case ESign:
1.267 + CreateFinalEncodingL();
1.268 + Reset();
1.269 + break;
1.270 +
1.271 + default:
1.272 + User::Invariant();
1.273 + }
1.274 + }
1.275 +
1.276 +CASN1EncBase* CPKCS10Request::MakeAttrEncLC()
1.277 + {
1.278 + if (iAttributes)
1.279 + {
1.280 + CASN1EncBase* result = iAttributes->TakeEncodingLC();
1.281 + delete iAttributes;
1.282 + iAttributes = NULL;
1.283 + return result;
1.284 + }
1.285 + else
1.286 + {
1.287 + CASN1EncSequence* contextSpecific = CASN1EncSequence::NewLC();
1.288 + contextSpecific->SetTag(0);
1.289 + return contextSpecific;
1.290 + }
1.291 + }
1.292 +
1.293 +CASN1EncSequence* CPKCS10Request::MakeCertRequestInfoEncLC()
1.294 + {
1.295 + // Top-level sequence contains distinguished name and other
1.296 + // stuff. This is what gets signed with the entity's private key.
1.297 + CASN1EncSequence* certRequestInfo = CASN1EncSequence::NewLC();
1.298 +
1.299 + // Encode version number, which is 0.
1.300 + CASN1EncInt* version = CASN1EncInt::NewLC(0);
1.301 + certRequestInfo->AddAndPopChildL(version);
1.302 +
1.303 + // Encode distinguished name.
1.304 + CASN1EncBase* distinguishedName = iDN->EncodeASN1LC();
1.305 + certRequestInfo->AddAndPopChildL(distinguishedName);
1.306 +
1.307 + // Encode SubjectPublicKeyInfo.
1.308 + CASN1EncBase* subjectPubKeyInfo = iKeyHelper->EncodeKeyLC();
1.309 + certRequestInfo->AddAndPopChildL(subjectPubKeyInfo);
1.310 +
1.311 + // Encode attributes, if any.
1.312 + CASN1EncBase* attr = MakeAttrEncLC();
1.313 + certRequestInfo->AddAndPopChildL(attr);
1.314 +
1.315 + return certRequestInfo;
1.316 + }
1.317 +
1.318 +void CPKCS10Request::EncodeTBSDataL()
1.319 + {
1.320 + // The data we provide for signing is the certRequestInfo object.
1.321 + CASN1EncBase* certRequestInfo = MakeCertRequestInfoEncLC();
1.322 + // Write DER of it to the buffer.
1.323 + delete iTBSData;
1.324 + iTBSData = HBufC8::NewMaxL(certRequestInfo->LengthDER());
1.325 + TPtr8 dataPtr = iTBSData->Des();
1.326 + TUint pos = 0;
1.327 + certRequestInfo->WriteDERL(dataPtr, pos);
1.328 + CleanupStack::PopAndDestroy(certRequestInfo);
1.329 + }
1.330 +
1.331 +void CPKCS10Request::CreateFinalEncodingL()
1.332 + {
1.333 + // the root sequence contains all other components of a X509 signed object
1.334 + CASN1EncSequence* root = CASN1EncSequence::NewLC();
1.335 +
1.336 + // wrap data to be signed in a sequence and add it to the root
1.337 + CASN1EncEncoding* encenc = CASN1EncEncoding::NewLC(*iTBSData);
1.338 + root->AddAndPopChildL(encenc);
1.339 +
1.340 + // encode signature algorithm and parameters and add them to the root
1.341 + CASN1EncSequence* sigalg = iKeyHelper->EncodeSignatureAlgorithmLC();
1.342 + root->AddAndPopChildL(sigalg);
1.343 +
1.344 + // Create ASN.1 bit string from the signature
1.345 + CASN1EncBitString* encSig = iKeyHelper->EncodeSignatureLC();
1.346 + root->AddAndPopChildL(encSig);
1.347 +
1.348 + // encode the object in a DER encoding
1.349 + HBufC8* der = HBufC8::NewMaxLC(root->LengthDER());
1.350 + TPtr8 pder(der->Des());
1.351 + TUint pos = 0;
1.352 + root->WriteDERL(pder, pos);
1.353 + CleanupStack::Pop(der);
1.354 + CleanupStack::PopAndDestroy(root);
1.355 +
1.356 + *iResult = der;
1.357 + User::RequestComplete(iClientStatus, KErrNone);
1.358 + }
1.359 +