1/* 2 * Copyright (c) 2003-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 * pkc12Crypto.cpp - PKCS12-specific cyptrographic routines 26 */ 27 28#include "pkcs12Crypto.h" 29#include "pkcs12Utils.h" 30#include "pkcs12Debug.h" 31#include <security_cdsa_utils/cuCdsaUtils.h> 32#include <security_cdsa_utilities/cssmacl.h> 33#include <security_keychain/Access.h> 34 35/* 36 * Given appropriate P12-style parameters, cook up a CSSM_KEY. 37 * Caller MUST CSSM_FreeKey() when it's done with the key. 38 */ 39#define KEY_LABEL "p12 key" 40 41CSSM_RETURN p12KeyGen( 42 CSSM_CSP_HANDLE cspHand, 43 CSSM_KEY &key, 44 bool isForEncr, // true: en/decrypt false: MAC 45 CSSM_ALGORITHMS keyAlg, 46 CSSM_ALGORITHMS pbeHashAlg, // actually must be SHA1 for now 47 uint32 keySizeInBits, 48 uint32 iterCount, 49 const CSSM_DATA &salt, 50 /* exactly one of the following two must be valid */ 51 const CSSM_DATA *pwd, // unicode external representation 52 const CSSM_KEY *passKey, 53 CSSM_DATA &iv) // referent is optional 54{ 55 CSSM_RETURN crtn; 56 CSSM_CC_HANDLE ccHand; 57 CSSM_DATA dummyLabel; 58 CSSM_ACCESS_CREDENTIALS creds; 59 60 memset(&key, 0, sizeof(CSSM_KEY)); 61 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 62 63 /* infer key derivation algorithm */ 64 CSSM_ALGORITHMS deriveAlg = CSSM_ALGID_NONE; 65 if(pbeHashAlg != CSSM_ALGID_SHA1) { 66 return CSSMERR_CSP_INVALID_ALGORITHM; 67 } 68 if(isForEncr) { 69 /* 70 * FIXME - if this key is going to be used to wrap/unwrap a 71 * shrouded key bag, its usage will change accordingly... 72 */ 73 deriveAlg = CSSM_ALGID_PKCS12_PBE_ENCR; 74 } 75 else { 76 deriveAlg = CSSM_ALGID_PKCS12_PBE_MAC; 77 } 78 CSSM_CRYPTO_DATA seed; 79 if(pwd) { 80 seed.Param = *pwd; 81 } 82 else { 83 seed.Param.Data = NULL; 84 seed.Param.Length = 0; 85 } 86 seed.Callback = NULL; 87 seed.CallerCtx = NULL; 88 89 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand, 90 deriveAlg, 91 keyAlg, 92 keySizeInBits, 93 &creds, 94 passKey, // BaseKey 95 iterCount, 96 &salt, 97 &seed, // seed 98 &ccHand); 99 if(crtn) { 100 p12LogCssmError("CSSM_CSP_CreateDeriveKeyContext", crtn); 101 return crtn; 102 } 103 104 dummyLabel.Length = strlen(KEY_LABEL); 105 dummyLabel.Data = (uint8 *)KEY_LABEL; 106 107 /* KEYUSE_ANY - this is just an ephemeral session key */ 108 crtn = CSSM_DeriveKey(ccHand, 109 &iv, 110 CSSM_KEYUSE_ANY, 111 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, 112 &dummyLabel, 113 NULL, // cred and acl 114 &key); 115 CSSM_DeleteContext(ccHand); 116 if(crtn) { 117 p12LogCssmError("CSSM_DeriveKey", crtn); 118 } 119 return crtn; 120} 121 122/* 123 * Decrypt (typically, an encrypted P7 ContentInfo contents) 124 */ 125CSSM_RETURN p12Decrypt( 126 CSSM_CSP_HANDLE cspHand, 127 const CSSM_DATA &cipherText, 128 CSSM_ALGORITHMS keyAlg, 129 CSSM_ALGORITHMS encrAlg, 130 CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only 131 uint32 keySizeInBits, 132 uint32 blockSizeInBytes, // for IV 133 CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. 134 CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. 135 uint32 iterCount, 136 const CSSM_DATA &salt, 137 /* exactly one of the following two must be valid */ 138 const CSSM_DATA *pwd, // unicode external representation 139 const CSSM_KEY *passKey, 140 SecNssCoder &coder, // for mallocing plainText 141 CSSM_DATA &plainText) 142{ 143 CSSM_RETURN crtn; 144 CSSM_KEY ckey; 145 CSSM_CC_HANDLE ccHand = 0; 146 CSSM_DATA ourPtext = {0, NULL}; 147 CSSM_DATA remData = {0, NULL}; 148 149 /* P12 style IV derivation, optional */ 150 CSSM_DATA iv = {0, NULL}; 151 CSSM_DATA_PTR ivPtr = NULL; 152 if(blockSizeInBytes) { 153 coder.allocItem(iv, blockSizeInBytes); 154 ivPtr = &iv; 155 } 156 157 /* P12 style key derivation */ 158 crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, 159 keySizeInBits, iterCount, salt, pwd, passKey, iv); 160 if(crtn) { 161 return crtn; 162 } 163 /* subsequent errors to errOut: */ 164 165 /* CSSM context */ 166 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 167 encrAlg, 168 mode, 169 NULL, // access cred 170 &ckey, 171 ivPtr, // InitVector, optional 172 padding, 173 NULL, // Params 174 &ccHand); 175 if(crtn) { 176 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn); 177 goto errOut; 178 } 179 180 /* go - CSP mallocs ptext and rem data */ 181 CSSM_SIZE bytesDecrypted; 182 crtn = CSSM_DecryptData(ccHand, 183 &cipherText, 184 1, 185 &ourPtext, 186 1, 187 &bytesDecrypted, 188 &remData); 189 if(crtn) { 190 cuPrintError("CSSM_DecryptData", crtn); 191 } 192 else { 193 coder.allocCopyItem(ourPtext, plainText); 194 plainText.Length = bytesDecrypted; 195 196 /* plaintext copied into coder space; free the memory allocated 197 * by the CSP */ 198 freeCssmMemory(cspHand, ourPtext.Data); 199 } 200 /* an artifact of CSPFullPLuginSession - this never contains 201 * valid data but sometimes gets mallocds */ 202 if(remData.Data) { 203 freeCssmMemory(cspHand, remData.Data); 204 } 205errOut: 206 if(ccHand) { 207 CSSM_DeleteContext(ccHand); 208 } 209 CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); 210 return crtn; 211} 212 213/* 214 * Decrypt (typically, an encrypted P7 ContentInfo contents) 215 */ 216CSSM_RETURN p12Encrypt( 217 CSSM_CSP_HANDLE cspHand, 218 const CSSM_DATA &plainText, 219 CSSM_ALGORITHMS keyAlg, 220 CSSM_ALGORITHMS encrAlg, 221 CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only 222 uint32 keySizeInBits, 223 uint32 blockSizeInBytes, // for IV 224 CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. 225 CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. 226 uint32 iterCount, 227 const CSSM_DATA &salt, 228 /* exactly one of the following two must be valid */ 229 const CSSM_DATA *pwd, // unicode external representation 230 const CSSM_KEY *passKey, 231 SecNssCoder &coder, // for mallocing cipherText 232 CSSM_DATA &cipherText) 233{ 234 CSSM_RETURN crtn; 235 CSSM_KEY ckey; 236 CSSM_CC_HANDLE ccHand = 0; 237 CSSM_DATA ourCtext = {0, NULL}; 238 CSSM_DATA remData = {0, NULL}; 239 240 /* P12 style IV derivation, optional */ 241 CSSM_DATA iv = {0, NULL}; 242 CSSM_DATA_PTR ivPtr = NULL; 243 if(blockSizeInBytes) { 244 coder.allocItem(iv, blockSizeInBytes); 245 ivPtr = &iv; 246 } 247 248 /* P12 style key derivation */ 249 crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, 250 keySizeInBits, iterCount, salt, pwd, passKey, iv); 251 if(crtn) { 252 return crtn; 253 } 254 /* subsequent errors to errOut: */ 255 256 /* CSSM context */ 257 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 258 encrAlg, 259 mode, 260 NULL, // access cred 261 &ckey, 262 ivPtr, // InitVector, optional 263 padding, 264 NULL, // Params 265 &ccHand); 266 if(crtn) { 267 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn); 268 goto errOut; 269 } 270 271 /* go - CSP mallocs ctext and rem data */ 272 CSSM_SIZE bytesEncrypted; 273 crtn = CSSM_EncryptData(ccHand, 274 &plainText, 275 1, 276 &ourCtext, 277 1, 278 &bytesEncrypted, 279 &remData); 280 if(crtn) { 281 cuPrintError("CSSM_DecryptData", crtn); 282 } 283 else { 284 coder.allocCopyItem(ourCtext, cipherText); 285 cipherText.Length = bytesEncrypted; 286 287 /* plaintext copied into coder space; free the memory allocated 288 * by the CSP */ 289 freeCssmMemory(cspHand, ourCtext.Data); 290 } 291 /* an artifact of CSPFUllPLuginSession - this never contains 292 * valid data but sometimes gets mallocds */ 293 if(remData.Data) { 294 freeCssmMemory(cspHand, remData.Data); 295 } 296errOut: 297 if(ccHand) { 298 CSSM_DeleteContext(ccHand); 299 } 300 CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); 301 return crtn; 302} 303 304/* 305 * Calculate the MAC for a PFX. Caller is either going compare 306 * the result against an existing PFX's MAC or drop the result into 307 * a newly created PFX. 308 */ 309CSSM_RETURN p12GenMac( 310 CSSM_CSP_HANDLE cspHand, 311 const CSSM_DATA &ptext, // e.g., NSS_P12_DecodedPFX.derAuthSaafe 312 CSSM_ALGORITHMS alg, // better be SHA1! 313 unsigned iterCount, 314 const CSSM_DATA &salt, 315 /* exactly one of the following two must be valid */ 316 const CSSM_DATA *pwd, // unicode external representation 317 const CSSM_KEY *passKey, 318 SecNssCoder &coder, // for mallocing macData 319 CSSM_DATA &macData) // RETURNED 320{ 321 CSSM_RETURN crtn; 322 CSSM_CC_HANDLE ccHand = 0; 323 324 /* P12 style key derivation */ 325 unsigned keySizeInBits; 326 CSSM_ALGORITHMS hmacAlg; 327 switch(alg) { 328 case CSSM_ALGID_SHA1: 329 keySizeInBits = 160; 330 hmacAlg = CSSM_ALGID_SHA1HMAC; 331 break; 332 case CSSM_ALGID_MD5: 333 /* not even sure if this is legal in p12 world... */ 334 keySizeInBits = 128; 335 hmacAlg = CSSM_ALGID_MD5HMAC; 336 break; 337 default: 338 return CSSMERR_CSP_INVALID_ALGORITHM; 339 } 340 CSSM_KEY macKey; 341 CSSM_DATA iv = {0, NULL}; 342 crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg, 343 keySizeInBits, iterCount, salt, pwd, passKey, iv); 344 if(crtn) { 345 return crtn; 346 } 347 /* subsequent errors to errOut: */ 348 349 /* prealloc the mac data */ 350 coder.allocItem(macData, keySizeInBits / 8); 351 crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand); 352 if(crtn) { 353 cuPrintError("CSSM_CSP_CreateMacContext", crtn); 354 goto errOut; 355 } 356 357 crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData); 358 if(crtn) { 359 cuPrintError("CSSM_GenerateMac", crtn); 360 } 361errOut: 362 if(ccHand) { 363 CSSM_DeleteContext(ccHand); 364 } 365 CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE); 366 return crtn; 367} 368 369/* 370 * Unwrap a shrouded key. 371 */ 372CSSM_RETURN p12UnwrapKey( 373 CSSM_CSP_HANDLE cspHand, 374 CSSM_DL_DB_HANDLE_PTR dlDbHand, // optional 375 int keyIsPermanent, // nonzero - store in DB 376 const CSSM_DATA &shroudedKeyBits, 377 CSSM_ALGORITHMS keyAlg, // of the unwrapping key 378 CSSM_ALGORITHMS encrAlg, 379 CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only 380 uint32 keySizeInBits, 381 uint32 blockSizeInBytes, // for IV 382 CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. 383 CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. 384 uint32 iterCount, 385 const CSSM_DATA &salt, 386 const CSSM_DATA *pwd, // unicode external representation 387 const CSSM_KEY *passKey, 388 SecNssCoder &coder, // for mallocing privKey 389 const CSSM_DATA &labelData, 390 SecAccessRef access, // optional 391 bool noAcl, 392 CSSM_KEYUSE keyUsage, 393 CSSM_KEYATTR_FLAGS keyAttrs, 394 395 /* 396 * Result: a private key, reference format, optionaly stored 397 * in dlDbHand 398 */ 399 CSSM_KEY_PTR &privKey) 400{ 401 CSSM_RETURN crtn; 402 CSSM_KEY ckey; 403 CSSM_CC_HANDLE ccHand = 0; 404 CSSM_KEY wrappedKey; 405 CSSM_KEY unwrappedKey; 406 CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader; 407 CSSM_DATA descrData = {0, NULL}; // not used for PKCS8 wrap 408 CSSM_KEYATTR_FLAGS reqAttr = keyAttrs; 409 410 ResourceControlContext rcc; 411 ResourceControlContext *rccPtr = NULL; 412 Security::KeychainCore::Access::Maker maker; 413 414 /* P12 style IV derivation, optional */ 415 CSSM_DATA iv = {0, NULL}; 416 CSSM_DATA_PTR ivPtr = NULL; 417 if(blockSizeInBytes) { 418 coder.allocItem(iv, blockSizeInBytes); 419 ivPtr = &iv; 420 } 421 422 /* P12 style key derivation */ 423 crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, 424 keySizeInBits, iterCount, salt, pwd, passKey, iv); 425 if(crtn) { 426 return crtn; 427 } 428 /* subsequent errors to errOut: */ 429 430 /* CSSM context */ 431 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 432 encrAlg, 433 mode, 434 NULL, // access cred 435 &ckey, 436 ivPtr, // InitVector, optional 437 padding, 438 NULL, // Params 439 &ccHand); 440 if(crtn) { 441 p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); 442 goto errOut; 443 } 444 if(dlDbHand) { 445 crtn = p12AddContextAttribute(ccHand, 446 CSSM_ATTRIBUTE_DL_DB_HANDLE, 447 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE), 448 dlDbHand); 449 if(crtn) { 450 p12LogCssmError("AddContextAttribute", crtn); 451 goto errOut; 452 } 453 } 454 455 /* 456 * Cook up minimal WrappedKey header fields 457 */ 458 memset(&wrappedKey, 0, sizeof(CSSM_KEY)); 459 memset(&unwrappedKey, 0, sizeof(CSSM_KEY)); 460 461 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; 462 hdr.BlobType = CSSM_KEYBLOB_WRAPPED; 463 hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; 464 465 /* 466 * This one we do not know. The CSP will figure out the format 467 * of the unwrapped key after it decrypts the raw key material. 468 */ 469 hdr.AlgorithmId = CSSM_ALGID_NONE; 470 hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; 471 472 /* also inferred by CSP */ 473 hdr.LogicalKeySizeInBits = 0; 474 hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE; 475 hdr.KeyUsage = CSSM_KEYUSE_ANY; 476 hdr.WrapAlgorithmId = encrAlg; 477 hdr.WrapMode = mode; 478 479 if(dlDbHand && keyIsPermanent) { 480 reqAttr |= CSSM_KEYATTR_PERMANENT; 481 } 482 483 wrappedKey.KeyData = shroudedKeyBits; 484 485 if(!noAcl) { 486 // Create a Access::Maker for the initial owner of the private key. 487 memset(&rcc, 0, sizeof(rcc)); 488 maker.initialOwner(rcc); 489 rccPtr = &rcc; 490 } 491 492 crtn = CSSM_UnwrapKey(ccHand, 493 NULL, // PublicKey 494 &wrappedKey, 495 keyUsage, 496 reqAttr, 497 &labelData, 498 rccPtr, // CredAndAclEntry 499 privKey, 500 &descrData); // required 501 if(crtn) { 502 p12LogCssmError("CSSM_UnwrapKey", crtn); 503 if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) { 504 /* report in a keychain-friendly way */ 505 crtn = errSecDuplicateItem; 506 } 507 } 508 509 // Finally fix the acl and owner of the private key to the 510 // specified access control settings. 511 if((crtn == CSSM_OK) && !noAcl) { 512 try { 513 CssmClient::KeyAclBearer bearer( 514 cspHand, *privKey, Allocator::standard()); 515 SecPointer<KeychainCore::Access> initialAccess(access ? 516 KeychainCore::Access::required(access) : /* caller-supplied */ 517 new KeychainCore::Access("privateKey")); /* default */ 518 initialAccess->setAccess(bearer, maker); 519 } 520 catch (const CssmError &e) { 521 /* not implemented means we're talking to the CSP which does 522 * not implement ACLs */ 523 if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) { 524 crtn = e.error; 525 } 526 } 527 catch(...) { 528 p12ErrorLog("p12 exception on setAccess\n"); 529 crtn = errSecAuthFailed; /* ??? */ 530 } 531 } 532 533errOut: 534 if(ccHand) { 535 CSSM_DeleteContext(ccHand); 536 } 537 CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); 538 return crtn; 539} 540 541/* 542 * Wrap a private key, yielding shrouded key bits. 543 */ 544CSSM_RETURN p12WrapKey( 545 CSSM_CSP_HANDLE cspHand, 546 CSSM_KEY_PTR privKey, 547 const CSSM_ACCESS_CREDENTIALS *privKeyCreds, 548 CSSM_ALGORITHMS keyAlg, // of the unwrapping key 549 CSSM_ALGORITHMS encrAlg, 550 CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only 551 uint32 keySizeInBits, 552 uint32 blockSizeInBytes, // for IV 553 CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. 554 CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. 555 uint32 iterCount, 556 const CSSM_DATA &salt, 557 const CSSM_DATA *pwd, // unicode external representation 558 const CSSM_KEY *passKey, 559 SecNssCoder &coder, // for mallocing keyBits 560 CSSM_DATA &shroudedKeyBits) // RETURNED 561{ 562 CSSM_RETURN crtn; 563 CSSM_KEY ckey; 564 CSSM_CC_HANDLE ccHand = 0; 565 CSSM_KEY wrappedKey; 566 CSSM_CONTEXT_ATTRIBUTE attr; 567 CSSM_DATA descrData = {0, NULL}; 568 CSSM_ACCESS_CREDENTIALS creds; 569 570 /* key must be extractable */ 571 if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { 572 return errSecDataNotAvailable; 573 } 574 575 if(privKeyCreds == NULL) { 576 /* i.e., key is from the bare CSP with no ACL support */ 577 memset(&creds, 0, sizeof(creds)); 578 privKeyCreds = &creds; 579 } 580 581 /* P12 style IV derivation, optional */ 582 CSSM_DATA iv = {0, NULL}; 583 CSSM_DATA_PTR ivPtr = NULL; 584 if(blockSizeInBytes) { 585 coder.allocItem(iv, blockSizeInBytes); 586 ivPtr = &iv; 587 } 588 589 /* P12 style key derivation */ 590 crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, 591 keySizeInBits, iterCount, salt, pwd, passKey, iv); 592 if(crtn) { 593 return crtn; 594 } 595 /* subsequent errors to errOut: */ 596 597 /* CSSM context */ 598 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 599 encrAlg, 600 mode, 601 NULL, // access cred 602 &ckey, 603 ivPtr, // InitVector, optional 604 padding, 605 NULL, // Params 606 &ccHand); 607 if(crtn) { 608 p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); 609 goto errOut; 610 } 611 612 memset(&wrappedKey, 0, sizeof(CSSM_KEY)); 613 614 /* specify PKCS8 wrap format */ 615 attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; 616 attr.AttributeLength = sizeof(uint32); 617 attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; 618 crtn = CSSM_UpdateContextAttributes( 619 ccHand, 620 1, 621 &attr); 622 if(crtn) { 623 p12LogCssmError("CSSM_UpdateContextAttributes", crtn); 624 goto errOut; 625 } 626 627 crtn = CSSM_WrapKey(ccHand, 628 privKeyCreds, 629 privKey, 630 &descrData, // DescriptiveData 631 &wrappedKey); 632 if(crtn) { 633 p12LogCssmError("CSSM_WrapKey", crtn); 634 } 635 else { 636 coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits); 637 638 /* this was mallocd by CSP */ 639 freeCssmMemory(cspHand, wrappedKey.KeyData.Data); 640 } 641errOut: 642 if(ccHand) { 643 CSSM_DeleteContext(ccHand); 644 } 645 CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); 646 return crtn; 647} 648