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
:
223 return errSecInternal
;
228 // Convert from securityd error codes to OSStatus for legacy API.
229 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
232 status
= errSecSuccess
;
234 CFStringRef domain
= CFErrorGetDomain(error
);
235 if (domain
== NULL
) {
236 secerror("No error domain for error: %@", error
);
237 status
= errSecInternal
;
238 } else if (CFEqual(kSecErrorDomain
, domain
)) {
239 status
= (OSStatus
)CFErrorGetCode(error
);
240 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
241 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
242 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
243 status
= (OSStatus
)CFErrorGetCode(error
);
244 } else if (CFEqual(kSecKernDomain
, domain
)) {
245 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
246 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
247 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
248 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
249 status
= osstatus_for_der_error(CFErrorGetCode(error
));
250 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
251 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
252 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
253 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
254 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
255 status
= errSecInternal
;
257 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
258 status
= errSecInternal
;
265 lastErrorReleaseError(void *value
)
272 getLastErrorKey(pthread_key_t
*kv
)
274 static pthread_key_t key
;
275 static bool haveKey
= false;
276 static dispatch_once_t onceToken
;
277 dispatch_once(&onceToken
, ^{
278 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
286 SetLastError(CFErrorRef newError
)
289 if (!getLastErrorKey(&key
))
291 CFErrorRef oldError
= pthread_getspecific(key
);
296 pthread_setspecific(key
, newError
);
300 SecCopyLastError(OSStatus status
)
305 if (!getLastErrorKey(&key
))
308 error
= pthread_getspecific(key
);
310 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
319 // Wrapper to provide a CFErrorRef for legacy API.
320 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
321 CFErrorRef error
= NULL
;
323 if (perform(&error
)) {
324 assert(error
== NULL
);
326 status
= errSecSuccess
;
330 status
= SecErrorGetOSStatus(error
);
331 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
332 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
333 CFReleaseNull(error
);
339 logUnreasonableDataLength(CFDictionaryRef attributes
)
344 if (isDictionary(attributes
)) {
345 data
= CFDictionaryGetValue(attributes
, kSecValueData
);
347 length
= CFDataGetLength(data
);
348 if (length
> REASONABLE_DATA_SIZE
) {
349 // This log message is vague, as we may not know anything else about the item.
350 // securityd logging (correlate by activity ID) will have more information.
351 secwarning("keychain item data exceeds reasonable size (%lu bytes)", (unsigned long)length
);
357 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
358 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
361 static CFDictionaryRef
362 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
364 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
365 if (filtered
== NULL
)
367 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
368 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
369 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
370 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
371 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
372 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
373 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
374 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
375 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
376 CFDictionaryRemoveValue(filtered
, kSecAttrIsPermanent
);
382 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
383 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
385 Currently in need of conversion below:
386 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
387 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
388 currently implemented at all, but when it is needs to short circuit to
389 local evaluation, different from the sql query abilities
392 static CFDictionaryRef
393 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
394 CFDictionaryRef refDictionary
= NULL
;
395 CFTypeID typeID
= CFGetTypeID(ref
);
396 if (typeID
== SecKeyGetTypeID()) {
397 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
398 if (refDictionary
&& forQuery
) {
399 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
400 CFAssignRetained(refDictionary
, filtered
);
402 } else if (typeID
== SecCertificateGetTypeID()) {
403 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
404 } else if (typeID
== SecIdentityGetTypeID()) {
406 SecIdentityRef identity
= (SecIdentityRef
)ref
;
407 SecCertificateRef cert
= NULL
;
408 SecKeyRef key
= NULL
;
409 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
410 !SecIdentityCopyPrivateKey(identity
, &key
))
412 CFDataRef data
= SecCertificateCopyData(cert
);
413 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
415 if (key_dict
&& data
) {
416 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
417 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
419 CFReleaseNull(key_dict
);
425 return refDictionary
;
428 #ifdef SECITEM_SHIM_OSX
429 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
433 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
434 CFTypeRef ref
= NULL
;
435 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
436 if (CFEqual(class, kSecClassKey
)) {
437 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
438 } else if (CFEqual(class, kSecClassCertificate
)) {
439 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
440 } else if (CFEqual(class, kSecClassIdentity
)) {
441 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
442 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
443 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
445 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
448 secerror("SecItem: failed to create identity");
453 #ifdef SECITEM_SHIM_OSX
455 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
463 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
466 return -1 /* errSecUnimplemented */;
468 #endif // TARGET_OS_OSX
470 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
472 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
473 OSStatus
*return_status
, CFTypeRef
*return_result
)
475 bool handled
= false;
476 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
478 CFTypeID typeID
= CFGetTypeID(value
);
479 if (typeID
== SecIdentityGetTypeID()) {
481 OSStatus status
= errSecSuccess
;
482 SecIdentityRef identity
= (SecIdentityRef
)value
;
483 SecCertificateRef cert
= NULL
;
484 SecKeyRef key
= NULL
;
485 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
486 !SecIdentityCopyPrivateKey(identity
, &key
))
488 CFMutableDictionaryRef partial_query
=
489 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
490 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
491 CFTypeRef result
= NULL
;
492 bool duplicate_cert
= false;
493 /* an identity is first and foremost a key, but it can have multiple
494 certs associated with it: so we identify it by the cert */
495 status
= operation(partial_query
, return_result
? &result
: NULL
);
496 if ((operation
== (secitem_operation
)SecItemAdd
) &&
497 (status
== errSecDuplicateItem
)) {
498 duplicate_cert
= true;
499 status
= errSecSuccess
;
502 if (!status
|| status
== errSecItemNotFound
) {
503 bool skip_key_operation
= false;
505 /* if the key is still in use, skip deleting it */
506 if (operation
== (secitem_operation
)SecItemDelete
) {
507 // find certs with cert.pkhh == keys.klbl
508 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
509 CFDataRef pkhh
= NULL
;
511 key_dict
= SecKeyCopyAttributeDictionary(key
);
513 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
514 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
515 const void *vals
[] = { kSecClassCertificate
, pkhh
};
517 query_dict
= CFDictionaryCreate(NULL
, keys
,
518 vals
, (array_size(keys
)),
521 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
522 skip_key_operation
= true;
523 CFReleaseSafe(query_dict
);
524 CFReleaseSafe(key_dict
);
527 if (!skip_key_operation
) {
528 /* now perform the operation for the key */
529 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
530 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
532 status
= operation(partial_query
, NULL
);
533 if ((operation
== (secitem_operation
)SecItemAdd
) &&
534 (status
== errSecDuplicateItem
) &&
536 status
= errSecSuccess
;
539 /* add and copy matching for an identityref have a persistent ref result */
542 /* result is a persistent ref to a cert */
544 CFDictionaryRef tokenAttrs
= NULL
;
545 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
, &tokenAttrs
)) {
546 *return_result
= _SecItemCreatePersistentRef(kSecClassIdentity
, rowid
, tokenAttrs
);
548 CFReleaseNull(tokenAttrs
);
553 CFReleaseNull(partial_query
);
556 status
= errSecInvalidItemRef
;
560 *return_status
= status
;
563 value
= CFDictionaryGetValue(attributes
, kSecClass
);
564 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
565 (operation
== (secitem_operation
)SecItemDelete
)) {
566 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
567 CFDictionaryRemoveValue(dict
, kSecClass
);
568 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
569 OSStatus status
= SecItemDelete(dict
);
571 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
572 status
= SecItemDelete(dict
);
575 *return_status
= status
;
583 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
586 CFErrorRef lastError
= SecCopyLastError(status
);
588 CFErrorPropagate(lastError
, error
);
590 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
597 handleUpdateIdentity(CFDictionaryRef query
,
598 CFDictionaryRef update
,
602 CFMutableDictionaryRef updatedQuery
= NULL
;
603 SecCertificateRef cert
= NULL
;
604 SecKeyRef key
= NULL
;
605 bool handled
= false;
609 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
611 CFTypeID typeID
= CFGetTypeID(value
);
612 if (typeID
== SecIdentityGetTypeID()) {
613 SecIdentityRef identity
= (SecIdentityRef
)value
;
618 status
= SecIdentityCopyCertificate(identity
, &cert
);
619 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
621 status
= SecIdentityCopyPrivateKey(identity
, &key
);
622 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
624 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
625 require_action_quiet(updatedQuery
, errOut
, *result
= false);
627 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
628 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
630 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
631 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
635 value
= CFDictionaryGetValue(query
, kSecClass
);
636 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
639 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
640 require_action_quiet(updatedQuery
, errOut
, *result
= false);
642 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
643 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
645 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
646 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
648 CFReleaseNull(updatedQuery
);
653 CFReleaseNull(updatedQuery
);
659 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
661 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
662 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
663 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
664 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
665 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
667 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
668 CFReleaseNull(label
);
674 static CFDataRef
CreateTokenPersistentRefData(CFTypeRef
class, CFDictionaryRef attributes
)
676 CFDataRef tokenPersistentRef
= NULL
;
677 CFStringRef tokenId
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
678 CFDictionaryRef itemValue
= NULL
;
679 if (CFEqual(class, kSecClassIdentity
)) {
680 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecAttrIdentityCertificateData
), NULL
);
682 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecValueData
), NULL
);
684 require(itemValue
, out
);
685 CFDataRef oid
= CFDictionaryGetValue(itemValue
, kSecTokenValueObjectIDKey
);
687 CFArrayRef array
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, class, tokenId
, oid
, NULL
);
688 tokenPersistentRef
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, NULL
);
691 CFReleaseNull(itemValue
);
692 return tokenPersistentRef
;
695 static const uint8_t tk_persistent_ref_id
[] = {'t', 'k', 'p', 'r'};
696 /* A persistent ref is just the class and the rowid of the record.
697 Persistent ref for token items is a der blob with class, tokenID and objectId. */
698 CFDataRef
_SecItemCreatePersistentRef(CFTypeRef
class, sqlite_int64 rowid
, CFDictionaryRef attributes
)
700 CFDataRef result
= NULL
;
701 if (attributes
&& CFDictionaryContainsKey(attributes
, CFEqual(class, kSecClassIdentity
) ? kSecAttrIdentityCertificateTokenID
: kSecAttrTokenID
)) {
702 CFDataRef tokenPersistentRef
= CreateTokenPersistentRefData(class, attributes
);
703 require(tokenPersistentRef
, out
);
704 CFMutableDataRef tmpData
= CFDataCreateMutable(kCFAllocatorDefault
, sizeof(tk_persistent_ref_id
) + CFDataGetLength(tokenPersistentRef
));
705 CFDataAppendBytes(tmpData
, tk_persistent_ref_id
, sizeof(tk_persistent_ref_id
));
706 CFDataAppend(tmpData
, tokenPersistentRef
);
707 CFReleaseNull(tokenPersistentRef
);
710 require(rowid
>= 0, out
);
711 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
712 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
713 kCFStringEncodingUTF8
))
715 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
716 result
= CFDataCreate(NULL
, bytes
, sizeof(bytes
));
723 static Boolean
isValidClass(CFStringRef
class, CFStringRef
*return_class
) {
724 const void *valid_classes
[] = { kSecClassGenericPassword
,
725 kSecClassInternetPassword
,
726 kSecClassAppleSharePassword
,
727 kSecClassCertificate
,
731 for (size_t i
= 0; i
< array_size(valid_classes
); i
++) {
732 if (CFEqual(valid_classes
[i
], class)) {
734 *return_class
= valid_classes
[i
];
742 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref
, CFStringRef
*return_class
, CFDictionaryRef
*return_token_attrs
) {
743 bool valid_ref
= false;
744 CFPropertyListRef pl
= NULL
;
745 const uint8_t *der
= CFDataGetBytePtr(persistent_ref
) + sizeof(tk_persistent_ref_id
);
746 const uint8_t *der_end
= der
+ (CFDataGetLength(persistent_ref
) - sizeof(tk_persistent_ref_id
));
747 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &pl
, NULL
, der
, der_end
), out
);
748 require_quiet(der
== der_end
, out
);
749 require_quiet(CFGetTypeID(pl
) == CFArrayGetTypeID(), out
);
750 require_quiet(CFArrayGetCount(pl
) == 3, out
);
751 require_quiet(valid_ref
= isValidClass(CFArrayGetValueAtIndex(pl
, 0), return_class
), out
);
752 if (return_token_attrs
) {
753 *return_token_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
754 kSecAttrTokenID
, CFArrayGetValueAtIndex(pl
, 1),
755 kSecAttrTokenOID
, CFArrayGetValueAtIndex(pl
, 2), NULL
);
762 /* AUDIT[securityd](done):
763 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
765 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
, CFDictionaryRef
*return_token_attrs
)
767 bool valid_ref
= false;
768 require(CFGetTypeID(persistent_ref
) == CFDataGetTypeID(), out
);
770 if (CFDataGetLength(persistent_ref
) > (CFIndex
)sizeof(tk_persistent_ref_id
) &&
771 memcmp(tk_persistent_ref_id
, CFDataGetBytePtr(persistent_ref
), sizeof(tk_persistent_ref_id
)) == 0) {
772 valid_ref
= ParseTokenPersistentRefData(persistent_ref
, return_class
, return_token_attrs
);
773 } else if (CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
774 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
775 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
777 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
778 bytes
, CFStringGetLength(kSecClassGenericPassword
),
779 kCFStringEncodingUTF8
, true);
781 if ((valid_ref
= isValidClass(class, return_class
))) {
783 *return_rowid
= rowid
;
791 static bool cf_bool_value(CFTypeRef cf_bool
) {
792 return cf_bool
&& CFBooleanGetValue(cf_bool
);
795 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
796 if (cow_dictionary
->mutable_dictionary
== NULL
) {
797 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
798 if (cow_dictionary
->dictionary
!= NULL
) {
799 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
800 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
803 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
806 return cow_dictionary
->mutable_dictionary
;
809 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
810 // access_control and optionally of the data value.
811 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
812 CFMutableDictionaryRef value
= NULL
;
813 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
814 kSecTokenValueObjectIDKey
, oid
,
815 kSecTokenValueAccessControlKey
, access_control
,
817 if (object_value
!= NULL
) {
818 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
821 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
826 CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
827 CFPropertyListRef plist
= NULL
;
828 const uint8_t *der
= CFDataGetBytePtr(db_value
);
829 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
830 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
831 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
832 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
833 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
839 TKTokenRef
SecTokenCreate(CFStringRef token_id
, SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
) {
840 CFMutableDictionaryRef token_attrs
= NULL
;
841 TKTokenRef token
= NULL
;
843 static CFMutableDictionaryRef sharedLAContexts
= NULL
;
844 static dispatch_once_t onceToken
;
845 static os_unfair_lock lock
= OS_UNFAIR_LOCK_INIT
;
846 if ((auth_params
->dictionary
== NULL
|| CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
) == NULL
) && !CFStringHasPrefix(token_id
, kSecAttrTokenIDSecureEnclave
)) {
847 dispatch_once(&onceToken
, ^{
848 sharedLAContexts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
851 os_unfair_lock_lock(&lock
);
852 CFTypeRef ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
854 ctx
= LACreateNewContextWithACMContext(NULL
, error
);
856 os_unfair_lock_unlock(&lock
);
857 secerror("Failed to create authentication context %@", *error
);
860 CFDictionarySetValue(sharedLAContexts
, token_id
, ctx
);
862 ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
865 CFDataRef credRef
= NULL
;
867 credRef
= LACopyACMContext(ctx
, NULL
);
871 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, ctx
);
872 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, credRef
);
875 os_unfair_lock_unlock(&lock
);
878 token_attrs
= (auth_params
->dictionary
!= NULL
) ?
879 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
->dictionary
) :
880 CFDictionaryCreateMutableForCFTypes(NULL
);
881 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
883 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
884 token
= TKTokenCreate(token_attrs
, error
);
886 CFReleaseSafe(token_attrs
);
890 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params_dict
,
891 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
893 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
894 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
895 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
896 if (token_id
!= NULL
&& object_id
!= NULL
) {
897 if (CFRetainSafe(token
) == NULL
) {
898 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
901 if (auth_params
.dictionary
!= NULL
) {
902 CFDictionaryForEach(auth_params
.dictionary
, ^(const void *key
, const void *value
) {
903 CFDictionaryAddValue(attrs
, key
, value
);
906 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
907 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
910 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
914 CFReleaseSafe(attrs
);
915 CFReleaseSafe(auth_params
.mutable_dictionary
);
920 /* Turn the returned single value or dictionary that contains all the attributes to create a
921 ref into the exact result the client asked for */
922 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
923 CFDictionaryRef query
, CFDictionaryRef auth_params_dict
,
924 CFTypeRef
*result
, CFErrorRef
*error
) {
926 CFDataRef ac_data
= NULL
;
927 CFDataRef value
= NULL
;
928 CFTypeRef persistent_ref
= NULL
;
929 CFStringRef token_id
= NULL
;
930 CFStringRef cert_token_id
= NULL
;
931 CFDataRef object_id
= NULL
;
932 CFMutableDictionaryRef attrs
= NULL
;
933 CFDataRef cert_data
= NULL
;
934 CFDataRef cert_object_id
= NULL
;
935 TKTokenRef cert_token
= NULL
;
936 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
938 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
939 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
940 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
941 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
943 // Get token value if not provided by the caller.
944 bool token_item
= false;
945 bool cert_token_item
= false;
947 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
948 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
949 token_item
= (token_id
!= NULL
);
951 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
952 cert_token_item
= (cert_token_id
!= NULL
);
956 cert_token_item
= true;
958 CFRetainAssign(cert_token
, token
);
961 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
963 cert_token_item
= false;
966 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
967 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
968 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
969 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
971 value
= CFRetainSafe(raw_result
);
972 if (token_item
&& value
!= NULL
) {
973 // Parse token-based item's data field.
974 CFDataRef object_value
= NULL
;
975 CFDictionaryRef parsed_value
= NULL
;
976 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
977 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
978 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
979 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
980 CFRelease(parsed_value
);
981 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
982 // Retrieve value directly from the token.
984 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
986 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
987 if (CFEqual(object_value
, kCFNull
))
988 CFReleaseNull(object_value
);
990 CFAssignRetained(value
, object_value
);
993 // If only thing requested is data, return them directly.
994 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
995 *result
= CFRetainSafe(value
);
1001 // Extract persistent_ref, if caller wants it.
1002 if (wants_persistent_ref
) {
1003 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
1004 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
1006 persistent_ref
= CFRetainSafe(raw_result
);
1008 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
1009 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
1010 *result
= CFRetainSafe(persistent_ref
);
1016 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
1022 // For other cases we need an output dictionary.
1023 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
1024 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
1026 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
1027 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
1029 if ((wants_data
|| wants_ref
) && value
!= NULL
)
1030 CFDictionarySetValue(output
, kSecValueData
, value
);
1032 CFDictionaryRemoveValue(output
, kSecValueData
);
1034 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
1035 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
1037 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
1039 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
1040 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
1041 // Decode also certdata field of the identity.
1042 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
1044 CFDictionaryRef parsed_value
;
1045 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
1046 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
1047 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
1048 CFRelease(parsed_value
);
1049 if (cert_data
== NULL
) {
1050 // Retrieve value directly from the token.
1051 if (cert_token
== NULL
) {
1052 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, &auth_params
, error
), out
);
1054 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1055 if (CFEqual(cert_data
, kCFNull
))
1056 CFReleaseNull(cert_data
);
1058 if (cert_data
!= NULL
) {
1059 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1061 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1066 if (wants_ref
|| wants_attributes
) {
1067 // Convert serialized form of access control to object form.
1069 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1072 if (ac_data
!= NULL
) {
1073 SecAccessControlRef ac
;
1074 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1075 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1082 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
.dictionary
, token
, object_id
, &ref
, error
), out
);
1083 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1084 CFAssignRetained(*result
, ref
);
1085 } else if (ref
!= NULL
) {
1086 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1089 // We could have stored data value previously to make ref creation succeed.
1090 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1091 CFDictionaryRemoveValue(output
, kSecValueData
);
1099 CFReleaseSafe(cert_object_id
);
1100 CFReleaseSafe(cert_data
);
1101 CFReleaseSafe(ac_data
);
1102 CFReleaseSafe(value
);
1103 CFReleaseSafe(persistent_ref
);
1104 CFReleaseSafe(object_id
);
1105 CFReleaseSafe(attrs
);
1106 CFReleaseSafe(token
);
1107 CFReleaseSafe(cert_token
);
1108 CFReleaseSafe(auth_params
.mutable_dictionary
);
1112 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1113 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1115 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1116 require_action_quiet(result
!= NULL
, out
, ok
= true);
1118 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1119 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1120 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1121 for (i
= 0; i
< count
; i
++) {
1123 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1124 token
, query
, auth_params
, &ref
, error
), out
);
1126 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1131 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1140 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1141 void *la_lib
= NULL
;
1142 CFDataRef acm_context
= NULL
;
1143 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1144 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1145 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1146 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1147 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1148 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1149 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1151 if (la_lib
!= NULL
) {
1157 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1159 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1160 void *la_lib
= NULL
;
1162 // If a ref was specified we get its attribute dictionary and parse it.
1163 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1165 CFDictionaryRef ref_attributes
;
1166 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1167 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1169 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1170 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1171 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1172 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1173 // so add only those attributes from 'ref' which are missing in attrs.
1174 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1176 CFRelease(ref_attributes
);
1179 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1182 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1183 // another roundtrip to token driver.
1184 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1185 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1189 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1190 if (access_control
!= NULL
) {
1191 require_action_quiet(CFGetTypeID(access_control
) == SecAccessControlGetTypeID(), out
,
1192 SecError(errSecParam
, error
, CFSTR("Unexpected type of kSecAttrAccessControl attribute")));
1193 require_action_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
,
1194 SecError(errSecParam
, error
, CFSTR("unsupported kSecAttrAccessControl in query")));
1195 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1198 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1200 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1201 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1202 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1203 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1204 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1207 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1209 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1210 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1212 CFTypeRef values
[] = { policy
};
1213 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1214 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1215 CFReleaseSafe(policiesArray
);
1216 require_action_quiet(policiesArrayXPC
, out
,
1217 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1219 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1220 xpc_release(policiesArrayXPC
);
1221 require_action_quiet(objectReadyForXPC
, out
,
1222 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1224 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1225 CFRelease(objectReadyForXPC
);
1227 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1229 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1230 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1231 DERDecodedInfo content
;
1232 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1233 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1234 if (canonical_issuer
) {
1235 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1236 CFRelease(canonical_issuer
);
1241 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1242 // This use flag is client-only, securityd does not understand it.
1243 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1249 if (la_lib
!= NULL
) {
1252 CFReleaseSafe(ac_data
);
1253 CFReleaseSafe(acm_context
);
1257 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1259 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1261 CFArrayForEachC(ac_pairs
, ac_pair
) {
1262 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1263 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1264 CFStringAppend(log_string
, str
);
1265 CFRelease(acl_hex_string
);
1269 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1270 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1271 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1273 CFRelease(log_string
);
1277 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1278 void (^newCredentialRefAdded
)(void)) {
1280 CFArrayRef ac_pairs
= NULL
;
1281 SecCFDictionaryCOW auth_options
= { NULL
};
1283 for (uint32_t i
= 0;; ++i
) {
1284 // If the operation succeeded or failed with other than auth-needed error, just leave.
1285 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1286 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1287 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1289 // If auth_params were not created up to now, do create them because we will definitely need them.
1290 SecCFDictionaryCOWGetMutable(auth_params
);
1292 // Retrieve or create authentication handle and/or ACM context.
1293 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1294 if (auth_handle
== NULL
) {
1295 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1296 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1297 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1298 CFRelease(auth_handle
);
1299 if (acm_context
== NULL
) {
1300 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1301 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1302 CFRelease(acm_context
);
1303 if (newCredentialRefAdded
) {
1304 newCredentialRefAdded();
1309 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1310 // user retry limit.
1311 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1313 // Prepare auth options dictionary.
1314 if (auth_options
.dictionary
== NULL
) {
1315 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1316 if (operation_prompt
!= NULL
) {
1317 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1318 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1322 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1323 if (caller_name
!= NULL
) {
1324 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1325 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1329 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1330 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1331 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1332 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1337 // Go through all access_control-operation pairs and evaluate them.
1339 CFArrayForEachC(ac_pairs
, ac_pair
) {
1340 CFDataRef updated_acl
= NULL
;
1341 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1342 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1343 auth_options
.dictionary
, &updated_acl
, error
), out
);
1345 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1346 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1347 SecAccessControlRef ac
= NULL
;
1348 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1349 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1350 SecAccessControlSetBound(ac
, true);
1351 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1352 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1353 CFRelease(updated_acl
);
1362 CFReleaseSafe(auth_options
.mutable_dictionary
);
1363 CFReleaseSafe(ac_pairs
);
1367 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1368 // Store operation prompt.
1369 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1370 if (operation_prompt
!= NULL
) {
1371 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1372 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1375 // Store caller name.
1376 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1377 if (caller_name
!= NULL
) {
1378 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1379 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1382 // Find out whether we are allowed to pop up a UI.
1383 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1384 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1385 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1386 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1387 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1388 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1389 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1390 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1393 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1394 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1397 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1398 if (acm_context
!= NULL
) {
1399 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1403 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1405 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1406 // Extract ACLs to be verified from the error.
1407 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1408 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1409 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1410 if (*ac_pairs
== NULL
)
1411 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1414 CFRelease(user_info
);
1415 CFReleaseNull(*error
);
1416 return kSecItemAuthResultNeedAuth
;
1418 return kSecItemAuthResultError
;
1421 // Wrapper to handle automatic authentication and token/secd case switching.
1422 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1423 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1425 __block SecCFDictionaryCOW auth_params
= { NULL
};
1426 __block TKTokenRef token
= NULL
;
1428 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1429 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1430 require_action_quiet(access_control
== NULL
|| CFGetTypeID(access_control
) == SecAccessControlGetTypeID(), out
,
1431 SecError(errSecParam
, error
, CFSTR("Unexpected type of kSecAttrAccessControl attribute")));
1433 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1434 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1435 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1436 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1439 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1440 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1442 secItemOperation
== SecItemCopyMatching
||
1443 secItemOperation
== SecItemUpdate
||
1444 secItemOperation
== SecItemDelete
;
1446 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1447 if (attributes
!= NULL
)
1448 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1450 // Populate auth_params dictionary according to initial query contents.
1451 SecItemAuthCopyParams(&auth_params
, query
);
1453 if (secItemOperation
!= SecItemCopyMatching
) {
1454 // UISkip is allowed only for CopyMatching.
1455 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1456 SecError(errSecParam
, error
,
1457 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1460 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1461 SecItemAuthResult result
= kSecItemAuthResultError
;
1463 // Propagate actual credential reference to the query.
1464 if (auth_params
.dictionary
!= NULL
) {
1465 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1466 if (acm_context
!= NULL
) {
1467 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1470 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1471 if (acl_data_ref
!= NULL
) {
1472 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1476 // Prepare connection to target token if it is present.
1477 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1478 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1479 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, &auth_params
, error
)), out
);
1482 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1483 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1484 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1487 result
= kSecItemAuthResultOK
;
1492 require_quiet(ok
, out
);
1497 CFReleaseSafe(token
);
1498 CFReleaseSafe(auth_params
.mutable_dictionary
);
1502 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1504 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1505 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1506 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1508 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1514 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1516 CFArrayRef result
= NULL
;
1517 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1518 if(success
&& !isArray(result
)){
1519 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1520 CFReleaseNull(result
);
1525 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1526 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1529 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1531 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1532 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1536 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1538 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1540 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1545 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1553 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1555 return dict_to_error_request(op
, query
, error
);
1558 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1559 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1560 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1561 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1562 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1563 keys
, ac_pairs
, 1));
1565 CFRelease(ac_pairs
[0]);
1570 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1571 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1572 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationNeeded
) {
1573 // Replace error with the one which is augmented with access control and operation which failed,
1574 // which will cause SecItemDoWithAuth to throw UI.
1575 // Create array containing tuple (array) with error and requested operation.
1576 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
);
1577 if (access_control
!= NULL
) {
1578 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1579 CFRelease(access_control
);
1585 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1586 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
, result
= NULL
;
1587 SecAccessControlRef ac
= NULL
;
1588 CFDictionaryRef old_attrs
= NULL
;
1590 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1591 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1592 if (ac_data
!= NULL
) {
1593 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1594 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1595 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1598 // Create or update the object on the token.
1599 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1600 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1601 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1602 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1603 if (!CFEqual(key
, kSecValueData
)) {
1604 CFDictionaryAddValue(attributes
, key
, value
);
1608 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1609 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1610 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1611 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1612 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1614 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1615 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1616 CFRetainAssign(result
, new_object_id
);
1620 CFReleaseSafe(access_control
);
1621 CFReleaseSafe(db_value
);
1622 CFReleaseSafe(old_attrs
);
1623 CFReleaseSafe(new_object_id
);
1627 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1628 CFTypeRef
*result
, CFErrorRef
*error
) {
1630 CFTypeRef object_id
= NULL
, ref
= NULL
;
1631 CFDictionaryRef ref_attrs
= NULL
;
1632 CFTypeRef db_result
= NULL
;
1633 CFDataRef db_value
= NULL
;
1634 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1636 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1637 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1638 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1639 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1640 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1641 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1642 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1643 // the ref from the dictionary since it is of no use any more.
1644 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1646 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1647 // by creating ref and getting back its attributes.
1648 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1650 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1651 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1652 if (!CFEqual(key
, kSecValueData
)) {
1653 CFDictionaryAddValue(attrs
, key
, value
);
1660 // Make sure that both attributes and data are returned.
1661 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1662 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1664 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1665 // IsPermanent is not present or is true, so add item to the db.
1666 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1667 SecSecurityClientGet(), &db_result
, error
), out
);
1669 // Process directly result of token call.
1670 db_result
= CFRetain(attrs
);
1672 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1676 CFReleaseSafe(db_result
);
1677 CFReleaseSafe(db_value
);
1678 CFReleaseSafe(attrs
);
1679 CFReleaseSafe(ref_attrs
);
1680 CFReleaseSafe(object_id
);
1685 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1686 __block SecCFDictionaryCOW attrs
= { attributes
};
1689 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1690 os_activity_scope(activity
);
1691 os_release(activity
);
1693 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1694 infer_cert_label(&attrs
);
1696 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1697 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1698 if (token
== NULL
) {
1699 CFTypeRef raw_result
= NULL
;
1700 logUnreasonableDataLength(attributes
);
1701 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1704 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1705 CFReleaseSafe(raw_result
);
1708 // Send request to an appropriate token instead of secd.
1709 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1715 CFReleaseSafe(attrs
.mutable_dictionary
);
1716 secdebug("secitem", "SecItemAdd returned: %d", (int)status
);
1722 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1724 __block SecCFDictionaryCOW query
= { inQuery
};
1726 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1727 os_activity_scope(activity
);
1728 os_release(activity
);
1730 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1732 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1733 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1734 if ((wants_data
&& !wants_attributes
)) {
1735 // When either attributes or data are requested, we need to query both, because for token based items,
1736 // both are needed in order to generate proper data and/or attributes results.
1737 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1740 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1741 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1742 CFTypeRef raw_result
= NULL
;
1743 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1746 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1747 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1748 // to currently processed item.
1749 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1750 CFReleaseSafe(raw_result
);
1756 secdebug("secitem", "SecItemCopyMatching_ios returned: %d", (int)status
);
1757 CFReleaseSafe(query
.mutable_dictionary
);
1761 // Invokes token-object handler for each item matching specified query.
1762 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1763 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1764 CFErrorRef
*error
)) {
1766 CFMutableDictionaryRef list_query
= NULL
;
1767 CFTypeRef items
= NULL
;
1768 CFArrayRef ref_array
= NULL
;
1769 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1771 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1772 // items in the keychain.
1773 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1774 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1775 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1777 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1778 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1779 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1780 SecSecurityClientGet(), &items
, error
), out
);
1781 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1782 // Wrap single returned item into the array.
1783 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1784 CFAssignRetained(items
, item_array
);
1788 CFArrayForEachC(items
, item
) {
1789 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1790 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1792 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1793 require_quiet(item_data
, out
);
1795 CFAssignRetained(item_query
,
1796 CFDictionaryCreateForCFTypes(NULL
,
1797 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1799 require_quiet(perform(item_data
, item_query
, error
), out
);
1805 CFReleaseSafe(list_query
);
1806 CFReleaseSafe(items
);
1807 CFReleaseSafe(item_data
);
1808 CFReleaseSafe(ref_array
);
1809 CFReleaseSafe(item_query
);
1813 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1816 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1817 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1818 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1819 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1822 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1824 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1825 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1826 logUnreasonableDataLength(attributesToUpdate
);
1827 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1829 ok
= securityd_message_no_error(reply
, error
);
1833 xpc_release(message
);
1839 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1840 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1842 CFDataRef object_id
= NULL
;
1843 CFMutableDictionaryRef db_value
= NULL
;
1845 // Update attributes on the token.
1846 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1847 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1848 attributes
, error
), out
);
1850 // Update attributes in the database.
1851 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1856 CFReleaseSafe(object_id
);
1857 CFReleaseSafe(attributes
);
1858 CFReleaseSafe(db_value
);
1863 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1864 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1865 os_activity_scope(activity
);
1866 os_release(activity
);
1868 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1869 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1874 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1875 CFDictionaryRef inAttributesToUpdate
,
1878 __block SecCFDictionaryCOW query
= { inQuery
};
1879 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1880 bool result
= false;
1882 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1885 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1886 if (token
== NULL
) {
1887 return SecItemRawUpdate(query
, attributes
, error
);
1889 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1894 CFReleaseSafe(query
.mutable_dictionary
);
1895 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1896 secdebug("secitem", "SecItemUpdateWithError returned: %d", (int)result
);
1900 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1902 OSStatus status
= errSecSuccess
;
1903 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1905 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1906 && CFEqual(class, kSecClassIdentity
)) {
1907 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1908 const void *vals
[] = { kCFBooleanTrue
, persist
};
1909 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1910 vals
, (array_size(keys
)), NULL
, NULL
);
1911 CFTypeRef item_query
= NULL
;
1912 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1913 CFReleaseNull(persistent_query
);
1916 if (item_query
== NULL
)
1917 return errSecItemNotFound
;
1919 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1920 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1921 CFRelease(item_query
);
1927 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1929 __block SecCFDictionaryCOW query
= { inQuery
};
1931 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1932 os_activity_scope(activity
);
1933 os_release(activity
);
1935 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1936 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1938 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1939 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1940 if (token
== NULL
) {
1941 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1943 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1946 // Delete item from the token.
1947 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1948 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1949 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1951 // Delete the item from the keychain.
1952 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1953 SecSecurityClientGet(), error
), out
);
1964 CFReleaseSafe(query
.mutable_dictionary
);
1965 secdebug("secitem", "SecItemDelete returned: %d", (int)status
);
1971 SecItemDeleteAll(void)
1973 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1976 if (!gSecurityd
->sec_item_delete_all(error
))
1977 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1979 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1987 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1989 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1990 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1995 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1997 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1998 os_activity_scope(activity
);
1999 os_release(activity
);
2001 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
2002 SecSecurityClientGet(), error
);
2009 #if SECITEM_SHIM_OSX
2010 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
2012 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
2017 os_activity_t activity
= os_activity_create("SecItemUpdateTokenItems_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2018 os_activity_scope(activity
);
2019 os_release(activity
);
2021 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
2022 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
2023 if (tokenItemsAttributes
) {
2024 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
2025 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
2026 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
2027 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
2028 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
2029 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
2030 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
2031 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
2033 CFRelease(tokenItems
);
2037 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
2038 CFDictionarySetValue(attributes
, kSecValueData
, data
);
2039 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
2040 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2041 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2042 CFArrayAppendValue(tokenItems
, attributes
);
2043 CFRelease(attributes
);
2047 CFArrayAppendValue(tokenItems
, itemAttributes
);
2050 tmpArrayRef
= tokenItems
;
2053 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2059 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2060 __block CFArrayRef result
;
2061 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2062 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2067 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2069 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2071 do_if_registered(sec_roll_keys
, force
, error
);
2073 __block
bool result
= false;
2075 secdebug("secitem","enter - %s", __FUNCTION__
);
2076 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2077 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2078 xpc_dictionary_set_bool(message
, "force", force
);
2081 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2082 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2088 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2089 __block CFArrayRef results
= NULL
;
2090 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2091 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2092 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2094 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2095 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2100 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2101 __block
bool result
= false;
2102 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2103 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2104 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2105 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2107 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2108 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2114 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2115 CFArrayRef results
= NULL
;
2117 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2118 os_activity_scope(activity
);
2119 os_release(activity
);
2121 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2126 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2127 bool results
= false;
2129 os_activity_t activity
= os_activity_create("SecItemCertificateExists", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2130 os_activity_scope(activity
);
2131 os_release(activity
);
2133 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);