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 <security_utilities/simulatecrash_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 ¶mData, 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 ¶mData, // 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 ¶mData, // 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 ¶mData, // 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 ¶mData, 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 ¶mData, // 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 ¶mData = 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 }