]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecImportExportPkcs8.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecImportExportPkcs8.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecImportExportPkcs8.cpp - support for generating and parsing/decoding
26 * private keys in PKCS8 format.
27 *
28 * The current version (as of March 12 2004) can parse and decode every
29 * PKCS8 blob generated by openssl with the exception of those using
30 * double DES encryption. This has been verified by actually generating
31 * those blobs with openssl and decoding them here.
32 *
33 * PLEASE: don't even *think* about changing a single line of code here
34 * without verifying the results against the full import/export regression
35 * test in SecurityTests/clxutils/importExport.
36 *
37 */
38
39 #include <Security/SecImportExport.h>
40 #include "SecImportExportPkcs8.h"
41 #include "SecPkcs8Templates.h"
42 #include "SecImportExportUtils.h"
43 #include "SecImportExportCrypto.h"
44 #include <security_pkcs12/pkcs12Utils.h>
45 #include <security_pkcs12/pkcs12Crypto.h>
46 #include <security_asn1/SecNssCoder.h>
47 #include <Security/keyTemplates.h>
48 #include <Security/SecAsn1Templates.h>
49 #include <Security/secasn1t.h>
50 #include <security_asn1/nssUtils.h>
51 #include <security_utilities/debugging.h>
52 #include <security_utilities/devrandom.h>
53 #include <Security/oidsalg.h>
54 #include <Security/SecKeyPriv.h>
55 #include <security_cdsa_utils/cuCdsaUtils.h>
56 #include <openssl/pem.h>
57 #include <assert.h>
58 #include <Security/SecBase.h>
59
60 #define SecPkcs8Dbg(args...) secdebug("SecPkcs8", ## args)
61
62 #pragma mark --- PKCS5 v1.5 Key Derivation ---
63
64 /*
65 * PKCS5 v1.5. Caller has gleaned everything except salt,
66 * iterationCount, and IV from the AlgId.algorithm OID.
67 *
68 * We get salt and iteration count from the incoming alg params.
69 * IV is derived along with the unwrapping key from the passphrase.
70 */
71 static CSSM_RETURN pkcs5_v15_genKey(
72 CSSM_CSP_HANDLE cspHand,
73 SecNssCoder &coder,
74 const SecKeyImportExportParameters *keyParams,
75 const CSSM_DATA &paramData,
76 CSSM_ALGORITHMS keyAlg,
77 CSSM_ALGORITHMS pbeHashAlg,
78 uint32 keySizeInBits,
79 uint32 blockSizeInBytes,
80 impExpKeyUnwrapParams *unwrapParams)
81 {
82 CSSM_KEY *passKey = NULL;
83 CFDataRef cfPhrase = NULL;
84 CSSM_RETURN crtn;
85 OSStatus ortn;
86 CSSM_CRYPTO_DATA seed;
87 CSSM_CC_HANDLE ccHand = 0;
88 CSSM_ACCESS_CREDENTIALS creds;
89
90
91 /* passphrase or passkey? */
92 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, VP_Import,
93 (CFTypeRef *)&cfPhrase, &passKey);
94 if(ortn) {
95 return ortn;
96 }
97 /* subsequent errors to errOut: */
98
99 memset(&seed, 0, sizeof(seed));
100 if(cfPhrase != NULL) {
101 size_t len = CFDataGetLength(cfPhrase);
102 coder.allocItem(seed.Param, len);
103 memmove(seed.Param.Data, CFDataGetBytePtr(cfPhrase), len);
104 CFRelease(cfPhrase);
105 }
106
107 /* hash algorithm --> PBE alg for CSP */
108 CSSM_ALGORITHMS pbeAlg;
109 switch(pbeHashAlg) {
110 case CSSM_ALGID_MD2:
111 pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_MD2;
112 break;
113 case CSSM_ALGID_MD5:
114 pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_MD5;
115 break;
116 case CSSM_ALGID_SHA1:
117 pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_SHA1;
118 break;
119 default:
120 /* really shouldn't happen - pbeHashAlg was inferred by
121 * pkcsOidToParams() */
122 SecPkcs8Dbg("PKCS8: PKCS5 v1/5 bogus hash alg");
123 crtn = CSSMERR_CSP_INTERNAL_ERROR;
124 goto errOut;
125 }
126
127 /* Salt and iteration count from alg parameters */
128 impExpPKCS5_PBE_Parameters pbeParams;
129 memset(&pbeParams, 0, sizeof(pbeParams));
130 if(coder.decodeItem(paramData, impExpPKCS5_PBE_ParametersTemplate, &pbeParams)) {
131 SecPkcs8Dbg("PKCS8: PKCS5 v1.5 pbeParams decode error");
132 crtn = errSecUnknownFormat;
133 goto errOut;
134 }
135 uint32 iterCount;
136 if(!p12DataToInt(pbeParams.iterations, iterCount)) {
137 SecPkcs8Dbg("PKCS8: bad PKCS5 v1.5 iteration count");
138 crtn = errSecUnknownFormat;
139 goto errOut;
140 }
141
142 /* ask for hard coded 8 bytes of IV */
143 coder.allocItem(unwrapParams->iv, 8);
144
145 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
146 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
147 pbeAlg,
148 keyAlg,
149 keySizeInBits,
150 &creds,
151 passKey, // BaseKey
152 iterCount,
153 &pbeParams.salt,
154 &seed,
155 &ccHand);
156 if(crtn) {
157 SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_CSP_CreateDeriveKeyContext failure");
158 goto errOut;
159 }
160
161 memset(unwrapParams->unwrappingKey, 0, sizeof(CSSM_KEY));
162
163 CSSM_DATA dummyLabel;
164 dummyLabel.Data = (uint8 *)"temp unwrap key";
165 dummyLabel.Length = strlen((char *)dummyLabel.Data);
166
167 crtn = CSSM_DeriveKey(ccHand,
168 &unwrapParams->iv, // IV returned in in/out Param
169 CSSM_KEYUSE_ANY,
170 /* not extractable even for the short time this key lives */
171 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
172 &dummyLabel,
173 NULL, // cred and acl
174 unwrapParams->unwrappingKey);
175 if(crtn) {
176 SecPkcs8Dbg("PKCS8: PKCS5 v1.5 CSSM_DeriveKey failure");
177 }
178 errOut:
179 if(ccHand != 0) {
180 CSSM_DeleteContext(ccHand);
181 }
182 if(passKey != NULL) {
183 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
184 free(passKey);
185 }
186 return crtn;
187 }
188
189 #pragma mark --- PKCS5 v2.0 Key Derivation ---
190
191 /*
192 * PKCS5 v2.0 has different means of encoding algorithm parameters,
193 * depending on the encryption algorithm.
194 */
195 /*
196 * Obtain encryption parameters for PKCS5 v2.0, DES and DES3 variants.
197 */
198 static OSStatus pkcs5_DES_params(
199 const CSSM_DATA &paramData, // encryptionScheme.parameters
200 CSSM_OID *encrOid,
201 impExpKeyUnwrapParams *unwrapParams,
202 CSSM_ALGORITHMS *keyAlg, // RETURNED
203 uint32 *keySizeInBits, // IN/OUT (returned if 0 on entry)
204 SecNssCoder &coder)
205 {
206 /* Params is iv as OCTET STRING */
207 if(coder.decodeItem(paramData, kSecAsn1OctetStringTemplate, &unwrapParams->iv)) {
208 SecPkcs8Dbg("PKCS8: PKCS5 v2 DES init vector decode error");
209 return errSecUnknownFormat;
210 }
211 if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_DES_EDE3_CBC)) {
212 *keyAlg = CSSM_ALGID_3DES_3KEY;
213 unwrapParams->encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
214 if(*keySizeInBits == 0) {
215 *keySizeInBits = 3 * 64;
216 }
217 }
218 else {
219 *keyAlg = CSSM_ALGID_DES;
220 unwrapParams->encrAlg = CSSM_ALGID_DES;
221 if(*keySizeInBits == 0) {
222 *keySizeInBits = 64;
223 }
224 }
225 unwrapParams->encrPad = CSSM_PADDING_PKCS7;
226 unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
227 return errSecSuccess;
228 }
229
230 /*
231 * Obtain encryption parameters for PKCS5 v2.0, RC2 variant.
232 */
233 static OSStatus pkcs5_RC2_params(
234 const CSSM_DATA &paramData, // encryptionScheme.parameters
235 impExpKeyUnwrapParams *unwrapParams,
236 CSSM_ALGORITHMS *keyAlg, // RETURNED
237 uint32 *keySizeInBits, // IN/OUT (returned if 0 on entry)
238 SecNssCoder &coder)
239 {
240 /* Params is impExpPKCS5_RC2Params */
241 impExpPKCS5_RC2Params rc2Params;
242 memset(&rc2Params, 0, sizeof(rc2Params));
243 if(coder.decodeItem(paramData, impExpPKCS5_RC2ParamsTemplate, &rc2Params)) {
244 SecPkcs8Dbg("PKCS8: PKCS5 v2 RC2 params decode error");
245 return errSecUnknownFormat;
246 }
247
248 *keyAlg = CSSM_ALGID_RC2;
249 unwrapParams->encrAlg = CSSM_ALGID_RC2;
250 unwrapParams->encrPad = CSSM_PADDING_PKCS7;
251 unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
252
253 /* the version actually maps to effective key size like this */
254 /* I swear all of this is in the PKCS5 v2.0 spec */
255 unwrapParams->effectiveKeySizeInBits = 32; // default
256 if(rc2Params.version.Data) {
257 uint32 v;
258 if(!p12DataToInt(rc2Params.version, v)) {
259 SecPkcs8Dbg("PKCS8: bad PKCS5 rc2Params.version");
260 return errSecUnknownFormat;
261 }
262 switch(v) {
263 case 160:
264 unwrapParams->effectiveKeySizeInBits = 40;
265 break;
266 case 120:
267 unwrapParams->effectiveKeySizeInBits = 64;
268 break;
269 case 58:
270 unwrapParams->effectiveKeySizeInBits = 128;
271 break;
272 default:
273 if(v >= 256) {
274 unwrapParams->effectiveKeySizeInBits = v;
275 }
276 else {
277 /* not in the spec, use as zero */
278 }
279 break;
280 }
281 }
282 unwrapParams->iv = rc2Params.iv;
283
284 /* the PKCS5 spec does not give a default for the RC2 key size */
285 if(*keySizeInBits == 0) {
286 SecPkcs8Dbg("PKCS8: NO RC2 DEFAULT KEYSIZE!");
287 return errSecUnknownFormat;
288 }
289 return errSecSuccess;
290 }
291
292 /*
293 * Infer encryption parameters for PKCS5 v2.0, RC5 variant.
294 * All info contained in encryptionScheme.parameters.
295 */
296 static OSStatus pkcs5_RC5_params(
297 const CSSM_DATA &paramData, // encryptionScheme.parameters
298 impExpKeyUnwrapParams *unwrapParams,
299 CSSM_ALGORITHMS *keyAlg, // RETURNED
300 uint32 *keySizeInBits, // IN/OUT (returned if 0 on entry)
301 SecNssCoder &coder)
302 {
303 /* Params is a impExpPKCS5_RC5Params */
304 impExpPKCS5_RC5Params rc5Params;
305 memset(&rc5Params, 0, sizeof(rc5Params));
306 if(coder.decodeItem(paramData, impExpPKCS5_RC5ParamsTemplate, &rc5Params)) {
307 SecPkcs8Dbg("PKCS8: PKCS5 v2 RC5 params decode error");
308 return errSecUnknownFormat;
309 }
310
311 *keyAlg = CSSM_ALGID_RC5;
312 unwrapParams->encrAlg = CSSM_ALGID_RC5;
313 unwrapParams->encrPad = CSSM_PADDING_PKCS7;
314 unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
315
316 if(rc5Params.rounds.Data) {
317 if(!p12DataToInt(rc5Params.rounds, unwrapParams->rounds)) {
318 SecPkcs8Dbg("PKCS8: bad PKCS5 rc5Params.rounds");
319 return errSecUnknownFormat;
320 }
321 }
322 if(rc5Params.blockSizeInBits.Data) {
323 if(!p12DataToInt(rc5Params.blockSizeInBits, unwrapParams->blockSizeInBits)) {
324 SecPkcs8Dbg("PKCS8: bad PKCS5 rc5Params.blockSizeInBits");
325 return errSecUnknownFormat;
326 }
327 }
328
329 /* Spec says default iv is zeroes */
330 unwrapParams->iv = rc5Params.iv;
331 if(unwrapParams->iv.Length == 0) {
332 uint32 len = unwrapParams->blockSizeInBits / 8;
333 coder.allocItem(unwrapParams->iv, len);
334 memset(unwrapParams->iv.Data, 0, len);
335 }
336
337 /*
338 * Spec does not give a default for key RC5 size, and openssl doesn't
339 * support RC5 for PKCS8.
340 */
341 if(*keySizeInBits == 0) {
342 SecPkcs8Dbg("PKCS8: NO RC5 DEFAULT KEYSIZE!");
343 return errSecUnknownFormat;
344 }
345 return errSecSuccess;
346 }
347
348 /*
349 * Common code to derive a wrap/unwrap key using PBKDF2 (i.e., using PKCS5 v2.0
350 * key derivation). Caller must CSSM_FreeKey when done.
351 */
352 static CSSM_RETURN pbkdf2DeriveKey(
353 CSSM_CSP_HANDLE cspHand,
354 SecNssCoder &coder,
355 CSSM_ALGORITHMS keyAlg,
356 uint32 keySizeInBits,
357 uint32 iterationCount,
358 const CSSM_DATA &salt,
359 const SecKeyImportExportParameters *keyParams, // required
360 impExpVerifyPhrase verifyPhrase, // for secure passphrase
361 CSSM_KEY_PTR symKey) // RETURNED
362 {
363 CSSM_KEY *passKey = NULL;
364 CFDataRef cfPhrase = NULL;
365 CSSM_PKCS5_PBKDF2_PARAMS pbeParams;
366 CSSM_RETURN crtn;
367 OSStatus ortn;
368 CSSM_DATA dummyLabel;
369 CSSM_DATA pbeData;
370 uint32 keyAttr;
371 CSSM_CC_HANDLE ccHand = 0;
372 CSSM_ACCESS_CREDENTIALS creds;
373
374 memset(&pbeParams, 0, sizeof(pbeParams));
375
376 /* passphrase or passkey? */
377 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, verifyPhrase,
378 (CFTypeRef *)&cfPhrase, &passKey);
379 if(ortn) {
380 return ortn;
381 }
382 /* subsequent errors to errOut: */
383
384 if(cfPhrase != NULL) {
385 size_t len = CFDataGetLength(cfPhrase);
386 coder.allocItem(pbeParams.Passphrase, len);
387 memmove(pbeParams.Passphrase.Data,
388 CFDataGetBytePtr(cfPhrase), len);
389 CFRelease(cfPhrase);
390 }
391
392 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
393 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
394 CSSM_ALGID_PKCS5_PBKDF2,
395 keyAlg,
396 keySizeInBits,
397 &creds,
398 passKey, // BaseKey
399 iterationCount,
400 &salt,
401 NULL, // seed
402 &ccHand);
403 if(crtn) {
404 SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_CSP_CreateDeriveKeyContext failure");
405 goto errOut;
406 }
407
408 memset(symKey, 0, sizeof(CSSM_KEY));
409
410 /* not extractable even for the short time this key lives */
411 keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE;
412 dummyLabel.Data = (uint8 *)"temp unwrap key";
413 dummyLabel.Length = strlen((char *)dummyLabel.Data);
414
415 pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
416 pbeData.Data = (uint8 *)&pbeParams;
417 pbeData.Length = sizeof(pbeParams);
418 crtn = CSSM_DeriveKey(ccHand,
419 &pbeData,
420 CSSM_KEYUSE_ANY,
421 keyAttr,
422 &dummyLabel,
423 NULL, // cred and acl
424 symKey);
425 if(crtn) {
426 SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_DeriveKey failure");
427 }
428 errOut:
429 if(ccHand != 0) {
430 CSSM_DeleteContext(ccHand);
431 }
432 if(passKey != NULL) {
433 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
434 free(passKey);
435 }
436 return crtn;
437 }
438
439 /*
440 * Obtain PKCS5, v.2.0 key derivation and encryption parameters and
441 * derive the key. This one obtains all of the crypt parameters
442 * from the top-level AlgId.Params. What a mess.
443 */
444 static CSSM_RETURN pkcs5_v2_genKey(
445 CSSM_CSP_HANDLE cspHand,
446 SecNssCoder &coder,
447 const CSSM_DATA &paramData,
448 const SecKeyImportExportParameters *keyParams,
449 impExpKeyUnwrapParams *unwrapParams)
450 {
451 SecPkcs8Dbg("PKCS8: generating PKCS5 v2.0 key");
452
453 CSSM_ALGORITHMS keyAlg = CSSM_ALGID_NONE;
454 uint32 prf = 0; // CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1...
455
456 /* caller should check */
457 assert(keyParams != NULL);
458
459 /* AlgId.Params --> impExpPKCS5_PBES2_Params */
460 if(paramData.Length == 0) {
461 SecPkcs8Dbg("PKCS8: empty PKCS5 v2 pbes2Params");
462 return errSecUnknownFormat;
463 }
464 impExpPKCS5_PBES2_Params pbes2Params;
465 memset(&pbes2Params, 0, sizeof(pbes2Params));
466 if(coder.decodeItem(paramData, impExpPKCS5_PBES2_ParamsTemplate, &pbes2Params)) {
467 SecPkcs8Dbg("PKCS8: PKCS5 v2 pbes2Params decode error");
468 return errSecUnknownFormat;
469 }
470
471 /*
472 * As far as I know the keyDerivationFunc OID must be id-PBKDF2
473 */
474 if(!nssCompareCssmData(&pbes2Params.keyDerivationFunc.algorithm,
475 &CSSMOID_PKCS5_PBKDF2)) {
476 SecPkcs8Dbg("PKCS8: PKCS5 v2 unexpected keyDerivationFunc alg");
477 return errSecUnknownFormat;
478 }
479
480 /*
481 * The params of the keyDerivationFunc algId are an encoded
482 * impExpPKCS5_PBKDF2_Params.
483 */
484 impExpPKCS5_PBKDF2_Params pbkdf2Params;
485 memset(&pbkdf2Params, 0, sizeof(pbkdf2Params));
486 if(coder.decodeItem(pbes2Params.keyDerivationFunc.parameters,
487 impExpPKCS5_PBKDF2_ParamsTemplate, &pbkdf2Params)) {
488 SecPkcs8Dbg("PKCS8: PKCS5 v2 pbkdf2Params decode error");
489 return errSecUnknownFormat;
490 }
491
492 /*
493 * Salt and iteration count from the impExpPKCS5_PBKDF2_Params (ignoring the
494 * possible CHOICE for salt source).
495 */
496 CSSM_DATA salt = pbkdf2Params.salt;
497 uint32 iterCount;
498 if(!p12DataToInt(pbkdf2Params.iterationCount, iterCount)) {
499 SecPkcs8Dbg("PKCS8: bad PKCS5 v2 iteration count");
500 return errSecUnknownFormat;
501 }
502
503 /*
504 * Key size optional, use defaults per alg (later) if it's not there
505 */
506 uint32 keySizeInBits = 0;
507 if(pbkdf2Params.keyLengthInBytes.Data) {
508 uint32 keyLengthInBytes;
509 if(!p12DataToInt(pbkdf2Params.keyLengthInBytes, keyLengthInBytes)) {
510 SecPkcs8Dbg("PKCS8: bad PKCS5 v2 key size");
511 return errSecUnknownFormat;
512 }
513 keySizeInBits = keyLengthInBytes * 8;
514 }
515 /* else we'll infer key size from the encryption algorithm */
516
517 /* prf optional, but if it's there it better be CSSMOID_PKCS5_HMAC_SHA1 */
518 if(pbkdf2Params.prf.Data) {
519 if(!nssCompareCssmData(&pbkdf2Params.prf, &CSSMOID_PKCS5_HMAC_SHA1)) {
520 SecPkcs8Dbg("PKCS8: PKCS5 v2 unexpected prf OID");
521 return errSecUnknownFormat;
522 }
523 }
524 prf = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
525
526 /*
527 * Now process the encryptionScheme, which is even messier - the algParams
528 * varies per encryption algorithm.
529 */
530 CSSM_X509_ALGORITHM_IDENTIFIER &encrScheme = pbes2Params.encryptionScheme;
531 CSSM_OID *encrOid = &encrScheme.algorithm;
532 OSStatus ortn;
533 CSSM_DATA &encrParam = encrScheme.parameters;
534
535 if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_DES_EDE3_CBC) ||
536 nssCompareCssmData(encrOid, &CSSMOID_DES_CBC)) {
537 ortn = pkcs5_DES_params(encrParam, encrOid, unwrapParams, &keyAlg,
538 &keySizeInBits, coder);
539 if(ortn) {
540 return ortn;
541 }
542 }
543 else if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_RC2_CBC)) {
544 ortn = pkcs5_RC2_params(encrParam, unwrapParams, &keyAlg,
545 &keySizeInBits, coder);
546 if(ortn) {
547 return ortn;
548 }
549 }
550 else if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_RC5_CBC)) {
551 ortn = pkcs5_RC5_params(encrParam, unwrapParams, &keyAlg,
552 &keySizeInBits, coder);
553 if(ortn) {
554 return ortn;
555 }
556 }
557 else {
558 SecPkcs8Dbg("PKCS8: PKCS5 v2 unknown encrScheme.algorithm");
559 return errSecUnknownFormat;
560 }
561
562 /* We should be ready to go */
563 assert(keyAlg != CSSM_ALGID_NONE);
564 assert(unwrapParams->encrAlg != CSSM_ALGID_NONE);
565
566 /* use all the stuff we just figured out to derive a symmetric decryption key */
567 return pbkdf2DeriveKey(cspHand, coder,
568 keyAlg, keySizeInBits,
569 iterCount, salt,
570 keyParams,
571 VP_Import,
572 unwrapParams->unwrappingKey);
573 }
574
575 #pragma mark --- PKCS12 Key Derivation ---
576
577 /*
578 * PKCS12 style key derivation. Caller has gleaned everything except
579 * salt, iterationCount, and IV from the AlgId.algorithm OID.
580 *
581 * We get salt and iteration count from the incoming alg params.
582 * IV is derived along with the unwrapping key from the passphrase.
583 */
584 static CSSM_RETURN pkcs12_genKey(
585 CSSM_CSP_HANDLE cspHand,
586 SecNssCoder &coder,
587 const SecKeyImportExportParameters *keyParams,
588 const CSSM_DATA &paramData, // from algID
589 CSSM_ALGORITHMS keyAlg, // valid on entry
590 CSSM_ALGORITHMS pbeHashAlg, // valid on entry
591 uint32 keySizeInBits, // valid on entry
592 uint32 blockSizeInBytes, // for IV
593 impExpKeyUnwrapParams *unwrapParams)
594 {
595 SecPkcs8Dbg("PKCS8: generating PKCS12 key");
596
597 assert(keyAlg != CSSM_ALGID_NONE);
598 assert(pbeHashAlg != CSSM_ALGID_NONE);
599 assert(keySizeInBits != 0);
600
601 /* get iteration count, salt from alg params */
602 NSS_P12_PBE_Params pbeParams;
603
604 if(paramData.Length == 0) {
605 SecPkcs8Dbg("PKCS8: empty P12 pbeParams");
606 return errSecUnknownFormat;
607 }
608 memset(&pbeParams, 0, sizeof(pbeParams));
609 if(coder.decodeItem(paramData, NSS_P12_PBE_ParamsTemplate, &pbeParams)) {
610 SecPkcs8Dbg("PKCS8: P12 pbeParams decode error");
611 return errSecUnknownFormat;
612 }
613
614 uint32 iterCount = 0;
615 if(!p12DataToInt(pbeParams.iterations, iterCount)) {
616 SecPkcs8Dbg("PKCS8: bad P12 iteration count");
617 return errSecUnknownFormat;
618 }
619
620 /* passphrase or passkey? */
621 CSSM_KEY *passKey = NULL;
622 CFStringRef phraseStr = NULL;
623 CSSM_DATA phraseData = {0, NULL};
624 CSSM_DATA *phraseDataP = NULL;
625 OSStatus ortn;
626 CSSM_RETURN crtn;
627
628 assert(keyParams != NULL);
629
630 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String, VP_Import,
631 (CFTypeRef *)&phraseStr, &passKey);
632 if(ortn) {
633 return ortn;
634 }
635 /* subsequent errors to errOut: */
636
637 if(phraseStr != NULL) {
638 /* convert to CSSM_DATA for use with p12KeyGen() */
639 try {
640 p12ImportPassPhrase(phraseStr, coder, phraseData);
641 }
642 catch(...) {
643 SecPkcs8Dbg("PKCS8: p12ImportPassPhrase threw");
644 crtn = errSecAllocate;
645 goto errOut;
646 }
647 CFRelease(phraseStr);
648 phraseDataP = &phraseData;
649 }
650
651 /* use p12 module to cook up the key and IV */
652 if(blockSizeInBytes) {
653 coder.allocItem(unwrapParams->iv, blockSizeInBytes);
654 }
655 crtn = p12KeyGen(cspHand,
656 *unwrapParams->unwrappingKey,
657 true, // isForEncr
658 keyAlg,
659 pbeHashAlg,
660 keySizeInBits,
661 iterCount,
662 pbeParams.salt,
663 phraseDataP,
664 passKey,
665 unwrapParams->iv);
666 if(crtn) {
667 SecPkcs8Dbg("PKCS8: p12KeyGen failed");
668 }
669 errOut:
670 if(passKey != NULL) {
671 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
672 free(passKey);
673 }
674 return crtn;
675 }
676
677 #pragma mark --- Public PKCS8 import function ---
678
679 /*
680 * Called out from SecImportRep::importWrappedKey().
681 * If cspHand is provided instead of importKeychain, the CSP
682 * handle MUST be for the CSPDL, not for the raw CSP.
683 */
684 OSStatus impExpPkcs8Import(
685 CFDataRef inData,
686 SecKeychainRef importKeychain, // optional
687 CSSM_CSP_HANDLE cspHand, // required
688 SecItemImportExportFlags flags,
689 const SecKeyImportExportParameters *keyParams, // REQUIRED for unwrap
690 CFMutableArrayRef outArray) // optional, append here
691 {
692 CSSM_KEY wrappedKey;
693 CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader;
694 CSSM_RETURN crtn = CSSM_OK;
695
696 /* key derivation and encryption parameters gleaned from alg ID */
697 impExpKeyUnwrapParams unwrapParams;
698 memset(&unwrapParams, 0, sizeof(unwrapParams));
699 CSSM_ALGORITHMS keyAlg = CSSM_ALGID_NONE;
700 CSSM_ALGORITHMS pbeHashAlg = CSSM_ALGID_NONE; // SHA1 or MD5
701 uint32 keySizeInBits;
702 uint32 blockSizeInBytes;
703 PKCS_Which pkcs = PW_None;
704
705 if( (keyParams == NULL) ||
706 ( (keyParams->passphrase == NULL) &&
707 !(keyParams->flags & kSecKeySecurePassphrase) ) ) {
708 /* passphrase mandatory */
709 return errSecPassphraseRequired;
710 }
711 assert(cspHand != 0);
712
713 /*
714 * Top-level decode
715 */
716 SecNssCoder coder;
717 NSS_EncryptedPrivateKeyInfo encrPrivKeyInfo;
718
719 memset(&encrPrivKeyInfo, 0, sizeof(encrPrivKeyInfo));
720 if(coder.decode(CFDataGetBytePtr(inData),
721 CFDataGetLength(inData),
722 kSecAsn1EncryptedPrivateKeyInfoTemplate, &encrPrivKeyInfo)) {
723 SecImpExpDbg("impExpPkcs8Import: error decoding top-level encrPrivKeyInfo");
724 return errSecUnknownFormat;
725 }
726
727 /*
728 * The algorithm OID of that top-level struct is the key piece of info
729 * for now...
730 */
731 bool found = false;
732 found = pkcsOidToParams(&encrPrivKeyInfo.algorithm.algorithm,
733 keyAlg, unwrapParams.encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
734 unwrapParams.encrPad, unwrapParams.encrMode, pkcs);
735 if(!found) {
736 SecImpExpDbg("impExpPkcs8Import: unknown OID in top-level encrPrivKeyInfo");
737 return errSecUnknownFormat;
738 }
739
740 /*
741 * Each PBE method has its own way of filling in the remaining gaps
742 * in impExpKeyUnwrapParams and generating a key.
743 */
744 CSSM_KEY unwrappingKey;
745 memset(&unwrappingKey, 0, sizeof(unwrappingKey));
746 unwrapParams.unwrappingKey = &unwrappingKey;
747 CSSM_DATA &paramData = encrPrivKeyInfo.algorithm.parameters;
748
749 switch(pkcs) {
750 case PW_PKCS5_v1_5:
751 /* we have everything except iv, iterations, salt */
752 crtn = pkcs5_v15_genKey(cspHand, coder, keyParams, paramData,
753 keyAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
754 &unwrapParams);
755 break;
756
757 case PW_PKCS5_v2:
758 /* obtain everything, including iv, from alg params */
759 crtn = pkcs5_v2_genKey(cspHand, coder, paramData, keyParams, &unwrapParams);
760 break;
761 case PW_PKCS12:
762 /* we have everything except iv, iterations, salt */
763 crtn = pkcs12_genKey(cspHand, coder, keyParams, paramData,
764 keyAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
765 &unwrapParams);
766 break;
767 case PW_None:
768 /* satisfy compiler */
769 assert(0);
770 return errSecUnknownFormat;
771 }
772 if(crtn) {
773 SecPkcs8Dbg("PKCS8: key derivation failed");
774 return crtn;
775 }
776
777 /* we should be ready to rock'n'roll no matter how we got here */
778 assert(unwrapParams.encrAlg != CSSM_ALGID_NONE);
779 assert(unwrappingKey.KeyData.Data != NULL);
780 assert(unwrappingKey.KeyHeader.AlgorithmId != CSSM_ALGID_NONE);
781
782 /* set up key to unwrap */
783 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
784 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
785 /* CspId : don't care */
786 hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
787 hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
788 /* AlgorithmId : inferred by CSP */
789 hdr.AlgorithmId = CSSM_ALGID_NONE;
790 hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
791 /* LogicalKeySizeInBits : calculated by CSP during unwrap */
792 hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
793 hdr.KeyUsage = CSSM_KEYUSE_ANY;
794
795 wrappedKey.KeyData = encrPrivKeyInfo.encryptedData;
796
797 crtn = impExpImportKeyCommon(
798 &wrappedKey,
799 importKeychain,
800 cspHand,
801 flags,
802 keyParams,
803 &unwrapParams,
804 NULL, // default label
805 outArray);
806 CSSM_FreeKey(cspHand, NULL, &unwrappingKey, CSSM_FALSE);
807 return crtn;
808 }
809
810 #pragma mark --- Public PKCS8 export function ---
811
812 #define PKCS5_V2_SALT_LEN 8
813 #define PKCS5_V2_ITERATIONS 2048
814 #define PKCS5_V2_DES_IV_SIZE 8
815
816 /*
817 * Unlike impExpPkcs8Import(), which can handle every PBE algorithm in the spec
818 * and implemented by openssl, this one has a fixed PBE and encryption scheme.
819 * We do not provide a means at the API for the client to specify these.
820 *
821 * We generate blobs with triple DES encryption, with PKCS5 v2.0 key
822 * derivation.
823 */
824 OSStatus impExpPkcs8Export(
825 SecKeyRef secKey,
826 SecItemImportExportFlags flags,
827 const SecKeyImportExportParameters *keyParams, // optional
828 CFMutableDataRef outData, // output appended here
829 const char **pemHeader)
830 {
831 DevRandomGenerator rng;
832 SecNssCoder coder;
833 impExpPKCS5_PBES2_Params pbes2Params;
834 CSSM_X509_ALGORITHM_IDENTIFIER &keyDeriveAlgId = pbes2Params.keyDerivationFunc;
835 CSSM_ATTRIBUTE_TYPE formatAttrType = CSSM_ATTRIBUTE_NONE;
836 CSSM_KEYBLOB_FORMAT blobForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
837 const CSSM_KEY *cssmKey;
838
839 if(keyParams == NULL) {
840 return errSecParam;
841 }
842 assert(secKey != NULL);
843 assert(outData != NULL);
844
845 memset(&pbes2Params, 0, sizeof(pbes2Params));
846
847 /*
848 * keyDeriveAlgId
849 * parameters is an encoded impExpPKCS5_PBKDF2_Params
850 * We generate random salt
851 */
852 keyDeriveAlgId.algorithm = CSSMOID_PKCS5_PBKDF2;
853 impExpPKCS5_PBKDF2_Params pbkdf2Params;
854 memset(&pbkdf2Params, 0, sizeof(pbkdf2Params));
855 coder.allocItem(pbkdf2Params.salt, PKCS5_V2_SALT_LEN);
856 rng.random(pbkdf2Params.salt.Data, PKCS5_V2_SALT_LEN);
857 p12IntToData(PKCS5_V2_ITERATIONS, pbkdf2Params.iterationCount, coder);
858 /* leave pbkdf2Params.keyLengthInBytes NULL for default */
859 /* openssl can't handle this, which is the default value:
860 pbkdf2Params.prf = CSSMOID_PKCS5_HMAC_SHA1;
861 */
862
863 coder.encodeItem(&pbkdf2Params, impExpPKCS5_PBKDF2_ParamsTemplate,
864 keyDeriveAlgId.parameters);
865
866 /*
867 * encryptionScheme
868 * parameters is an encoded OCTET STRING containing the (random) IV
869 */
870 CSSM_X509_ALGORITHM_IDENTIFIER &encrScheme = pbes2Params.encryptionScheme;
871 encrScheme.algorithm = CSSMOID_PKCS5_DES_EDE3_CBC;
872 CSSM_DATA rawIv = {0, NULL};
873 coder.allocItem(rawIv, PKCS5_V2_DES_IV_SIZE);
874 rng.random(rawIv.Data, PKCS5_V2_DES_IV_SIZE);
875
876 coder.encodeItem(&rawIv, kSecAsn1OctetStringTemplate,
877 encrScheme.parameters);
878
879 /*
880 * Top level NSS_EncryptedPrivateKeyInfo, whose parameters is the encoded
881 * impExpPKCS5_PBES2_Params.
882 */
883 NSS_EncryptedPrivateKeyInfo encrPrivKeyInfo;
884 memset(&encrPrivKeyInfo, 0, sizeof(encrPrivKeyInfo));
885 CSSM_X509_ALGORITHM_IDENTIFIER &topAlgId = encrPrivKeyInfo.algorithm;
886 topAlgId.algorithm = CSSMOID_PKCS5_PBES2;
887 coder.encodeItem(&pbes2Params, impExpPKCS5_PBES2_ParamsTemplate,
888 topAlgId.parameters);
889
890 /*
891 * Now all we have to do is generate the encrypted key data itself.
892 * When doing a WrapKey op in PKCS8 form, the CSP gives us the
893 * NSS_EncryptedPrivateKeyInfo.encryptedData values.
894 */
895
896 /* we need a CSPDL handle - try to get it from the key */
897 CSSM_CSP_HANDLE cspdlHand = 0;
898 OSStatus ortn;
899 bool releaseCspHand = false;
900 CSSM_DATA encodedKeyInfo = {0, NULL};
901
902 ortn = SecKeyGetCSPHandle(secKey, &cspdlHand);
903 if(ortn) {
904 cspdlHand = cuCspStartup(CSSM_FALSE);
905 if(cspdlHand == 0) {
906 return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
907 }
908 releaseCspHand = true;
909 }
910 /* subsequent errors to errOut: */
911
912 /* get wrapping key from parameters we just set up */
913 CSSM_KEY wrappingKey;
914 memset(&wrappingKey, 0, sizeof(CSSM_KEY));
915 CSSM_RETURN crtn = pbkdf2DeriveKey(cspdlHand, coder,
916 CSSM_ALGID_3DES_3KEY, 3 * 64,
917 PKCS5_V2_ITERATIONS, pbkdf2Params.salt,
918 keyParams,
919 VP_Export,
920 &wrappingKey);
921 if(crtn) {
922 goto errOut;
923 }
924
925 /*
926 * Special case for DSA, ECDSA: specify that the raw blob, pre-encrypt, is in
927 * the PKCS8 PrivateKeyInfo format that openssl understands. The
928 * default is BSAFE.
929 */
930 crtn = SecKeyGetCSSMKey(secKey, &cssmKey);
931 if(crtn) {
932 SecImpExpDbg("impExpPkcs8Export SecKeyGetCSSMKey error");
933 goto errOut;
934 }
935 switch(cssmKey->KeyHeader.AlgorithmId) {
936 case CSSM_ALGID_DSA:
937 case CSSM_ALGID_ECDSA:
938 formatAttrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
939 blobForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
940 break;
941 default:
942 break;
943 }
944
945 /* GO */
946 CSSM_KEY wrappedKey;
947 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
948
949 crtn = impExpExportKeyCommon(cspdlHand, secKey, &wrappingKey, &wrappedKey,
950 CSSM_ALGID_3DES_3KEY_EDE, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS7,
951 CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8, formatAttrType, blobForm, NULL, &rawIv);
952 if(crtn) {
953 goto errOut;
954 }
955
956 /*
957 * OK... *that* wrapped key's data goes into the top-level
958 * NSS_EncryptedPrivateKeyInfo, which we then encode; the caller
959 * gets the result of that encoding.
960 */
961 encrPrivKeyInfo.encryptedData = wrappedKey.KeyData;
962 coder.encodeItem(&encrPrivKeyInfo, kSecAsn1EncryptedPrivateKeyInfoTemplate,
963 encodedKeyInfo);
964
965 CFDataAppendBytes(outData, encodedKeyInfo.Data, encodedKeyInfo.Length);
966 CSSM_FreeKey(cspdlHand, NULL, &wrappedKey, CSSM_FALSE);
967
968 *pemHeader = PEM_STRING_PKCS8;
969
970 errOut:
971 if(wrappingKey.KeyData.Data) {
972 CSSM_FreeKey(cspdlHand, NULL, &wrappingKey, CSSM_FALSE);
973 }
974 if(releaseCspHand) {
975 cuCspDetachUnload(cspdlHand, CSSM_FALSE);
976 }
977 return crtn;
978 }