2 * Copyright (c) 2006-2014 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 #include <Security/SecItemShim.h>
35 #include <Security/SecAccessControl.h>
36 #include <Security/SecAccessControlPriv.h>
37 #include <Security/SecKey.h>
38 #include <Security/SecKeyPriv.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecIdentity.h>
41 #include <Security/SecIdentityPriv.h>
42 #include <Security/SecRandom.h>
43 #include <Security/SecBasePriv.h>
44 #include <Security/SecCTKKeyPriv.h>
45 #include <Security/SecTask.h>
46 #include <Security/SecPolicyInternal.h>
53 #include <sys/param.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 <corecrypto/ccder.h>
65 #include <utilities/array_size.h>
66 #include <utilities/debugging.h>
67 #include <utilities/SecCFError.h>
68 #include <utilities/SecCFWrappers.h>
69 #include <utilities/SecIOFormat.h>
70 #include <utilities/SecXPCError.h>
71 #include <utilities/der_plist.h>
72 #include <utilities/der_plist_internal.h>
75 #include <libaks_acl_cf_keys.h>
76 #include <os/activity.h>
80 #include <Security/SecInternal.h>
81 #include "keychain/SecureObjectSync/SOSInternal.h"
82 #include <TargetConditionals.h>
83 #include <ipc/securityd_client.h>
84 #include <Security/SecuritydXPC.h>
85 #include <AssertMacros.h>
87 #include <sys/types.h>
91 #include <libDER/asn1Types.h>
93 #include <utilities/SecDb.h>
94 #include <IOKit/IOReturn.h>
96 #include <coreauthd_spi.h>
97 #include <LocalAuthentication/LAPrivateDefines.h>
98 #include <LocalAuthentication/LACFSupport.h>
100 #include <ctkclient/ctkclient.h>
103 * See corresponding definition in SecDbKeychainItemV7. This is the unserialized
104 * maximum, so the daemon's limit is not exactly the same.
106 #define REASONABLE_DATA_SIZE 4096
108 const CFStringRef kSecNetworkExtensionAccessGroupSuffix
= CFSTR("com.apple.networkextensionsharing");
110 /* Return an OSStatus for a sqlite3 error code. */
111 static OSStatus
osstatus_for_s3e(int s3e
)
117 return errSecSuccess
;
118 case SQLITE_READONLY
:
119 return errSecReadOnly
;
120 case SQLITE_CONSTRAINT
:
121 return errSecDuplicateItem
;
122 case SQLITE_ABORT
: // There is no errSecOperationCancelled
124 case SQLITE_MISMATCH
:
125 return errSecNoSuchAttr
;
127 return errSecAllocate
;
130 case SQLITE_INTERNAL
:
131 return errSecInternalComponent
;
132 case SQLITE_FULL
: // Happens if we run out of uniqueids or disk is full (TODO: replace with better code)
133 case SQLITE_PERM
: // No acess permission
134 case SQLITE_AUTH
: // No authorization (e.g. no class key for file)
135 case SQLITE_CANTOPEN
: // can be several reasons for this. Caller should sqlite3_system_errno()
136 case SQLITE_EMPTY
: // SQLite does not seem to use this. Was already here, so keeping
139 return errSecNotAvailable
;
143 static OSStatus
osstatus_for_kern_return(CFIndex kernResult
)
148 return errSecSuccess
;
149 case kIOReturnNotReadable
:
150 case kIOReturnNotWritable
:
151 return errSecAuthFailed
;
152 case kIOReturnNotPermitted
:
153 case kIOReturnNotPrivileged
:
154 case kIOReturnLockedRead
:
155 case kIOReturnLockedWrite
:
156 return errSecInteractionNotAllowed
;
159 case kIOReturnBadArgument
:
162 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
166 static OSStatus
osstatus_for_xpc_error(CFIndex xpcError
) {
169 case kSecXPCErrorSuccess
:
170 return errSecSuccess
;
171 case kSecXPCErrorUnexpectedType
:
172 case kSecXPCErrorUnexpectedNull
:
174 case kSecXPCErrorConnectionFailed
:
175 return errSecNotAvailable
;
176 case kSecXPCErrorUnknown
:
178 return errSecInternal
;
182 static OSStatus
osstatus_for_der_error(CFIndex derError
) {
185 case kSecDERErrorUnknownEncoding
:
186 case kSecDERErrorUnsupportedDERType
:
187 case kSecDERErrorUnsupportedNumberType
:
189 case kSecDERErrorUnsupportedCFObject
:
191 case kSecDERErrorAllocationFailure
:
192 return errSecAllocate
;
194 return errSecInternal
;
198 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
199 // Wrap LA error in Sec error.
201 case kLAErrorUserCancel
:
202 return errSecUserCanceled
;
203 case kLAErrorParameter
:
205 case kLAErrorNotInteractive
:
206 return errSecInteractionNotAllowed
;
208 return errSecAuthFailed
;
212 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
214 case kTKErrorCodeBadParameter
:
216 case kTKErrorCodeNotImplemented
:
217 return errSecUnimplemented
;
218 case kTKErrorCodeCanceledByUser
:
219 return errSecUserCanceled
;
220 case kTKErrorCodeCorruptedData
:
222 case kTKErrorCodeTokenNotFound
:
223 case kTKErrorCodeObjectNotFound
:
224 return errSecItemNotFound
;
226 return errSecInternal
;
231 // Convert from securityd error codes to OSStatus for legacy API.
232 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
235 status
= errSecSuccess
;
237 CFStringRef domain
= CFErrorGetDomain(error
);
238 if (domain
== NULL
) {
239 secerror("No error domain for error: %@", error
);
240 status
= errSecInternal
;
241 } else if (CFEqual(kSecErrorDomain
, domain
)) {
242 status
= (OSStatus
)CFErrorGetCode(error
);
243 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
244 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
245 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
246 status
= (OSStatus
)CFErrorGetCode(error
);
247 } else if (CFEqual(kSecKernDomain
, domain
)) {
248 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
249 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
250 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
251 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
252 status
= osstatus_for_der_error(CFErrorGetCode(error
));
253 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
254 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
255 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
256 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
257 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
258 status
= errSecInternal
;
260 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
261 status
= errSecInternal
;
268 lastErrorReleaseError(void *value
)
275 getLastErrorKey(pthread_key_t
*kv
)
277 static pthread_key_t key
;
278 static bool haveKey
= false;
279 static dispatch_once_t onceToken
;
280 dispatch_once(&onceToken
, ^{
281 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
289 SetLastError(CFErrorRef newError
)
292 if (!getLastErrorKey(&key
))
294 CFErrorRef oldError
= pthread_getspecific(key
);
299 pthread_setspecific(key
, newError
);
303 SecCopyLastError(OSStatus status
)
308 if (!getLastErrorKey(&key
))
311 error
= pthread_getspecific(key
);
313 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
322 // Wrapper to provide a CFErrorRef for legacy API.
323 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
324 CFErrorRef error
= NULL
;
326 if (perform(&error
)) {
327 assert(error
== NULL
);
329 status
= errSecSuccess
;
333 status
= SecErrorGetOSStatus(error
);
334 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
335 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
336 CFReleaseNull(error
);
342 logUnreasonableDataLength(CFDictionaryRef attributes
)
347 if (isDictionary(attributes
)) {
348 data
= CFDictionaryGetValue(attributes
, kSecValueData
);
350 length
= CFDataGetLength(data
);
351 if (length
> REASONABLE_DATA_SIZE
) {
352 // This log message is vague, as we may not know anything else about the item.
353 // securityd logging (correlate by activity ID) will have more information.
354 secwarning("keychain item data exceeds reasonable size (%lu bytes)", (unsigned long)length
);
360 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
361 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
364 static CFDictionaryRef
365 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
367 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
368 if (filtered
== NULL
)
370 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
371 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
372 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
373 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
374 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
375 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
376 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
377 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
378 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
379 CFDictionaryRemoveValue(filtered
, kSecAttrIsPermanent
);
385 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
386 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
388 Currently in need of conversion below:
389 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
390 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
391 currently implemented at all, but when it is needs to short circuit to
392 local evaluation, different from the sql query abilities
395 static CFDictionaryRef
396 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
397 CFDictionaryRef refDictionary
= NULL
;
398 CFTypeID typeID
= CFGetTypeID(ref
);
399 if (typeID
== SecKeyGetTypeID()) {
400 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
401 if (refDictionary
&& forQuery
) {
402 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
403 CFAssignRetained(refDictionary
, filtered
);
405 } else if (typeID
== SecCertificateGetTypeID()) {
406 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
407 } else if (typeID
== SecIdentityGetTypeID()) {
409 SecIdentityRef identity
= (SecIdentityRef
)ref
;
410 SecCertificateRef cert
= NULL
;
411 SecKeyRef key
= NULL
;
412 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
413 !SecIdentityCopyPrivateKey(identity
, &key
))
415 CFDataRef data
= SecCertificateCopyData(cert
);
416 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
418 if (key_dict
&& data
) {
419 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
420 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
422 CFReleaseNull(key_dict
);
428 return refDictionary
;
431 #ifdef SECITEM_SHIM_OSX
432 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
436 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
437 CFTypeRef ref
= NULL
;
438 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
439 if (CFEqual(class, kSecClassKey
)) {
440 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
441 } else if (CFEqual(class, kSecClassCertificate
)) {
442 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
443 } else if (CFEqual(class, kSecClassIdentity
)) {
444 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
445 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
446 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
448 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
451 secerror("SecItem: failed to create identity");
456 #ifdef SECITEM_SHIM_OSX
458 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
466 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
469 return -1 /* errSecUnimplemented */;
471 #endif // TARGET_OS_OSX
473 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
475 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
476 OSStatus
*return_status
, CFTypeRef
*return_result
)
478 bool handled
= false;
479 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
481 CFTypeID typeID
= CFGetTypeID(value
);
482 if (typeID
== SecIdentityGetTypeID()) {
484 OSStatus status
= errSecSuccess
;
485 SecIdentityRef identity
= (SecIdentityRef
)value
;
486 SecCertificateRef cert
= NULL
;
487 SecKeyRef key
= NULL
;
488 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
489 !SecIdentityCopyPrivateKey(identity
, &key
))
491 CFMutableDictionaryRef partial_query
=
492 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
493 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
494 CFTypeRef result
= NULL
;
495 bool duplicate_cert
= false;
496 /* an identity is first and foremost a key, but it can have multiple
497 certs associated with it: so we identify it by the cert */
498 status
= operation(partial_query
, return_result
? &result
: NULL
);
499 if ((operation
== (secitem_operation
)SecItemAdd
) &&
500 (status
== errSecDuplicateItem
)) {
501 duplicate_cert
= true;
502 status
= errSecSuccess
;
505 if (!status
|| status
== errSecItemNotFound
) {
506 bool skip_key_operation
= false;
508 /* if the key is still in use, skip deleting it */
509 if (operation
== (secitem_operation
)SecItemDelete
) {
510 // find certs with cert.pkhh == keys.klbl
511 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
512 CFDataRef pkhh
= NULL
;
514 key_dict
= SecKeyCopyAttributeDictionary(key
);
516 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
517 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
518 const void *vals
[] = { kSecClassCertificate
, pkhh
};
520 query_dict
= CFDictionaryCreate(NULL
, keys
,
521 vals
, (array_size(keys
)),
524 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
525 skip_key_operation
= true;
526 CFReleaseSafe(query_dict
);
527 CFReleaseSafe(key_dict
);
530 if (!skip_key_operation
) {
531 /* now perform the operation for the key */
532 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
533 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
535 status
= operation(partial_query
, NULL
);
536 if ((operation
== (secitem_operation
)SecItemAdd
) &&
537 (status
== errSecDuplicateItem
) &&
539 status
= errSecSuccess
;
542 /* add and copy matching for an identityref have a persistent ref result */
545 /* result is a persistent ref to a cert */
547 CFDictionaryRef tokenAttrs
= NULL
;
548 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
, &tokenAttrs
)) {
549 *return_result
= _SecItemCreatePersistentRef(kSecClassIdentity
, rowid
, tokenAttrs
);
551 CFReleaseNull(tokenAttrs
);
556 CFReleaseNull(partial_query
);
559 status
= errSecInvalidItemRef
;
563 *return_status
= status
;
566 value
= CFDictionaryGetValue(attributes
, kSecClass
);
567 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
568 (operation
== (secitem_operation
)SecItemDelete
)) {
569 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
570 CFDictionaryRemoveValue(dict
, kSecClass
);
571 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
572 OSStatus status
= SecItemDelete(dict
);
574 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
575 status
= SecItemDelete(dict
);
578 *return_status
= status
;
586 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
589 CFErrorRef lastError
= SecCopyLastError(status
);
591 CFErrorPropagate(lastError
, error
);
593 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
600 handleUpdateIdentity(CFDictionaryRef query
,
601 CFDictionaryRef update
,
605 CFMutableDictionaryRef updatedQuery
= NULL
;
606 SecCertificateRef cert
= NULL
;
607 SecKeyRef key
= NULL
;
608 bool handled
= false;
612 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
614 CFTypeID typeID
= CFGetTypeID(value
);
615 if (typeID
== SecIdentityGetTypeID()) {
616 SecIdentityRef identity
= (SecIdentityRef
)value
;
621 status
= SecIdentityCopyCertificate(identity
, &cert
);
622 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
624 status
= SecIdentityCopyPrivateKey(identity
, &key
);
625 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
627 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
628 require_action_quiet(updatedQuery
, errOut
, *result
= false);
630 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
631 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
633 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
634 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
638 value
= CFDictionaryGetValue(query
, kSecClass
);
639 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
642 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
643 require_action_quiet(updatedQuery
, errOut
, *result
= false);
645 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
646 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
648 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
649 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
651 CFReleaseNull(updatedQuery
);
656 CFReleaseNull(updatedQuery
);
662 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
664 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
665 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
666 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
667 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
668 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
670 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
671 CFReleaseNull(label
);
677 static CFDataRef
CreateTokenPersistentRefData(CFTypeRef
class, CFDictionaryRef attributes
)
679 CFDataRef tokenPersistentRef
= NULL
;
681 CFDictionaryRef itemValue
= NULL
;
682 require_quiet(tokenId
= CFCast(CFString
, CFDictionaryGetValue(attributes
, kSecAttrTokenID
)), out
);
683 if (CFEqual(class, kSecClassIdentity
)) {
684 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecAttrIdentityCertificateData
), NULL
);
686 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecValueData
), NULL
);
688 require_quiet(itemValue
, out
);
689 CFDataRef oid
= CFDictionaryGetValue(itemValue
, kSecTokenValueObjectIDKey
);
690 require_quiet(oid
, out
);
691 CFArrayRef array
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, class, tokenId
, oid
, NULL
);
692 tokenPersistentRef
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, NULL
);
695 CFReleaseNull(itemValue
);
696 return tokenPersistentRef
;
699 static const uint8_t tk_persistent_ref_id
[] = {'t', 'k', 'p', 'r'};
700 /* A persistent ref is just the class and the rowid of the record.
701 Persistent ref for token items is a der blob with class, tokenID and objectId. */
702 CFDataRef
_SecItemCreatePersistentRef(CFTypeRef
class, sqlite_int64 rowid
, CFDictionaryRef attributes
)
704 CFDataRef result
= NULL
;
705 if (attributes
&& CFDictionaryContainsKey(attributes
, CFEqual(class, kSecClassIdentity
) ? kSecAttrIdentityCertificateTokenID
: kSecAttrTokenID
)) {
706 CFDataRef tokenPersistentRef
= CreateTokenPersistentRefData(class, attributes
);
707 require(tokenPersistentRef
, out
);
708 CFMutableDataRef tmpData
= CFDataCreateMutable(kCFAllocatorDefault
, sizeof(tk_persistent_ref_id
) + CFDataGetLength(tokenPersistentRef
));
709 CFDataAppendBytes(tmpData
, tk_persistent_ref_id
, sizeof(tk_persistent_ref_id
));
710 CFDataAppend(tmpData
, tokenPersistentRef
);
711 CFReleaseNull(tokenPersistentRef
);
714 require(rowid
>= 0, out
);
715 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
716 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
717 kCFStringEncodingUTF8
))
719 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
720 result
= CFDataCreate(NULL
, bytes
, sizeof(bytes
));
727 static Boolean
isValidClass(CFStringRef
class, CFStringRef
*return_class
) {
728 const void *valid_classes
[] = { kSecClassGenericPassword
,
729 kSecClassInternetPassword
,
730 kSecClassAppleSharePassword
,
731 kSecClassCertificate
,
735 for (size_t i
= 0; i
< array_size(valid_classes
); i
++) {
736 if (CFEqual(valid_classes
[i
], class)) {
738 *return_class
= valid_classes
[i
];
746 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref
, CFStringRef
*return_class
, CFDictionaryRef
*return_token_attrs
) {
747 bool valid_ref
= false;
748 CFPropertyListRef pl
= NULL
;
749 const uint8_t *der
= CFDataGetBytePtr(persistent_ref
) + sizeof(tk_persistent_ref_id
);
750 const uint8_t *der_end
= der
+ (CFDataGetLength(persistent_ref
) - sizeof(tk_persistent_ref_id
));
751 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &pl
, NULL
, der
, der_end
), out
);
752 require_quiet(der
== der_end
, out
);
753 require_quiet(CFGetTypeID(pl
) == CFArrayGetTypeID(), out
);
754 require_quiet(CFArrayGetCount(pl
) == 3, out
);
755 require_quiet(valid_ref
= isValidClass(CFArrayGetValueAtIndex(pl
, 0), return_class
), out
);
756 if (return_token_attrs
) {
757 *return_token_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
758 kSecAttrTokenID
, CFArrayGetValueAtIndex(pl
, 1),
759 kSecAttrTokenOID
, CFArrayGetValueAtIndex(pl
, 2), NULL
);
766 /* AUDIT[securityd](done):
767 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
769 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
, CFDictionaryRef
*return_token_attrs
)
771 bool valid_ref
= false;
772 require(CFGetTypeID(persistent_ref
) == CFDataGetTypeID(), out
);
774 if (CFDataGetLength(persistent_ref
) > (CFIndex
)sizeof(tk_persistent_ref_id
) &&
775 memcmp(tk_persistent_ref_id
, CFDataGetBytePtr(persistent_ref
), sizeof(tk_persistent_ref_id
)) == 0) {
776 valid_ref
= ParseTokenPersistentRefData(persistent_ref
, return_class
, return_token_attrs
);
777 } else if (CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
778 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
779 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
781 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
782 bytes
, CFStringGetLength(kSecClassGenericPassword
),
783 kCFStringEncodingUTF8
, true);
785 if ((valid_ref
= isValidClass(class, return_class
))) {
787 *return_rowid
= rowid
;
795 static bool cf_bool_value(CFTypeRef cf_bool
) {
796 return cf_bool
&& CFBooleanGetValue(cf_bool
);
799 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
800 if (cow_dictionary
->mutable_dictionary
== NULL
) {
801 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
802 if (cow_dictionary
->dictionary
!= NULL
) {
803 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
804 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
807 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
810 return cow_dictionary
->mutable_dictionary
;
813 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
814 // access_control and optionally of the data value.
815 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
816 CFMutableDictionaryRef value
= NULL
;
817 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
818 kSecTokenValueObjectIDKey
, oid
,
819 kSecTokenValueAccessControlKey
, access_control
,
821 if (object_value
!= NULL
) {
822 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
825 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
830 CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
831 CFPropertyListRef plist
= NULL
;
832 require_quiet(CFCastWithError(CFData
, db_value
, error
), out
);
833 const uint8_t *der
= CFDataGetBytePtr(db_value
);
834 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
835 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
836 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
837 CFTypeRef value
= CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
);
838 require_action_quiet(CFCast(CFData
, value
) != NULL
, out
,
839 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
840 value
= CFDictionaryGetValue(plist
, kSecTokenValueAccessControlKey
);
841 require_quiet(value
== NULL
|| CFCastWithError(CFData
, value
, error
), out
);
842 value
= CFDictionaryGetValue(plist
, kSecTokenValueDataKey
);
843 require_quiet(value
== NULL
|| CFCastWithError(CFData
, value
, error
), out
);
849 TKTokenRef
SecTokenCreate(CFStringRef token_id
, SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
) {
850 CFMutableDictionaryRef token_attrs
= NULL
;
851 TKTokenRef token
= NULL
;
853 static CFMutableDictionaryRef sharedLAContexts
= NULL
;
854 static dispatch_once_t onceToken
;
855 static os_unfair_lock lock
= OS_UNFAIR_LOCK_INIT
;
856 if ((auth_params
->dictionary
== NULL
|| CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
) == NULL
) && !CFStringHasPrefix(token_id
, kSecAttrTokenIDSecureEnclave
)) {
857 dispatch_once(&onceToken
, ^{
858 sharedLAContexts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
861 os_unfair_lock_lock(&lock
);
862 CFTypeRef ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
864 ctx
= LACreateNewContextWithACMContext(NULL
, error
);
866 os_unfair_lock_unlock(&lock
);
867 secerror("Failed to create authentication context %@", *error
);
870 CFDictionarySetValue(sharedLAContexts
, token_id
, ctx
);
872 ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
875 CFDataRef credRef
= NULL
;
877 credRef
= LACopyACMContext(ctx
, NULL
);
881 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, ctx
);
882 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, credRef
);
885 os_unfair_lock_unlock(&lock
);
888 token_attrs
= (auth_params
->dictionary
!= NULL
) ?
889 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
->dictionary
) :
890 CFDictionaryCreateMutableForCFTypes(NULL
);
891 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
893 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
894 token
= TKTokenCreate(token_attrs
, error
);
896 CFReleaseSafe(token_attrs
);
900 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params_dict
,
901 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
903 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
904 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
905 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
906 if (token_id
!= NULL
&& object_id
!= NULL
) {
907 require_quiet(CFCastWithError(CFString
, token_id
, error
), out
);
908 if (CFRetainSafe(token
) == NULL
) {
909 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
912 if (auth_params
.dictionary
!= NULL
) {
913 CFDictionaryForEach(auth_params
.dictionary
, ^(const void *key
, const void *value
) {
914 CFDictionaryAddValue(attrs
, key
, value
);
917 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
918 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
921 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
925 CFReleaseSafe(attrs
);
926 CFReleaseSafe(auth_params
.mutable_dictionary
);
931 /* Turn the returned single value or dictionary that contains all the attributes to create a
932 ref into the exact result the client asked for */
933 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
934 CFDictionaryRef query
, CFDictionaryRef auth_params_dict
,
935 CFTypeRef
*result
, CFErrorRef
*error
) {
937 CFDataRef ac_data
= NULL
;
938 CFDataRef value
= NULL
;
939 CFTypeRef persistent_ref
= NULL
;
940 CFStringRef token_id
= NULL
;
941 CFStringRef cert_token_id
= NULL
;
942 CFDataRef object_id
= NULL
;
943 CFMutableDictionaryRef attrs
= NULL
;
944 CFDataRef cert_data
= NULL
;
945 CFDataRef cert_object_id
= NULL
;
946 TKTokenRef cert_token
= NULL
;
947 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
949 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
950 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
951 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
952 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
954 // Get token value if not provided by the caller.
955 bool token_item
= false;
956 bool cert_token_item
= false;
958 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
959 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
960 require_quiet(token_id
== NULL
|| CFCastWithError(CFString
, token_id
, error
) != NULL
, out
);
961 token_item
= (token_id
!= NULL
);
963 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
964 require_quiet(cert_token_id
== NULL
|| CFCastWithError(CFString
, cert_token_id
, error
) != NULL
, out
);
965 cert_token_item
= (cert_token_id
!= NULL
);
969 cert_token_item
= true;
971 CFRetainAssign(cert_token
, token
);
974 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
976 cert_token_item
= false;
979 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
980 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
981 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
982 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
984 value
= CFRetainSafe(raw_result
);
985 if (token_item
&& value
!= NULL
) {
986 // Parse token-based item's data field.
987 CFDataRef object_value
= NULL
;
988 CFDictionaryRef parsed_value
= NULL
;
989 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
990 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
991 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
992 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
993 CFRelease(parsed_value
);
994 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
995 // Retrieve value directly from the token.
997 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
999 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
1000 if (CFEqual(object_value
, kCFNull
))
1001 CFReleaseNull(object_value
);
1003 CFAssignRetained(value
, object_value
);
1006 // If only thing requested is data, return them directly.
1007 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
1008 *result
= CFRetainSafe(value
);
1014 // Extract persistent_ref, if caller wants it.
1015 if (wants_persistent_ref
) {
1016 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
1017 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
1019 persistent_ref
= CFRetainSafe(raw_result
);
1021 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
1022 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
1023 *result
= CFRetainSafe(persistent_ref
);
1029 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
1035 // For other cases we need an output dictionary.
1036 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
1037 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
1039 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
1040 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
1042 if ((wants_data
|| wants_ref
) && value
!= NULL
)
1043 CFDictionarySetValue(output
, kSecValueData
, value
);
1045 CFDictionaryRemoveValue(output
, kSecValueData
);
1047 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
1048 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
1050 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
1052 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
1053 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
1054 // Decode also certdata field of the identity.
1055 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
1057 CFDictionaryRef parsed_value
;
1058 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
1059 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
1060 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
1061 CFRelease(parsed_value
);
1062 if (cert_data
== NULL
) {
1063 // Retrieve value directly from the token.
1064 if (cert_token
== NULL
) {
1065 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, &auth_params
, error
), out
);
1067 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1068 if (CFEqual(cert_data
, kCFNull
))
1069 CFReleaseNull(cert_data
);
1071 if (cert_data
!= NULL
) {
1072 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1074 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1079 if (wants_ref
|| wants_attributes
) {
1080 // Convert serialized form of access control to object form.
1082 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1085 if (ac_data
!= NULL
) {
1086 SecAccessControlRef ac
;
1087 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1088 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1095 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
.dictionary
, token
, object_id
, &ref
, error
), out
);
1096 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1097 CFAssignRetained(*result
, ref
);
1098 } else if (ref
!= NULL
) {
1099 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1102 // We could have stored data value previously to make ref creation succeed.
1103 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1104 CFDictionaryRemoveValue(output
, kSecValueData
);
1112 CFReleaseSafe(cert_object_id
);
1113 CFReleaseSafe(cert_data
);
1114 CFReleaseSafe(ac_data
);
1115 CFReleaseSafe(value
);
1116 CFReleaseSafe(persistent_ref
);
1117 CFReleaseSafe(object_id
);
1118 CFReleaseSafe(attrs
);
1119 CFReleaseSafe(token
);
1120 CFReleaseSafe(cert_token
);
1121 CFReleaseSafe(auth_params
.mutable_dictionary
);
1125 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1126 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1128 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1129 require_action_quiet(result
!= NULL
, out
, ok
= true);
1131 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1132 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1133 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1134 for (i
= 0; i
< count
; i
++) {
1136 CFErrorRef localError
= NULL
;
1137 bool prepared
= SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1138 token
, query
, auth_params
, &ref
, &localError
);
1140 // TokenNotFound or TokenObjectNotFound will just not insert failing item into resulting array, other errors abort processing.
1141 require_action_quiet(localError
!= NULL
&& CFEqual(CFErrorGetDomain(localError
), CFSTR(kTKErrorDomain
)) &&
1142 (CFErrorGetCode(localError
) == kTKErrorCodeTokenNotFound
|| CFErrorGetCode(localError
) == kTKErrorCodeObjectNotFound
), out
,
1143 CFErrorPropagate(localError
, error
));
1144 CFReleaseNull(localError
);
1145 } else if (ref
!= NULL
) {
1146 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1151 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1160 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1162 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1163 void *la_lib
= NULL
;
1165 // If a ref was specified we get its attribute dictionary and parse it.
1166 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1168 CFDictionaryRef ref_attributes
;
1169 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1170 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1172 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1173 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1174 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1175 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1176 // so add only those attributes from 'ref' which are missing in attrs.
1177 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1179 CFRelease(ref_attributes
);
1182 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1185 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1186 // another roundtrip to token driver.
1187 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1188 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1192 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1193 if (access_control
!= NULL
) {
1194 require_action_quiet(CFGetTypeID(access_control
) == SecAccessControlGetTypeID(), out
,
1195 SecError(errSecParam
, error
, CFSTR("Unexpected type of kSecAttrAccessControl attribute")));
1196 require_action_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
,
1197 SecError(errSecParam
, error
, CFSTR("unsupported kSecAttrAccessControl in query")));
1198 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1201 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1203 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1204 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1205 require_quiet(acm_context
= LACopyACMContext(la_context
, error
), out
);
1206 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1207 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1210 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1212 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1213 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1215 CFTypeRef values
[] = { policy
};
1216 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1217 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1218 CFReleaseSafe(policiesArray
);
1219 require_action_quiet(policiesArrayXPC
, out
,
1220 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1222 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1223 xpc_release(policiesArrayXPC
);
1224 require_action_quiet(objectReadyForXPC
, out
,
1225 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1227 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1228 CFRelease(objectReadyForXPC
);
1230 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1232 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1234 require_quiet(issuer
= CFCastWithError(CFData
, value
, error
), out
);
1235 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
) };
1236 DERDecodedInfo content
;
1237 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1238 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1239 if (canonical_issuer
) {
1240 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1241 CFRelease(canonical_issuer
);
1246 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1247 // This use flag is client-only, securityd does not understand it.
1248 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1254 if (la_lib
!= NULL
) {
1257 CFReleaseSafe(ac_data
);
1258 CFReleaseSafe(acm_context
);
1262 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1264 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1266 CFArrayForEachC(ac_pairs
, ac_pair
) {
1267 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1268 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1269 CFStringAppend(log_string
, str
);
1270 CFRelease(acl_hex_string
);
1274 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1275 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1276 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1278 CFRelease(log_string
);
1282 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1283 void (^newCredentialRefAdded
)(void)) {
1285 CFArrayRef ac_pairs
= NULL
;
1286 SecCFDictionaryCOW auth_options
= { NULL
};
1288 for (uint32_t i
= 0;; ++i
) {
1289 // If the operation succeeded or failed with other than auth-needed error, just leave.
1290 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1291 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1292 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1294 // If auth_params were not created up to now, do create them because we will definitely need them.
1295 SecCFDictionaryCOWGetMutable(auth_params
);
1297 // Retrieve or create authentication handle and/or ACM context.
1298 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1299 if (auth_handle
== NULL
) {
1300 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1301 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1302 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1303 CFRelease(auth_handle
);
1304 if (acm_context
== NULL
) {
1305 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1306 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1307 CFRelease(acm_context
);
1308 if (newCredentialRefAdded
) {
1309 newCredentialRefAdded();
1314 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1315 // user retry limit.
1316 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1318 // Prepare auth options dictionary.
1319 if (auth_options
.dictionary
== NULL
) {
1320 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1321 if (operation_prompt
!= NULL
) {
1322 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1323 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1327 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1328 if (caller_name
!= NULL
) {
1329 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1330 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1334 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1335 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1336 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1337 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1342 // Go through all access_control-operation pairs and evaluate them.
1344 CFArrayForEachC(ac_pairs
, ac_pair
) {
1345 CFDataRef updated_acl
= NULL
;
1346 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1347 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1348 auth_options
.dictionary
, &updated_acl
, error
), out
);
1350 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1351 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1352 SecAccessControlRef ac
= NULL
;
1353 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1354 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1355 SecAccessControlSetBound(ac
, true);
1356 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1357 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1358 CFRelease(updated_acl
);
1367 CFReleaseSafe(auth_options
.mutable_dictionary
);
1368 CFReleaseSafe(ac_pairs
);
1372 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1373 // Store operation prompt.
1374 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1375 if (operation_prompt
!= NULL
) {
1376 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1377 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1380 // Store caller name.
1381 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1382 if (caller_name
!= NULL
) {
1383 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1384 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1387 // Find out whether we are allowed to pop up a UI.
1388 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1389 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1390 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1391 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1392 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1393 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1394 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1395 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1398 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1399 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1402 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1403 if (acm_context
!= NULL
) {
1404 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1408 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1410 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1411 // Extract ACLs to be verified from the error.
1412 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1413 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1414 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1415 if (*ac_pairs
== NULL
)
1416 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1419 CFRelease(user_info
);
1420 CFReleaseNull(*error
);
1421 return kSecItemAuthResultNeedAuth
;
1423 return kSecItemAuthResultError
;
1426 // Wrapper to handle automatic authentication and token/secd case switching.
1427 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1428 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1430 __block SecCFDictionaryCOW auth_params
= { NULL
};
1431 __block TKTokenRef token
= NULL
;
1433 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1434 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1435 require_action_quiet(access_control
== NULL
|| CFGetTypeID(access_control
) == SecAccessControlGetTypeID(), out
,
1436 SecError(errSecParam
, error
, CFSTR("Unexpected type of kSecAttrAccessControl attribute")));
1438 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1439 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1440 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1441 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1444 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1445 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1447 secItemOperation
== SecItemCopyMatching
||
1448 secItemOperation
== SecItemUpdate
||
1449 secItemOperation
== SecItemDelete
;
1451 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1452 if (attributes
!= NULL
)
1453 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1455 // Populate auth_params dictionary according to initial query contents.
1456 SecItemAuthCopyParams(&auth_params
, query
);
1458 if (secItemOperation
!= SecItemCopyMatching
) {
1459 // UISkip is allowed only for CopyMatching.
1460 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1461 SecError(errSecParam
, error
,
1462 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1465 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1466 SecItemAuthResult result
= kSecItemAuthResultError
;
1468 // Propagate actual credential reference to the query.
1469 if (auth_params
.dictionary
!= NULL
) {
1470 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1471 if (acm_context
!= NULL
) {
1472 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1475 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1476 if (acl_data_ref
!= NULL
) {
1477 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1481 // Prepare connection to target token if it is present.
1482 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1483 require_quiet(token_id
== NULL
|| CFCastWithError(CFString
, token_id
, error
) != NULL
, out
);
1484 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
&& !cf_bool_value(CFDictionaryGetValue(query
->dictionary
, kSecUseTokenRawItems
))) {
1485 CFErrorRef localError
= NULL
;
1486 CFAssignRetained(token
, SecTokenCreate(token_id
, &auth_params
, &localError
));
1487 if (token
== NULL
) {
1488 require_action_quiet(secItemOperation
== SecItemDelete
&&
1489 CFEqual(CFErrorGetDomain(localError
), CFSTR(kTKErrorDomain
)) &&
1490 CFErrorGetCode(localError
) == kTKErrorCodeTokenNotFound
,
1491 out
, CFErrorPropagate(localError
, error
));
1493 // In case that token cannot be found and deletion is required, just continue and delete item from keychain only.
1494 CFReleaseNull(localError
);
1498 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1499 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1500 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1503 result
= kSecItemAuthResultOK
;
1508 require_quiet(ok
, out
);
1513 CFReleaseSafe(token
);
1514 CFReleaseSafe(auth_params
.mutable_dictionary
);
1518 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1520 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1521 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1522 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1524 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1530 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1532 CFArrayRef result
= NULL
;
1533 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1534 if(success
&& !isArray(result
)){
1535 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1536 CFReleaseNull(result
);
1541 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1542 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1545 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1547 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1548 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1552 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1554 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1556 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1561 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1569 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1571 return dict_to_error_request(op
, query
, error
);
1574 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1575 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1576 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1577 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1578 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1579 keys
, ac_pairs
, 1));
1581 CFRelease(ac_pairs
[0]);
1586 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1587 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1588 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationNeeded
) {
1589 // Replace error with the one which is augmented with access control and operation which failed,
1590 // which will cause SecItemDoWithAuth to throw UI.
1591 // Create array containing tuple (array) with error and requested operation.
1592 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
);
1593 if (access_control
!= NULL
) {
1594 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1595 CFRelease(access_control
);
1601 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1602 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
, result
= NULL
;
1603 SecAccessControlRef ac
= NULL
;
1604 CFDictionaryRef old_attrs
= NULL
;
1606 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1607 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1608 if (ac_data
!= NULL
) {
1609 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1610 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1611 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1614 // Create or update the object on the token.
1615 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1616 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1617 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1618 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1619 if (!CFEqual(key
, kSecValueData
)) {
1620 CFDictionaryAddValue(attributes
, key
, value
);
1624 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1625 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1626 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1627 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1628 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1630 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1631 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1632 CFRetainAssign(result
, new_object_id
);
1636 CFReleaseSafe(access_control
);
1637 CFReleaseSafe(db_value
);
1638 CFReleaseSafe(old_attrs
);
1639 CFReleaseSafe(new_object_id
);
1643 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1644 CFTypeRef
*result
, CFErrorRef
*error
) {
1646 CFTypeRef object_id
= NULL
, ref
= NULL
;
1647 CFDictionaryRef ref_attrs
= NULL
;
1648 CFTypeRef db_result
= NULL
;
1649 CFDataRef db_value
= NULL
;
1650 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1652 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1653 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1654 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1655 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1656 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1657 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1658 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1659 // the ref from the dictionary since it is of no use any more.
1660 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1662 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1663 // by creating ref and getting back its attributes.
1664 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1666 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1667 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1668 if (!CFEqual(key
, kSecValueData
)) {
1669 CFDictionaryAddValue(attrs
, key
, value
);
1676 // Make sure that both attributes and data are returned.
1677 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1678 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1680 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1681 // IsPermanent is not present or is true, so add item to the db.
1682 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1683 SecSecurityClientGet(), &db_result
, error
), out
);
1685 // Process directly result of token call.
1686 db_result
= CFRetain(attrs
);
1688 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1692 CFReleaseSafe(db_result
);
1693 CFReleaseSafe(db_value
);
1694 CFReleaseSafe(attrs
);
1695 CFReleaseSafe(ref_attrs
);
1696 CFReleaseSafe(object_id
);
1701 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1702 __block SecCFDictionaryCOW attrs
= { attributes
};
1705 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1706 os_activity_scope(activity
);
1707 os_release(activity
);
1709 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1710 infer_cert_label(&attrs
);
1712 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1713 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1714 if (token
== NULL
) {
1715 CFTypeRef raw_result
= NULL
;
1716 logUnreasonableDataLength(attributes
);
1717 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1720 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1721 CFReleaseSafe(raw_result
);
1724 // Send request to an appropriate token instead of secd.
1725 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1731 CFReleaseSafe(attrs
.mutable_dictionary
);
1732 secdebug("secitem", "SecItemAdd returned: %d", (int)status
);
1738 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1740 __block SecCFDictionaryCOW query
= { inQuery
};
1742 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1743 os_activity_scope(activity
);
1744 os_release(activity
);
1746 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1748 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1749 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1750 if ((wants_data
&& !wants_attributes
)) {
1751 // When either attributes or data are requested, we need to query both, because for token based items,
1752 // both are needed in order to generate proper data and/or attributes results.
1753 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1756 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1757 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1758 CFTypeRef raw_result
= NULL
;
1759 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1762 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1763 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1764 // to currently processed item.
1765 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1766 CFReleaseSafe(raw_result
);
1772 secdebug("secitem", "SecItemCopyMatching_ios returned: %d", (int)status
);
1773 CFReleaseSafe(query
.mutable_dictionary
);
1777 // Invokes token-object handler for each item matching specified query.
1778 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1779 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1780 CFErrorRef
*error
)) {
1782 CFMutableDictionaryRef list_query
= NULL
;
1783 CFTypeRef items
= NULL
;
1784 CFArrayRef ref_array
= NULL
;
1785 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1787 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1788 // items in the keychain.
1789 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1790 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1791 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1793 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1794 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1795 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1796 SecSecurityClientGet(), &items
, error
), out
);
1797 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1798 // Wrap single returned item into the array.
1799 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1800 CFAssignRetained(items
, item_array
);
1804 CFArrayForEachC(items
, item
) {
1805 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1806 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1808 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1809 require_quiet(item_data
, out
);
1811 CFAssignRetained(item_query
,
1812 CFDictionaryCreateForCFTypes(NULL
,
1813 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1815 require_quiet(perform(item_data
, item_query
, error
), out
);
1821 CFReleaseSafe(list_query
);
1822 CFReleaseSafe(items
);
1823 CFReleaseSafe(item_data
);
1824 CFReleaseSafe(ref_array
);
1825 CFReleaseSafe(item_query
);
1829 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1832 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1833 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1834 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1835 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1838 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1840 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1841 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1842 logUnreasonableDataLength(attributesToUpdate
);
1843 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1845 ok
= securityd_message_no_error(reply
, error
);
1849 xpc_release(message
);
1855 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1856 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1858 CFDataRef object_id
= NULL
;
1859 CFMutableDictionaryRef db_value
= NULL
;
1861 // Update attributes on the token.
1862 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1863 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1864 attributes
, error
), out
);
1866 // Update attributes in the database.
1867 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1872 CFReleaseSafe(object_id
);
1873 CFReleaseSafe(attributes
);
1874 CFReleaseSafe(db_value
);
1879 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1880 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1881 os_activity_scope(activity
);
1882 os_release(activity
);
1884 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1885 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1890 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1891 CFDictionaryRef inAttributesToUpdate
,
1894 __block SecCFDictionaryCOW query
= { inQuery
};
1895 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1896 bool result
= false;
1898 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1901 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1902 if (token
== NULL
) {
1903 return SecItemRawUpdate(query
, attributes
, error
);
1905 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1910 CFReleaseSafe(query
.mutable_dictionary
);
1911 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1912 secdebug("secitem", "SecItemUpdateWithError returned: %d", (int)result
);
1916 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1918 OSStatus status
= errSecSuccess
;
1919 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1921 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1922 && CFEqual(class, kSecClassIdentity
)) {
1923 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1924 const void *vals
[] = { kCFBooleanTrue
, persist
};
1925 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1926 vals
, (array_size(keys
)), NULL
, NULL
);
1927 CFTypeRef item_query
= NULL
;
1928 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1929 CFReleaseNull(persistent_query
);
1932 if (item_query
== NULL
)
1933 return errSecItemNotFound
;
1935 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1936 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1937 CFRelease(item_query
);
1943 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1945 __block SecCFDictionaryCOW query
= { inQuery
};
1947 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1948 os_activity_scope(activity
);
1949 os_release(activity
);
1951 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1952 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1954 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1955 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1956 if (token
== NULL
) {
1957 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1959 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1962 // Delete item from the token.
1963 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1964 CFErrorRef localError
= NULL
;
1965 if (!TKTokenDeleteObject(token
, object_id
, &localError
)) {
1966 // Check whether object was not found; in this case, ignore the error.
1967 require_action_quiet(CFEqual(CFErrorGetDomain(localError
), CFSTR(kTKErrorDomain
)) &&
1968 CFErrorGetCode(localError
) == kTKErrorCodeObjectNotFound
, out
,
1969 (CFErrorPropagate(localError
, error
), SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
)));
1970 CFReleaseNull(localError
);
1973 // Delete the item from the keychain.
1974 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1975 SecSecurityClientGet(), error
), out
);
1986 CFReleaseSafe(query
.mutable_dictionary
);
1987 secdebug("secitem", "SecItemDelete returned: %d", (int)status
);
1993 SecItemDeleteAll(void)
1995 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1998 if (!gSecurityd
->sec_item_delete_all(error
))
1999 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
2001 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
2009 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
2011 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2012 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
2017 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
2019 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2020 os_activity_scope(activity
);
2021 os_release(activity
);
2023 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
2024 SecSecurityClientGet(), error
);
2031 #if SECITEM_SHIM_OSX
2032 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
2034 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
2039 os_activity_t activity
= os_activity_create("SecItemUpdateTokenItems_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2040 os_activity_scope(activity
);
2041 os_release(activity
);
2043 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
2044 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
2045 if (tokenItemsAttributes
) {
2046 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
2047 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
2048 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
2049 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
2050 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
2051 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
2052 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
2053 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
2055 CFRelease(tokenItems
);
2059 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
2060 CFDictionarySetValue(attributes
, kSecValueData
, data
);
2061 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
2062 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2063 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2064 CFArrayAppendValue(tokenItems
, attributes
);
2065 CFRelease(attributes
);
2069 CFArrayAppendValue(tokenItems
, itemAttributes
);
2072 tmpArrayRef
= tokenItems
;
2075 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2081 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2082 __block CFArrayRef result
;
2083 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2084 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2089 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2091 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2093 do_if_registered(sec_roll_keys
, force
, error
);
2095 __block
bool result
= false;
2097 secdebug("secitem","enter - %s", __FUNCTION__
);
2098 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2099 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2100 xpc_dictionary_set_bool(message
, "force", force
);
2103 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2104 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2110 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2111 __block CFArrayRef results
= NULL
;
2112 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2113 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2114 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2116 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2117 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2122 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2123 __block
bool result
= false;
2124 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2125 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2126 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2127 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2129 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2130 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2136 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2137 CFArrayRef results
= NULL
;
2139 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2140 os_activity_scope(activity
);
2141 os_release(activity
);
2143 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2148 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2149 bool results
= false;
2151 os_activity_t activity
= os_activity_create("SecItemCertificateExists", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2152 os_activity_scope(activity
);
2153 os_release(activity
);
2155 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);