1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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 * SecImportExportCrypto.cpp - low-level crypto routines for wrapping and unwrapping 25 * keys. 26 */ 27 28#include "SecImportExport.h" 29#include "SecImportExportCrypto.h" 30#include "SecImportExportUtils.h" 31#include "Keychains.h" 32#include "Access.h" 33#include "Item.h" 34#include "SecKeyPriv.h" 35#include "KCEventNotifier.h" 36#include <security_cdsa_utilities/cssmacl.h> 37#include <security_cdsa_utilities/KeySchema.h> 38#include <security_cdsa_utilities/cssmdata.h> 39#include <security_cdsa_utils/cuCdsaUtils.h> 40#include <security_utilities/devrandom.h> 41#include <security_cdsa_client/securestorage.h> 42#include <security_cdsa_client/dlclient.h> 43#include <Security/cssmapi.h> 44 45/* 46 * Key attrribute names and values. 47 * 48 * This is where the public key hash goes. 49 */ 50#define SEC_KEY_HASH_ATTR_NAME "Label" 51 52/* 53 * This is where the publicly visible name goes. 54 */ 55#define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName" 56 57/* 58 * Default values we ultimately assign to the PrintName attr. 59 */ 60#define SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE "Imported Private Key" 61#define SEC_PUBKEY_PRINT_NAME_ATTR_VALUE "Imported Public Key" 62#define SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE "Imported Key" 63 64/* 65 * Set private key's Label and PrintName attributes. On entry Label 66 * is typically a random string to faciliate finding the key in a DL; 67 * the PrintName is currently set to the same value by the DL. We 68 * replace the Label attr with the public key hash and the PrintName 69 * attr with a caller-supplied value. 70 */ 71static CSSM_RETURN impExpSetKeyLabel( 72 CSSM_CSP_HANDLE cspHand, // where the key lives 73 CSSM_DL_DB_HANDLE dlDbHand, // ditto 74 SecKeychainRef kcRef, // ditto 75 CSSM_KEY_PTR cssmKey, 76 const CSSM_DATA *existKeyLabel, // existing label, a random string 77 const CSSM_DATA *newPrintName, 78 CssmOwnedData &newLabel, // RETURNED as what we set 79 SecKeyRef *secKey) // RETURNED 80{ 81 CSSM_RETURN crtn; 82 CSSM_DATA keyDigest = {0, NULL}; 83 84 crtn = impExpKeyDigest(cspHand, cssmKey, &keyDigest); 85 if(crtn) { 86 return crtn; 87 } 88 89 /* caller needs this for subsequent DL lookup */ 90 newLabel.copy(keyDigest); 91 92 /* Find this key as a SecKeychainItem */ 93 SecItemClass itemClass = (cssmKey->KeyHeader.KeyClass == 94 CSSM_KEYCLASS_PRIVATE_KEY) ? kSecPrivateKeyItemClass : 95 kSecPublicKeyItemClass; 96 SecKeychainAttribute kcAttr = {kSecKeyLabel, (UInt32)existKeyLabel->Length, existKeyLabel->Data}; 97 SecKeychainAttributeList kcAttrList = {1, &kcAttr}; 98 SecKeychainSearchRef srchRef = NULL; 99 OSStatus ortn; 100 SecKeychainItemRef itemRef = NULL; 101 102 ortn = SecKeychainSearchCreateFromAttributes(kcRef, itemClass, 103 &kcAttrList, &srchRef); 104 if(ortn) { 105 SecImpExpDbg("SecKeychainSearchCreateFromAttributes error"); 106 crtn = ortn; 107 goto errOut; 108 } 109 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef); 110 if(ortn) { 111 SecImpExpDbg("SecKeychainSearchCopyNext error"); 112 crtn = ortn; 113 goto errOut; 114 } 115 #ifndef NDEBUG 116 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef); 117 if(ortn == errSecSuccess) { 118 SecImpExpDbg("impExpSetKeyLabel: found second key with same label!"); 119 crtn = errSecInternalComponent; 120 goto errOut; 121 } 122 #endif /* NDEBUG */ 123 124 /* modify two attributes... */ 125 SecKeychainAttribute modAttrs[2]; 126 modAttrs[0].tag = kSecKeyLabel; 127 modAttrs[0].length = (UInt32)keyDigest.Length; 128 modAttrs[0].data = keyDigest.Data; 129 modAttrs[1].tag = kSecKeyPrintName; 130 modAttrs[1].length = (UInt32)newPrintName->Length; 131 modAttrs[1].data = newPrintName->Data; 132 kcAttrList.count = 2; 133 kcAttrList.attr = modAttrs; 134 ortn = SecKeychainItemModifyAttributesAndData(itemRef, &kcAttrList, 135 0, NULL); 136 if(ortn) { 137 SecImpExpDbg("SecKeychainItemModifyAttributesAndData error"); 138 crtn = ortn; 139 goto errOut; 140 } 141 *secKey = (SecKeyRef)itemRef; 142errOut: 143 if(keyDigest.Data) { 144 /* mallocd by CSP */ 145 impExpFreeCssmMemory(cspHand, keyDigest.Data); 146 } 147 if(srchRef) { 148 CFRelease(srchRef); 149 } 150 return crtn; 151} 152 153/* 154 * Import a raw key. This can be used as a lightweight "guess" evaluator 155 * if a handle to the raw CSP is passed in (with no keychain), or as 156 * the real thing which does full keychain import. 157 */ 158OSStatus impExpImportRawKey( 159 CFDataRef inData, 160 SecExternalFormat externForm, 161 SecExternalItemType itemType, 162 CSSM_ALGORITHMS keyAlg, 163 SecKeychainRef importKeychain, // optional 164 CSSM_CSP_HANDLE cspHand, // required 165 SecItemImportExportFlags flags, 166 const SecKeyImportExportParameters *keyParams, // optional 167 const char *printName, // optional 168 CFMutableArrayRef outArray) // optional, append here 169{ 170 CSSM_RETURN crtn; 171 CSSM_KEY wrappedKey; 172 CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader; 173 CSSM_CSP_HANDLE rawCspHand = 0; 174 CSSM_KEY_SIZE keySize; 175 CSSM_KEYBLOB_FORMAT format; 176 CSSM_KEYCLASS keyClass; 177 178 /* First convert external format and types to CSSM style. */ 179 crtn = impExpKeyForm(externForm, itemType, keyAlg, &format, &keyClass); 180 181 /* cook up key to be null-unwrapped */ 182 memset(&wrappedKey, 0, sizeof(CSSM_KEY)); 183 wrappedKey.KeyData.Length = CFDataGetLength(inData); 184 wrappedKey.KeyData.Data = (uint8 *)CFDataGetBytePtr(inData); 185 186 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; 187 /* CspId don't care */ 188 hdr.BlobType = CSSM_KEYBLOB_RAW; 189 hdr.Format = format; 190 hdr.AlgorithmId = keyAlg; 191 hdr.KeyClass = keyClass; 192 /* LogicalKeySizeInBits calculated below */ 193 /* attr and usage are for the incoming unwrapped key... */ 194 hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; 195 hdr.KeyUsage = CSSM_KEYUSE_ANY; 196 197 /* 198 * Get key size in bits from raw CSP. Doing this right now is a good 199 * optimization for the "guessing" case; getting the key size from the 200 * raw CSP involves a full decode on an alg- and format-specific manner. 201 * If we've been given the wrong params, we'll fail right here without 202 * the complication of a full UnwrapKey op. 203 */ 204 rawCspHand = cuCspStartup(CSSM_TRUE); 205 if(rawCspHand == 0) { 206 return CSSMERR_CSSM_ADDIN_LOAD_FAILED; 207 } 208 crtn = CSSM_QueryKeySizeInBits(rawCspHand, CSSM_INVALID_HANDLE, &wrappedKey, &keySize); 209 cuCspDetachUnload(rawCspHand, CSSM_TRUE); 210 if(crtn) { 211 SecImpExpDbg("CSSM_QueryKeySizeInBits error"); 212 return crtn; 213 } 214 hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; 215 216 impExpKeyUnwrapParams unwrapParams; 217 memset(&unwrapParams, 0, sizeof(unwrapParams)); 218 unwrapParams.encrAlg = CSSM_ALGID_NONE; 219 unwrapParams.encrMode = CSSM_ALGMODE_NONE; 220 unwrapParams.unwrappingKey = NULL; 221 unwrapParams.encrPad = CSSM_PADDING_NONE; 222 223 return impExpImportKeyCommon( 224 &wrappedKey, 225 importKeychain, 226 cspHand, 227 flags, 228 keyParams, 229 &unwrapParams, 230 printName, 231 outArray); 232} 233 234using namespace KeychainCore; 235 236/* 237 * Post notification of a "new key added" event. 238 * If you know of another way to do this, other than a dlclient-based lookup of the 239 * existing key in order to get a KeychainCore::Item, by all means have at it. 240 */ 241OSStatus impExpKeyNotify( 242 SecKeychainRef importKeychain, 243 const CssmData &keyLabel, // stored with this, we use it to do a lookup 244 const CSSM_KEY &cssmKey) // unwrapped key in CSSM format 245{ 246 /* 247 * Look up key in the DLDB by label, key class, algorithm, and key size. 248 */ 249 CSSM_DB_RECORDTYPE recordType; 250 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader; 251 252 switch(hdr.KeyClass) { 253 case CSSM_KEYCLASS_PUBLIC_KEY: 254 recordType = CSSM_DL_DB_RECORD_PUBLIC_KEY; 255 break; 256 case CSSM_KEYCLASS_PRIVATE_KEY: 257 recordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; 258 break; 259 case CSSM_KEYCLASS_SESSION_KEY: 260 recordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY; 261 break; 262 default: 263 return errSecParam; 264 } 265 assert(importKeychain != NULL); 266 Keychain keychain = KeychainImpl::required(importKeychain); 267 268 SSDbImpl* impl = dynamic_cast<CssmClient::SSDbImpl *>(&(*keychain->database())); 269 if (impl == NULL) // did we go bad? 270 { 271 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); 272 } 273 274 CssmClient::SSDb ssDb(impl); 275 276 CssmClient::DbAttributes dbAttributes; 277 CssmClient::DbUniqueRecord uniqueId; 278 CssmClient::SSDbCursor dbCursor(ssDb, 3); // three attributes 279 dbCursor->recordType(recordType); 280 dbCursor->add(CSSM_DB_EQUAL, KeySchema::Label, keyLabel); 281 dbCursor->add(CSSM_DB_EQUAL, KeySchema::KeyType, hdr.AlgorithmId); 282 dbCursor->add(CSSM_DB_EQUAL, KeySchema::KeySizeInBits, hdr.LogicalKeySizeInBits); 283 CssmClient::Key key; 284 if (!dbCursor->nextKey(&dbAttributes, key, uniqueId)) { 285 SecImpExpDbg("impExpKeyNotify: key not found"); 286 return errSecItemNotFound; 287 } 288 289 /* 290 * Get a Keychain-style Item, post notification. 291 */ 292 Item keyItem = keychain->item(recordType, uniqueId); 293 keychain->postEvent(kSecAddEvent, keyItem); 294 295 return errSecSuccess; 296} 297 298/* 299 * Size of random label string in ASCII chars to facilitate DL lookup. 300 */ 301#define SEC_RANDOM_LABEL_LEN 16 302 303#define SEC_KEYATTR_RETURN_MASK \ 304 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE) 305 306/* 307 * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and 308 * wrapped keys. 309 */ 310OSStatus impExpImportKeyCommon( 311 const CSSM_KEY *wrappedKey, 312 SecKeychainRef importKeychain, // optional 313 CSSM_CSP_HANDLE cspHand, // required, if importKeychain is 314 // present, must be from there 315 SecItemImportExportFlags flags, 316 const SecKeyImportExportParameters *keyParams, // optional 317 const impExpKeyUnwrapParams *unwrapParams, 318 const char *printName, // optional 319 CFMutableArrayRef outArray) // optional, append here 320{ 321 CSSM_CC_HANDLE ccHand = 0; 322 CSSM_RETURN crtn; 323 CSSM_DATA labelData; 324 CSSM_KEY unwrappedKey; 325 CSSM_DL_DB_HANDLE dlDbHandle; 326 CSSM_DL_DB_HANDLE *dlDbPtr = NULL; 327 OSStatus ortn; 328 CSSM_ACCESS_CREDENTIALS nullCreds; 329 uint8 randLabel[SEC_RANDOM_LABEL_LEN + 1]; 330 CSSM_KEYUSE keyUsage = 0; // default 331 CSSM_KEYATTR_FLAGS keyAttributes = 0; // default 332 const CSSM_KEYHEADER &hdr = wrappedKey->KeyHeader; 333 CSSM_DATA descrData = {0, NULL}; 334 ResourceControlContext rcc; 335 Security::KeychainCore::Access::Maker maker; 336 ResourceControlContext *rccPtr = NULL; 337 SecAccessRef accessRef = keyParams ? keyParams->accessRef : NULL; 338 CssmAutoData keyLabel(Allocator::standard()); 339 SecKeyRef secKeyRef = NULL; 340 bool usedSecKeyCreate = false; 341 342 assert(unwrapParams != NULL); 343 assert(cspHand != 0); 344 345 if(importKeychain) { 346 ortn = SecKeychainGetDLDBHandle(importKeychain, &dlDbHandle); 347 if(ortn) { 348 return ortn; 349 } 350 dlDbPtr = &dlDbHandle; 351 } 352 353 memset(&unwrappedKey, 0, sizeof(CSSM_KEY)); 354 memset(&nullCreds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 355 356 /* context for unwrap */ 357 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 358 unwrapParams->encrAlg, 359 unwrapParams->encrMode, 360 &nullCreds, 361 unwrapParams->unwrappingKey, 362 unwrapParams->iv.Data ? &unwrapParams->iv : NULL, 363 unwrapParams->encrPad, 364 0, // Params 365 &ccHand); 366 if(crtn) { 367 goto errOut; 368 } 369 if(dlDbPtr) { 370 /* Importing to a keychain - add DLDB to context */ 371 crtn = impExpAddContextAttribute(ccHand, 372 CSSM_ATTRIBUTE_DL_DB_HANDLE, 373 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE), 374 dlDbPtr); 375 if(crtn) { 376 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error"); 377 goto errOut; 378 } 379 } 380 381 if((hdr.KeyClass != CSSM_KEYCLASS_SESSION_KEY) && (dlDbPtr != NULL)) { 382 /* Generate random 16-char label to facilitate DL lookup */ 383 char *randAscii = (char *)randLabel; 384 uint8 randBinary[SEC_RANDOM_LABEL_LEN / 2]; 385 unsigned randBinaryLen = SEC_RANDOM_LABEL_LEN / 2; 386 DevRandomGenerator rng; 387 388 rng.random(randBinary, randBinaryLen); 389 for(unsigned i=0; i<randBinaryLen; i++) { 390 sprintf(randAscii, "%02X", randBinary[i]); 391 randAscii += 2; 392 } 393 labelData.Data = randLabel; 394 labelData.Length = SEC_RANDOM_LABEL_LEN; 395 /* actual keyLabel value set later */ 396 } 397 else { 398 labelData.Data = (uint8 *)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE; 399 labelData.Length = strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE); 400 keyLabel.copy(labelData); 401 } 402 403 /* 404 * key attr flags and usage. First the defaults. 405 */ 406 if(keyParams) { 407 keyUsage = keyParams->keyUsage; 408 keyAttributes = keyParams->keyAttributes; 409 } 410 if(keyUsage == 0) { 411 /* default */ 412 keyUsage = CSSM_KEYUSE_ANY; 413 } 414 if(keyAttributes == 0) { 415 /* default */ 416 keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE; 417 if(dlDbPtr) { 418 keyAttributes |= CSSM_KEYATTR_PERMANENT; 419 } 420 if(hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) { 421 keyAttributes |= (CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE); 422 } 423 } 424 else { 425 /* caller-supplied; ensure we're generating a reference key */ 426 keyAttributes &= ~SEC_KEYATTR_RETURN_MASK; 427 keyAttributes |= CSSM_KEYATTR_RETURN_REF; 428 } 429 430 if( (dlDbPtr != NULL) && // not permanent, no ACL 431 (hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) && // ACLs only for private key 432 ( (keyParams == NULL) || // NULL --> default ACL 433 !(keyParams->flags & kSecKeyNoAccessControl) // explicity request no ACL 434 ) 435 ) { 436 /* 437 * Prepare to set up either a default ACL or one provided by caller via 438 * keyParams->accessRef. 439 */ 440 memset(&rcc, 0, sizeof(rcc)); 441 maker.initialOwner(rcc); 442 rccPtr = &rcc; 443 } 444 445 /* 446 * Additional optional parameters: block size, rounds, 447 * effectiveKeySize. 448 * WARNING: block size and rounds, used for RC5, have not been tested. 449 * OpenSSL, as of Panther ship, did not support RC5 encryption. 450 */ 451 if(unwrapParams->effectiveKeySizeInBits != 0) { 452 assert(unwrapParams->unwrappingKey->KeyHeader.AlgorithmId == 453 CSSM_ALGID_RC2); 454 SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu", 455 (unsigned long)unwrapParams->effectiveKeySizeInBits); 456 crtn = impExpAddContextAttribute(ccHand, 457 CSSM_ATTRIBUTE_EFFECTIVE_BITS, 458 sizeof(uint32), 459 (void *)((size_t) unwrapParams->effectiveKeySizeInBits)); 460 if(crtn) { 461 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error"); 462 goto errOut; 463 } 464 } 465 466 if(unwrapParams->rounds != 0) { 467 assert(unwrapParams->unwrappingKey->KeyHeader.AlgorithmId == 468 CSSM_ALGID_RC5); 469 SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu", 470 (unsigned long)unwrapParams->rounds); 471 crtn = impExpAddContextAttribute(ccHand, 472 CSSM_ATTRIBUTE_ROUNDS, 473 sizeof(uint32), 474 (void *)((size_t)unwrapParams->rounds)); 475 if(crtn) { 476 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error"); 477 goto errOut; 478 } 479 } 480 481 if(unwrapParams->blockSizeInBits != 0) { 482 /* Our RC5 implementation has a fixed block size */ 483 if(unwrapParams->blockSizeInBits != 64) { 484 SecImpExpDbg("WARNING impExpImportKeyCommon: setting block size to %lu", 485 (unsigned long)unwrapParams->blockSizeInBits); 486 /* 487 * With the current CSP this will actually be ignored 488 */ 489 crtn = impExpAddContextAttribute(ccHand, 490 CSSM_ATTRIBUTE_BLOCK_SIZE, 491 sizeof(uint32), 492 (void *)((size_t)unwrapParams->blockSizeInBits)); 493 if(crtn) { 494 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error"); 495 goto errOut; 496 } 497 } 498 } 499 500 /* Here we go */ 501 crtn = CSSM_UnwrapKey(ccHand, 502 NULL, // public key 503 (const CSSM_WRAP_KEY *)wrappedKey, 504 keyUsage, 505 keyAttributes, 506 &labelData, 507 rccPtr, // CredAndAclEntry 508 &unwrappedKey, 509 &descrData); // required 510 if(crtn != CSSM_OK) { 511 SecImpExpDbg("CSSM_UnwrapKey failure"); 512 if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) { 513 /* report in a keychain-friendly way */ 514 crtn = errSecDuplicateItem; 515 } 516 goto errOut; 517 } 518 519 /* Private and public keys: update Label as public key hash */ 520 if((hdr.KeyClass != CSSM_KEYCLASS_SESSION_KEY) && (dlDbPtr != NULL)) { 521 CSSM_DATA newPrintName; 522 if(printName) { 523 /* caller specified */ 524 newPrintName.Data = (uint8 *)printName; 525 } 526 else { 527 /* use defaults */ 528 if(hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) { 529 newPrintName.Data = (uint8 *)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE; 530 } 531 else { 532 newPrintName.Data = (uint8 *)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE; 533 } 534 } 535 newPrintName.Length = strlen((char *)newPrintName.Data); 536 #if old_way 537 crtn = impExpSetKeyLabel(cspHand, *dlDbPtr, &unwrappedKey, 538 &labelData, &newPrintName, keyLabel); 539 #else 540 crtn = impExpSetKeyLabel(cspHand, *dlDbPtr, importKeychain, 541 &unwrappedKey, &labelData, &newPrintName, keyLabel, &secKeyRef); 542 #endif 543 if(crtn) { 544 goto errOut; 545 } 546 } 547 548 /* Private key: adjust ACL as appropriate */ 549 if(rccPtr != NULL) { 550 SecPointer<KeychainCore::Access> theAccess(accessRef ? 551 KeychainCore::Access::required(accessRef) : 552 new KeychainCore::Access("Imported Private Key")); 553 try { 554 CssmClient::KeyAclBearer bearer(cspHand, unwrappedKey, Allocator::standard()); 555 theAccess->setAccess(bearer, maker); 556 } 557 catch (const CssmError &e) { 558 /* not implemented means we're talking to the raw CSP which does 559 * not implement ACLs */ 560 if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) { 561 crtn = e.error; 562 } 563 } 564 catch(...) { 565 SecImpExpDbg("keyImport: exception on setAccess\n"); 566 crtn = errSecAuthFailed; /* ??? */ 567 } 568 } 569 570 /* 571 * If importKeychain is non-NULL we've already added the key to the keychain. 572 * If importKeychain is NULL, and outArray is non-NULL, we have to use the 573 * half-baked SecKeyCreateWithCSSMKey to give the caller *something*. 574 */ 575 if(outArray) { 576 if(secKeyRef == NULL) { 577 assert(importKeychain == NULL); 578 ortn = SecKeyCreateWithCSSMKey(&unwrappedKey, &secKeyRef); 579 if(ortn) { 580 SecImpExpDbg("SecKeyCreateWithCSSMKey failure"); 581 crtn = ortn; 582 goto errOut; 583 } 584 /* don't CSSM_FreeKey() this key */ 585 usedSecKeyCreate = true; 586 } 587 CFArrayAppendValue(outArray, secKeyRef); 588 } 589 590 if(importKeychain) { 591 impExpKeyNotify(importKeychain, keyLabel.get(), unwrappedKey); 592 } 593 594errOut: 595 if(ccHand != 0) { 596 CSSM_DeleteContext(ccHand); 597 } 598 if(secKeyRef) { 599 CFRelease(secKeyRef); 600 } 601 if((unwrappedKey.KeyData.Data != NULL) && !usedSecKeyCreate) { 602 /* skip this free if we used SecKeyCreateWithCSSMKey() */ 603 CSSM_FreeKey(cspHand, NULL, &unwrappedKey, CSSM_FALSE); 604 } 605 return crtn; 606} 607 608/* 609 * Common code to wrap a key for export. 610 */ 611CSSM_RETURN impExpExportKeyCommon( 612 CSSM_CSP_HANDLE cspHand, // for all three keys 613 SecKeyRef secKey, 614 CSSM_KEY_PTR wrappingKey, 615 CSSM_KEY_PTR wrappedKey, // RETURNED 616 CSSM_ALGORITHMS wrapAlg, 617 CSSM_ENCRYPT_MODE wrapMode, 618 CSSM_PADDING wrapPad, 619 CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8, OPENSSL 620 CSSM_ATTRIBUTE_TYPE blobAttrType, // optional raw key format attr 621 CSSM_KEYBLOB_FORMAT blobForm, // ditto 622 const CSSM_DATA *descData, // optional descriptive data 623 const CSSM_DATA *iv) 624{ 625 OSStatus ortn; 626 CSSM_RETURN crtn; 627 628 const CSSM_KEY *unwrappedKey; 629 ortn = SecKeyGetCSSMKey(secKey, &unwrappedKey); 630 if(ortn) { 631 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error"); 632 return ortn; 633 } 634 else if(!(unwrappedKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { 635 SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable"); 636 return errSecDataNotAvailable; 637 } 638 639 /* 640 * Creds needed only for wrapping private keys. 641 * We bother checking in case we ever want to use this to wrap 642 * session keys. 643 */ 644 CSSM_ACCESS_CREDENTIALS nullCreds; 645 memset(&nullCreds, 0, sizeof(nullCreds)); 646 const CSSM_ACCESS_CREDENTIALS *creds = &nullCreds; // default 647 648 CSSM_KEYCLASS keyClass = unwrappedKey->KeyHeader.KeyClass; 649 if(keyClass == CSSM_KEYCLASS_PRIVATE_KEY) { 650 ortn = SecKeyGetCredentials(secKey, 651 CSSM_ACL_AUTHORIZATION_DECRYPT, // HACK will change! 652 kSecCredentialTypeDefault, 653 &creds); 654 if(ortn) { 655 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error"); 656 return ortn; 657 } 658 } 659 660 CSSM_CC_HANDLE ccHand; 661 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 662 wrapAlg, 663 wrapMode, 664 &nullCreds, // creds for wrapping key, never a private key here 665 wrappingKey, 666 iv, 667 wrapPad, 668 0, // Params 669 &ccHand); 670 if(ortn) { 671 SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error"); 672 return crtn; 673 } 674 675 /* a couple of optional caller-specified attributes */ 676 if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { 677 crtn = impExpAddContextAttribute(ccHand, 678 CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, 679 sizeof(uint32), 680 (void *)((size_t)wrapFormat)); 681 if(crtn) { 682 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)"); 683 CSSM_DeleteContext(ccHand); 684 return crtn; 685 } 686 } 687 688 if(blobAttrType != CSSM_ATTRIBUTE_NONE) { 689 crtn = impExpAddContextAttribute(ccHand, 690 blobAttrType, 691 sizeof(uint32), 692 (void *)((size_t)blobForm)); 693 if(crtn) { 694 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error"); 695 return crtn; 696 } 697 } 698 699 CSSM_DATA dData = {0, 0}; 700 if(descData) { 701 dData = *descData; 702 } 703 704 crtn = CSSM_WrapKey(ccHand, 705 creds, 706 unwrappedKey, 707 &dData, 708 wrappedKey); 709 CSSM_DeleteContext(ccHand); 710 switch(crtn) { 711 case CSSM_OK: 712 break; 713 case CSSMERR_CSP_INVALID_KEYATTR_MASK: 714 { 715 /* 716 * This is what comes back when we try to wrap an unextractable 717 * key, or when we null wrap a sensitive key. Give the caller 718 * some useful info. 719 */ 720 CSSM_KEYATTR_FLAGS attr = unwrappedKey->KeyHeader.KeyAttr; 721 if(!(attr & CSSM_KEYATTR_EXTRACTABLE)) { 722 SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE"); 723 return errSecDataNotAvailable; 724 } 725 if((attr & CSSM_KEYATTR_SENSITIVE) && (wrappingKey == NULL)) { 726 SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap"); 727 return errSecPassphraseRequired; 728 } 729 730 } 731 default: 732 SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error"); 733 } 734 return crtn; 735} 736