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 */ 71static CSSM_RETURN pkcs5_v15_genKey( 72 CSSM_CSP_HANDLE cspHand, 73 SecNssCoder &coder, 74 const SecKeyImportExportParameters *keyParams, 75 const CSSM_DATA ¶mData, 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 } 178errOut: 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 */ 198static OSStatus pkcs5_DES_params( 199 const CSSM_DATA ¶mData, // 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 */ 233static OSStatus pkcs5_RC2_params( 234 const CSSM_DATA ¶mData, // 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 */ 296static OSStatus pkcs5_RC5_params( 297 const CSSM_DATA ¶mData, // 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 */ 352static 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 } 428errOut: 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 */ 444static CSSM_RETURN pkcs5_v2_genKey( 445 CSSM_CSP_HANDLE cspHand, 446 SecNssCoder &coder, 447 const CSSM_DATA ¶mData, 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 */ 584static CSSM_RETURN pkcs12_genKey( 585 CSSM_CSP_HANDLE cspHand, 586 SecNssCoder &coder, 587 const SecKeyImportExportParameters *keyParams, 588 const CSSM_DATA ¶mData, // 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 } 669errOut: 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 */ 684OSStatus 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 ¶mData = 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 */ 824OSStatus 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 970errOut: 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} 979