Update contrib.
2 * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
25 #include <keyidentifierutil.h>
27 /*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeDERL(const TDesC8& aBinaryData)
29 return (CDecPKCS8Data::NewL(aBinaryData));
33 EncryptedPrivateKeyInfo ::= SEQUENCE {
34 encryptionAlgorithm EncryptionAlgorithmIdentifier,
35 encryptedData EncryptedData }
36 EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
37 EncryptedData ::= OCTET STRING
40 /*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeEncryptedDERL(const TDesC8& aBinaryData, const TDesC8& aPassword)
42 TASN1DecGeneric seqGen(aBinaryData);
44 if (seqGen.Tag() != EASN1Sequence)
46 User::Leave(KErrArgument);
50 CArrayPtrFlat<TASN1DecGeneric>* theData = dec.DecodeDERLC(seqGen);
52 TInt count = theData->Count();
53 if (seqIndex >= count)
55 User::Leave(KErrArgument);
58 // Get the first part of the sequence -> PKCS5 data
59 TASN1DecGeneric* pkcs5 = theData->operator[](seqIndex);
60 TPtrC8 theContent(pkcs5->Encoding()); // expect this to be a sequence
61 CPBEncryptParms* encryptParams = TASN1DecPKCS5::DecodeDERL(theContent);
62 CleanupStack::PushL(encryptParams);
64 // Create the decryptor
65 CPBEncryptElement* encryptElement = CPBEncryptElement::NewLC(aPassword, *encryptParams);
66 CPBDecryptor* decryptor = encryptElement->NewDecryptLC();
67 // Decrypt the final part of the sequence -> encrypted PKCS8 object
68 TASN1DecGeneric* pkcs8 = theData->operator[](count-1);
69 if (pkcs8->Tag() != EASN1OctetString)
71 User::Leave(KErrArgument);
73 TPtrC8 encryptedKey(pkcs8->GetContentDER());
74 TUint encryptLength = encryptedKey.Length();
75 TUint maxDecryptLength = decryptor->MaxOutputLength(encryptLength);
76 if (maxDecryptLength<=0)
78 User::Leave(KErrGeneral);
81 HBufC8* decryptOutput = HBufC8::NewLC(encryptLength);
82 TPtr8 decryptOutputPtr(decryptOutput->Des());
83 decryptOutputPtr.FillZ();
84 decryptor->Process(encryptedKey, decryptOutputPtr);
86 CDecPKCS8Data* pkcs8Data = CDecPKCS8Data::NewL(decryptOutputPtr);
88 // decryptOutput decryptor encryptElement
89 // encryptParams theData
90 CleanupStack::PopAndDestroy(5, theData);
96 Sample cleartext pkcs8 data from pkcs8dsa.001:
99 30 Tag: Constructed sequence
100 81 c8 Length (may be one or more bytes)
108 30 Tag: Constructed sequence
109 81 a9 Length (may be one or more bytes)
115 Value: dsa (1 2 840 10040 4 1)
118 _LIT8(KPKCS8DataVersion0, "\x02\x01\x00");
119 _LIT8(KPKCS8DataOIDDSA, "\x06\x07\x2a\x86\x48\xce\x38\x04\x01");
120 _LIT8(KPKCS8DataOIDRSA, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01");
122 /*static*/ EXPORT_C TBool TASN1DecPKCS8::IsPKCS8Data(const TDesC8& aBinaryData)
124 // We don't decode the data because we may only have the first few bytes -
125 // instead we check the ASN1 by hand.
127 ASSERT(aBinaryData.Length() >= KIsPKCS8DataMinLength);
131 IsASN1Sequence(aBinaryData, pos) &&
132 IsExpectedData(aBinaryData, pos, KPKCS8DataVersion0) &&
133 IsASN1Sequence(aBinaryData, pos) &&
134 (IsExpectedData(aBinaryData, pos, KPKCS8DataOIDDSA) ||
135 IsExpectedData(aBinaryData, pos, KPKCS8DataOIDRSA));
139 Sample encrypted pkcs8 data from encryptPK8rsa1.txt
142 30 Tag: Constructed sequence
143 82 01 a3 Length (may be one or more bytes)
146 30 Tag: Constructed sequence
147 3d Length (may be one or more bytes)
152 2a 86 48 86 f7 0d 01 05 0d
153 Value: pkcs5PBES2 (1 2 840 113549 1 5 13)
156 30 Tag: Constructed sequence
157 30 Length (may be one or more bytes)
160 30 Tag: Constructed sequence
161 1b Length (may be one or more bytes)
166 2a 86 48 86 f7 0d 01 05 0c
167 Value: pkcs5PBKDF2 (1 2 840 113549 1 5 12)
170 _LIT8(KEncryptedPKCS8DataOIDpkcs5PBES2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0d");
171 _LIT8(KEncryptedPKCS8DataOIDpkcs5PBKDF2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c");
173 EXPORT_C TBool TASN1DecPKCS8::IsEncryptedPKCS8Data(const TDesC8& aBinaryData)
175 // We don't decode the data because we may only have the first few bytes -
176 // instead we check the ASN1 by hand.
178 ASSERT(aBinaryData.Length() >= KIsEncryptedPKCS8DataMinLength);
182 IsASN1Sequence(aBinaryData, pos) &&
183 IsASN1Sequence(aBinaryData, pos) &&
184 IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBES2) &&
185 IsASN1Sequence(aBinaryData, pos) &&
186 IsASN1Sequence(aBinaryData, pos) &&
187 IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBKDF2);
191 * Determine if the some data represents the start of an ASN1 sequence. The
192 * data is specified by a descriptor and an offset. If the data matches, the
193 * offset is advanced to point to the contents of the sequence.
195 TBool TASN1DecPKCS8::IsASN1Sequence(const TDesC8& aBinaryData, TInt& aPos)
197 // Check we have enough data
198 if ((aPos + 2) >= aBinaryData.Length())
202 // Check the outermost sequence is valid
203 if (aBinaryData[aPos++] != 0x30 /* constructed sequence */)
207 // Skip sequence length
208 TInt length0 = aBinaryData[aPos++];
211 aPos += length0 & 0x7f;
217 * Determine if some data starts with an expected string. The data is specified
218 * by a descriptor and an offset. If the data matches, the offset is advanced
219 * to point after the match.
221 TBool TASN1DecPKCS8::IsExpectedData(const TDesC8& aBinaryData, TInt& aPos, const TDesC8& aExpectedData)
223 TInt length = aExpectedData.Length();
224 // Check we have enough data
225 if (aPos + length >= aBinaryData.Length())
229 // Check data matches
230 if (aBinaryData.Mid(aPos, length) != aExpectedData)
238 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\
239 // PKCS#8 object data representation
240 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\
242 /*static*/ CDecPKCS8Data* CDecPKCS8Data::NewL(const TDesC8& aData)
244 CDecPKCS8Data* me = new (ELeave) CDecPKCS8Data();
245 CleanupStack::PushL(me);
246 me->ConstructL(aData);
247 CleanupStack::Pop(me);
251 CDecPKCS8Data::CDecPKCS8Data()
254 CDecPKCS8Data::~CDecPKCS8Data()
258 iKeyPairData->Release();
269 // Because this is part of construction, don't rely on
270 // cleanup of partially constructed items...
271 void CDecPKCS8Data::ConstructL(const TDesC8& aData)
273 TASN1DecGeneric seqGen(aData);
275 if (seqGen.Tag() != EASN1Sequence)
277 User::Leave(KErrArgument);
280 TASN1DecSequence seq;
281 CArrayPtrFlat<TASN1DecGeneric>* seqContents = seq.DecodeDERLC(seqGen);
282 if (seqContents->Count() < 3 || seqContents->Count() > 4)
284 User::Leave(KErrArgument);
288 if (seqContents->At(0)->Tag() != EASN1Integer)
290 User::Leave(KErrArgument);
292 TASN1DecInteger intDecoder;
293 iVersion = intDecoder.DecodeDERShortL(*(seqContents->At(0)));
296 User::Leave(KErrArgument);
300 CX509AlgorithmIdentifier* algorithm = CX509AlgorithmIdentifier::NewLC(seqContents->At(1)->Encoding());
301 iAlgorithmID = algorithm->Algorithm();
304 switch (iAlgorithmID)
305 {// Only support RSA, DSA, DH
307 iKeyPairData = CPKCS8KeyPairRSA::NewL(*(seqContents->At(2)));
312 TPtrC8 params(algorithm->EncodedParams());
313 iKeyPairData = CPKCS8KeyPairDSA::NewL(params, *(seqContents->At(2)));
317 case EDH: // Currently not supported because no test data is available
319 User::Leave(KErrNotSupported);
323 CleanupStack::PopAndDestroy(algorithm);
325 if (seqContents->Count() == 4)
327 // I think we should check the tag is zero here, but we're going to be
328 // lenient due to lack of real test data
330 //if (seqContents->At(3)->Tag() != 0) // Implicitly tagged
332 // User::Leave(KErrArgument);
335 iAttributes = seqContents->At(3)->Encoding().AllocL();
338 CleanupStack::PopAndDestroy(seqContents);
341 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\
343 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\
345 /*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairRSA::NewL(const TASN1DecGeneric& aSource)
347 CPKCS8KeyPairRSA* me = new (ELeave) CPKCS8KeyPairRSA();
348 CleanupStack::PushL(me);
349 me->ConstructL(aSource);
350 CleanupStack::Pop(me);
355 MPKCS8DecodedKeyPairData::~MPKCS8DecodedKeyPairData()
359 CPKCS8KeyPairRSA::~CPKCS8KeyPairRSA()
365 void CPKCS8KeyPairRSA::Release()
370 void CPKCS8KeyPairRSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
373 KeyIdentifierUtil::RSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);
375 User::Leave(KErrNotReady);
378 TUint CPKCS8KeyPairRSA::KeySize() const
386 const TInteger& modulus = iPublicKey->N();
388 TUint size = modulus.BitCount();
392 void CPKCS8KeyPairRSA::ConstructL(const TASN1DecGeneric& aSource)
394 TPtrC8 theContent(aSource.GetContentDER());
395 TASN1DecRSAKeyPair keyPairDecoder;
397 keyPairDecoder.DecodeDERL(theContent, tempPos, iPublicKey, iPrivateKey);
401 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\
403 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\
405 /*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairDSA::NewL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
407 CPKCS8KeyPairDSA* me = new (ELeave) CPKCS8KeyPairDSA();
408 CleanupStack::PushL(me);
409 me->ConstructL(aParamsData, aSource);
410 CleanupStack::Pop(me);
415 CPKCS8KeyPairDSA::~CPKCS8KeyPairDSA()
421 void CPKCS8KeyPairDSA::Release()
426 void CPKCS8KeyPairDSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
429 KeyIdentifierUtil::DSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);
431 User::Leave(KErrNotReady);
434 TUint CPKCS8KeyPairDSA::KeySize() const
442 const TInteger& P = iPublicKey->P();
444 TUint size = P.BitCount();
448 void CPKCS8KeyPairDSA::ConstructL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
450 TX509KeyFactory keyFactory;
451 CDSAParameters* params = keyFactory.DSAParametersL(aParamsData);
452 CleanupStack::PushL(params);
454 RInteger P = RInteger::NewL(params->P());
455 CleanupStack::PushL(P);
457 RInteger Q = RInteger::NewL(params->Q());
458 CleanupStack::PushL(Q);
460 RInteger G = RInteger::NewL(params->G());
461 CleanupStack::PushL(G);
463 if (aSource.Tag() != EASN1OctetString)
465 User::Leave(KErrArgument);
467 TASN1DecOctetString octetDecoder;
468 HBufC8* wrapped = octetDecoder.DecodeDERL(aSource);
469 CleanupStack::PushL(wrapped);
471 TASN1DecGeneric integer(*wrapped);
473 if (integer.Tag() != EASN1Integer)
475 User::Leave(KErrArgument);
477 TASN1DecInteger decInt;
478 RInteger X = decInt.DecodeDERLongL(integer);
479 CleanupStack::PopAndDestroy(wrapped);
480 CleanupStack::PushL(X);
482 RInteger P1 = RInteger::NewL(params->P());
483 CleanupStack::PushL(P1);
485 RInteger Q1 = RInteger::NewL(params->Q());
486 CleanupStack::PushL(Q1);
488 RInteger G1 = RInteger::NewL(params->G());
489 CleanupStack::PushL(G1);
491 RInteger Y = TInteger::ModularExponentiateL(G, X, P);
492 CleanupStack::PushL(Y);
494 iPublicKey = CDSAPublicKey::NewL(P1, Q1, G1, Y);
496 // Now have to pop everything owned by iPublicKey otherwise it will be
497 // deleted twice if the CDSAPrivateKey::NewL leaves
499 CleanupStack::Pop(4, &P1); // now owned by iPublicKey
501 iPrivateKey = CDSAPrivateKey::NewL(P, Q, G, X);
503 CleanupStack::Pop(4, &P); // now owned by iPrivateKey
505 CleanupStack::PopAndDestroy(params);