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
);