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