1; 2/* 3 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25/* 26 * SecItem.c - CoreFoundation-based constants and functions for 27 access to Security items (certificates, keys, identities, and 28 passwords.) 29 */ 30 31#include <Security/SecBasePriv.h> 32#include <Security/SecItem.h> 33#include <Security/SecItemPriv.h> 34#include <Security/SecItemInternal.h> 35#include <Security/SecAccessControl.h> 36#include <Security/SecAccessControlPriv.h> 37#ifndef SECITEM_SHIM_OSX 38#include <Security/SecKey.h> 39#include <Security/SecKeyPriv.h> 40#include <Security/SecCertificateInternal.h> 41#include <Security/SecIdentity.h> 42#include <Security/SecIdentityPriv.h> 43#include <Security/SecRandom.h> 44#include <Security/SecBasePriv.h> 45#endif // *** END SECITEM_SHIM_OSX *** 46#include <Security/SecTask.h> 47#include <errno.h> 48#include <limits.h> 49#include <sqlite3.h> 50#include <stdint.h> 51#include <stdlib.h> 52#include <string.h> 53#include <sys/param.h> 54#include <sys/stat.h> 55#include <Security/SecBase.h> 56#include <CoreFoundation/CFData.h> 57#include <CoreFoundation/CFDate.h> 58#include <CoreFoundation/CFDictionary.h> 59#include <CoreFoundation/CFNumber.h> 60#include <CoreFoundation/CFString.h> 61#include <CoreFoundation/CFURL.h> 62#include <CommonCrypto/CommonDigest.h> 63#include <libkern/OSByteOrder.h> 64#include <utilities/array_size.h> 65#include <utilities/debugging.h> 66#include <utilities/SecCFError.h> 67#include <utilities/SecCFWrappers.h> 68#include <utilities/SecIOFormat.h> 69#include <utilities/SecXPCError.h> 70#include <utilities/der_plist.h> 71#include <assert.h> 72 73#include <Security/SecInternal.h> 74#include <TargetConditionals.h> 75#include <ipc/securityd_client.h> 76#include <Security/SecuritydXPC.h> 77#include <AssertMacros.h> 78#include <asl.h> 79#include <sys/types.h> 80#include <pwd.h> 81#include <grp.h> 82#include <unistd.h> 83#ifndef SECITEM_SHIM_OSX 84#include <libDER/asn1Types.h> 85#endif // *** END SECITEM_SHIM_OSX *** 86 87/* label when certificate data is joined with key data */ 88#define CERTIFICATE_DATA_COLUMN_LABEL "certdata" 89 90#include <utilities/SecDb.h> 91#include <IOKit/IOReturn.h> 92 93/* Return an OSStatus for a sqlite3 error code. */ 94static OSStatus osstatus_for_s3e(int s3e) 95{ 96 if (s3e > 0 && s3e <= SQLITE_DONE) switch (s3e) 97 { 98 case SQLITE_OK: 99 return 0; 100 case SQLITE_ERROR: 101 return errSecNotAvailable; /* errSecDuplicateItem; */ 102 case SQLITE_FULL: /* Happens if we run out of uniqueids */ 103 return errSecNotAvailable; /* TODO: Replace with a better error code. */ 104 case SQLITE_PERM: 105 case SQLITE_READONLY: 106 return errSecNotAvailable; 107 case SQLITE_CANTOPEN: 108 return errSecNotAvailable; 109 case SQLITE_EMPTY: 110 return errSecNotAvailable; 111 case SQLITE_CONSTRAINT: 112 return errSecDuplicateItem; 113 case SQLITE_ABORT: 114 return -1; 115 case SQLITE_MISMATCH: 116 return errSecNoSuchAttr; 117 case SQLITE_AUTH: 118 return errSecNotAvailable; 119 case SQLITE_NOMEM: 120 return -2; /* TODO: Replace with a real error code. */ 121 case SQLITE_INTERNAL: 122 default: 123 return errSecNotAvailable; /* TODO: Replace with a real error code. */ 124 } 125 return s3e; 126} 127 128static OSStatus osstatus_for_kern_return(CFIndex kernResult) 129{ 130 switch (kernResult) 131 { 132 case KERN_SUCCESS: 133 return errSecSuccess; 134 case kIOReturnNotReadable: 135 case kIOReturnNotWritable: 136 return errSecAuthFailed; 137 case kIOReturnNotPermitted: 138 case kIOReturnNotPrivileged: 139 case kIOReturnLockedRead: 140 case kIOReturnLockedWrite: 141 return errSecInteractionNotAllowed; 142 case kIOReturnError: 143 return errSecDecode; 144 case kIOReturnBadArgument: 145 return errSecParam; 146 default: 147 return errSecNotAvailable; /* TODO: Replace with a real error code. */ 148 } 149} 150 151static OSStatus osstatus_for_xpc_error(CFIndex xpcError) { 152 switch (xpcError) 153 { 154 case kSecXPCErrorSuccess: 155 return errSecSuccess; 156 case kSecXPCErrorUnexpectedType: 157 case kSecXPCErrorUnexpectedNull: 158 return errSecParam; 159 case kSecXPCErrorConnectionFailed: 160 return errSecNotAvailable; 161 case kSecXPCErrorUnknown: 162 default: 163 return errSecInternal; 164 } 165} 166 167static OSStatus osstatus_for_der_error(CFIndex derError) { 168 switch (derError) 169 { 170 case kSecDERErrorUnknownEncoding: 171 case kSecDERErrorUnsupportedDERType: 172 case kSecDERErrorUnsupportedNumberType: 173 return errSecDecode; 174 case kSecDERErrorUnsupportedCFObject: 175 return errSecParam; 176 case kSecDERErrorAllocationFailure: 177 return errSecAllocate; 178 default: 179 return errSecInternal; 180 } 181} 182 183// Convert from securityd error codes to OSStatus for legacy API. 184OSStatus SecErrorGetOSStatus(CFErrorRef error) { 185 OSStatus status; 186 if (error == NULL) { 187 status = errSecSuccess; 188 } else { 189 CFStringRef domain = CFErrorGetDomain(error); 190 if (domain == NULL) { 191 secerror("No error domain for error: %@", error); 192 status = errSecInternal; 193 } else if (CFEqual(kSecErrorDomain, domain)) { 194 status = (OSStatus)CFErrorGetCode(error); 195 } else if (CFEqual(kSecDbErrorDomain, domain)) { 196 status = osstatus_for_s3e((int)CFErrorGetCode(error)); 197 } else if (CFEqual(kSecErrnoDomain, domain)) { 198 status = (OSStatus)CFErrorGetCode(error); 199 } else if (CFEqual(kSecKernDomain, domain)) { 200 status = osstatus_for_kern_return(CFErrorGetCode(error)); 201 } else if (CFEqual(sSecXPCErrorDomain, domain)) { 202 status = osstatus_for_xpc_error(CFErrorGetCode(error)); 203 } else if (CFEqual(sSecDERErrorDomain, domain)) { 204 status = osstatus_for_der_error(CFErrorGetCode(error)); 205 } else { 206 secnotice("securityd", "unknown error domain: %@ for error: %@", domain, error); 207 status = errSecInternal; 208 } 209 } 210 return status; 211} 212 213// Wrapper to provide a CFErrorRef for legacy API. 214OSStatus SecOSStatusWith(bool (^perform)(CFErrorRef *error)) { 215 CFErrorRef error = NULL; 216 OSStatus status; 217 if (perform(&error)) { 218 assert(error == NULL); 219 status = errSecSuccess; 220 } else { 221 assert(error); 222 status = SecErrorGetOSStatus(error); 223 if (status != errSecItemNotFound) // Occurs in normal operation, so exclude 224 secerror("error:[%" PRIdOSStatus "] %@", status, error); 225 CFReleaseNull(error); 226 } 227 return status; 228} 229 230 231/* IPC uses CFPropertyList to un/marshall input/output data and can handle: 232 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber 233 234 Currently in need of conversion below: 235 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef 236 @@@ kSecMatchPolicy allows a query with a SecPolicyRef 237 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't 238 currently implemented at all, but when it is needs to short circuit to 239 local evaluation, different from the sql query abilities 240*/ 241 242#ifndef SECITEM_SHIM_OSX 243static CFDictionaryRef 244SecItemCopyAttributeDictionary(CFTypeRef ref) { 245 CFDictionaryRef refDictionary = NULL; 246 CFTypeID typeID = CFGetTypeID(ref); 247 if (typeID == SecKeyGetTypeID()) { 248 refDictionary = SecKeyCopyAttributeDictionary((SecKeyRef)ref); 249 } else if (typeID == SecCertificateGetTypeID()) { 250 refDictionary = 251 SecCertificateCopyAttributeDictionary((SecCertificateRef)ref); 252 } else if (typeID == SecIdentityGetTypeID()) { 253 assert(false); 254 SecIdentityRef identity = (SecIdentityRef)ref; 255 SecCertificateRef cert = NULL; 256 SecKeyRef key = NULL; 257 if (!SecIdentityCopyCertificate(identity, &cert) && 258 !SecIdentityCopyPrivateKey(identity, &key)) 259 { 260 CFDataRef data = SecCertificateCopyData(cert); 261 CFDictionaryRef key_dict = SecKeyCopyAttributeDictionary(key); 262 263 if (key_dict && data) { 264 refDictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, key_dict); 265 CFDictionarySetValue((CFMutableDictionaryRef)refDictionary, 266 CFSTR(CERTIFICATE_DATA_COLUMN_LABEL), data); 267 } 268 CFReleaseNull(key_dict); 269 CFReleaseNull(data); 270 } 271 CFReleaseNull(cert); 272 CFReleaseNull(key); 273 } else { 274 refDictionary = NULL; 275 } 276 return refDictionary; 277} 278 279static CFTypeRef 280SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { 281 CFTypeRef ref = NULL; 282 CFStringRef class = CFDictionaryGetValue(refAttributes, kSecClass); 283 if (CFEqual(class, kSecClassCertificate)) { 284 ref = SecCertificateCreateFromAttributeDictionary(refAttributes); 285 } else if (CFEqual(class, kSecClassKey)) { 286 ref = SecKeyCreateFromAttributeDictionary(refAttributes); 287 } else if (CFEqual(class, kSecClassIdentity)) { 288 CFAllocatorRef allocator = NULL; 289 CFDataRef data = CFDictionaryGetValue(refAttributes, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL)); 290 SecCertificateRef cert = SecCertificateCreateWithData(allocator, data); 291 SecKeyRef key = SecKeyCreateFromAttributeDictionary(refAttributes); 292 if (key && cert) 293 ref = SecIdentityCreate(allocator, cert, key); 294 CFReleaseSafe(cert); 295 CFReleaseSafe(key); 296#if 0 297 /* We don't support SecKeychainItemRefs yet. */ 298 } else if (CFEqual(class, kSecClassGenericPassword)) { 299 } else if (CFEqual(class, kSecClassInternetPassword)) { 300 } else if (CFEqual(class, kSecClassAppleSharePassword)) { 301#endif 302 } else { 303 ref = NULL; 304 } 305 return ref; 306} 307#else 308 309extern CFTypeRef SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes); 310 311#endif 312 313OSStatus 314SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames) 315{ 316 // @@@ TBI 317 return -1 /* errSecUnimplemented */; 318} 319 320#ifndef SECITEM_SHIM_OSX 321static void merge_dictionary_by_overwrite(const void *key, const void *value, void *context) 322{ 323 if (!CFEqual(key, kSecValueRef)) 324 CFDictionarySetValue((CFMutableDictionaryRef)context, key, value); 325} 326 327static void copy_applier(const void *key, const void *value, void *context) 328{ 329 CFDictionarySetValue(context, key, value); 330} 331 332static OSStatus cook_query(CFDictionaryRef query, CFMutableDictionaryRef *explode) 333{ 334 /* If a ref was specified we get it's attribute dictionary and parse it. */ 335 CFMutableDictionaryRef args = NULL; 336 CFTypeRef value = CFDictionaryGetValue(query, kSecValueRef); 337 if (value) { 338 CFDictionaryRef refAttributes = SecItemCopyAttributeDictionary(value); 339 if (!refAttributes) 340 return errSecValueRefUnsupported; 341 342 /* Replace any attributes we already got from the ref with the ones 343 from the attributes dictionary the caller passed us. This allows 344 a caller to add an item using attributes from the ref and still 345 override some of them in the dictionary directly. */ 346 args = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, refAttributes); 347 CFRelease(refAttributes); 348 CFDictionaryApplyFunction(query, merge_dictionary_by_overwrite, args); 349 } 350 value = CFDictionaryGetValue(query, kSecAttrIssuer); 351 if (value) { 352 /* convert DN to canonical issuer, if value is DN (top level sequence) */ 353 const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) }; 354 DERDecodedInfo content; 355 if (!DERDecodeItem(&name, &content) && 356 (content.tag == ASN1_CONSTR_SEQUENCE)) 357 { 358 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content); 359 if (canonical_issuer) { 360 if (!args) { 361 args = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 362 /* This is necessary because we rely on non NULL callbacks */ 363 CFDictionaryApplyFunction(query, copy_applier, args); 364 } 365 /* Overwrite with new issuer */ 366 CFDictionarySetValue(args, kSecAttrIssuer, canonical_issuer); 367 CFRelease(canonical_issuer); 368 } 369 } 370 } 371 *explode = args; 372 return errSecSuccess; 373} 374 375typedef OSStatus (*secitem_operation)(CFDictionaryRef attributes, CFTypeRef *result); 376 377static bool explode_identity(CFDictionaryRef attributes, secitem_operation operation, 378 OSStatus *return_status, CFTypeRef *return_result) 379{ 380 bool handled = false; 381 CFTypeRef value = CFDictionaryGetValue(attributes, kSecValueRef); 382 if (value) { 383 CFTypeID typeID = CFGetTypeID(value); 384 if (typeID == SecIdentityGetTypeID()) { 385 handled = true; 386 OSStatus status = errSecSuccess; 387 SecIdentityRef identity = (SecIdentityRef)value; 388 SecCertificateRef cert = NULL; 389 SecKeyRef key = NULL; 390 if (!SecIdentityCopyCertificate(identity, &cert) && 391 !SecIdentityCopyPrivateKey(identity, &key)) 392 { 393 CFMutableDictionaryRef partial_query = 394 CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes); 395 CFDictionarySetValue(partial_query, kSecValueRef, cert); 396 CFTypeRef result = NULL; 397 bool duplicate_cert = false; 398 /* an identity is first and foremost a key, but it can have multiple 399 certs associated with it: so we identify it by the cert */ 400 status = operation(partial_query, return_result ? &result : NULL); 401 if ((operation == (secitem_operation)SecItemAdd) && 402 (status == errSecDuplicateItem)) { 403 duplicate_cert = true; 404 status = errSecSuccess; 405 } 406 407 if (!status || status == errSecItemNotFound) { 408 bool skip_key_operation = false; 409 410 /* if the key is still in use, skip deleting it */ 411 if (operation == (secitem_operation)SecItemDelete) { 412 // find certs with cert.pkhh == keys.klbl 413 CFDictionaryRef key_dict = NULL, query_dict = NULL; 414 CFDataRef pkhh = NULL; 415 416 key_dict = SecKeyCopyAttributeDictionary(key); 417 if (key_dict) 418 pkhh = (CFDataRef)CFDictionaryGetValue(key_dict, kSecAttrApplicationLabel); 419 const void *keys[] = { kSecClass, kSecAttrPublicKeyHash }; 420 const void *vals[] = { kSecClassCertificate, pkhh }; 421 if (pkhh) 422 query_dict = CFDictionaryCreate(NULL, keys, 423 vals, (array_size(keys)), 424 NULL, NULL); 425 if (query_dict) 426 if (errSecSuccess == SecItemCopyMatching(query_dict, NULL)) 427 skip_key_operation = true; 428 CFReleaseSafe(query_dict); 429 CFReleaseSafe(key_dict); 430 } 431 432 if (!skip_key_operation) { 433 /* now perform the operation for the key */ 434 CFDictionarySetValue(partial_query, kSecValueRef, key); 435 CFDictionarySetValue(partial_query, kSecReturnPersistentRef, kCFBooleanFalse); 436 status = operation(partial_query, NULL); 437 if ((operation == (secitem_operation)SecItemAdd) && 438 (status == errSecDuplicateItem) && 439 !duplicate_cert) 440 status = errSecSuccess; 441 } 442 443 /* add and copy matching for an identityref have a persistent ref result */ 444 if (result) { 445 if (!status) { 446 /* result is a persistent ref to a cert */ 447 sqlite_int64 rowid; 448 if (_SecItemParsePersistentRef(result, NULL, &rowid)) { 449 *return_result = _SecItemMakePersistentRef(kSecClassIdentity, rowid); 450 } 451 } 452 CFRelease(result); 453 } 454 } 455 CFReleaseNull(partial_query); 456 } 457 else 458 status = errSecInvalidItemRef; 459 460 CFReleaseNull(cert); 461 CFReleaseNull(key); 462 *return_status = status; 463 } 464 } else { 465 value = CFDictionaryGetValue(attributes, kSecClass); 466 if (value && CFEqual(kSecClassIdentity, value) && 467 (operation == (secitem_operation)SecItemDelete)) { 468 CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes); 469 CFDictionaryRemoveValue(dict, kSecClass); 470 CFDictionarySetValue(dict, kSecClass, kSecClassCertificate); 471 OSStatus status = SecItemDelete(dict); 472 if (!status) { 473 CFDictionarySetValue(dict, kSecClass, kSecClassKey); 474 status = SecItemDelete(dict); 475 } 476 CFRelease(dict); 477 *return_status = status; 478 handled = true; 479 } 480 } 481 return handled; 482} 483 484static void infer_cert_label(CFDictionaryRef attributes, CFMutableDictionaryRef args) 485{ 486 if (!args || !attributes) 487 return; 488 489 if (CFDictionaryContainsKey(attributes, kSecAttrLabel)) 490 return; 491 492 CFTypeRef value_ref = CFDictionaryGetValue(attributes, kSecValueRef); 493 if (!value_ref || (CFGetTypeID(value_ref) != SecCertificateGetTypeID())) 494 return; 495 496 SecCertificateRef certificate = (SecCertificateRef)value_ref; 497 CFStringRef label = SecCertificateCopySubjectSummary(certificate); 498 if (label) { 499 CFDictionarySetValue(args, kSecAttrLabel, label); 500 CFReleaseNull(label); 501 } 502} 503 504/* A persistent ref is just the class and the rowid of the record. */ 505CF_RETURNS_RETAINED CFDataRef _SecItemMakePersistentRef(CFTypeRef class, sqlite_int64 rowid) 506{ 507 uint8_t bytes[sizeof(sqlite_int64) + 4]; 508 if (rowid < 0) 509 return NULL; 510 if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/, 511 kCFStringEncodingUTF8)) 512 { 513 OSWriteBigInt64(bytes + 4, 0, rowid); 514 return CFDataCreate(NULL, bytes, sizeof(bytes)); 515 } 516 return NULL; 517} 518 519/* AUDIT[securityd](done): 520 persistent_ref (ok) is a caller provided, non NULL CFTypeRef. 521 */ 522bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid) 523{ 524 bool valid_ref = false; 525 if (CFGetTypeID(persistent_ref) == CFDataGetTypeID() && 526 CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) { 527 const uint8_t *bytes = CFDataGetBytePtr(persistent_ref); 528 sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0); 529 530 CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault, 531 bytes, CFStringGetLength(kSecClassGenericPassword), 532 kCFStringEncodingUTF8, true); 533 const void *valid_classes[] = { kSecClassGenericPassword, 534 kSecClassInternetPassword, 535 kSecClassAppleSharePassword, 536 kSecClassCertificate, 537 kSecClassKey, 538 kSecClassIdentity }; 539 540 unsigned i; 541 for (i=0; i< array_size(valid_classes); i++) { 542 if (CFEqual(valid_classes[i], class)) { 543 if (return_class) 544 *return_class = valid_classes[i]; 545 if (return_rowid) 546 *return_rowid = rowid; 547 valid_ref = true; 548 break; 549 } 550 } 551 CFRelease(class); 552 } 553 return valid_ref; 554} 555 556#endif // *** END SECITEM_SHIM_OSX *** 557 558static bool cf_bool_value(CFTypeRef cf_bool) 559{ 560 return (cf_bool && CFEqual(kCFBooleanTrue, cf_bool)); 561} 562 563/* Turn the returned dictionary that contains all the attributes to create a 564 ref into the exact result the client asked for */ 565CF_RETURNS_RETAINED 566static CFTypeRef makeResult(CFTypeRef ref, bool return_ref, bool return_data, bool return_attributes, bool return_persistentref) 567{ 568 CFTypeRef result = NULL; 569 if (!ref || (CFGetTypeID(ref) != CFDictionaryGetTypeID())) 570 return CFRetainSafe(ref); 571 572 CFTypeRef returned_ref = return_ref ? SecItemCreateFromAttributeDictionary(ref) : NULL; 573 574 if (return_data || return_attributes || return_persistentref) { 575 if (return_attributes) 576 result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, ref); 577 else 578 result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 579 580 if (returned_ref) { 581 CFDictionarySetValue((CFMutableDictionaryRef)result, kSecValueRef, returned_ref); 582 CFRelease(returned_ref); 583 } 584 585 if (return_data) { 586 CFTypeRef r_data = CFDictionaryGetValue(ref, kSecValueData); 587 if (r_data) 588 CFDictionarySetValue((CFMutableDictionaryRef)result, kSecValueData, r_data); 589 } else { 590 CFDictionaryRemoveValue((CFMutableDictionaryRef)result, kSecValueData); 591 } 592 593 if (return_persistentref) { 594 CFTypeRef persistent_ref = CFDictionaryGetValue(ref, kSecValuePersistentRef); 595 if (persistent_ref) 596 CFDictionarySetValue((CFMutableDictionaryRef)result, kSecValuePersistentRef, persistent_ref); 597 } 598 599 CFDataRef ac_data = CFDictionaryGetValue(result, kSecAttrAccessControl); 600 if (ac_data) { 601 SecAccessControlRef ac = SecAccessControlCreateFromData(kCFAllocatorDefault, ac_data, NULL); 602 if (ac) { 603 CFDictionarySetValue((CFMutableDictionaryRef)result, kSecAttrAccessControl, ac); 604 CFRelease(ac); 605 } 606 } 607 } else if (return_ref) 608 result = returned_ref; 609 610 return result; 611} 612 613static void 614result_post(CFDictionaryRef query, CFTypeRef raw_result, CFTypeRef *result) { 615 if (!raw_result) 616 return; 617 618 if (!result) { 619 CFRelease(raw_result); 620 return; 621 } 622 623 bool return_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef)); 624 bool return_data = cf_bool_value(CFDictionaryGetValue(query, kSecReturnData)); 625 bool return_attributes = cf_bool_value(CFDictionaryGetValue(query, kSecReturnAttributes)); 626 bool return_persistentref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnPersistentRef)); 627 628 if (CFGetTypeID(raw_result) == CFArrayGetTypeID()) { 629 CFIndex i, count = CFArrayGetCount(raw_result); 630 CFMutableArrayRef tmp_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); 631 for (i = 0; i < count; i++) { 632 CFTypeRef ref = makeResult(CFArrayGetValueAtIndex(raw_result, i), return_ref, return_data, return_attributes, 633 return_persistentref); 634 if (ref) { 635 CFArrayAppendValue(tmp_array, ref); 636 CFRelease(ref); 637 } 638 } 639 *result = tmp_array; 640 } else 641 *result = makeResult(raw_result, return_ref, return_data, return_attributes, return_persistentref); 642 643 CFRelease(raw_result); 644} 645 646static void attributes_pre(CFDictionaryRef attributes, CFMutableDictionaryRef *result) { 647 CFDataRef data = NULL; 648 SecAccessControlRef access_control = NULL; 649 *result = NULL; 650 access_control = (SecAccessControlRef)CFDictionaryGetValue(attributes, kSecAttrAccessControl); 651 require_quiet(access_control, out); 652 data = SecAccessControlCopyData(access_control); 653 require_quiet(data, out); 654 *result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes); 655 CFDictionarySetValue(*result, kSecAttrAccessControl, data); 656 657out: 658 CFReleaseSafe(data); 659} 660 661#if SECITEM_SHIM_OSX 662/* TODO: Should be in some header */ 663OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result); 664OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result); 665OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate); 666OSStatus SecItemDelete_ios(CFDictionaryRef query); 667#endif 668 669static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error) 670{ 671 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 672 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error); 673 }, ^bool(xpc_object_t response, CFErrorRef *error) { 674 if (result) { 675 return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error); 676 } 677 return true; 678 }); 679} 680 681static CFArrayRef dict_to_array_error_request(enum SecXPCOperation op, CFDictionaryRef attributes, CFErrorRef *error) 682{ 683 CFArrayRef result = NULL; 684 bool success = cftype_to_bool_cftype_error_request(op, attributes, (CFTypeRef*)&result, error); 685 if(success && !isArray(result)){ 686 SecError(errSecUnimplemented, error, CFSTR("Unexpected nonarray returned: %@"), result); 687 CFReleaseNull(result); 688 } 689 return result; 690} 691 692bool cftype_ag_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error) { 693 return cftype_to_bool_cftype_error_request(op, attributes, result, error); 694} 695 696static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error) 697{ 698 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 699 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error); 700 }, NULL); 701} 702 703static bool dict_ag_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused CFArrayRef accessGroups, CFErrorRef *error) 704{ 705 return dict_to_error_request(op, query, error); 706} 707 708static CFDataRef data_data_to_data_error_request(enum SecXPCOperation op, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { 709 __block CFDataRef result = NULL; 710 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 711 return SecXPCDictionarySetDataOptional(message, kSecXPCKeyKeybag, keybag, error) 712 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); 713 }, ^bool(xpc_object_t response, CFErrorRef *error) { 714 return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error)); 715 }); 716 return result; 717} 718 719static bool data_data_data_to_error_request(enum SecXPCOperation op, CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { 720 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 721 return SecXPCDictionarySetData(message, kSecXPCKeyBackup, backup, error) 722 && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) 723 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); 724 } , NULL); 725} 726 727static bool dict_data_data_to_error_request(enum SecXPCOperation op, CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { 728 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 729 return SecXPCDictionarySetPList(message, kSecXPCKeyBackup, backup, error) 730 && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) 731 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); 732 } , NULL); 733} 734 735static CFDictionaryRef data_data_dict_to_dict_error_request(enum SecXPCOperation op, CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { 736 __block CFDictionaryRef dict = NULL; 737 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 738 return SecXPCDictionarySetPListOptional(message, kSecXPCKeyBackup, backup, error) 739 && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) 740 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); 741 }, ^bool(xpc_object_t response, CFErrorRef *error) { 742 return (dict = SecXPCDictionaryCopyDictionary(response, kSecXPCKeyResult, error)); 743 }); 744 return dict; 745} 746 747OSStatus 748#if SECITEM_SHIM_OSX 749SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result) 750#else 751SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) 752#endif // *** END SECITEM_SHIM_OSX *** 753{ 754 CFMutableDictionaryRef args1 = NULL, args2 = NULL; 755 OSStatus status; 756 757#ifndef SECITEM_SHIM_OSX 758 require_quiet(!explode_identity(attributes, (secitem_operation)SecItemAdd, &status, result), errOut); 759 require_noerr_quiet(status = cook_query(attributes, &args1), errOut); 760 infer_cert_label(attributes, args1); 761 if (args1) 762 attributes = args1; 763#endif // *** END SECITEM_SHIM_OSX *** 764 765 SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(attributes, kSecAttrAccessControl); 766 if(access_control && SecAccessControlGetConstraints(access_control) && CFEqualSafe(CFDictionaryGetValue(attributes, kSecAttrSynchronizable), kCFBooleanTrue)) 767 require_noerr_quiet(status = errSecParam, errOut); 768 769 attributes_pre(attributes, &args2); 770 if (args2) 771 attributes = args2; 772 773 require_noerr_quiet(status = SecOSStatusWith(^bool (CFErrorRef *error) { 774 CFTypeRef raw_result = NULL; 775 if (!SECURITYD_XPC(sec_item_add, cftype_ag_to_bool_cftype_error_request, attributes, SecAccessGroupsGetCurrent(), &raw_result, error)) 776 return false; 777 778 result_post(attributes, raw_result, result); 779 return true; 780 }), errOut); 781 782errOut: 783 CFReleaseSafe(args1); 784 CFReleaseSafe(args2); 785 return status; 786} 787 788 789OSStatus 790#if SECITEM_SHIM_OSX 791SecItemCopyMatching_ios(CFDictionaryRef inQuery, CFTypeRef *result) 792#else 793SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) 794#endif // *** END SECITEM_SHIM_OSX *** 795{ 796 __block CFDictionaryRef query = inQuery; 797 __block CFMutableDictionaryRef args1 = NULL, args2 = NULL; 798 OSStatus status; 799 800#ifndef SECITEM_SHIM_OSX 801 require_quiet(!explode_identity(query, (secitem_operation)SecItemCopyMatching, &status, result), errOut); 802 require_noerr_quiet(status = cook_query(query, &args1), errOut); 803 if (args1) 804 query = args1; 805#endif // *** END SECITEM_SHIM_OSX *** 806 807 attributes_pre(query, &args2); 808 if (args2) 809 query = args2; 810 811 require_noerr_quiet(status = SecOSStatusWith(^bool (CFErrorRef *error) { 812 CFTypeRef raw_result = NULL; 813 if (!SECURITYD_XPC(sec_item_copy_matching, cftype_ag_to_bool_cftype_error_request, query, SecAccessGroupsGetCurrent(), &raw_result, error)) 814 return false; 815 816 result_post(query, raw_result, result); 817 return true; 818 }), errOut); 819 820errOut: 821 CFReleaseSafe(args1); 822 CFReleaseSafe(args2); 823 return status; 824} 825 826OSStatus 827#if SECITEM_SHIM_OSX 828SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) 829#else 830SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) 831#endif // *** END SECITEM_SHIM_OSX *** 832{ 833 CFMutableDictionaryRef args1 = NULL, args2 = NULL, args3 = NULL; 834 __block OSStatus status; // TODO loose block once gSecurityd functions return CFErrorRefs 835#ifndef SECITEM_SHIM_OSX 836 require_noerr_quiet(status = cook_query(query, &args1), errOut); 837 if (args1) 838 query = args1; 839#endif 840 841 attributes_pre(attributesToUpdate, &args2); 842 if (args2) 843 attributesToUpdate = args2; 844 845 attributes_pre(query, &args3); 846 if (args3) 847 query = args3; 848 849 require_noerr_quiet(status = SecOSStatusWith(^bool (CFErrorRef *error) { 850 bool ok = false; 851 if (gSecurityd) { 852 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks. 853 CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 854 CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); }); 855 ok = gSecurityd->sec_item_update(query, tmp, SecAccessGroupsGetCurrent(), error); 856 CFRelease(tmp); 857 } else { 858 xpc_object_t message = securityd_create_message(sec_item_update_id, error); 859 if (message) { 860 if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) && 861 SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) { 862 xpc_object_t reply = securityd_message_with_reply_sync(message, error); 863 if (reply) { 864 ok = securityd_message_no_error(reply, error); 865 xpc_release(reply); 866 } 867 } 868 xpc_release(message); 869 } 870 } 871 return ok; 872 }), errOut); 873 874errOut: 875 CFReleaseSafe(args1); 876 CFReleaseSafe(args2); 877 CFReleaseSafe(args3); 878 return status; 879} 880 881#ifndef SECITEM_SHIM_OSX 882static void copy_all_keys_and_values(const void *key, const void *value, void *context) 883{ 884 CFDictionaryAddValue((CFMutableDictionaryRef)context, key, value); 885} 886#endif 887 888#ifndef SECITEM_SHIM_OSX 889static OSStatus explode_persistent_identity_ref(CFDictionaryRef query, CFMutableDictionaryRef *delete_query) 890{ 891 OSStatus status = errSecSuccess; 892 CFTypeRef persist = CFDictionaryGetValue(query, kSecValuePersistentRef); 893 CFStringRef class; 894 if (persist && _SecItemParsePersistentRef(persist, &class, NULL) 895 && CFEqual(class, kSecClassIdentity)) { 896 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef }; 897 const void *vals[] = { kCFBooleanTrue, persist }; 898 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys, 899 vals, (array_size(keys)), NULL, NULL); 900 CFTypeRef item_query = NULL; 901 status = SecItemCopyMatching(persistent_query, &item_query); 902 CFReleaseNull(persistent_query); 903 if (status) 904 return status; 905 CFMutableDictionaryRef new_query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 906 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 907 if (new_query) { 908 CFDictionaryApplyFunction(query, copy_all_keys_and_values, new_query); 909 CFDictionaryRemoveValue(new_query, kSecValuePersistentRef); 910 CFDictionarySetValue(new_query, kSecValueRef, item_query); 911 *delete_query = new_query; 912 } else 913 status = errSecAllocate; 914 CFRelease(item_query); 915 } 916 917 return status; 918} 919#endif 920 921OSStatus 922#if SECITEM_SHIM_OSX 923SecItemDelete_ios(CFDictionaryRef query) 924#else 925SecItemDelete(CFDictionaryRef query) 926#endif // *** END SECITEM_SHIM_OSX *** 927{ 928 CFMutableDictionaryRef args1 = NULL, args2 = NULL, args3 = NULL; 929 OSStatus status; 930 931#ifndef SECITEM_SHIM_OSX 932 require_noerr_quiet(status = explode_persistent_identity_ref(query, &args1), errOut); 933 if (args1) 934 query = args1; 935 require_quiet(!explode_identity(query, (secitem_operation)SecItemDelete, &status, NULL), errOut); 936 require_noerr_quiet(status = cook_query(query, &args2), errOut); 937 if (args2) 938 query = args2; 939#endif // *** END SECITEM_SHIM_OSX *** 940 941 attributes_pre(query, &args3); 942 if (args3) 943 query = args3; 944 945 require_noerr_quiet(status = SecOSStatusWith(^bool (CFErrorRef *error) { 946 return SECURITYD_XPC(sec_item_delete, dict_ag_to_error_request, query, SecAccessGroupsGetCurrent(), error); 947 }), errOut); 948 949errOut: 950 CFReleaseSafe(args1); 951 CFReleaseSafe(args2); 952 CFReleaseSafe(args3); 953 return status; 954} 955 956OSStatus 957SecItemDeleteAll(void) 958{ 959 return SecOSStatusWith(^bool (CFErrorRef *error) { 960 bool ok; 961 if (gSecurityd) { 962 ok = true; 963#ifndef SECITEM_SHIM_OSX 964 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser); 965 if (!gSecurityd->sec_truststore_remove_all(ts, error)) 966 ok = SecError(errSecInternal, error, CFSTR("sec_truststore_remove_all is NULL")); 967#endif // *** END SECITEM_SHIM_OSX *** 968 if (!gSecurityd->sec_item_delete_all(error)) 969 ok = SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL")); 970 } else { 971 ok = securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL); 972 } 973 return ok; 974 }); 975} 976 977CFDataRef _SecKeychainCopyOTABackup(void) { 978 return SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, NULL, NULL, NULL); 979} 980 981CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password) { 982 return SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, backupKeybag, password, NULL); 983} 984 985OSStatus _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag, 986 CFDataRef password) { 987 return SecOSStatusWith(^bool (CFErrorRef *error) { 988 return SECURITYD_XPC(sec_keychain_restore, data_data_data_to_error_request, backup, backupKeybag, password, error); 989 }); 990} 991 992CFArrayRef _SecKeychainSyncUpdateKeyParameter(CFDictionaryRef updates, CFErrorRef *error) { 993 994 return SECURITYD_XPC(sec_keychain_sync_update_key_parameter, dict_to_array_error_request, updates, error); 995} 996 997CFArrayRef _SecKeychainSyncUpdateCircle(CFDictionaryRef updates, CFErrorRef *error) { 998 999 return SECURITYD_XPC(sec_keychain_sync_update_circle, dict_to_array_error_request, updates, error); 1000} 1001 1002CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) { 1003 1004 return SECURITYD_XPC(sec_keychain_sync_update_message, dict_to_array_error_request, updates, error); 1005} 1006 1007OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out) 1008{ 1009 return SecOSStatusWith(^bool (CFErrorRef *error) { 1010 *backup_out = SECURITYD_XPC(sec_keychain_backup_syncable, data_data_dict_to_dict_error_request, backup_in, keybag, password, error); 1011 return *backup_out != NULL; 1012 }); 1013} 1014 1015OSStatus _SecKeychainRestoreSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in) 1016{ 1017 return SecOSStatusWith(^bool (CFErrorRef *error) { 1018 return SECURITYD_XPC(sec_keychain_restore_syncable, dict_data_data_to_error_request, backup_in, keybag, password, error); 1019 }); 1020} 1021 1022#ifndef SECITEM_SHIM_OSX 1023OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); 1024 1025OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement) 1026{ 1027 return -1; /* this is only on OS X currently */ 1028} 1029 1030#else 1031 1032extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); 1033 1034#endif 1035 1036#define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); } 1037 1038bool _SecKeychainRollKeys(bool force, CFErrorRef *error) 1039{ 1040 do_if_registered(sec_roll_keys, force, error); 1041 1042 __block bool result = false; 1043 1044 secdebug("secitem","enter - %s", __FUNCTION__); 1045 securityd_send_sync_and_do(kSecXPCOpRollKeys, error, 1046 ^bool(xpc_object_t message, CFErrorRef *error) { 1047 xpc_dictionary_set_bool(message, "force", force); 1048 return true; 1049 }, 1050 ^bool(xpc_object_t response, __unused CFErrorRef *error) { 1051 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult); 1052 return result; 1053 }); 1054 return result; 1055} 1056 1057 1058