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