2  * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * SecItem.c - CoreFoundation-based constants and functions for 
  26     access to Security items (certificates, keys, identities, and 
  30 #include <Security/SecBasePriv.h> 
  31 #include <Security/SecItem.h> 
  32 #include <Security/SecItemPriv.h> 
  33 #include <Security/SecItemInternal.h> 
  34 #ifndef SECITEM_SHIM_OSX 
  35 #include <Security/SecKey.h> 
  36 #include <Security/SecKeyPriv.h> 
  37 #include <Security/SecCertificateInternal.h> 
  38 #include <Security/SecIdentity.h> 
  39 #include <Security/SecIdentityPriv.h> 
  40 #include <Security/SecRandom.h> 
  41 #include <Security/SecBasePriv.h> 
  42 #endif // *** END SECITEM_SHIM_OSX *** 
  43 #include <Security/SecTask.h> 
  50 #include <sys/param.h> 
  52 #include <Security/SecBase.h> 
  53 #include <CoreFoundation/CFData.h> 
  54 #include <CoreFoundation/CFDate.h> 
  55 #include <CoreFoundation/CFDictionary.h> 
  56 #include <CoreFoundation/CFNumber.h> 
  57 #include <CoreFoundation/CFString.h> 
  58 #include <CoreFoundation/CFURL.h> 
  59 #include <CommonCrypto/CommonDigest.h> 
  60 #include <libkern/OSByteOrder.h> 
  61 #include <utilities/array_size.h> 
  62 #include <utilities/debugging.h> 
  63 #include <utilities/SecCFError.h> 
  64 #include <utilities/SecCFWrappers.h> 
  65 #include <utilities/SecIOFormat.h> 
  66 #include <utilities/SecXPCError.h> 
  67 #include <utilities/der_plist.h> 
  70 #include <Security/SecInternal.h> 
  71 #include <TargetConditionals.h> 
  72 #include "securityd_client.h" 
  73 #include "SecuritydXPC.h" 
  74 #include <AssertMacros.h> 
  76 #include <sys/types.h> 
  80 #ifndef SECITEM_SHIM_OSX 
  81 #include <libDER/asn1Types.h> 
  82 #endif // *** END SECITEM_SHIM_OSX *** 
  84 /* label when certificate data is joined with key data */ 
  85 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"  
  87 #include <utilities/SecDb.h> 
  88 #include <IOKit/IOReturn.h> 
  90 /* Return an OSStatus for a sqlite3 error code. */ 
  91 static OSStatus 
osstatus_for_s3e(int s3e
) 
  93         if (s3e 
> 0 && s3e 
<= SQLITE_DONE
) switch (s3e
) 
  98             return errSecNotAvailable
; /* errSecDuplicateItem; */ 
  99         case SQLITE_FULL
: /* Happens if we run out of uniqueids */ 
 100             return errSecNotAvailable
; /* TODO: Replace with a better error code. */ 
 102         case SQLITE_READONLY
: 
 103             return errSecNotAvailable
; 
 104         case SQLITE_CANTOPEN
: 
 105             return errSecNotAvailable
; 
 107             return errSecNotAvailable
; 
 108         case SQLITE_CONSTRAINT
: 
 109             return errSecDuplicateItem
; 
 112         case SQLITE_MISMATCH
: 
 113             return errSecNoSuchAttr
; 
 115             return errSecNotAvailable
; 
 117             return -2; /* TODO: Replace with a real error code. */ 
 118         case SQLITE_INTERNAL
: 
 120             return errSecNotAvailable
; /* TODO: Replace with a real error code. */ 
 125 static OSStatus 
osstatus_for_kern_return(CFIndex kernResult
) 
 130             return errSecSuccess
; 
 131         case kIOReturnNotReadable
: 
 132         case kIOReturnNotWritable
: 
 133             return errSecAuthFailed
; 
 134         case kIOReturnNotPermitted
: 
 135         case kIOReturnNotPrivileged
: 
 136         case kIOReturnLockedRead
: 
 137         case kIOReturnLockedWrite
: 
 138             return errSecInteractionNotAllowed
; 
 141         case kIOReturnBadArgument
: 
 144             return errSecNotAvailable
; /* TODO: Replace with a real error code. */ 
 148 static OSStatus 
osstatus_for_xpc_error(CFIndex xpcError
) { 
 151         case kSecXPCErrorSuccess
: 
 152             return errSecSuccess
; 
 153         case kSecXPCErrorUnexpectedType
: 
 154         case kSecXPCErrorUnexpectedNull
: 
 156         case kSecXPCErrorConnectionFailed
: 
 157             return errSecNotAvailable
; 
 158         case kSecXPCErrorUnknown
: 
 160             return errSecInternal
; 
 164 static OSStatus 
osstatus_for_der_error(CFIndex derError
) { 
 167         case kSecDERErrorUnknownEncoding
: 
 168         //case kSecDERErrorUnsupportedDERType: 
 170         case kSecDERErrorUnsupportedCFObject
: 
 171         case kSecDERErrorUnsupportedNumberType
: 
 173         case kSecDERErrorAllocationFailure
: 
 174         case kSecDERErrorUnderlyingError
: 
 175             return errSecAllocate
; 
 177             return errSecInternal
; 
 181 // Convert from securityd error codes to OSStatus for legacy API. 
 182 OSStatus 
SecErrorGetOSStatus(CFErrorRef error
) { 
 185         status 
= errSecSuccess
; 
 187         CFStringRef domain 
= CFErrorGetDomain(error
); 
 188         if (domain 
== NULL
) { 
 189             secerror("No error domain for error: %@", error
); 
 190             status 
= errSecInternal
; 
 191         } else if (CFEqual(kSecErrorDomain
, domain
)) { 
 192             status 
= (OSStatus
)CFErrorGetCode(error
); 
 193         } else if (CFEqual(kSecDbErrorDomain
, domain
)) { 
 194             status 
= osstatus_for_s3e((int)CFErrorGetCode(error
)); 
 195         } else if (CFEqual(kSecErrnoDomain
, domain
)) { 
 196             status 
= (OSStatus
)CFErrorGetCode(error
); 
 197         } else if (CFEqual(kSecKernDomain
, domain
)) { 
 198             status 
= osstatus_for_kern_return(CFErrorGetCode(error
)); 
 199         } else if (CFEqual(sSecXPCErrorDomain
, domain
)) { 
 200             status 
= osstatus_for_xpc_error(CFErrorGetCode(error
)); 
 201         } else if (CFEqual(sSecDERErrorDomain
, domain
)) { 
 202             status 
= osstatus_for_der_error(CFErrorGetCode(error
)); 
 204             secerror("unknown error domain: %@ for error: %@", domain
, error
); 
 205             status 
= errSecInternal
; 
 211 // Wrapper to provide a CFErrorRef for legacy API. 
 212 OSStatus 
SecOSStatusWith(bool (^perform
)(CFErrorRef 
*error
)) { 
 213     CFErrorRef error 
= NULL
; 
 215     if (perform(&error
)) { 
 216         assert(error 
== NULL
); 
 217         status 
= errSecSuccess
; 
 220         status 
= SecErrorGetOSStatus(error
); 
 221         if (status 
!= errSecItemNotFound
)           // Occurs in normal operation, so exclude 
 222             secerror("error:[%" PRIdOSStatus 
"] %@", status
, error
); 
 223         CFReleaseNull(error
); 
 229 /* IPC uses CFPropertyList to un/marshall input/output data and can handle: 
 230    CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber 
 232    Currently in need of conversion below: 
 233    @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef 
 234    @@@ kSecMatchPolicy allows a query with a SecPolicyRef 
 235    @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't 
 236        currently implemented at all, but when it is needs to short circuit to 
 237            local evaluation, different from the sql query abilities 
 240 #ifndef SECITEM_SHIM_OSX 
 241 static CFDictionaryRef
 
 242 SecItemCopyAttributeDictionary(CFTypeRef ref
) { 
 243         CFDictionaryRef refDictionary 
= NULL
; 
 244         CFTypeID typeID 
= CFGetTypeID(ref
); 
 245         if (typeID 
== SecKeyGetTypeID()) { 
 246                 refDictionary 
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
); 
 247         } else if (typeID 
== SecCertificateGetTypeID()) { 
 249                         SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
); 
 250         } else if (typeID 
== SecIdentityGetTypeID()) { 
 252         SecIdentityRef identity 
= (SecIdentityRef
)ref
; 
 253         SecCertificateRef cert 
= NULL
; 
 254         SecKeyRef key 
= NULL
; 
 255         if (!SecIdentityCopyCertificate(identity
, &cert
) && 
 256             !SecIdentityCopyPrivateKey(identity
, &key
))  
 258             CFDataRef data 
= SecCertificateCopyData(cert
); 
 259             CFDictionaryRef key_dict 
= SecKeyCopyAttributeDictionary(key
); 
 261             if (key_dict 
&& data
) { 
 262                 refDictionary 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
); 
 263                 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
,  
 264                     CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
), data
); 
 266             CFReleaseNull(key_dict
); 
 272                 refDictionary 
= NULL
; 
 274         return refDictionary
; 
 278 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) { 
 279         CFTypeRef ref 
= NULL
; 
 280         CFStringRef 
class = CFDictionaryGetValue(refAttributes
, kSecClass
); 
 281         if (CFEqual(class, kSecClassCertificate
)) { 
 282                 ref 
= SecCertificateCreateFromAttributeDictionary(refAttributes
); 
 283         } else if (CFEqual(class, kSecClassKey
)) { 
 284                 ref 
= SecKeyCreateFromAttributeDictionary(refAttributes
); 
 285         } else if (CFEqual(class, kSecClassIdentity
)) { 
 286                 CFAllocatorRef allocator 
= NULL
; 
 287                 CFDataRef data 
= CFDictionaryGetValue(refAttributes
, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
)); 
 288                 SecCertificateRef cert 
= SecCertificateCreateWithData(allocator
, data
); 
 289                 SecKeyRef key 
= SecKeyCreateFromAttributeDictionary(refAttributes
); 
 291                         ref 
= SecIdentityCreate(allocator
, cert
, key
); 
 295         /* We don't support SecKeychainItemRefs yet. */ 
 296         } else if (CFEqual(class, kSecClassGenericPassword
)) { 
 297         } else if (CFEqual(class, kSecClassInternetPassword
)) { 
 298         } else if (CFEqual(class, kSecClassAppleSharePassword
)) { 
 307 extern CFTypeRef 
SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
); 
 311 /* Turn the returned dictionary that contains all the attributes to create a 
 312    ref into the exact result the client asked for */ 
 313 static CFTypeRef 
makeRef(CFTypeRef ref
, bool return_data
, bool return_attributes
) 
 315         CFTypeRef result 
= NULL
; 
 316         if (!ref 
|| (CFGetTypeID(ref
) != CFDictionaryGetTypeID())) 
 319         CFTypeRef return_ref 
= SecItemCreateFromAttributeDictionary(ref
); 
 321         if (return_data 
|| return_attributes
) { 
 322                 if (return_attributes
) 
 323                         result 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, ref
); 
 325                         result 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 328                         CFDictionarySetValue((CFMutableDictionaryRef
)result
, kSecValueRef
, return_ref
); 
 329                         CFRelease(return_ref
); 
 333                         CFDictionaryRemoveValue((CFMutableDictionaryRef
)result
, kSecValueData
); 
 341 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef 
*displayNames
) 
 344     return -1 /* errSecUnimplemented */; 
 347 #ifndef SECITEM_SHIM_OSX 
 348 static void merge_dictionary_by_overwrite(const void *key
, const void *value
, void *context
) 
 350         if (!CFEqual(key
, kSecValueRef
)) 
 351                 CFDictionarySetValue((CFMutableDictionaryRef
)context
, key
, value
); 
 354 static void copy_applier(const void *key
, const void *value
, void *context
) 
 356     CFDictionarySetValue(context
, key
, value
); 
 359 static OSStatus 
cook_query(CFDictionaryRef query
, CFMutableDictionaryRef 
*explode
) 
 361         /* If a ref was specified we get it's attribute dictionary and parse it. */ 
 362         CFMutableDictionaryRef args 
= NULL
; 
 363         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecValueRef
); 
 365                 CFDictionaryRef refAttributes 
= SecItemCopyAttributeDictionary(value
); 
 367                         return errSecValueRefUnsupported
; 
 369                 /* Replace any attributes we already got from the ref with the ones 
 370                    from the attributes dictionary the caller passed us.  This allows 
 371                    a caller to add an item using attributes from the ref and still 
 372                    override some of them in the dictionary directly.  */ 
 373                 args 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, refAttributes
); 
 374                 CFRelease(refAttributes
); 
 375                 CFDictionaryApplyFunction(query
, merge_dictionary_by_overwrite
, args
); 
 377     value 
= CFDictionaryGetValue(query
, kSecAttrIssuer
); 
 379         /* convert DN to canonical issuer, if value is DN (top level sequence) */ 
 380         const DERItem name 
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) }; 
 381         DERDecodedInfo content
; 
 382         if (!DERDecodeItem(&name
, &content
) && 
 383             (content
.tag 
== ASN1_CONSTR_SEQUENCE
)) 
 385             CFDataRef canonical_issuer 
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
); 
 386             if (canonical_issuer
) { 
 388                     args 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 389                     /* This is necessary because we rely on non NULL callbacks */ 
 390                     CFDictionaryApplyFunction(query
, copy_applier
, args
); 
 392                 /* Overwrite with new issuer */ 
 393                 CFDictionarySetValue(args
, kSecAttrIssuer
, canonical_issuer
); 
 394                 CFRelease(canonical_issuer
); 
 399         return errSecSuccess
; 
 402 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
 404 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,  
 405     OSStatus 
*return_status
, CFTypeRef 
*return_result
) 
 407     bool handled 
= false; 
 408         CFTypeRef value 
= CFDictionaryGetValue(attributes
, kSecValueRef
); 
 410         CFTypeID typeID 
= CFGetTypeID(value
); 
 411         if (typeID 
== SecIdentityGetTypeID()) { 
 413             OSStatus status 
= errSecSuccess
; 
 414             SecIdentityRef identity 
= (SecIdentityRef
)value
; 
 415             SecCertificateRef cert 
= NULL
; 
 416             SecKeyRef key 
= NULL
; 
 417             if (!SecIdentityCopyCertificate(identity
, &cert
) && 
 418                 !SecIdentityCopyPrivateKey(identity
, &key
))  
 420                 CFMutableDictionaryRef partial_query 
= 
 421                     CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
); 
 422                 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
); 
 423                 CFTypeRef result 
= NULL
; 
 424                 bool duplicate_cert 
= false; 
 425                 /* an identity is first and foremost a key, but it can have multiple 
 426                    certs associated with it: so we identify it by the cert */ 
 427                 status 
= operation(partial_query
, return_result 
? &result 
: NULL
); 
 428                 if ((operation 
== (secitem_operation
)SecItemAdd
) && 
 429                     (status 
== errSecDuplicateItem
)) { 
 430                         duplicate_cert 
= true; 
 431                         status 
= errSecSuccess
; 
 434                 if (!status 
|| status 
== errSecItemNotFound
) { 
 435                                         bool skip_key_operation 
= false; 
 437                                         /* if the key is still in use, skip deleting it */ 
 438                                         if (operation 
== (secitem_operation
)SecItemDelete
) { 
 439                                                 // find certs with cert.pkhh == keys.klbl 
 440                                                 CFDictionaryRef key_dict 
= NULL
, query_dict 
= NULL
; 
 441                                                 CFDataRef pkhh 
= NULL
; 
 443                                                 key_dict 
= SecKeyCopyAttributeDictionary(key
); 
 445                                                         pkhh 
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
); 
 446                                                 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash 
}; 
 447                                                 const void *vals
[] = { kSecClassCertificate
, pkhh 
}; 
 449                                                         query_dict 
= CFDictionaryCreate(NULL
, keys
,  
 450                                                     vals
, (array_size(keys
)), 
 453                                                         if (errSecSuccess 
== SecItemCopyMatching(query_dict
, NULL
)) 
 454                                                                 skip_key_operation 
= true; 
 455                                                 CFReleaseSafe(query_dict
); 
 456                                                 CFReleaseSafe(key_dict
); 
 459                                         if (!skip_key_operation
) { 
 460                             /* now perform the operation for the key */ 
 461                             CFDictionarySetValue(partial_query
, kSecValueRef
, key
); 
 462                             CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
); 
 463                             status 
= operation(partial_query
, NULL
); 
 464                             if ((operation 
== (secitem_operation
)SecItemAdd
) && 
 465                                 (status 
== errSecDuplicateItem
) && 
 467                                     status 
= errSecSuccess
; 
 470                     /* add and copy matching for an identityref have a persistent ref result */ 
 473                             /* result is a persistent ref to a cert */ 
 475                             if (_SecItemParsePersistentRef(result
, NULL
, &rowid
)) { 
 476                                 *return_result 
= _SecItemMakePersistentRef(kSecClassIdentity
, rowid
); 
 482                 CFReleaseNull(partial_query
); 
 485                 status 
= errSecInvalidItemRef
; 
 489             *return_status 
= status
; 
 492                 value 
= CFDictionaryGetValue(attributes
, kSecClass
); 
 493                 if (value 
&& CFEqual(kSecClassIdentity
, value
) &&  
 494                         (operation 
== (secitem_operation
)SecItemDelete
)) { 
 495                         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
); 
 496                         CFDictionaryRemoveValue(dict
, kSecClass
); 
 497                         CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
); 
 498                         OSStatus status 
= SecItemDelete(dict
); 
 500                                 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
); 
 501                                 status 
= SecItemDelete(dict
); 
 504                         *return_status 
= status
; 
 511 static void infer_cert_label(CFDictionaryRef attributes
, CFMutableDictionaryRef args
) 
 513         if (!args 
|| !attributes
) 
 516         if (CFDictionaryContainsKey(attributes
, kSecAttrLabel
)) 
 519         CFTypeRef value_ref 
= CFDictionaryGetValue(attributes
, kSecValueRef
); 
 520         if (!value_ref 
|| (CFGetTypeID(value_ref
) != SecCertificateGetTypeID())) 
 523         SecCertificateRef certificate 
= (SecCertificateRef
)value_ref
; 
 524         CFStringRef label 
= SecCertificateCopySubjectSummary(certificate
); 
 526                 CFDictionarySetValue(args
, kSecAttrLabel
, label
); 
 527                 CFReleaseNull(label
); 
 531 /* A persistent ref is just the class and the rowid of the record. */ 
 532 CF_RETURNS_RETAINED CFDataRef 
_SecItemMakePersistentRef(CFTypeRef 
class, sqlite_int64 rowid
) 
 534     uint8_t bytes
[sizeof(sqlite_int64
) + 4]; 
 537     if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,  
 538         kCFStringEncodingUTF8
)) 
 540         OSWriteBigInt64(bytes 
+ 4, 0, rowid
); 
 541         return CFDataCreate(NULL
, bytes
, sizeof(bytes
)); 
 546 /* AUDIT[securityd](done): 
 547    persistent_ref (ok) is a caller provided, non NULL CFTypeRef. 
 549 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef 
*return_class
, sqlite_int64 
*return_rowid
) 
 551         bool valid_ref 
= false; 
 552     if (CFGetTypeID(persistent_ref
) == CFDataGetTypeID() && 
 553         CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) { 
 554         const uint8_t *bytes 
= CFDataGetBytePtr(persistent_ref
); 
 555         sqlite_int64 rowid 
= OSReadBigInt64(bytes 
+ 4, 0); 
 557         CFStringRef 
class = CFStringCreateWithBytes(kCFAllocatorDefault
,  
 558             bytes
, CFStringGetLength(kSecClassGenericPassword
),  
 559             kCFStringEncodingUTF8
, true); 
 560         const void *valid_classes
[] = { kSecClassGenericPassword
, 
 561             kSecClassInternetPassword
, 
 562             kSecClassAppleSharePassword
, 
 563             kSecClassCertificate
, 
 568         for (i
=0; i
< array_size(valid_classes
); i
++) { 
 569             if (CFEqual(valid_classes
[i
], class)) { 
 571                     *return_class 
= valid_classes
[i
]; 
 573                     *return_rowid 
= rowid
; 
 583 #endif // *** END SECITEM_SHIM_OSX *** 
 585 static bool cf_bool_value(CFTypeRef cf_bool
) 
 587         return (cf_bool 
&& CFEqual(kCFBooleanTrue
, cf_bool
)); 
 592 result_post(CFDictionaryRef query
, CFTypeRef raw_result
, CFTypeRef 
*result
) { 
 597         CFRelease(raw_result
); 
 601         bool return_ref 
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
)); 
 602         bool return_data 
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
)); 
 603         bool return_attributes 
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
)); 
 606                 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) { 
 607                         CFIndex i
, count 
= CFArrayGetCount(raw_result
); 
 608                         CFMutableArrayRef tmp_array 
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
); 
 609                         for (i 
= 0; i 
< count
; i
++) { 
 610                                 CFTypeRef ref 
= makeRef(CFArrayGetValueAtIndex(raw_result
, i
), return_data
, return_attributes
); 
 612                                         CFArrayAppendValue(tmp_array
, ref
); 
 618                         *result 
= makeRef(raw_result
, return_data
, return_attributes
); 
 620                 CFRelease(raw_result
); 
 622                 *result 
= raw_result
; 
 626 /* TODO: Should be in some header */ 
 627 OSStatus 
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
 628 OSStatus 
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef 
*result
); 
 629 OSStatus 
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
 630 OSStatus 
SecItemDelete_ios(CFDictionaryRef query
); 
 633 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef 
*result
, CFErrorRef 
*error
) 
 635     return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef 
*error
) { 
 636         return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
); 
 637     }, ^bool(xpc_object_t response
, CFErrorRef 
*error
) { 
 639             return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
); 
 645 static bool cftype_ag_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused CFArrayRef accessGroups
, CFTypeRef 
*result
, CFErrorRef 
*error
) { 
 646     return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
); 
 649 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef 
*error
) 
 651     return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef 
*error
) { 
 652         return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
); 
 656 static bool dict_ag_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused CFArrayRef accessGroups
, CFErrorRef 
*error
) 
 658     return dict_to_error_request(op
, query
, error
); 
 661 static CFDataRef 
data_data_to_data_error_request(enum SecXPCOperation op
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef 
*error
) { 
 662     __block CFDataRef result 
= NULL
; 
 663     securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef 
*error
) { 
 664         return SecXPCDictionarySetDataOptional(message
, kSecXPCKeyKeybag
, keybag
, error
) 
 665         && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
); 
 666     }, ^bool(xpc_object_t response
, CFErrorRef 
*error
) { 
 667         return (result 
= SecXPCDictionaryCopyData(response
, kSecXPCKeyResult
, error
)); 
 672 static bool data_data_data_to_error_request(enum SecXPCOperation op
, CFDataRef backup
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef 
*error
) { 
 673     return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef 
*error
) { 
 674         return SecXPCDictionarySetData(message
, kSecXPCKeyBackup
, backup
, error
) 
 675         && SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
) 
 676         && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
); 
 680 static bool dict_data_data_to_error_request(enum SecXPCOperation op
, CFDictionaryRef backup
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef 
*error
) { 
 681     return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef 
*error
) { 
 682         return SecXPCDictionarySetPList(message
, kSecXPCKeyBackup
, backup
, error
) 
 683         && SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
) 
 684         && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
); 
 688 static CFDictionaryRef 
data_data_dict_to_dict_error_request(enum SecXPCOperation op
, CFDictionaryRef backup
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef 
*error
) { 
 689     __block CFDictionaryRef dict 
= NULL
; 
 690     securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef 
*error
) { 
 691         return SecXPCDictionarySetPListOptional(message
, kSecXPCKeyBackup
, backup
, error
) 
 692         && SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
) 
 693         && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
); 
 694     }, ^bool(xpc_object_t response
, CFErrorRef 
*error
) { 
 695         return (dict 
= SecXPCDictionaryCopyDictionary(response
, kSecXPCKeyResult
, error
)); 
 702 SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
 704 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
 705 #endif // *** END SECITEM_SHIM_OSX *** 
 707     CFMutableDictionaryRef args 
= NULL
; 
 710 #ifndef SECITEM_SHIM_OSX 
 711     require_quiet(!explode_identity(attributes
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
); 
 712         require_noerr_quiet(status 
= cook_query(attributes
, &args
), errOut
); 
 713         infer_cert_label(attributes
, args
); 
 714 #endif // *** END SECITEM_SHIM_OSX *** 
 718     status 
= SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 719         CFTypeRef raw_result 
= NULL
; 
 720         if (!SECURITYD_XPC(sec_item_add
, cftype_ag_to_bool_cftype_error_request
, attributes
, SecAccessGroupsGetCurrent(), &raw_result
, error
)) 
 723         result_post(attributes
, raw_result
, result
); 
 727 #ifndef SECITEM_SHIM_OSX 
 729 #endif // *** END SECITEM_SHIM_OSX *** 
 737 SecItemCopyMatching_ios(CFDictionaryRef inQuery
, CFTypeRef 
*result
) 
 739 SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef 
*result
) 
 740 #endif // *** END SECITEM_SHIM_OSX *** 
 742     __block CFDictionaryRef query 
= inQuery
; 
 743     __block CFMutableDictionaryRef args 
= NULL
; 
 746 #ifndef SECITEM_SHIM_OSX 
 747     require_quiet(!explode_identity(query
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
); 
 748     require_noerr_quiet(status 
= cook_query(query
, &args
), errOut
); 
 749 #endif // *** END SECITEM_SHIM_OSX *** 
 753     status 
= SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 754         CFTypeRef raw_result 
= NULL
; 
 755         if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_ag_to_bool_cftype_error_request
, query
, SecAccessGroupsGetCurrent(), &raw_result
, error
)) 
 758 #ifdef SECITEM_SHIM_OSX 
 759         if ((!cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
)))  && cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
))) { 
 761             args 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
); 
 762             CFDictionaryAddValue(args
, kSecReturnPersistentRef
, kCFBooleanTrue
); 
 766         result_post(query
, raw_result
, result
); 
 770 #ifndef SECITEM_SHIM_OSX 
 772 #endif // *** END SECITEM_SHIM_OSX *** 
 779 SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
 781 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
 782 #endif // *** END SECITEM_SHIM_OSX *** 
 784     CFMutableDictionaryRef args 
= NULL
; 
 785     __block OSStatus status
; // TODO loose block once gSecurityd functions return CFErrorRefs 
 786 #ifndef SECITEM_SHIM_OSX 
 787     require_noerr_quiet(status 
= cook_query(query
, &args
), errOut
); 
 792     status 
= SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 795             // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks. 
 796             CFMutableDictionaryRef tmp 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
); 
 797             CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); }); 
 798             ok 
= gSecurityd
->sec_item_update(query
, tmp
, SecAccessGroupsGetCurrent(), error
); 
 801             xpc_object_t message 
= securityd_create_message(sec_item_update_id
, error
); 
 803                 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) && 
 804                     SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) { 
 805                     xpc_object_t reply 
= securityd_message_with_reply_sync(message
, error
); 
 807                         ok 
= securityd_message_no_error(reply
, error
); 
 811                 xpc_release(message
); 
 817 #ifndef SECITEM_SHIM_OSX 
 824 #ifndef SECITEM_SHIM_OSX 
 825 static void copy_all_keys_and_values(const void *key
, const void *value
, void *context
) 
 827     CFDictionaryAddValue((CFMutableDictionaryRef
)context
, key
, value
); 
 831 #ifndef SECITEM_SHIM_OSX 
 832 static OSStatus 
explode_persistent_identity_ref(CFDictionaryRef query
, CFMutableDictionaryRef 
*delete_query
) 
 834     OSStatus status 
= errSecSuccess
; 
 835     CFTypeRef persist 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
 837     if (persist 
&& _SecItemParsePersistentRef(persist
, &class, NULL
) 
 838         && CFEqual(class, kSecClassIdentity
)) { 
 839         const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef 
}; 
 840         const void *vals
[] = { kCFBooleanTrue
, persist 
}; 
 841         CFDictionaryRef persistent_query 
= CFDictionaryCreate(NULL
, keys
,  
 842             vals
, (array_size(keys
)), NULL
, NULL
); 
 843         CFTypeRef item_query 
= NULL
; 
 844         status 
= SecItemCopyMatching(persistent_query
, &item_query
); 
 845         CFReleaseNull(persistent_query
); 
 848         CFMutableDictionaryRef new_query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,  
 849             &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 851             CFDictionaryApplyFunction(query
, copy_all_keys_and_values
, new_query
); 
 852             CFDictionaryRemoveValue(new_query
, kSecValuePersistentRef
); 
 853             CFDictionarySetValue(new_query
, kSecValueRef
, item_query
); 
 854             *delete_query 
= new_query
; 
 856             status 
= errSecAllocate
; 
 857         CFRelease(item_query
); 
 866 SecItemDelete_ios(CFDictionaryRef query
) 
 868 SecItemDelete(CFDictionaryRef query
) 
 869 #endif // *** END SECITEM_SHIM_OSX ***  
 871         CFMutableDictionaryRef args1 
= NULL
, args2 
= NULL
; 
 874 #ifndef SECITEM_SHIM_OSX 
 875     require_noerr_quiet(status 
= explode_persistent_identity_ref(query
, &args1
), errOut
); 
 878     require_quiet(!explode_identity(query
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
); 
 879         require_noerr_quiet(status 
= cook_query(query
, &args2
), errOut
); 
 880 #endif // *** END SECITEM_SHIM_OSX ***     
 884     status 
= SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 885         return SECURITYD_XPC(sec_item_delete
, dict_ag_to_error_request
, query
, SecAccessGroupsGetCurrent(), error
); 
 888 #ifndef SECITEM_SHIM_OSX 
 890 #endif // *** END SECITEM_SHIM_OSX *** 
 891     CFReleaseSafe(args1
); 
 892     CFReleaseSafe(args2
); 
 897 SecItemDeleteAll(void) 
 899     return SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 902 #ifndef SECITEM_SHIM_OSX 
 903             SecTrustStoreRef ts 
= SecTrustStoreForDomain(kSecTrustStoreDomainUser
); 
 904             if (!gSecurityd
->sec_truststore_remove_all(ts
, error
)) 
 905                 ok 
= SecError(errSecInternal
, error
, CFSTR("sec_truststore_remove_all is NULL")); 
 906 #endif // *** END SECITEM_SHIM_OSX *** 
 907             if (!gSecurityd
->sec_item_delete_all(error
)) 
 908                 ok 
= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL")); 
 911             ok 
= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
); 
 917 CFDataRef 
_SecKeychainCopyOTABackup(void) { 
 918     return SECURITYD_XPC(sec_keychain_backup
, data_data_to_data_error_request
, NULL
, NULL
, NULL
); 
 921 CFDataRef 
_SecKeychainCopyBackup(CFDataRef backupKeybag
, CFDataRef password
) { 
 922     return SECURITYD_XPC(sec_keychain_backup
, data_data_to_data_error_request
, backupKeybag
, password
, NULL
); 
 925 OSStatus 
_SecKeychainRestoreBackup(CFDataRef backup
, CFDataRef backupKeybag
, 
 926     CFDataRef password
) { 
 927     return SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 928         return SECURITYD_XPC(sec_keychain_restore
, data_data_data_to_error_request
, backup
, backupKeybag
, password
, error
); 
 932 bool _SecKeychainSyncUpdate(CFDictionaryRef updates
, CFErrorRef 
*error
) { 
 933     return SECURITYD_XPC(sec_keychain_sync_update
, dict_to_error_request
, updates
, error
); 
 936 OSStatus 
_SecKeychainBackupSyncable(CFDataRef keybag
, CFDataRef password
, CFDictionaryRef backup_in
, CFDictionaryRef 
*backup_out
) 
 938     return SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 939         *backup_out 
= SECURITYD_XPC(sec_keychain_backup_syncable
, data_data_dict_to_dict_error_request
, backup_in
, keybag
, password
, error
); 
 940         return *backup_out 
!= NULL
; 
 944 OSStatus 
_SecKeychainRestoreSyncable(CFDataRef keybag
, CFDataRef password
, CFDictionaryRef backup_in
) 
 946     return SecOSStatusWith(^bool (CFErrorRef 
*error
) { 
 947         return SECURITYD_XPC(sec_keychain_restore_syncable
, dict_data_data_to_error_request
, backup_in
, keybag
, password
, error
); 
 952 #ifndef SECITEM_SHIM_OSX 
 953 OSStatus 
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
); 
 955 OSStatus 
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
) 
 957     return -1; /* this is only on OS X currently */ 
 962 extern OSStatus 
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);