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/SecAccessControl.h>
35 #include <Security/SecAccessControlPriv.h>
36 #ifndef SECITEM_SHIM_OSX
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 #endif // *** END SECITEM_SHIM_OSX ***
45 #include <Security/SecCTKKeyPriv.h>
46 #include <Security/SecTask.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>
77 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
79 #include <Security/SecInternal.h>
80 #include <TargetConditionals.h>
81 #include <ipc/securityd_client.h>
82 #include <Security/SecuritydXPC.h>
83 #include <AssertMacros.h>
85 #include <sys/types.h>
89 #ifndef SECITEM_SHIM_OSX
90 #include <libDER/asn1Types.h>
91 #endif // *** END SECITEM_SHIM_OSX ***
93 /* label when certificate data is joined with key data */
94 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
96 #include <utilities/SecDb.h>
97 #include <IOKit/IOReturn.h>
99 #include <coreauthd_spi.h>
100 #include <LocalAuthentication/LAPrivateDefines.h>
101 #include <LocalAuthentication/LACFSupport.h>
103 #include <ctkclient.h>
105 /* Return an OSStatus for a sqlite3 error code. */
106 static OSStatus
osstatus_for_s3e(int s3e
)
108 if (s3e
> 0 && s3e
<= SQLITE_DONE
) switch (s3e
)
113 return errSecNotAvailable
; /* errSecDuplicateItem; */
114 case SQLITE_FULL
: /* Happens if we run out of uniqueids */
115 return errSecNotAvailable
; /* TODO: Replace with a better error code. */
117 case SQLITE_READONLY
:
118 return errSecNotAvailable
;
119 case SQLITE_CANTOPEN
:
120 return errSecNotAvailable
;
122 return errSecNotAvailable
;
123 case SQLITE_CONSTRAINT
:
124 return errSecDuplicateItem
;
127 case SQLITE_MISMATCH
:
128 return errSecNoSuchAttr
;
130 return errSecNotAvailable
;
132 return -2; /* TODO: Replace with a real error code. */
133 case SQLITE_INTERNAL
:
135 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
140 static OSStatus
osstatus_for_kern_return(CFIndex kernResult
)
145 return errSecSuccess
;
146 case kIOReturnNotReadable
:
147 case kIOReturnNotWritable
:
148 return errSecAuthFailed
;
149 case kIOReturnNotPermitted
:
150 case kIOReturnNotPrivileged
:
151 case kIOReturnLockedRead
:
152 case kIOReturnLockedWrite
:
153 return errSecInteractionNotAllowed
;
156 case kIOReturnBadArgument
:
159 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
163 static OSStatus
osstatus_for_xpc_error(CFIndex xpcError
) {
166 case kSecXPCErrorSuccess
:
167 return errSecSuccess
;
168 case kSecXPCErrorUnexpectedType
:
169 case kSecXPCErrorUnexpectedNull
:
171 case kSecXPCErrorConnectionFailed
:
172 return errSecNotAvailable
;
173 case kSecXPCErrorUnknown
:
175 return errSecInternal
;
179 static OSStatus
osstatus_for_der_error(CFIndex derError
) {
182 case kSecDERErrorUnknownEncoding
:
183 case kSecDERErrorUnsupportedDERType
:
184 case kSecDERErrorUnsupportedNumberType
:
186 case kSecDERErrorUnsupportedCFObject
:
188 case kSecDERErrorAllocationFailure
:
189 return errSecAllocate
;
191 return errSecInternal
;
195 static OSStatus
osstatus_for_ids_error(CFIndex idsError
) {
198 case kSecIDSErrorNoDeviceID
:
199 return errSecDeviceIDNeeded
;
200 case kSecIDSErrorNotRegistered
:
201 return errSecIDSNotRegistered
;
202 case kSecIDSErrorFailedToSend
:
203 return errSecFailedToSendIDSMessage
;
204 case kSecIDSErrorCouldNotFindMatchingAuthToken
:
205 return errSecDeviceIDNoMatch
;
207 return errSecInternal
;
211 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
212 // Wrap LA error in Sec error.
214 case kLAErrorUserCancel
:
215 return errSecUserCanceled
;
216 case kLAErrorParameter
:
218 case kLAErrorNotInteractive
:
219 return errSecInteractionNotAllowed
;
221 return errSecAuthFailed
;
225 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
226 // Hack, get rid of it once dep lands: <rdar://problem/21181736> Export error code constants from ctkclient.h header
227 #ifndef kTKErrorCodeNotImplemented
228 #define kTKErrorCodeNotImplemented -1
230 #ifndef kTKErrorCodeCanceledByUser
231 #define kTKErrorCodeCanceledByUser -4
235 case kTKErrorCodeBadParameter
:
237 case kTKErrorCodeNotImplemented
:
238 return errSecUnimplemented
;
239 case kTKErrorCodeCanceledByUser
:
240 return errSecUserCanceled
;
242 return errSecInternal
;
246 // Convert from securityd error codes to OSStatus for legacy API.
247 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
250 status
= errSecSuccess
;
252 CFStringRef domain
= CFErrorGetDomain(error
);
253 if (domain
== NULL
) {
254 secerror("No error domain for error: %@", error
);
255 status
= errSecInternal
;
256 } else if (CFEqual(kSecErrorDomain
, domain
)) {
257 status
= (OSStatus
)CFErrorGetCode(error
);
258 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
259 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
260 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
261 status
= (OSStatus
)CFErrorGetCode(error
);
262 } else if (CFEqual(kSecKernDomain
, domain
)) {
263 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
264 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
265 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
266 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
267 status
= osstatus_for_der_error(CFErrorGetCode(error
));
268 } else if (CFEqual(kSecIDSErrorDomain
, domain
)) {
269 status
= osstatus_for_ids_error(CFErrorGetCode(error
));
270 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
271 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
272 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
273 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
275 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
276 status
= errSecInternal
;
282 // Wrapper to provide a CFErrorRef for legacy API.
283 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
284 CFErrorRef error
= NULL
;
286 if (perform(&error
)) {
287 assert(error
== NULL
);
288 status
= errSecSuccess
;
291 status
= SecErrorGetOSStatus(error
);
292 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
293 secerror("error:[%" PRIdOSStatus
"] %@", status
, error
);
294 CFReleaseNull(error
);
299 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
300 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
302 Currently in need of conversion below:
303 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
304 @@@ kSecMatchPolicy allows a query with a SecPolicyRef
305 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
306 currently implemented at all, but when it is needs to short circuit to
307 local evaluation, different from the sql query abilities
310 #ifndef SECITEM_SHIM_OSX
311 static CFDictionaryRef
312 SecItemCopyAttributeDictionary(CFTypeRef ref
) {
313 CFDictionaryRef refDictionary
= NULL
;
314 CFTypeID typeID
= CFGetTypeID(ref
);
315 if (typeID
== SecKeyGetTypeID()) {
316 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
317 } else if (typeID
== SecCertificateGetTypeID()) {
319 SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
320 } else if (typeID
== SecIdentityGetTypeID()) {
322 SecIdentityRef identity
= (SecIdentityRef
)ref
;
323 SecCertificateRef cert
= NULL
;
324 SecKeyRef key
= NULL
;
325 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
326 !SecIdentityCopyPrivateKey(identity
, &key
))
328 CFDataRef data
= SecCertificateCopyData(cert
);
329 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
331 if (key_dict
&& data
) {
332 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
333 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
,
334 CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
), data
);
336 CFReleaseNull(key_dict
);
342 refDictionary
= NULL
;
344 return refDictionary
;
348 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
349 CFTypeRef ref
= NULL
;
350 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
351 if (CFEqual(class, kSecClassCertificate
)) {
352 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
353 } else if (CFEqual(class, kSecClassKey
)) {
354 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
355 } else if (CFEqual(class, kSecClassIdentity
)) {
356 CFAllocatorRef allocator
= NULL
;
357 CFDataRef data
= CFDictionaryGetValue(refAttributes
, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
));
358 SecCertificateRef cert
= SecCertificateCreateWithData(allocator
, data
);
359 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
361 ref
= SecIdentityCreate(allocator
, cert
, key
);
365 /* We don't support SecKeychainItemRefs yet. */
366 } else if (CFEqual(class, kSecClassGenericPassword
)) {
367 } else if (CFEqual(class, kSecClassInternetPassword
)) {
368 } else if (CFEqual(class, kSecClassAppleSharePassword
)) {
377 extern CFTypeRef
SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
);
382 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
385 return -1 /* errSecUnimplemented */;
388 #ifndef SECITEM_SHIM_OSX
389 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
391 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
392 OSStatus
*return_status
, CFTypeRef
*return_result
)
394 bool handled
= false;
395 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
397 CFTypeID typeID
= CFGetTypeID(value
);
398 if (typeID
== SecIdentityGetTypeID()) {
400 OSStatus status
= errSecSuccess
;
401 SecIdentityRef identity
= (SecIdentityRef
)value
;
402 SecCertificateRef cert
= NULL
;
403 SecKeyRef key
= NULL
;
404 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
405 !SecIdentityCopyPrivateKey(identity
, &key
))
407 CFMutableDictionaryRef partial_query
=
408 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
409 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
410 CFTypeRef result
= NULL
;
411 bool duplicate_cert
= false;
412 /* an identity is first and foremost a key, but it can have multiple
413 certs associated with it: so we identify it by the cert */
414 status
= operation(partial_query
, return_result
? &result
: NULL
);
415 if ((operation
== (secitem_operation
)SecItemAdd
) &&
416 (status
== errSecDuplicateItem
)) {
417 duplicate_cert
= true;
418 status
= errSecSuccess
;
421 if (!status
|| status
== errSecItemNotFound
) {
422 bool skip_key_operation
= false;
424 /* if the key is still in use, skip deleting it */
425 if (operation
== (secitem_operation
)SecItemDelete
) {
426 // find certs with cert.pkhh == keys.klbl
427 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
428 CFDataRef pkhh
= NULL
;
430 key_dict
= SecKeyCopyAttributeDictionary(key
);
432 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
433 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
434 const void *vals
[] = { kSecClassCertificate
, pkhh
};
436 query_dict
= CFDictionaryCreate(NULL
, keys
,
437 vals
, (array_size(keys
)),
440 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
441 skip_key_operation
= true;
442 CFReleaseSafe(query_dict
);
443 CFReleaseSafe(key_dict
);
446 if (!skip_key_operation
) {
447 /* now perform the operation for the key */
448 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
449 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
450 status
= operation(partial_query
, NULL
);
451 if ((operation
== (secitem_operation
)SecItemAdd
) &&
452 (status
== errSecDuplicateItem
) &&
454 status
= errSecSuccess
;
457 /* add and copy matching for an identityref have a persistent ref result */
460 /* result is a persistent ref to a cert */
462 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
)) {
463 *return_result
= _SecItemMakePersistentRef(kSecClassIdentity
, rowid
);
469 CFReleaseNull(partial_query
);
472 status
= errSecInvalidItemRef
;
476 *return_status
= status
;
479 value
= CFDictionaryGetValue(attributes
, kSecClass
);
480 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
481 (operation
== (secitem_operation
)SecItemDelete
)) {
482 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
483 CFDictionaryRemoveValue(dict
, kSecClass
);
484 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
485 OSStatus status
= SecItemDelete(dict
);
487 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
488 status
= SecItemDelete(dict
);
491 *return_status
= status
;
498 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
500 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
501 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
502 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
503 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
504 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
506 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
507 CFReleaseNull(label
);
513 /* A persistent ref is just the class and the rowid of the record. */
514 CF_RETURNS_RETAINED CFDataRef
_SecItemMakePersistentRef(CFTypeRef
class, sqlite_int64 rowid
)
516 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
519 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
520 kCFStringEncodingUTF8
))
522 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
523 return CFDataCreate(NULL
, bytes
, sizeof(bytes
));
528 /* AUDIT[securityd](done):
529 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
531 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
)
533 bool valid_ref
= false;
534 if (CFGetTypeID(persistent_ref
) == CFDataGetTypeID() &&
535 CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
536 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
537 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
539 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
540 bytes
, CFStringGetLength(kSecClassGenericPassword
),
541 kCFStringEncodingUTF8
, true);
542 const void *valid_classes
[] = { kSecClassGenericPassword
,
543 kSecClassInternetPassword
,
544 kSecClassAppleSharePassword
,
545 kSecClassCertificate
,
550 for (i
=0; i
< array_size(valid_classes
); i
++) {
551 if (CFEqual(valid_classes
[i
], class)) {
553 *return_class
= valid_classes
[i
];
555 *return_rowid
= rowid
;
565 #endif // *** END SECITEM_SHIM_OSX ***
567 static bool cf_bool_value(CFTypeRef cf_bool
)
569 return (cf_bool
&& CFEqual(kCFBooleanTrue
, cf_bool
));
572 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
573 if (cow_dictionary
->mutable_dictionary
== NULL
) {
574 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
575 if (cow_dictionary
->dictionary
!= NULL
) {
576 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
577 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
580 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
583 return cow_dictionary
->mutable_dictionary
;
586 // Keys for dictionary of kSecvalueData of token-based items.
587 static const CFStringRef kSecTokenValueObjectIDKey
= CFSTR("oid");
588 static const CFStringRef kSecTokenValueAccessControlKey
= CFSTR("ac");
589 static const CFStringRef kSecTokenValueDataKey
= CFSTR("data");
591 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
592 // access_control and optionally of the data value.
593 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
594 CFMutableDictionaryRef value
= NULL
;
595 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
596 kSecTokenValueObjectIDKey
, oid
,
597 kSecTokenValueAccessControlKey
, access_control
,
599 if (object_value
!= NULL
) {
600 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
603 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
608 static CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
609 CFPropertyListRef plist
= NULL
;
610 const uint8_t *der
= CFDataGetBytePtr(db_value
);
611 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
612 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
613 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
614 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
615 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
621 TKTokenRef
SecTokenCreate(CFStringRef token_id
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
622 CFMutableDictionaryRef token_attrs
= NULL
;
623 TKTokenRef token
= NULL
;
624 token_attrs
= (auth_params
!= NULL
) ?
625 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
) :
626 CFDictionaryCreateMutableForCFTypes(NULL
);
627 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
629 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
630 token
= TKTokenCreate(token_attrs
, error
);
632 CFReleaseSafe(token_attrs
);
636 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
637 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
639 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
640 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
641 if (token_id
!= NULL
) {
642 if (CFRetainSafe(token
) == NULL
) {
643 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
646 if (auth_params
!= NULL
) {
647 CFDictionaryForEach(auth_params
, ^(const void *key
, const void *value
) {
648 CFDictionarySetValue(attrs
, key
, value
);
651 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
652 CFDictionarySetValue(attrs
, kSecUseTokenObjectID
, object_id
);
655 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
659 CFReleaseSafe(attrs
);
664 /* Turn the returned single value or dictionary that contains all the attributes to create a
665 ref into the exact result the client asked for */
666 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
667 CFDictionaryRef query
, CFDictionaryRef auth_params
,
668 CFTypeRef
*result
, CFErrorRef
*error
) {
670 CFDataRef ac_data
= NULL
;
671 CFDataRef value
= NULL
;
672 CFTypeRef persistent_ref
= NULL
;
673 CFStringRef token_id
= NULL
;
674 CFDataRef object_id
= NULL
;
675 CFMutableDictionaryRef attrs
= NULL
;
677 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
678 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
679 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
680 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
682 // Get token value if not provided by the caller.
683 bool token_item
= false;
685 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
686 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
687 token_item
= (token_id
!= NULL
);
694 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
695 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
696 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
697 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
699 value
= CFRetainSafe(raw_result
);
700 if (token_item
&& value
!= NULL
) {
701 // Parse token-based item's data field.
702 CFDataRef object_value
= NULL
;
703 CFDictionaryRef parsed_value
= NULL
;
704 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
705 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
706 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
707 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
708 CFRelease(parsed_value
);
709 if (wants_data
&& object_value
== NULL
) {
710 // Retrieve value directly from the token.
712 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
714 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
715 if (CFEqual(object_value
, kCFNull
))
716 CFReleaseNull(object_value
);
718 CFAssignRetained(value
, object_value
);
721 // If only thing requested is data, return them directly.
722 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
723 *result
= CFRetainSafe(value
);
729 // Extract persistent_ref, if caller wants it.
730 if (wants_persistent_ref
) {
731 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
732 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
734 persistent_ref
= CFRetainSafe(raw_result
);
736 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
737 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
738 *result
= CFRetainSafe(persistent_ref
);
744 if (wants_ref
|| wants_attributes
|| (wants_data
&& wants_persistent_ref
)) {
745 // For these cases we need output dictionary.
746 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
747 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
749 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
750 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
752 if ((wants_data
|| wants_ref
) && value
!= NULL
)
753 CFDictionarySetValue(output
, kSecValueData
, value
);
755 CFDictionaryRemoveValue(output
, kSecValueData
);
757 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
758 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
760 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
764 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
, token
, object_id
, &ref
, error
), out
);
765 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
766 CFAssignRetained(*result
, ref
);
767 } else if (ref
!= NULL
) {
768 CFDictionarySetValue(output
, kSecValueRef
, ref
);
771 // We could have stored data value previously to make ref creation succeed.
772 // They are not needed any more and in case that caller did not want the data, avoid returning them.
773 CFDictionaryRemoveValue(output
, kSecValueData
);
778 if (wants_attributes
) {
779 // Convert serialized form of access control to object form.
781 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
784 if (ac_data
!= NULL
) {
785 SecAccessControlRef ac
;
786 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
787 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
798 CFReleaseSafe(ac_data
);
799 CFReleaseSafe(value
);
800 CFReleaseSafe(persistent_ref
);
801 CFReleaseSafe(object_id
);
802 CFReleaseSafe(attrs
);
803 CFReleaseSafe(token
);
807 static bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
808 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
810 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
811 require_action_quiet(result
!= NULL
, out
, ok
= true);
813 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
814 CFIndex i
, count
= CFArrayGetCount(raw_result
);
815 *result
= CFArrayCreateMutableForCFTypes(NULL
);
816 for (i
= 0; i
< count
; i
++) {
818 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
819 token
, query
, auth_params
, &ref
, error
), out
);
821 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
826 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
835 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, CFErrorRef
*error
) {
837 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
840 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
841 if (access_control
!= NULL
) {
842 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
843 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
846 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
848 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
849 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
850 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
851 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
852 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
853 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
854 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
855 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
856 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
857 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
858 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
861 #ifndef SECITEM_SHIM_OSX
862 // If a ref was specified we get it's attribute dictionary and parse it.
863 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
865 CFDictionaryRef ref_attributes
;
866 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
), out
,
867 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
869 /* Replace any attributes we already got from the ref with the ones
870 from the attributes dictionary the caller passed us. This allows
871 a caller to add an item using attributes from the ref and still
872 override some of them in the dictionary directly. */
873 CFMutableDictionaryRef new_query
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, ref_attributes
);
874 CFRelease(ref_attributes
);
875 CFDictionaryForEach(attrs
->dictionary
, ^(const void *key
, const void *value
) {
876 if (!CFEqual(key
, kSecValueRef
))
877 CFDictionarySetValue(new_query
, key
, value
);
879 CFAssignRetained(attrs
->mutable_dictionary
, new_query
);
880 attrs
->dictionary
= attrs
->mutable_dictionary
;
882 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
884 /* convert DN to canonical issuer, if value is DN (top level sequence) */
885 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
886 DERDecodedInfo content
;
887 if (!DERDecodeItem(&name
, &content
) &&
888 (content
.tag
== ASN1_CONSTR_SEQUENCE
))
890 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
891 if (canonical_issuer
) {
892 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
893 CFRelease(canonical_issuer
);
902 if (la_lib
!= NULL
) {
905 CFReleaseSafe(ac_data
);
906 CFReleaseSafe(acm_context
);
910 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
912 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
914 CFArrayForEachC(ac_pairs
, ac_pair
) {
915 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
916 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
917 CFStringAppend(log_string
, str
);
918 CFRelease(acl_hex_string
);
922 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
923 SecError(errSecAuthFailed
, error
, reason
);
924 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
927 CFRelease(log_string
);
931 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
)) {
933 CFArrayRef ac_pairs
= NULL
;
934 SecCFDictionaryCOW auth_options
= { NULL
};
936 for (uint32_t i
= 0;; ++i
) {
937 // If the operation succeeded or failed with other than auth-needed error, just leave.
938 SecItemAuthResult auth_result
= perform(auth_params
->dictionary
, &ac_pairs
, error
);
939 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
940 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
942 // If auth_params were not created up to now, do create them because we will definitely need them.
943 SecCFDictionaryCOWGetMutable(auth_params
);
945 // Retrieve or create authentication handle and/or ACM context.
946 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
947 if (auth_handle
== NULL
) {
948 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
949 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
950 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
951 CFRelease(auth_handle
);
952 if (acm_context
== NULL
) {
953 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
954 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
955 CFRelease(acm_context
);
959 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
961 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
963 // Prepare auth options dictionary.
964 if (auth_options
.dictionary
== NULL
) {
965 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
966 if (operation_prompt
!= NULL
) {
967 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
968 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
972 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
973 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
974 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
975 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
980 // Go through all access_control-operation pairs and evaluate them.
982 CFArrayForEachC(ac_pairs
, ac_pair
) {
983 CFDataRef updated_acl
= NULL
;
984 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
985 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
986 auth_options
.dictionary
, &updated_acl
, error
), out
);
988 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
989 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
990 SecAccessControlRef ac
= NULL
;
991 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
992 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
993 SecAccessControlSetBound(ac
, true);
994 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
995 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
996 CFRelease(updated_acl
);
1005 CFReleaseSafe(auth_options
.mutable_dictionary
);
1006 CFReleaseSafe(ac_pairs
);
1010 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1011 // Store operation prompt.
1012 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1013 if (operation_prompt
!= NULL
) {
1014 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1015 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1018 // Find out whether we are allowed to pop up a UI.
1019 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1020 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1021 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1022 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1023 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1024 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1025 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1026 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1029 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1030 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1033 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1034 if (acm_context
!= NULL
) {
1035 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1039 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1041 if (error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1042 // Extract ACLs to be verified from the error.
1043 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1044 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1045 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1046 if (*ac_pairs
== NULL
)
1047 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1050 CFRelease(user_info
);
1051 CFReleaseNull(*error
);
1052 return kSecItemAuthResultNeedAuth
;
1054 return kSecItemAuthResultError
;
1057 // Wrapper to handle automatic authentication and token/secd case switching.
1058 static bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1059 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1061 SecCFDictionaryCOW auth_params
= { NULL
};
1062 SecAccessControlRef access_control
= NULL
;
1063 __block TKTokenRef token
= NULL
;
1065 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1066 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1067 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1068 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1069 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1070 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1073 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1074 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1075 require_quiet(SecItemAttributesPrepare(query
, error
), out
);
1076 if (attributes
!= NULL
)
1077 require_quiet(SecItemAttributesPrepare(attributes
, error
), out
);
1079 // Populate auth_params dictionary according to initial query contents.
1080 SecItemAuthCopyParams(&auth_params
, query
);
1082 if (secItemOperation
!= SecItemCopyMatching
) {
1083 // UISkip is allowed only for CopyMatching.
1084 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1085 SecError(errSecParam
, error
,
1086 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1089 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1090 SecItemAuthResult result
= kSecItemAuthResultError
;
1092 // Propagate actual credential reference to the query.
1093 if (auth_params
!= NULL
) {
1094 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
, kSecUseCredentialReference
);
1095 if (acm_context
!= NULL
) {
1096 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1099 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
, kSecAttrAccessControl
);
1100 if (acl_data_ref
!= NULL
) {
1101 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1105 // Prepare connection to target token if it is present.
1106 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1107 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1108 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, auth_params
, error
)), out
);
1111 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1112 if(!perform(token
, query
->dictionary
, attrs
, auth_params
, error
)) {
1113 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1116 result
= kSecItemAuthResultOK
;
1121 require_quiet(ok
, out
);
1126 CFReleaseSafe(token
);
1127 CFReleaseSafe(auth_params
.mutable_dictionary
);
1131 #if SECITEM_SHIM_OSX
1132 /* TODO: Should be in some header */
1133 OSStatus
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef
*result
);
1134 OSStatus
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef
*result
);
1135 OSStatus
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
);
1136 OSStatus
SecItemDelete_ios(CFDictionaryRef query
);
1139 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1141 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1142 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1143 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1145 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1151 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1153 CFArrayRef result
= NULL
;
1154 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1155 if(success
&& !isArray(result
)){
1156 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1157 CFReleaseNull(result
);
1162 bool cftype_ag_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused CFArrayRef accessGroups
, CFTypeRef
*result
, CFErrorRef
*error
) {
1163 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1166 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1168 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1169 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1173 static bool dict_ag_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused CFArrayRef accessGroups
, CFErrorRef
*error
)
1175 return dict_to_error_request(op
, query
, error
);
1178 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1179 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1180 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1181 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1182 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1183 keys
, ac_pairs
, 1));
1185 CFRelease(ac_pairs
[0]);
1190 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1191 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1192 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1193 // Replace error with the one which is augmented with access control and operation which failed,
1194 // which will cause SecItemDoWithAuth to throw UI.
1195 // Create array containing tuple (array) with error and requested operation.
1196 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1197 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1198 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1199 if (access_control
!= NULL
) {
1200 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1201 CFRelease(access_control
);
1207 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1208 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1209 SecAccessControlRef ac
= NULL
;
1211 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1212 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1213 if (ac_data
!= NULL
) {
1214 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1215 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1216 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1219 // Create or update the object on the token.
1220 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1221 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1223 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1224 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1225 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1226 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1227 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1229 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1230 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1234 CFReleaseSafe(access_control
);
1235 CFReleaseSafe(db_value
);
1236 return new_object_id
;
1239 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1240 CFTypeRef
*result
, CFErrorRef
*error
) {
1242 CFTypeRef object_id
= NULL
, ref
= NULL
;
1243 CFDictionaryRef ref_attrs
= NULL
;
1244 CFTypeRef db_result
= NULL
;
1246 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1247 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, NULL
, attrs
, error
), out
);
1249 #ifndef SECITEM_SHIM_OSX
1250 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1251 // by creating ref and getting back its attributes.
1252 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1254 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
)) != NULL
) {
1255 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1256 if (!CFEqual(key
, kSecValueData
)) {
1257 CFDictionaryAddValue(attrs
, key
, value
);
1264 // Make sure that both attributes and data are returned.
1265 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1266 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1268 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1269 // IsPermanent is not present or is true, so add item to the db.
1270 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_ag_to_bool_cftype_error_request
, attrs
,
1271 SecAccessGroupsGetCurrent(), &db_result
, error
), out
);
1273 // Process directly result of token call.
1274 db_result
= CFRetain(attrs
);
1276 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1281 CFReleaseSafe(db_result
);
1282 CFReleaseSafe(attrs
);
1283 CFReleaseSafe(ref_attrs
);
1284 CFReleaseSafe(object_id
);
1290 #if SECITEM_SHIM_OSX
1291 SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef
*result
)
1293 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
)
1294 #endif // *** END SECITEM_SHIM_OSX ***
1296 __block SecCFDictionaryCOW attrs
= { attributes
};
1299 os_activity_t trace_activity
= os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1301 #ifndef SECITEM_SHIM_OSX
1302 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1303 infer_cert_label(&attrs
);
1304 #endif // *** END SECITEM_SHIM_OSX ***
1306 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1307 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1308 if (token
== NULL
) {
1309 CFTypeRef raw_result
= NULL
;
1310 if (!SECURITYD_XPC(sec_item_add
, cftype_ag_to_bool_cftype_error_request
, attributes
, SecAccessGroupsGetCurrent(), &raw_result
, error
))
1313 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1314 CFReleaseSafe(raw_result
);
1317 // Send request to an appropriate token instead of secd.
1318 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1323 #ifndef SECITEM_SHIM_OSX
1326 CFReleaseSafe(attrs
.mutable_dictionary
);
1328 os_activity_end(trace_activity
);
1334 #if SECITEM_SHIM_OSX
1335 SecItemCopyMatching_ios(CFDictionaryRef inQuery
, CFTypeRef
*result
)
1337 SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
)
1338 #endif // *** END SECITEM_SHIM_OSX ***
1341 __block SecCFDictionaryCOW query
= { inQuery
};
1343 os_activity_t trace_activity
= os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1345 #ifndef SECITEM_SHIM_OSX
1346 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1347 #endif // *** END SECITEM_SHIM_OSX ***
1349 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1350 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1351 if ((wants_data
&& !wants_attributes
) || (!wants_data
&& wants_attributes
)) {
1352 // When either attributes or data are requested, we need to query both, because for token based items,
1353 // both are needed in order to generate proper data and/or attributes results.
1354 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1355 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnData
, kCFBooleanTrue
);
1358 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1359 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1360 CFTypeRef raw_result
= NULL
;
1361 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_ag_to_bool_cftype_error_request
, query
, SecAccessGroupsGetCurrent(), &raw_result
, error
))
1364 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1365 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1366 // to currently processed item.
1367 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1368 CFReleaseSafe(raw_result
);
1373 #ifndef SECITEM_SHIM_OSX
1377 CFReleaseSafe(query
.mutable_dictionary
);
1378 os_activity_end(trace_activity
);
1382 // Invokes token-object handler for each item matching specified query.
1383 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1384 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1385 CFErrorRef
*error
)) {
1387 CFMutableDictionaryRef list_query
= NULL
;
1388 CFTypeRef items
= NULL
;
1389 CFArrayRef ref_array
= NULL
;
1390 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1392 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1393 // items in the keychain.
1394 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1395 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1396 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1398 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1399 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1400 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_ag_to_bool_cftype_error_request
, list_query
,
1401 SecAccessGroupsGetCurrent(), &items
, error
), out
);
1402 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1403 // Wrap single returned item into the array.
1404 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1405 CFAssignRetained(items
, item_array
);
1409 CFArrayForEachC(items
, item
) {
1410 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1411 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1413 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1414 require_quiet(item_data
, out
);
1416 CFAssignRetained(item_query
,
1417 CFDictionaryCreateForCFTypes(NULL
,
1418 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1420 require_quiet(perform(item_data
, item_query
, error
), out
);
1426 CFReleaseSafe(list_query
);
1427 CFReleaseSafe(items
);
1428 CFReleaseSafe(item_data
);
1429 CFReleaseSafe(ref_array
);
1430 CFReleaseSafe(item_query
);
1434 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1437 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1438 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1439 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1440 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecAccessGroupsGetCurrent(), error
);
1443 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1445 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1446 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1447 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1449 ok
= securityd_message_no_error(reply
, error
);
1453 xpc_release(message
);
1459 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1460 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1462 CFDataRef object_id
= NULL
;
1463 CFMutableDictionaryRef db_value
= NULL
;
1465 // Update attributes on the token.
1466 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1467 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1468 attributes
, error
), out
);
1470 // Update attributes in the database.
1471 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1476 CFReleaseSafe(object_id
);
1477 CFReleaseSafe(attributes
);
1478 CFReleaseSafe(db_value
);
1484 #if SECITEM_SHIM_OSX
1485 SecItemUpdate_ios(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
)
1487 SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
)
1488 #endif // *** END SECITEM_SHIM_OSX ***
1491 __block SecCFDictionaryCOW query
= { inQuery
};
1492 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1494 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1495 return SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1496 if (token
== NULL
) {
1497 return SecItemRawUpdate(query
, attributes
, error
);
1499 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1504 CFReleaseSafe(query
.mutable_dictionary
);
1505 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1509 #ifndef SECITEM_SHIM_OSX
1510 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1512 OSStatus status
= errSecSuccess
;
1513 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1515 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
)
1516 && CFEqual(class, kSecClassIdentity
)) {
1517 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1518 const void *vals
[] = { kCFBooleanTrue
, persist
};
1519 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1520 vals
, (array_size(keys
)), NULL
, NULL
);
1521 CFTypeRef item_query
= NULL
;
1522 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1523 CFReleaseNull(persistent_query
);
1527 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1528 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1529 CFRelease(item_query
);
1537 #if SECITEM_SHIM_OSX
1538 SecItemDelete_ios(CFDictionaryRef inQuery
)
1540 SecItemDelete(CFDictionaryRef inQuery
)
1541 #endif // *** END SECITEM_SHIM_OSX ***
1544 __block SecCFDictionaryCOW query
= { inQuery
};
1546 os_activity_t trace_activity
= os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1548 #ifndef SECITEM_SHIM_OSX
1549 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1550 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1551 #endif // *** END SECITEM_SHIM_OSX ***
1553 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1554 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1555 if (token
== NULL
) {
1556 return SECURITYD_XPC(sec_item_delete
, dict_ag_to_error_request
, query
, SecAccessGroupsGetCurrent(), error
);
1558 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1561 // Delete item from the token.
1562 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1563 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1564 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1566 // Delete the item from the keychain.
1567 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_ag_to_error_request
, item_query
,
1568 SecAccessGroupsGetCurrent(), error
), out
);
1578 #ifndef SECITEM_SHIM_OSX
1582 CFReleaseSafe(query
.mutable_dictionary
);
1584 os_activity_end(trace_activity
);
1590 SecItemDeleteAll(void)
1592 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1596 #ifndef SECITEM_SHIM_OSX
1597 SecTrustStoreRef ts
= SecTrustStoreForDomain(kSecTrustStoreDomainUser
);
1598 if (!gSecurityd
->sec_truststore_remove_all(ts
, error
))
1599 ok
= SecError(errSecInternal
, error
, CFSTR("sec_truststore_remove_all is NULL"));
1600 #endif // *** END SECITEM_SHIM_OSX ***
1601 if (!gSecurityd
->sec_item_delete_all(error
))
1602 ok
= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1604 ok
= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1611 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
1612 __block CFArrayRef result
;
1613 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1614 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
1619 #ifndef SECITEM_SHIM_OSX
1620 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1622 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
)
1624 return -1; /* this is only on OS X currently */
1629 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1633 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1635 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
1637 do_if_registered(sec_roll_keys
, force
, error
);
1639 __block
bool result
= false;
1641 secdebug("secitem","enter - %s", __FUNCTION__
);
1642 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
1643 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1644 xpc_dictionary_set_bool(message
, "force", force
);
1647 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
1648 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);