|
1 /* |
|
2 * Copyright (c) 2004-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 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <asn1dec.h> |
|
20 #include <x509keys.h> |
|
21 #include <x509cert.h> |
|
22 #include "asnpkcs.h" |
|
23 #include <pbe.h> |
|
24 #include <pbedata.h> |
|
25 #include <keyidentifierutil.h> |
|
26 |
|
27 /*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeDERL(const TDesC8& aBinaryData) |
|
28 { |
|
29 return (CDecPKCS8Data::NewL(aBinaryData)); |
|
30 } |
|
31 |
|
32 /* |
|
33 EncryptedPrivateKeyInfo ::= SEQUENCE { |
|
34 encryptionAlgorithm EncryptionAlgorithmIdentifier, |
|
35 encryptedData EncryptedData } |
|
36 EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier |
|
37 EncryptedData ::= OCTET STRING |
|
38 */ |
|
39 |
|
40 /*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeEncryptedDERL(const TDesC8& aBinaryData, const TDesC8& aPassword) |
|
41 { |
|
42 TASN1DecGeneric seqGen(aBinaryData); |
|
43 seqGen.InitL(); |
|
44 if (seqGen.Tag() != EASN1Sequence) |
|
45 { |
|
46 User::Leave(KErrArgument); |
|
47 } |
|
48 |
|
49 TASN1DecSequence dec; |
|
50 CArrayPtrFlat<TASN1DecGeneric>* theData = dec.DecodeDERLC(seqGen); |
|
51 TInt seqIndex = 0; |
|
52 TInt count = theData->Count(); |
|
53 if (seqIndex >= count) |
|
54 { |
|
55 User::Leave(KErrArgument); |
|
56 } |
|
57 |
|
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); |
|
63 |
|
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) |
|
70 { |
|
71 User::Leave(KErrArgument); |
|
72 } |
|
73 TPtrC8 encryptedKey(pkcs8->GetContentDER()); |
|
74 TUint encryptLength = encryptedKey.Length(); |
|
75 TUint maxDecryptLength = decryptor->MaxOutputLength(encryptLength); |
|
76 if (maxDecryptLength<=0) |
|
77 { |
|
78 User::Leave(KErrGeneral); |
|
79 } |
|
80 |
|
81 HBufC8* decryptOutput = HBufC8::NewLC(encryptLength); |
|
82 TPtr8 decryptOutputPtr(decryptOutput->Des()); |
|
83 decryptOutputPtr.FillZ(); |
|
84 decryptor->Process(encryptedKey, decryptOutputPtr); |
|
85 |
|
86 CDecPKCS8Data* pkcs8Data = CDecPKCS8Data::NewL(decryptOutputPtr); |
|
87 |
|
88 // decryptOutput decryptor encryptElement |
|
89 // encryptParams theData |
|
90 CleanupStack::PopAndDestroy(5, theData); |
|
91 |
|
92 return (pkcs8Data); |
|
93 } |
|
94 |
|
95 /* |
|
96 Sample cleartext pkcs8 data from pkcs8dsa.001: |
|
97 |
|
98 SEQUENCE |
|
99 30 Tag: Constructed sequence |
|
100 81 c8 Length (may be one or more bytes) |
|
101 |
|
102 INTEGER |
|
103 02 Tag: Integer |
|
104 01 Length: 1 byte |
|
105 00 Value: 0 |
|
106 |
|
107 SEQUENCE |
|
108 30 Tag: Constructed sequence |
|
109 81 a9 Length (may be one or more bytes) |
|
110 |
|
111 OID |
|
112 06 Tag: OID |
|
113 07 Length: 7 bytes |
|
114 2a 86 48 ce 38 04 01 |
|
115 Value: dsa (1 2 840 10040 4 1) |
|
116 */ |
|
117 |
|
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"); |
|
121 |
|
122 /*static*/ EXPORT_C TBool TASN1DecPKCS8::IsPKCS8Data(const TDesC8& aBinaryData) |
|
123 { |
|
124 // We don't decode the data because we may only have the first few bytes - |
|
125 // instead we check the ASN1 by hand. |
|
126 |
|
127 ASSERT(aBinaryData.Length() >= KIsPKCS8DataMinLength); |
|
128 TInt pos = 0; |
|
129 |
|
130 return |
|
131 IsASN1Sequence(aBinaryData, pos) && |
|
132 IsExpectedData(aBinaryData, pos, KPKCS8DataVersion0) && |
|
133 IsASN1Sequence(aBinaryData, pos) && |
|
134 (IsExpectedData(aBinaryData, pos, KPKCS8DataOIDDSA) || |
|
135 IsExpectedData(aBinaryData, pos, KPKCS8DataOIDRSA)); |
|
136 } |
|
137 |
|
138 /* |
|
139 Sample encrypted pkcs8 data from encryptPK8rsa1.txt |
|
140 |
|
141 SEQUENCE |
|
142 30 Tag: Constructed sequence |
|
143 82 01 a3 Length (may be one or more bytes) |
|
144 |
|
145 SEQUENCE |
|
146 30 Tag: Constructed sequence |
|
147 3d Length (may be one or more bytes) |
|
148 |
|
149 OID |
|
150 06 Tag: OID |
|
151 09 Length: 9 bytes |
|
152 2a 86 48 86 f7 0d 01 05 0d |
|
153 Value: pkcs5PBES2 (1 2 840 113549 1 5 13) |
|
154 |
|
155 SEQUENCE |
|
156 30 Tag: Constructed sequence |
|
157 30 Length (may be one or more bytes) |
|
158 |
|
159 SEQUENCE |
|
160 30 Tag: Constructed sequence |
|
161 1b Length (may be one or more bytes) |
|
162 |
|
163 OID |
|
164 06 Tag: OID |
|
165 09 Length: 9 bytes |
|
166 2a 86 48 86 f7 0d 01 05 0c |
|
167 Value: pkcs5PBKDF2 (1 2 840 113549 1 5 12) |
|
168 */ |
|
169 |
|
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"); |
|
172 |
|
173 EXPORT_C TBool TASN1DecPKCS8::IsEncryptedPKCS8Data(const TDesC8& aBinaryData) |
|
174 { |
|
175 // We don't decode the data because we may only have the first few bytes - |
|
176 // instead we check the ASN1 by hand. |
|
177 |
|
178 ASSERT(aBinaryData.Length() >= KIsEncryptedPKCS8DataMinLength); |
|
179 TInt pos = 0; |
|
180 |
|
181 return |
|
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); |
|
188 } |
|
189 |
|
190 /** |
|
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. |
|
194 */ |
|
195 TBool TASN1DecPKCS8::IsASN1Sequence(const TDesC8& aBinaryData, TInt& aPos) |
|
196 { |
|
197 // Check we have enough data |
|
198 if ((aPos + 2) >= aBinaryData.Length()) |
|
199 { |
|
200 return EFalse; |
|
201 } |
|
202 // Check the outermost sequence is valid |
|
203 if (aBinaryData[aPos++] != 0x30 /* constructed sequence */) |
|
204 { |
|
205 return EFalse; |
|
206 } |
|
207 // Skip sequence length |
|
208 TInt length0 = aBinaryData[aPos++]; |
|
209 if (length0 & 0x80) |
|
210 { |
|
211 aPos += length0 & 0x7f; |
|
212 } |
|
213 return ETrue; |
|
214 } |
|
215 |
|
216 /** |
|
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. |
|
220 */ |
|
221 TBool TASN1DecPKCS8::IsExpectedData(const TDesC8& aBinaryData, TInt& aPos, const TDesC8& aExpectedData) |
|
222 { |
|
223 TInt length = aExpectedData.Length(); |
|
224 // Check we have enough data |
|
225 if (aPos + length >= aBinaryData.Length()) |
|
226 { |
|
227 return EFalse; |
|
228 } |
|
229 // Check data matches |
|
230 if (aBinaryData.Mid(aPos, length) != aExpectedData) |
|
231 { |
|
232 return EFalse; |
|
233 } |
|
234 aPos += length; |
|
235 return ETrue; |
|
236 } |
|
237 |
|
238 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ |
|
239 // PKCS#8 object data representation |
|
240 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ |
|
241 |
|
242 /*static*/ CDecPKCS8Data* CDecPKCS8Data::NewL(const TDesC8& aData) |
|
243 { |
|
244 CDecPKCS8Data* me = new (ELeave) CDecPKCS8Data(); |
|
245 CleanupStack::PushL(me); |
|
246 me->ConstructL(aData); |
|
247 CleanupStack::Pop(me); |
|
248 return (me); |
|
249 } |
|
250 |
|
251 CDecPKCS8Data::CDecPKCS8Data() |
|
252 {} |
|
253 |
|
254 CDecPKCS8Data::~CDecPKCS8Data() |
|
255 { |
|
256 if (iKeyPairData) |
|
257 { |
|
258 iKeyPairData->Release(); |
|
259 iKeyPairData = NULL; |
|
260 } |
|
261 |
|
262 if (iAttributes) |
|
263 { |
|
264 delete iAttributes; |
|
265 iAttributes = NULL; |
|
266 } |
|
267 } |
|
268 |
|
269 // Because this is part of construction, don't rely on |
|
270 // cleanup of partially constructed items... |
|
271 void CDecPKCS8Data::ConstructL(const TDesC8& aData) |
|
272 { |
|
273 TASN1DecGeneric seqGen(aData); |
|
274 seqGen.InitL(); |
|
275 if (seqGen.Tag() != EASN1Sequence) |
|
276 { |
|
277 User::Leave(KErrArgument); |
|
278 } |
|
279 |
|
280 TASN1DecSequence seq; |
|
281 CArrayPtrFlat<TASN1DecGeneric>* seqContents = seq.DecodeDERLC(seqGen); |
|
282 if (seqContents->Count() < 3 || seqContents->Count() > 4) |
|
283 { |
|
284 User::Leave(KErrArgument); |
|
285 } |
|
286 |
|
287 // VERSION |
|
288 if (seqContents->At(0)->Tag() != EASN1Integer) |
|
289 { |
|
290 User::Leave(KErrArgument); |
|
291 } |
|
292 TASN1DecInteger intDecoder; |
|
293 iVersion = intDecoder.DecodeDERShortL(*(seqContents->At(0))); |
|
294 if (iVersion!=0) |
|
295 { |
|
296 User::Leave(KErrArgument); |
|
297 } |
|
298 |
|
299 // ALGORITHM |
|
300 CX509AlgorithmIdentifier* algorithm = CX509AlgorithmIdentifier::NewLC(seqContents->At(1)->Encoding()); |
|
301 iAlgorithmID = algorithm->Algorithm(); |
|
302 |
|
303 // KEY DATA |
|
304 switch (iAlgorithmID) |
|
305 {// Only support RSA, DSA, DH |
|
306 case ERSA: |
|
307 iKeyPairData = CPKCS8KeyPairRSA::NewL(*(seqContents->At(2))); |
|
308 break; |
|
309 |
|
310 case EDSA: |
|
311 { |
|
312 TPtrC8 params(algorithm->EncodedParams()); |
|
313 iKeyPairData = CPKCS8KeyPairDSA::NewL(params, *(seqContents->At(2))); |
|
314 break; |
|
315 } |
|
316 |
|
317 case EDH: // Currently not supported because no test data is available |
|
318 default: |
|
319 User::Leave(KErrNotSupported); |
|
320 break; |
|
321 } |
|
322 |
|
323 CleanupStack::PopAndDestroy(algorithm); |
|
324 |
|
325 if (seqContents->Count() == 4) |
|
326 { |
|
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 |
|
329 |
|
330 //if (seqContents->At(3)->Tag() != 0) // Implicitly tagged |
|
331 // { |
|
332 // User::Leave(KErrArgument); |
|
333 // } |
|
334 |
|
335 iAttributes = seqContents->At(3)->Encoding().AllocL(); |
|
336 } |
|
337 |
|
338 CleanupStack::PopAndDestroy(seqContents); |
|
339 } |
|
340 |
|
341 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ |
|
342 // RSA decoding |
|
343 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ |
|
344 |
|
345 /*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairRSA::NewL(const TASN1DecGeneric& aSource) |
|
346 { |
|
347 CPKCS8KeyPairRSA* me = new (ELeave) CPKCS8KeyPairRSA(); |
|
348 CleanupStack::PushL(me); |
|
349 me->ConstructL(aSource); |
|
350 CleanupStack::Pop(me); |
|
351 |
|
352 return (me); |
|
353 } |
|
354 |
|
355 MPKCS8DecodedKeyPairData::~MPKCS8DecodedKeyPairData() |
|
356 { |
|
357 } |
|
358 |
|
359 CPKCS8KeyPairRSA::~CPKCS8KeyPairRSA() |
|
360 { |
|
361 delete iPublicKey; |
|
362 delete iPrivateKey; |
|
363 } |
|
364 |
|
365 void CPKCS8KeyPairRSA::Release() |
|
366 { |
|
367 delete this; |
|
368 } |
|
369 |
|
370 void CPKCS8KeyPairRSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const |
|
371 { |
|
372 if (iPublicKey) |
|
373 KeyIdentifierUtil::RSAKeyIdentifierL(*iPublicKey, aKeyIdentifier); |
|
374 else |
|
375 User::Leave(KErrNotReady); |
|
376 } |
|
377 |
|
378 TUint CPKCS8KeyPairRSA::KeySize() const |
|
379 { |
|
380 if (!iPublicKey) |
|
381 { |
|
382 ASSERT(EFalse); |
|
383 return (0xffffffff); |
|
384 } |
|
385 |
|
386 const TInteger& modulus = iPublicKey->N(); |
|
387 |
|
388 TUint size = modulus.BitCount(); |
|
389 return (size); |
|
390 } |
|
391 |
|
392 void CPKCS8KeyPairRSA::ConstructL(const TASN1DecGeneric& aSource) |
|
393 { |
|
394 TPtrC8 theContent(aSource.GetContentDER()); |
|
395 TASN1DecRSAKeyPair keyPairDecoder; |
|
396 TInt tempPos = 0; |
|
397 keyPairDecoder.DecodeDERL(theContent, tempPos, iPublicKey, iPrivateKey); |
|
398 } |
|
399 |
|
400 |
|
401 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ |
|
402 // DSA decoding |
|
403 // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ |
|
404 |
|
405 /*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairDSA::NewL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource) |
|
406 { |
|
407 CPKCS8KeyPairDSA* me = new (ELeave) CPKCS8KeyPairDSA(); |
|
408 CleanupStack::PushL(me); |
|
409 me->ConstructL(aParamsData, aSource); |
|
410 CleanupStack::Pop(me); |
|
411 |
|
412 return (me); |
|
413 } |
|
414 |
|
415 CPKCS8KeyPairDSA::~CPKCS8KeyPairDSA() |
|
416 { |
|
417 delete iPublicKey; |
|
418 delete iPrivateKey; |
|
419 } |
|
420 |
|
421 void CPKCS8KeyPairDSA::Release() |
|
422 { |
|
423 delete this; |
|
424 } |
|
425 |
|
426 void CPKCS8KeyPairDSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const |
|
427 { |
|
428 if (iPublicKey) |
|
429 KeyIdentifierUtil::DSAKeyIdentifierL(*iPublicKey, aKeyIdentifier); |
|
430 else |
|
431 User::Leave(KErrNotReady); |
|
432 } |
|
433 |
|
434 TUint CPKCS8KeyPairDSA::KeySize() const |
|
435 { |
|
436 if (!iPublicKey) |
|
437 { |
|
438 ASSERT(EFalse); |
|
439 return (0xffffffff); |
|
440 } |
|
441 |
|
442 const TInteger& P = iPublicKey->P(); |
|
443 |
|
444 TUint size = P.BitCount(); |
|
445 return (size); |
|
446 } |
|
447 |
|
448 void CPKCS8KeyPairDSA::ConstructL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource) |
|
449 { |
|
450 TX509KeyFactory keyFactory; |
|
451 CDSAParameters* params = keyFactory.DSAParametersL(aParamsData); |
|
452 CleanupStack::PushL(params); |
|
453 |
|
454 RInteger P = RInteger::NewL(params->P()); |
|
455 CleanupStack::PushL(P); |
|
456 |
|
457 RInteger Q = RInteger::NewL(params->Q()); |
|
458 CleanupStack::PushL(Q); |
|
459 |
|
460 RInteger G = RInteger::NewL(params->G()); |
|
461 CleanupStack::PushL(G); |
|
462 |
|
463 if (aSource.Tag() != EASN1OctetString) |
|
464 { |
|
465 User::Leave(KErrArgument); |
|
466 } |
|
467 TASN1DecOctetString octetDecoder; |
|
468 HBufC8* wrapped = octetDecoder.DecodeDERL(aSource); |
|
469 CleanupStack::PushL(wrapped); |
|
470 |
|
471 TASN1DecGeneric integer(*wrapped); |
|
472 integer.InitL(); |
|
473 if (integer.Tag() != EASN1Integer) |
|
474 { |
|
475 User::Leave(KErrArgument); |
|
476 } |
|
477 TASN1DecInteger decInt; |
|
478 RInteger X = decInt.DecodeDERLongL(integer); |
|
479 CleanupStack::PopAndDestroy(wrapped); |
|
480 CleanupStack::PushL(X); |
|
481 |
|
482 RInteger P1 = RInteger::NewL(params->P()); |
|
483 CleanupStack::PushL(P1); |
|
484 |
|
485 RInteger Q1 = RInteger::NewL(params->Q()); |
|
486 CleanupStack::PushL(Q1); |
|
487 |
|
488 RInteger G1 = RInteger::NewL(params->G()); |
|
489 CleanupStack::PushL(G1); |
|
490 |
|
491 RInteger Y = TInteger::ModularExponentiateL(G, X, P); |
|
492 CleanupStack::PushL(Y); |
|
493 |
|
494 iPublicKey = CDSAPublicKey::NewL(P1, Q1, G1, Y); |
|
495 |
|
496 // Now have to pop everything owned by iPublicKey otherwise it will be |
|
497 // deleted twice if the CDSAPrivateKey::NewL leaves |
|
498 |
|
499 CleanupStack::Pop(4, &P1); // now owned by iPublicKey |
|
500 |
|
501 iPrivateKey = CDSAPrivateKey::NewL(P, Q, G, X); |
|
502 |
|
503 CleanupStack::Pop(4, &P); // now owned by iPrivateKey |
|
504 |
|
505 CleanupStack::PopAndDestroy(params); |
|
506 } |