SecKeychainItem.cpp
1 /* 2 * Copyright (c) 2000-2004,2011-2016 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 #include <Security/SecBase.h> 25 #include <Security/SecKeychainItem.h> 26 #include <Security/SecKeychainItemPriv.h> 27 #include <Security/SecCertificatePriv.h> 28 #include <Security/SecItemPriv.h> 29 30 #include <security_keychain/Keychains.h> 31 #include <security_keychain/KeyItem.h> 32 #include <security_keychain/Item.h> 33 #include <security_keychain/Certificate.h> 34 #include <security_keychain/Identity.h> 35 #include <security_keychain/KCCursor.h> // @@@ Remove this when SecKeychainItemFindFirst moves to SecKeychainSearch 36 37 #include <securityd_client/dictionary.h> 38 #include <security_cdsa_utilities/Schema.h> 39 #include <Security/cssmapplePriv.h> 40 #include <syslog.h> 41 #include <os/activity.h> 42 43 #include "SecBridge.h" 44 #include "KCExceptions.h" 45 #include "Access.h" 46 #include "SecKeychainItemExtendedAttributes.h" 47 #include "LegacyAPICounts.h" 48 49 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref); 50 51 // 52 // Given a polymorphic Sec type object, return 53 // its AclBearer component. 54 // Note: Login ACLs are not hooked into this layer; 55 // modules or attachments have no Sec* layer representation. 56 // 57 static 58 RefPointer<AclBearer> aclBearer(CFTypeRef itemRef) 59 { 60 // well, exactly what kind of something are you? 61 CFTypeID id = CFGetTypeID(itemRef); 62 if (id == gTypes().ItemImpl.typeID) { 63 // keychain item. If it's in a protected group, return the group key 64 if (SSGroup group = ItemImpl::required(SecKeychainItemRef(itemRef))->group()) 65 return &*group; 66 } else if (id == SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef)itemRef)) { 67 // key item, return the key itself. 68 if (CssmClient::Key key = KeyItem::required(SecKeyRef(itemRef))->key()) 69 return &*key; 70 } else if (id == gTypes().KeychainImpl.typeID) { 71 // keychain (this yields the database ACL) 72 //@@@ not hooked up yet 73 } 74 // Guess not. Bummer 75 MacOSError::throwMe(errSecNoAccessForItem); 76 } 77 78 79 CFTypeID 80 SecKeychainItemGetTypeID(void) 81 { 82 BEGIN_SECAPI 83 return gTypes().ItemImpl.typeID; 84 85 END_SECAPI1(_kCFRuntimeNotATypeID) 86 } 87 88 89 OSStatus 90 SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeList *attrList, 91 UInt32 length, const void *data, SecKeychainRef keychainRef, 92 SecAccessRef initialAccess, SecKeychainItemRef *itemRef) 93 { 94 BEGIN_SECAPI 95 os_activity_t activity = os_activity_create("SecKeychainItemCreateFromContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 96 os_activity_scope(activity); 97 os_release(activity); 98 99 KCThrowParamErrIf_(length!=0 && data==NULL); 100 Item item(itemClass, attrList, length, data); 101 if (initialAccess) { 102 item->setAccess(Access::required(initialAccess)); 103 } 104 Keychain keychain = nil; 105 try 106 { 107 keychain = Keychain::optional(keychainRef); 108 if ( !keychain->exists() ) 109 { 110 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. 111 } 112 } 113 catch(...) 114 { 115 keychain = globals().storageManager.defaultKeychainUI(item); 116 } 117 118 keychain->add(item); 119 if (itemRef) { 120 *itemRef = item->handle(); 121 } 122 123 END_SECAPI 124 } 125 126 127 OSStatus 128 SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) 129 { 130 BEGIN_SECKCITEMAPI 131 os_activity_t activity = os_activity_create("SecKeychainItemModifyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 132 os_activity_scope(activity); 133 os_release(activity); 134 135 Item item = ItemImpl::required(__itemImplRef); 136 item->modifyContent(attrList, length, data); 137 138 END_SECKCITEMAPI 139 } 140 141 142 OSStatus 143 SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData) 144 { 145 BEGIN_SECKCITEMAPI 146 os_activity_t activity = os_activity_create("SecKeychainItemCopyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 147 os_activity_scope(activity); 148 os_release(activity); 149 150 Item item = ItemImpl::required(__itemImplRef); 151 item->getContent(itemClass, attrList, length, outData); 152 153 END_SECKCITEMAPI 154 } 155 156 157 OSStatus 158 SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data) 159 { 160 BEGIN_SECAPI 161 os_activity_t activity = os_activity_create("SecKeychainItemFreeContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 162 os_activity_scope(activity); 163 os_release(activity); 164 165 ItemImpl::freeContent(attrList, data); 166 167 END_SECAPI 168 } 169 170 171 OSStatus 172 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) 173 { 174 BEGIN_SECKCITEMAPI 175 os_activity_t activity = os_activity_create("SecKeychainItemModifyAttributesAndData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 176 os_activity_scope(activity); 177 os_release(activity); 178 179 Item item = ItemImpl::required(__itemImplRef); 180 item->modifyAttributesAndData(attrList, length, data); 181 182 END_SECKCITEMAPI 183 } 184 185 186 OSStatus 187 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, SecItemClass *itemClass, SecKeychainAttributeList **attrList, UInt32 *length, void **outData) 188 { 189 BEGIN_SECKCITEMAPI 190 191 Item item = ItemImpl::required(__itemImplRef); 192 item->getAttributesAndData(info, itemClass, attrList, length, outData); 193 194 END_SECKCITEMAPI 195 } 196 197 198 OSStatus 199 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *data) 200 { 201 BEGIN_SECAPI 202 ItemImpl::freeAttributesAndData(attrList, data); 203 204 END_SECAPI 205 } 206 207 208 OSStatus 209 SecKeychainItemDelete(SecKeychainItemRef itemRef) 210 { 211 BEGIN_SECKCITEMAPI 212 os_activity_t activity = os_activity_create("SecKeychainItemDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 213 os_activity_scope(activity); 214 os_release(activity); 215 216 Item item = ItemImpl::required(__itemImplRef); 217 Keychain keychain = item->keychain(); 218 // item must be persistent. 219 KCThrowIf_( !keychain, errSecInvalidItemRef ); 220 221 /* 222 * Before deleting the item, delete any existing Extended Attributes. 223 */ 224 OSStatus ortn; 225 CFArrayRef attrNames = NULL; 226 ortn = SecKeychainItemCopyAllExtendedAttributes(__itemImplRef, &attrNames, NULL); 227 if(ortn == errSecSuccess) { 228 CFIndex numAttrs = CFArrayGetCount(attrNames); 229 for(CFIndex dex=0; dex<numAttrs; dex++) { 230 CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex); 231 /* setting value to NULL ==> delete */ 232 SecKeychainItemSetExtendedAttribute(__itemImplRef, attrName, NULL); 233 } 234 } 235 236 /* now delete the item */ 237 keychain->deleteItem( item ); 238 239 END_SECKCITEMAPI 240 } 241 242 243 OSStatus 244 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef* keychainRef) 245 { 246 BEGIN_SECKCITEMAPI 247 248 // make sure this item has a keychain 249 Keychain kc = ItemImpl::required(__itemImplRef)->keychain(); 250 if (kc == NULL) 251 { 252 MacOSError::throwMe(errSecNoSuchKeychain); 253 } 254 255 Required(keychainRef) = kc->handle(); 256 257 END_SECKCITEMAPI 258 } 259 260 261 OSStatus 262 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychainRef, 263 SecAccessRef initialAccess, SecKeychainItemRef *itemCopy) 264 { 265 BEGIN_SECKCITEMAPI 266 os_activity_t activity = os_activity_create("SecKeychainItemCreateCopy", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 267 os_activity_scope(activity); 268 os_release(activity); 269 270 Item copy = ItemImpl::required(__itemImplRef)->copyTo(Keychain::optional(destKeychainRef), Access::optional(initialAccess)); 271 if (itemCopy) { 272 *itemCopy = copy->handle(); 273 } 274 275 END_SECKCITEMAPI 276 } 277 278 279 OSStatus 280 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM_DB_UNIQUE_RECORD **uniqueRecordID) 281 { 282 BEGIN_SECKCITEMAPI 283 os_activity_t activity = os_activity_create("SecKeychainItemGetUniqueRecordID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 284 os_activity_scope(activity); 285 os_release(activity); 286 287 Required(uniqueRecordID) = ItemImpl::required(__itemImplRef)->dbUniqueRecord(); 288 289 END_SECKCITEMAPI 290 } 291 292 293 OSStatus 294 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldbHandle) 295 { 296 BEGIN_SECKCITEMAPI 297 os_activity_t activity = os_activity_create("SecKeychainItemGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 298 os_activity_scope(activity); 299 os_release(activity); 300 301 *dldbHandle = ItemImpl::required(__itemImplRef)->keychain()->database()->handle(); 302 303 END_SECKCITEMAPI 304 } 305 306 OSStatus 307 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef) 308 { 309 BEGIN_SECKCITEMAPI 310 os_activity_t activity = os_activity_create("SecKeychainItemCopyAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 311 os_activity_scope(activity); 312 os_release(activity); 313 314 Required(accessRef); // preflight 315 SecPointer<Access> access = new Access(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef))); 316 *accessRef = access->handle(); 317 318 END_SECKCITEMAPI 319 } 320 321 322 OSStatus 323 SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef) 324 { 325 BEGIN_SECKCITEMAPI 326 os_activity_t activity = os_activity_create("SecKeychainItemSetAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 327 os_activity_scope(activity); 328 os_release(activity); 329 330 Access::required(accessRef)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)), true); 331 332 ItemImpl::required(__itemImplRef)->postItemEvent(kSecUpdateEvent); 333 334 END_SECKCITEMAPI 335 } 336 337 OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password) 338 { 339 BEGIN_SECKCITEMAPI 340 os_activity_t activity = os_activity_create("SecKeychainItemSetAccessWithPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 341 os_activity_scope(activity); 342 os_release(activity); 343 344 OSStatus result; 345 346 if(!__itemImplRef) { 347 return errSecParam; 348 } 349 350 // try to unlock the keychain with this password first 351 SecKeychainRef kc = NULL; 352 result = SecKeychainItemCopyKeychain(__itemImplRef, &kc); 353 if(!result) { 354 SecKeychainUnlock(kc, passwordLength, password, true); 355 if(kc) { 356 CFRelease(kc); 357 } 358 } 359 360 // Create some credentials with this password 361 CssmAutoData data(Allocator::standard(), password, passwordLength); 362 AclFactory::PassphraseUnlockCredentials cred(data, Allocator::standard()); 363 364 Access::required(accessRef)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)), true, cred.getAccessCredentials()); 365 ItemImpl::required(itemRef)->postItemEvent (kSecUpdateEvent); 366 367 END_SECKCITEMAPI 368 } 369 370 371 /* Sets an item's data for legacy "KC" CoreServices APIs. 372 Note this version sets the data, but doesn't update the item 373 as the KC behavior dictates. 374 */ 375 OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data) 376 { 377 BEGIN_SECKCITEMAPI 378 os_activity_t activity = os_activity_create("SecKeychainItemSetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 379 os_activity_scope(activity); 380 os_release(activity); 381 382 ItemImpl::required(__itemImplRef)->setData(length, data); 383 384 END_SECKCITEMAPI 385 } 386 387 /* Gets an item's data for legacy "KC" CoreServices APIs. 388 Note this version doesn't take a SecItemClass parameter. 389 */ 390 OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength) 391 { 392 BEGIN_SECKCITEMAPI 393 os_activity_t activity = os_activity_create("SecKeychainItemGetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 394 os_activity_scope(activity); 395 os_release(activity); 396 397 /* The caller either needs to specify data and maxLength or an actualLength, 398 * so we return either the data itself or the actual length of the data or both. 399 */ 400 if (!((data && maxLength) || actualLength)) { 401 MacOSError::throwMe(errSecParam); 402 } 403 CssmDataContainer aData; 404 ItemImpl::required(__itemImplRef)->getData(aData); 405 if (actualLength) { 406 *actualLength = (UInt32)aData.length(); 407 } 408 if (data) { 409 // Make sure the buffer is big enough 410 if (aData.length() > maxLength) { 411 MacOSError::throwMe(errSecBufferTooSmall); 412 } 413 memcpy(data, aData.data(), aData.length()); 414 } 415 416 END_SECKCITEMAPI 417 } 418 419 /* Update a keychain item for legacy "KC" CoreServices APIs. 420 The "KC" API's do a 'set attribute', then an 'update'. 421 */ 422 OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) 423 { 424 BEGIN_SECKCITEMAPI 425 os_activity_t activity = os_activity_create("SecKeychainItemUpdate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 426 os_activity_scope(activity); 427 os_release(activity); 428 429 ItemImpl::required(__itemImplRef)->update(); 430 431 END_SECKCITEMAPI 432 } 433 434 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs. 435 */ 436 OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef) 437 { 438 BEGIN_SECKCITEMAPI 439 os_activity_t activity = os_activity_create("SecKeychainItemAddNoUI", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 440 os_activity_scope(activity); 441 os_release(activity); 442 443 Item item = ItemImpl::required(__itemImplRef); 444 Keychain::optional(keychainRef)->add(item); 445 446 END_SECKCITEMAPI 447 } 448 449 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs. 450 */ 451 OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) 452 { 453 BEGIN_SECKCITEMAPI 454 os_activity_t activity = os_activity_create("SecKeychainItemAdd", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 455 os_activity_scope(activity); 456 os_release(activity); 457 458 Item item = ItemImpl::required(__itemImplRef); 459 Keychain defaultKeychain = globals().storageManager.defaultKeychainUI(item); 460 defaultKeychain->add(item); 461 462 END_SECKCITEMAPI 463 } 464 465 /* Creates a floating keychain item for legacy "KC" CoreServices APIs 466 */ 467 OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef) 468 { 469 BEGIN_SECAPI 470 os_activity_t activity = os_activity_create("SecKeychainItemCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 471 os_activity_scope(activity); 472 os_release(activity); 473 474 RequiredParam(itemRef) = Item(itemClass, itemCreator, length, data, false)->handle(); 475 476 END_SECAPI 477 } 478 479 /* Gets an individual attribute for legacy "KC" CoreServices APIs 480 */ 481 OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength) 482 { 483 BEGIN_SECKCITEMAPI 484 os_activity_t activity = os_activity_create("SecKeychainItemGetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 485 os_activity_scope(activity); 486 os_release(activity); 487 488 ItemImpl::required(__itemImplRef)->getAttribute(RequiredParam(attribute), actualLength); 489 490 END_SECKCITEMAPI 491 } 492 493 /* Sets an individual attribute for legacy "KC" CoreServices APIs 494 */ 495 OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute) 496 { 497 BEGIN_SECKCITEMAPI 498 os_activity_t activity = os_activity_create("SecKeychainItemSetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 499 os_activity_scope(activity); 500 os_release(activity); 501 502 ItemImpl::required(__itemImplRef)->setAttribute(RequiredParam(attribute)); 503 504 END_SECKCITEMAPI 505 } 506 507 /* Finds a keychain item for legacy "KC" CoreServices APIs. 508 Note: This version doesn't take a SecItemClass because 509 SecKeychainSearchCreateFromAttributes() requires it. 510 @@@ This should move to SecKeychainSearch.cpp 511 */ 512 OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef) 513 { 514 BEGIN_SECAPI 515 os_activity_t activity = os_activity_create("SecKeychainItemFindFirst", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 516 os_activity_scope(activity); 517 os_release(activity); 518 519 KCCursor cursor; 520 if (keychainRef) { 521 cursor = KeychainImpl::required(keychainRef)->createCursor(attrList); 522 } else { 523 cursor = globals().storageManager.createCursor(attrList); 524 } 525 526 Item item; 527 if (!cursor->next(item)) 528 return errSecItemNotFound; 529 530 *itemRef=item->handle(); 531 if (searchRef) { 532 *searchRef=cursor->handle(); 533 } 534 535 END_SECAPI 536 } 537 538 static OSStatus SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef, 539 CFDataRef *persistentItemRef, Boolean isIdentity) 540 { 541 COUNTLEGACYAPI 542 OSStatus __secapiresult; 543 if (!certRef || !persistentItemRef) { 544 return errSecParam; 545 } 546 547 // If we already have a keychain item, we won't need to look it up by serial and issuer 548 SecKeychainItemRef kcItem = NULL; 549 if (SecCertificateIsItemImplInstance(certRef)) { 550 kcItem = (SecKeychainItemRef) CFRetain(certRef); 551 } 552 else { 553 kcItem = (SecKeychainItemRef) SecCertificateCopyKeychainItem(certRef); 554 } 555 if (kcItem) { 556 __secapiresult = errSecParam; 557 try { 558 Item item = ItemImpl::required((kcItem)); 559 item->copyPersistentReference(*persistentItemRef, isIdentity); 560 __secapiresult = errSecSuccess; 561 } 562 catch(...) {} 563 CFRelease(kcItem); 564 if (__secapiresult == errSecSuccess) { 565 return __secapiresult; 566 } 567 } 568 569 // Certificate does not have a keychain item reference; look it up by serial and issuer 570 SecCertificateRef certItem = NULL; 571 if (SecCertificateIsItemImplInstance(certRef)) { 572 certItem = SecCertificateCreateFromItemImplInstance(certRef); 573 } 574 else { 575 certItem = (SecCertificateRef) CFRetain(certRef); 576 } 577 578 CFErrorRef errorRef = NULL; 579 CFDataRef serialData = SecCertificateCopySerialNumberData(certItem, &errorRef); 580 if (errorRef) { 581 CFIndex err = CFErrorGetCode(errorRef); 582 CFRelease(errorRef); 583 if (serialData) { CFRelease(serialData); } 584 if (certItem) { CFRelease(certItem); } 585 return (OSStatus)err; 586 } 587 CFDataRef issuerData = SecCertificateCopyNormalizedIssuerContent(certItem, &errorRef); 588 if (errorRef) { 589 CFIndex err = CFErrorGetCode(errorRef); 590 CFRelease(errorRef); 591 if (serialData) { CFRelease(serialData); } 592 if (issuerData) { CFRelease(issuerData); } 593 if (certItem) { CFRelease(certItem); } 594 return (OSStatus)err; 595 } 596 597 try { 598 // look up ItemImpl cert in keychain by normalized issuer and serial number 599 StorageManager::KeychainList keychains; 600 globals().storageManager.optionalSearchList(NULL, keychains); 601 KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuerData, serialData)); 602 Item item; 603 if (!cursor->next(item)) { 604 MacOSError::throwMe(errSecItemNotFound); 605 } 606 item->copyPersistentReference(*persistentItemRef, false); 607 __secapiresult = errSecSuccess; 608 } 609 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 610 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 611 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 612 catch (...) { __secapiresult=errSecInternalComponent; } 613 614 if (serialData) 615 CFRelease(serialData); 616 if (issuerData) 617 CFRelease(issuerData); 618 if (certItem) 619 CFRelease(certItem); 620 621 return __secapiresult; 622 } 623 624 OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef) 625 { 626 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */ 627 if (!itemRef || !persistentItemRef) { 628 return errSecParam; 629 } 630 // first, query the iOS keychain 631 { 632 const void *keys[] = { kSecValueRef, kSecReturnPersistentRef, kSecUseDataProtectionKeychain }; 633 const void *values[] = { itemRef, kCFBooleanTrue, kCFBooleanTrue }; 634 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 635 sizeof(keys) / sizeof(*keys), 636 &kCFTypeDictionaryKeyCallBacks, 637 &kCFTypeDictionaryValueCallBacks); 638 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)persistentItemRef); 639 if (status == errSecSuccess) { 640 return status; 641 } 642 } 643 // otherwise, handle certificate 644 SecCertificateRef certRef = NULL; 645 CFTypeID itemType = CFGetTypeID(itemRef); 646 bool isIdentity = false; 647 if (itemType == SecIdentityGetTypeID()) { 648 SecIdentityCopyCertificate((SecIdentityRef)itemRef, &certRef); 649 isIdentity = true; 650 } 651 else if (itemType == SecCertificateGetTypeID()) { 652 certRef = (SecCertificateRef) CFRetain(itemRef); 653 } 654 if (certRef) { 655 OSStatus status = SecKeychainItemCreatePersistentReferenceFromCertificate(certRef, persistentItemRef, isIdentity); 656 CFRelease(certRef); 657 return status; 658 } 659 // otherwise, not a certificate, so proceed as usual for keychain item 660 661 BEGIN_SECAPI 662 os_activity_t activity = os_activity_create("SecKeychainItemCreatePersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 663 os_activity_scope(activity); 664 os_release(activity); 665 Item item = ItemImpl::required(itemRef); 666 item->copyPersistentReference(*persistentItemRef, false); 667 END_SECAPI 668 } 669 670 OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef) 671 { 672 BEGIN_SECAPI 673 os_activity_t activity = os_activity_create("SecKeychainItemCopyFromPersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 674 os_activity_scope(activity); 675 os_release(activity); 676 677 KCThrowParamErrIf_(!persistentItemRef || !itemRef); 678 // first, query the iOS keychain 679 { 680 const void *keys[] = { kSecValuePersistentRef, kSecReturnRef, kSecUseDataProtectionKeychain}; 681 const void *values[] = { persistentItemRef, kCFBooleanTrue, kCFBooleanTrue }; 682 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 683 sizeof(keys) / sizeof(*keys), 684 &kCFTypeDictionaryKeyCallBacks, 685 &kCFTypeDictionaryValueCallBacks); 686 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)itemRef); 687 if (status == errSecSuccess) { 688 return status; 689 } 690 } 691 // otherwise, proceed as usual for keychain item 692 CFTypeRef result = NULL; 693 bool isIdentityRef = false; 694 Item item = ItemImpl::makeFromPersistentReference(persistentItemRef, &isIdentityRef); 695 if (isIdentityRef) { 696 // item was stored as an identity, attempt to reconstitute it 697 SecPointer<Certificate> certificatePtr(static_cast<Certificate *>(item.get())); 698 StorageManager::KeychainList keychains; 699 globals().storageManager.optionalSearchList(NULL, keychains); 700 SecPointer<Identity> identityPtr(new Identity(keychains, certificatePtr)); 701 result = identityPtr->handle(); 702 KCThrowIf_( !result, errSecItemNotFound ); 703 } 704 if (!result) { 705 result = item->handle(); 706 } 707 *itemRef = (SecKeychainItemRef) result; 708 709 /* see if we should convert outgoing item to a unified SecCertificateRef */ 710 SecItemClass tmpItemClass = Schema::itemClassFor(item->recordType()); 711 if (tmpItemClass == kSecCertificateItemClass && !isIdentityRef) { 712 SecPointer<Certificate> certificate(static_cast<Certificate *>(&*item)); 713 CssmData certData = certificate->data(); 714 CFDataRef data = NULL; 715 if (certData.Data && certData.Length) { 716 data = CFDataCreate(NULL, certData.Data, certData.Length); 717 } 718 if (!data) { 719 *itemRef = NULL; 720 if (certData.Data && !certData.Length) { 721 syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)", 722 (uintptr_t)certData.Data); 723 return errSecDataNotAvailable; 724 } 725 else { 726 syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)", 727 (long)certData.Length, (uintptr_t)certData.Data); 728 return errSecInternal; 729 } 730 } 731 SecKeychainItemRef tmpRef = *itemRef; 732 *itemRef = (SecKeychainItemRef) SecCertificateCreateWithKeychainItem(NULL, data, tmpRef); 733 if (data) 734 CFRelease(data); 735 if (tmpRef) 736 CFRelease(tmpRef); 737 } 738 739 END_SECAPI 740 } 741 742 OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier) 743 { 744 BEGIN_SECKCITEMAPI 745 os_activity_t activity = os_activity_create("SecKeychainItemCopyRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 746 os_activity_scope(activity); 747 os_release(activity); 748 749 CSSM_DATA data; 750 RequiredParam (recordIdentifier); 751 Item item = ItemImpl::required(__itemImplRef); 752 item->copyRecordIdentifier (data); 753 *recordIdentifier = ::CFDataCreate(kCFAllocatorDefault, (UInt8*) data.Data, data.Length); 754 free (data.Data); 755 756 END_SECKCITEMAPI 757 } 758 759 OSStatus 760 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef, 761 SecKeychainItemRef *itemRef, 762 CFDataRef recordIdentifier) 763 { 764 BEGIN_SECAPI 765 os_activity_t activity = os_activity_create("SecKeychainItemCopyFromRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 766 os_activity_scope(activity); 767 os_release(activity); 768 769 // make a local Keychain reference 770 RequiredParam (keychainRef); 771 Keychain keychain = KeychainImpl::optional (keychainRef); 772 RequiredParam (itemRef); 773 RequiredParam (recordIdentifier); 774 775 Db db(keychain->database()); 776 777 // make a raw database call to get the data 778 CSSM_DL_DB_HANDLE dbHandle = db.handle (); 779 CSSM_DB_UNIQUE_RECORD uniqueRecord; 780 781 // according to source, we should be able to reconsitute the uniqueRecord 782 // from the data we earlier retained 783 784 // prepare the record id 785 memset (&uniqueRecord, 0, sizeof (uniqueRecord)); 786 uniqueRecord.RecordIdentifier.Data = (uint8*) CFDataGetBytePtr (recordIdentifier); 787 uniqueRecord.RecordIdentifier.Length = CFDataGetLength (recordIdentifier); 788 789 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL 790 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr; 791 CSSM_RETURN result; 792 result = CSSM_DL_PassThrough (dbHandle, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER, &uniqueRecord, (void**) &outputUniqueRecordPtr); 793 KCThrowIf_(result != 0, errSecItemNotFound); 794 795 // from this, get the record type 796 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData; 797 memset (&attributeData, 0, sizeof (attributeData)); 798 799 result = CSSM_DL_DataGetFromUniqueRecordId (dbHandle, outputUniqueRecordPtr, &attributeData, NULL); 800 KCThrowIf_(result != 0, errSecItemNotFound); 801 CSSM_DB_RECORDTYPE recordType = attributeData.DataRecordType; 802 803 // make the unique record item -- precursor to creation of a SecKeychainItemRef 804 DbUniqueRecord unique(db); 805 CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = unique; 806 *uniquePtr = outputUniqueRecordPtr; 807 808 unique->activate (); 809 Item item = keychain->item (recordType, unique); 810 if (itemRef) 811 { 812 *itemRef = item->handle(); 813 } 814 815 END_SECAPI 816 } 817 818 OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass, 819 UInt32 length, const void *data, SecKeychainRef keychainRef, 820 SecAccessRef initialAccess, SecKeychainItemRef *itemRef, CFDataRef *localID) 821 { 822 BEGIN_SECAPI 823 os_activity_t activity = os_activity_create("SecKeychainItemCreateFromEncryptedContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 824 os_activity_scope(activity); 825 os_release(activity); 826 827 KCThrowParamErrIf_(length!=0 && data==NULL); 828 RequiredParam (localID); 829 RequiredParam (keychainRef); 830 831 Item item(itemClass, (uint32) 0, length, data, true); 832 if (initialAccess) 833 item->setAccess(Access::required(initialAccess)); 834 835 Keychain keychain = Keychain::optional(keychainRef); 836 if (!keychain->exists()) 837 { 838 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. 839 } 840 841 item->doNotEncrypt (); 842 try 843 { 844 keychain->add(item); 845 } 846 catch (const CommonError &err) 847 { 848 if (err.osStatus () == errSecNoSuchClass) 849 { 850 // the only time this should happen is if the item is a certificate (for keychain syncing) 851 if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE) 852 { 853 // create the certificate relation 854 Db db(keychain->database()); 855 856 db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE, 857 "CSSM_DL_DB_RECORD_X509_CERTIFICATE", 858 Schema::X509CertificateSchemaAttributeCount, 859 Schema::X509CertificateSchemaAttributeList, 860 Schema::X509CertificateSchemaIndexCount, 861 Schema::X509CertificateSchemaIndexList); 862 keychain->keychainSchema()->didCreateRelation( 863 CSSM_DL_DB_RECORD_X509_CERTIFICATE, 864 "CSSM_DL_DB_RECORD_X509_CERTIFICATE", 865 Schema::X509CertificateSchemaAttributeCount, 866 Schema::X509CertificateSchemaAttributeList, 867 Schema::X509CertificateSchemaIndexCount, 868 Schema::X509CertificateSchemaIndexList); 869 870 // add the item again 871 keychain->add(item); 872 } 873 } 874 else 875 { 876 throw; 877 } 878 } 879 880 if (itemRef) 881 *itemRef = item->handle(); 882 883 CSSM_DATA recordID; 884 item->copyRecordIdentifier (recordID); 885 886 *localID = CFDataCreate(kCFAllocatorDefault, (UInt8*) recordID.Data, recordID.Length); 887 free (recordID.Data); 888 889 END_SECAPI 890 } 891 892 OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, 893 SecItemClass *itemClass, SecKeychainAttributeList **attrList, 894 UInt32 *length, void **outData) 895 { 896 BEGIN_SECKCITEMAPI 897 os_activity_t activity = os_activity_create("SecKeychainItemCopyAttributesAndEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 898 os_activity_scope(activity); 899 os_release(activity); 900 901 Item item = ItemImpl::required(__itemImplRef); 902 item->doNotEncrypt (); 903 item->getAttributesAndData(info, itemClass, attrList, length, outData); 904 905 END_SECKCITEMAPI 906 } 907 908 OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data) 909 { 910 BEGIN_SECKCITEMAPI 911 os_activity_t activity = os_activity_create("SecKeychainItemModifyEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); 912 os_activity_scope(activity); 913 os_release(activity); 914 915 Item item = ItemImpl::required(__itemImplRef); 916 item->doNotEncrypt (); 917 item->modifyAttributesAndData(NULL, length, data); 918 919 END_SECKCITEMAPI 920 }