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
;
206 case kSecIDSErrorNoPeersAvailable
:
207 return errSecPeersNotAvailable
;
209 return errSecInternal
;
213 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
214 // Wrap LA error in Sec error.
216 case kLAErrorUserCancel
:
217 return errSecUserCanceled
;
218 case kLAErrorParameter
:
220 case kLAErrorNotInteractive
:
221 return errSecInteractionNotAllowed
;
223 return errSecAuthFailed
;
227 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
228 // Hack, get rid of it once dep lands: <rdar://problem/21181736> Export error code constants from ctkclient.h header
229 #ifndef kTKErrorCodeNotImplemented
230 #define kTKErrorCodeNotImplemented -1
232 #ifndef kTKErrorCodeCanceledByUser
233 #define kTKErrorCodeCanceledByUser -4
237 case kTKErrorCodeBadParameter
:
239 case kTKErrorCodeNotImplemented
:
240 return errSecUnimplemented
;
241 case kTKErrorCodeCanceledByUser
:
242 return errSecUserCanceled
;
244 return errSecInternal
;
248 // Convert from securityd error codes to OSStatus for legacy API.
249 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
252 status
= errSecSuccess
;
254 CFStringRef domain
= CFErrorGetDomain(error
);
255 if (domain
== NULL
) {
256 secerror("No error domain for error: %@", error
);
257 status
= errSecInternal
;
258 } else if (CFEqual(kSecErrorDomain
, domain
)) {
259 status
= (OSStatus
)CFErrorGetCode(error
);
260 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
261 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
262 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
263 status
= (OSStatus
)CFErrorGetCode(error
);
264 } else if (CFEqual(kSecKernDomain
, domain
)) {
265 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
266 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
267 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
268 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
269 status
= osstatus_for_der_error(CFErrorGetCode(error
));
270 } else if (CFEqual(kSecIDSErrorDomain
, domain
)) {
271 status
= osstatus_for_ids_error(CFErrorGetCode(error
));
272 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
273 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
274 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
275 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
277 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
278 status
= errSecInternal
;
284 // Wrapper to provide a CFErrorRef for legacy API.
285 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
286 CFErrorRef error
= NULL
;
288 if (perform(&error
)) {
289 assert(error
== NULL
);
290 status
= errSecSuccess
;
293 status
= SecErrorGetOSStatus(error
);
294 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
295 secerror("error:[%" PRIdOSStatus
"] %@", status
, error
);
296 CFReleaseNull(error
);
301 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
302 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
304 Currently in need of conversion below:
305 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
306 @@@ kSecMatchPolicy allows a query with a SecPolicyRef
307 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
308 currently implemented at all, but when it is needs to short circuit to
309 local evaluation, different from the sql query abilities
312 #ifndef SECITEM_SHIM_OSX
313 static CFDictionaryRef
314 SecItemCopyAttributeDictionary(CFTypeRef ref
) {
315 CFDictionaryRef refDictionary
= NULL
;
316 CFTypeID typeID
= CFGetTypeID(ref
);
317 if (typeID
== SecKeyGetTypeID()) {
318 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
319 } else if (typeID
== SecCertificateGetTypeID()) {
321 SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
322 } else if (typeID
== SecIdentityGetTypeID()) {
324 SecIdentityRef identity
= (SecIdentityRef
)ref
;
325 SecCertificateRef cert
= NULL
;
326 SecKeyRef key
= NULL
;
327 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
328 !SecIdentityCopyPrivateKey(identity
, &key
))
330 CFDataRef data
= SecCertificateCopyData(cert
);
331 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
333 if (key_dict
&& data
) {
334 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
335 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
,
336 CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
), data
);
338 CFReleaseNull(key_dict
);
344 refDictionary
= NULL
;
346 return refDictionary
;
350 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
351 CFTypeRef ref
= NULL
;
352 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
353 if (CFEqual(class, kSecClassCertificate
)) {
354 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
355 } else if (CFEqual(class, kSecClassKey
)) {
356 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
357 } else if (CFEqual(class, kSecClassIdentity
)) {
358 CFAllocatorRef allocator
= NULL
;
359 CFDataRef data
= CFDictionaryGetValue(refAttributes
, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL
));
360 SecCertificateRef cert
= SecCertificateCreateWithData(allocator
, data
);
361 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
363 ref
= SecIdentityCreate(allocator
, cert
, key
);
367 /* We don't support SecKeychainItemRefs yet. */
368 } else if (CFEqual(class, kSecClassGenericPassword
)) {
369 } else if (CFEqual(class, kSecClassInternetPassword
)) {
370 } else if (CFEqual(class, kSecClassAppleSharePassword
)) {
379 extern CFTypeRef
SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
);
384 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
387 return -1 /* errSecUnimplemented */;
390 #ifndef SECITEM_SHIM_OSX
391 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
393 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
394 OSStatus
*return_status
, CFTypeRef
*return_result
)
396 bool handled
= false;
397 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
399 CFTypeID typeID
= CFGetTypeID(value
);
400 if (typeID
== SecIdentityGetTypeID()) {
402 OSStatus status
= errSecSuccess
;
403 SecIdentityRef identity
= (SecIdentityRef
)value
;
404 SecCertificateRef cert
= NULL
;
405 SecKeyRef key
= NULL
;
406 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
407 !SecIdentityCopyPrivateKey(identity
, &key
))
409 CFMutableDictionaryRef partial_query
=
410 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
411 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
412 CFTypeRef result
= NULL
;
413 bool duplicate_cert
= false;
414 /* an identity is first and foremost a key, but it can have multiple
415 certs associated with it: so we identify it by the cert */
416 status
= operation(partial_query
, return_result
? &result
: NULL
);
417 if ((operation
== (secitem_operation
)SecItemAdd
) &&
418 (status
== errSecDuplicateItem
)) {
419 duplicate_cert
= true;
420 status
= errSecSuccess
;
423 if (!status
|| status
== errSecItemNotFound
) {
424 bool skip_key_operation
= false;
426 /* if the key is still in use, skip deleting it */
427 if (operation
== (secitem_operation
)SecItemDelete
) {
428 // find certs with cert.pkhh == keys.klbl
429 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
430 CFDataRef pkhh
= NULL
;
432 key_dict
= SecKeyCopyAttributeDictionary(key
);
434 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
435 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
436 const void *vals
[] = { kSecClassCertificate
, pkhh
};
438 query_dict
= CFDictionaryCreate(NULL
, keys
,
439 vals
, (array_size(keys
)),
442 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
443 skip_key_operation
= true;
444 CFReleaseSafe(query_dict
);
445 CFReleaseSafe(key_dict
);
448 if (!skip_key_operation
) {
449 /* now perform the operation for the key */
450 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
451 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
452 status
= operation(partial_query
, NULL
);
453 if ((operation
== (secitem_operation
)SecItemAdd
) &&
454 (status
== errSecDuplicateItem
) &&
456 status
= errSecSuccess
;
459 /* add and copy matching for an identityref have a persistent ref result */
462 /* result is a persistent ref to a cert */
464 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
)) {
465 *return_result
= _SecItemMakePersistentRef(kSecClassIdentity
, rowid
);
471 CFReleaseNull(partial_query
);
474 status
= errSecInvalidItemRef
;
478 *return_status
= status
;
481 value
= CFDictionaryGetValue(attributes
, kSecClass
);
482 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
483 (operation
== (secitem_operation
)SecItemDelete
)) {
484 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
485 CFDictionaryRemoveValue(dict
, kSecClass
);
486 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
487 OSStatus status
= SecItemDelete(dict
);
489 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
490 status
= SecItemDelete(dict
);
493 *return_status
= status
;
500 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
502 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
503 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
504 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
505 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
506 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
508 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
509 CFReleaseNull(label
);
515 /* A persistent ref is just the class and the rowid of the record. */
516 CF_RETURNS_RETAINED CFDataRef
_SecItemMakePersistentRef(CFTypeRef
class, sqlite_int64 rowid
)
518 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
521 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
522 kCFStringEncodingUTF8
))
524 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
525 return CFDataCreate(NULL
, bytes
, sizeof(bytes
));
530 /* AUDIT[securityd](done):
531 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
533 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
)
535 bool valid_ref
= false;
536 if (CFGetTypeID(persistent_ref
) == CFDataGetTypeID() &&
537 CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
538 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
539 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
541 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
542 bytes
, CFStringGetLength(kSecClassGenericPassword
),
543 kCFStringEncodingUTF8
, true);
544 const void *valid_classes
[] = { kSecClassGenericPassword
,
545 kSecClassInternetPassword
,
546 kSecClassAppleSharePassword
,
547 kSecClassCertificate
,
552 for (i
=0; i
< array_size(valid_classes
); i
++) {
553 if (CFEqual(valid_classes
[i
], class)) {
555 *return_class
= valid_classes
[i
];
557 *return_rowid
= rowid
;
567 #endif // *** END SECITEM_SHIM_OSX ***
569 static bool cf_bool_value(CFTypeRef cf_bool
)
571 return (cf_bool
&& CFEqual(kCFBooleanTrue
, cf_bool
));
574 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
575 if (cow_dictionary
->mutable_dictionary
== NULL
) {
576 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
577 if (cow_dictionary
->dictionary
!= NULL
) {
578 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
579 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
582 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
585 return cow_dictionary
->mutable_dictionary
;
588 // Keys for dictionary of kSecvalueData of token-based items.
589 static const CFStringRef kSecTokenValueObjectIDKey
= CFSTR("oid");
590 static const CFStringRef kSecTokenValueAccessControlKey
= CFSTR("ac");
591 static const CFStringRef kSecTokenValueDataKey
= CFSTR("data");
593 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
594 // access_control and optionally of the data value.
595 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
596 CFMutableDictionaryRef value
= NULL
;
597 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
598 kSecTokenValueObjectIDKey
, oid
,
599 kSecTokenValueAccessControlKey
, access_control
,
601 if (object_value
!= NULL
) {
602 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
605 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
610 static CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
611 CFPropertyListRef plist
= NULL
;
612 const uint8_t *der
= CFDataGetBytePtr(db_value
);
613 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
614 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
615 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
616 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
617 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
623 TKTokenRef
SecTokenCreate(CFStringRef token_id
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
624 CFMutableDictionaryRef token_attrs
= NULL
;
625 TKTokenRef token
= NULL
;
626 token_attrs
= (auth_params
!= NULL
) ?
627 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
) :
628 CFDictionaryCreateMutableForCFTypes(NULL
);
629 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
631 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
632 token
= TKTokenCreate(token_attrs
, error
);
634 CFReleaseSafe(token_attrs
);
638 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
639 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
641 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
642 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
643 if (token_id
!= NULL
) {
644 if (CFRetainSafe(token
) == NULL
) {
645 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
648 if (auth_params
!= NULL
) {
649 CFDictionaryForEach(auth_params
, ^(const void *key
, const void *value
) {
650 CFDictionarySetValue(attrs
, key
, value
);
653 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
654 CFDictionarySetValue(attrs
, kSecUseTokenObjectID
, object_id
);
657 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
661 CFReleaseSafe(attrs
);
666 /* Turn the returned single value or dictionary that contains all the attributes to create a
667 ref into the exact result the client asked for */
668 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
669 CFDictionaryRef query
, CFDictionaryRef auth_params
,
670 CFTypeRef
*result
, CFErrorRef
*error
) {
672 CFDataRef ac_data
= NULL
;
673 CFDataRef value
= NULL
;
674 CFTypeRef persistent_ref
= NULL
;
675 CFStringRef token_id
= NULL
;
676 CFDataRef object_id
= NULL
;
677 CFMutableDictionaryRef attrs
= NULL
;
679 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
680 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
681 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
682 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
684 // Get token value if not provided by the caller.
685 bool token_item
= false;
687 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
688 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
689 token_item
= (token_id
!= NULL
);
696 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
697 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
698 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
699 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
701 value
= CFRetainSafe(raw_result
);
702 if (token_item
&& value
!= NULL
) {
703 // Parse token-based item's data field.
704 CFDataRef object_value
= NULL
;
705 CFDictionaryRef parsed_value
= NULL
;
706 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
707 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
708 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
709 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
710 CFRelease(parsed_value
);
711 if (wants_data
&& object_value
== NULL
) {
712 // Retrieve value directly from the token.
714 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
716 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
717 if (CFEqual(object_value
, kCFNull
))
718 CFReleaseNull(object_value
);
720 CFAssignRetained(value
, object_value
);
723 // If only thing requested is data, return them directly.
724 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
725 *result
= CFRetainSafe(value
);
731 // Extract persistent_ref, if caller wants it.
732 if (wants_persistent_ref
) {
733 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
734 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
736 persistent_ref
= CFRetainSafe(raw_result
);
738 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
739 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
740 *result
= CFRetainSafe(persistent_ref
);
746 if (wants_ref
|| wants_attributes
|| (wants_data
&& wants_persistent_ref
)) {
747 // For these cases we need output dictionary.
748 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
749 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
751 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
752 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
754 if ((wants_data
|| wants_ref
) && value
!= NULL
)
755 CFDictionarySetValue(output
, kSecValueData
, value
);
757 CFDictionaryRemoveValue(output
, kSecValueData
);
759 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
760 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
762 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
766 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
, token
, object_id
, &ref
, error
), out
);
767 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
768 CFAssignRetained(*result
, ref
);
769 } else if (ref
!= NULL
) {
770 CFDictionarySetValue(output
, kSecValueRef
, ref
);
773 // We could have stored data value previously to make ref creation succeed.
774 // They are not needed any more and in case that caller did not want the data, avoid returning them.
775 CFDictionaryRemoveValue(output
, kSecValueData
);
780 if (wants_attributes
) {
781 // Convert serialized form of access control to object form.
783 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
786 if (ac_data
!= NULL
) {
787 SecAccessControlRef ac
;
788 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
789 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
800 CFReleaseSafe(ac_data
);
801 CFReleaseSafe(value
);
802 CFReleaseSafe(persistent_ref
);
803 CFReleaseSafe(object_id
);
804 CFReleaseSafe(attrs
);
805 CFReleaseSafe(token
);
809 static bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
810 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
812 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
813 require_action_quiet(result
!= NULL
, out
, ok
= true);
815 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
816 CFIndex i
, count
= CFArrayGetCount(raw_result
);
817 *result
= CFArrayCreateMutableForCFTypes(NULL
);
818 for (i
= 0; i
< count
; i
++) {
820 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
821 token
, query
, auth_params
, &ref
, error
), out
);
823 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
828 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
837 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, CFErrorRef
*error
) {
839 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
842 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
843 if (access_control
!= NULL
) {
844 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
845 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
848 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
850 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
851 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
852 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
853 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
854 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
855 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
856 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
857 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
858 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
859 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
860 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
863 #ifndef SECITEM_SHIM_OSX
864 // If a ref was specified we get it's attribute dictionary and parse it.
865 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
867 CFDictionaryRef ref_attributes
;
868 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
), out
,
869 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
871 /* Replace any attributes we already got from the ref with the ones
872 from the attributes dictionary the caller passed us. This allows
873 a caller to add an item using attributes from the ref and still
874 override some of them in the dictionary directly. */
875 CFMutableDictionaryRef new_query
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, ref_attributes
);
876 CFRelease(ref_attributes
);
877 CFDictionaryForEach(attrs
->dictionary
, ^(const void *key
, const void *value
) {
878 if (!CFEqual(key
, kSecValueRef
))
879 CFDictionarySetValue(new_query
, key
, value
);
881 CFAssignRetained(attrs
->mutable_dictionary
, new_query
);
882 attrs
->dictionary
= attrs
->mutable_dictionary
;
884 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
886 /* convert DN to canonical issuer, if value is DN (top level sequence) */
887 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
888 DERDecodedInfo content
;
889 if (!DERDecodeItem(&name
, &content
) &&
890 (content
.tag
== ASN1_CONSTR_SEQUENCE
))
892 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
893 if (canonical_issuer
) {
894 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
895 CFRelease(canonical_issuer
);
904 if (la_lib
!= NULL
) {
907 CFReleaseSafe(ac_data
);
908 CFReleaseSafe(acm_context
);
912 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
914 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
916 CFArrayForEachC(ac_pairs
, ac_pair
) {
917 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
918 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
919 CFStringAppend(log_string
, str
);
920 CFRelease(acl_hex_string
);
924 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
925 SecError(errSecAuthFailed
, error
, reason
);
926 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
929 CFRelease(log_string
);
933 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
)) {
935 CFArrayRef ac_pairs
= NULL
;
936 SecCFDictionaryCOW auth_options
= { NULL
};
938 for (uint32_t i
= 0;; ++i
) {
939 // If the operation succeeded or failed with other than auth-needed error, just leave.
940 SecItemAuthResult auth_result
= perform(auth_params
->dictionary
, &ac_pairs
, error
);
941 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
942 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
944 // If auth_params were not created up to now, do create them because we will definitely need them.
945 SecCFDictionaryCOWGetMutable(auth_params
);
947 // Retrieve or create authentication handle and/or ACM context.
948 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
949 if (auth_handle
== NULL
) {
950 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
951 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
952 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
953 CFRelease(auth_handle
);
954 if (acm_context
== NULL
) {
955 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
956 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
957 CFRelease(acm_context
);
961 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
963 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
965 // Prepare auth options dictionary.
966 if (auth_options
.dictionary
== NULL
) {
967 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
968 if (operation_prompt
!= NULL
) {
969 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
970 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
974 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
975 if (caller_name
!= NULL
) {
976 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
977 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
981 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
982 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
983 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
984 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
989 // Go through all access_control-operation pairs and evaluate them.
991 CFArrayForEachC(ac_pairs
, ac_pair
) {
992 CFDataRef updated_acl
= NULL
;
993 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
994 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
995 auth_options
.dictionary
, &updated_acl
, error
), out
);
997 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
998 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
999 SecAccessControlRef ac
= NULL
;
1000 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1001 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1002 SecAccessControlSetBound(ac
, true);
1003 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1004 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1005 CFRelease(updated_acl
);
1014 CFReleaseSafe(auth_options
.mutable_dictionary
);
1015 CFReleaseSafe(ac_pairs
);
1019 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1020 // Store operation prompt.
1021 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1022 if (operation_prompt
!= NULL
) {
1023 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1024 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1027 // Store caller name.
1028 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1029 if (caller_name
!= NULL
) {
1030 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1031 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1034 // Find out whether we are allowed to pop up a UI.
1035 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1036 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1037 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1038 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1039 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1040 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1041 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1042 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1045 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1046 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1049 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1050 if (acm_context
!= NULL
) {
1051 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1055 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1057 if (error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1058 // Extract ACLs to be verified from the error.
1059 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1060 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1061 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1062 if (*ac_pairs
== NULL
)
1063 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1066 CFRelease(user_info
);
1067 CFReleaseNull(*error
);
1068 return kSecItemAuthResultNeedAuth
;
1070 return kSecItemAuthResultError
;
1073 // Wrapper to handle automatic authentication and token/secd case switching.
1074 static bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1075 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1077 SecCFDictionaryCOW auth_params
= { NULL
};
1078 SecAccessControlRef access_control
= NULL
;
1079 __block TKTokenRef token
= NULL
;
1081 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1082 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1083 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1084 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1085 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1086 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1089 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1090 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1091 require_quiet(SecItemAttributesPrepare(query
, error
), out
);
1092 if (attributes
!= NULL
)
1093 require_quiet(SecItemAttributesPrepare(attributes
, error
), out
);
1095 // Populate auth_params dictionary according to initial query contents.
1096 SecItemAuthCopyParams(&auth_params
, query
);
1098 if (secItemOperation
!= SecItemCopyMatching
) {
1099 // UISkip is allowed only for CopyMatching.
1100 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1101 SecError(errSecParam
, error
,
1102 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1105 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1106 SecItemAuthResult result
= kSecItemAuthResultError
;
1108 // Propagate actual credential reference to the query.
1109 if (auth_params
!= NULL
) {
1110 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
, kSecUseCredentialReference
);
1111 if (acm_context
!= NULL
) {
1112 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1115 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
, kSecAttrAccessControl
);
1116 if (acl_data_ref
!= NULL
) {
1117 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1121 // Prepare connection to target token if it is present.
1122 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1123 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1124 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, auth_params
, error
)), out
);
1127 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1128 if(!perform(token
, query
->dictionary
, attrs
, auth_params
, error
)) {
1129 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1132 result
= kSecItemAuthResultOK
;
1137 require_quiet(ok
, out
);
1142 CFReleaseSafe(token
);
1143 CFReleaseSafe(auth_params
.mutable_dictionary
);
1147 #if SECITEM_SHIM_OSX
1148 /* TODO: Should be in some header */
1149 OSStatus
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef
*result
);
1150 OSStatus
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef
*result
);
1151 OSStatus
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
);
1152 OSStatus
SecItemDelete_ios(CFDictionaryRef query
);
1155 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1157 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1158 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1159 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1161 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1167 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1169 CFArrayRef result
= NULL
;
1170 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1171 if(success
&& !isArray(result
)){
1172 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1173 CFReleaseNull(result
);
1178 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1179 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1182 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1184 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1185 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1189 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1191 return dict_to_error_request(op
, query
, error
);
1194 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1195 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1196 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1197 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1198 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1199 keys
, ac_pairs
, 1));
1201 CFRelease(ac_pairs
[0]);
1206 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1207 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1208 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1209 // Replace error with the one which is augmented with access control and operation which failed,
1210 // which will cause SecItemDoWithAuth to throw UI.
1211 // Create array containing tuple (array) with error and requested operation.
1212 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1213 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1214 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1215 if (access_control
!= NULL
) {
1216 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1217 CFRelease(access_control
);
1223 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1224 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1225 SecAccessControlRef ac
= NULL
;
1227 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1228 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1229 if (ac_data
!= NULL
) {
1230 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1231 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1232 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1235 // Create or update the object on the token.
1236 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1237 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1239 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1240 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1241 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1242 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1243 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1245 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1246 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1250 CFReleaseSafe(access_control
);
1251 CFReleaseSafe(db_value
);
1252 return new_object_id
;
1255 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1256 CFTypeRef
*result
, CFErrorRef
*error
) {
1258 CFTypeRef object_id
= NULL
, ref
= NULL
;
1259 CFDictionaryRef ref_attrs
= NULL
;
1260 CFTypeRef db_result
= NULL
;
1262 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1263 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, NULL
, attrs
, error
), out
);
1265 #ifndef SECITEM_SHIM_OSX
1266 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1267 // by creating ref and getting back its attributes.
1268 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1270 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
)) != NULL
) {
1271 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1272 if (!CFEqual(key
, kSecValueData
)) {
1273 CFDictionaryAddValue(attrs
, key
, value
);
1280 // Make sure that both attributes and data are returned.
1281 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1282 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1284 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1285 // IsPermanent is not present or is true, so add item to the db.
1286 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1287 SecSecurityClientGet(), &db_result
, error
), out
);
1289 // Process directly result of token call.
1290 db_result
= CFRetain(attrs
);
1292 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1297 CFReleaseSafe(db_result
);
1298 CFReleaseSafe(attrs
);
1299 CFReleaseSafe(ref_attrs
);
1300 CFReleaseSafe(object_id
);
1306 #if SECITEM_SHIM_OSX
1307 SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef
*result
)
1309 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
)
1310 #endif // *** END SECITEM_SHIM_OSX ***
1312 __block SecCFDictionaryCOW attrs
= { attributes
};
1315 os_activity_t trace_activity
= os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1317 #ifndef SECITEM_SHIM_OSX
1318 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1319 infer_cert_label(&attrs
);
1320 #endif // *** END SECITEM_SHIM_OSX ***
1322 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1323 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1324 if (token
== NULL
) {
1325 CFTypeRef raw_result
= NULL
;
1326 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1329 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1330 CFReleaseSafe(raw_result
);
1333 // Send request to an appropriate token instead of secd.
1334 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1339 #ifndef SECITEM_SHIM_OSX
1342 CFReleaseSafe(attrs
.mutable_dictionary
);
1344 os_activity_end(trace_activity
);
1350 #if SECITEM_SHIM_OSX
1351 SecItemCopyMatching_ios(CFDictionaryRef inQuery
, CFTypeRef
*result
)
1353 SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
)
1354 #endif // *** END SECITEM_SHIM_OSX ***
1357 __block SecCFDictionaryCOW query
= { inQuery
};
1359 os_activity_t trace_activity
= os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1361 #ifndef SECITEM_SHIM_OSX
1362 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1363 #endif // *** END SECITEM_SHIM_OSX ***
1365 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1366 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1367 if ((wants_data
&& !wants_attributes
) || (!wants_data
&& wants_attributes
)) {
1368 // When either attributes or data are requested, we need to query both, because for token based items,
1369 // both are needed in order to generate proper data and/or attributes results.
1370 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1371 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnData
, kCFBooleanTrue
);
1374 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1375 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1376 CFTypeRef raw_result
= NULL
;
1377 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1380 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1381 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1382 // to currently processed item.
1383 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1384 CFReleaseSafe(raw_result
);
1389 #ifndef SECITEM_SHIM_OSX
1393 CFReleaseSafe(query
.mutable_dictionary
);
1394 os_activity_end(trace_activity
);
1398 // Invokes token-object handler for each item matching specified query.
1399 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1400 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1401 CFErrorRef
*error
)) {
1403 CFMutableDictionaryRef list_query
= NULL
;
1404 CFTypeRef items
= NULL
;
1405 CFArrayRef ref_array
= NULL
;
1406 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1408 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1409 // items in the keychain.
1410 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1411 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1412 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1414 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1415 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1416 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1417 SecSecurityClientGet(), &items
, error
), out
);
1418 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1419 // Wrap single returned item into the array.
1420 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1421 CFAssignRetained(items
, item_array
);
1425 CFArrayForEachC(items
, item
) {
1426 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1427 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1429 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1430 require_quiet(item_data
, out
);
1432 CFAssignRetained(item_query
,
1433 CFDictionaryCreateForCFTypes(NULL
,
1434 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1436 require_quiet(perform(item_data
, item_query
, error
), out
);
1442 CFReleaseSafe(list_query
);
1443 CFReleaseSafe(items
);
1444 CFReleaseSafe(item_data
);
1445 CFReleaseSafe(ref_array
);
1446 CFReleaseSafe(item_query
);
1450 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1453 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1454 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1455 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1456 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1459 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1461 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1462 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1463 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1465 ok
= securityd_message_no_error(reply
, error
);
1469 xpc_release(message
);
1475 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1476 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1478 CFDataRef object_id
= NULL
;
1479 CFMutableDictionaryRef db_value
= NULL
;
1481 // Update attributes on the token.
1482 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1483 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1484 attributes
, error
), out
);
1486 // Update attributes in the database.
1487 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1492 CFReleaseSafe(object_id
);
1493 CFReleaseSafe(attributes
);
1494 CFReleaseSafe(db_value
);
1500 #if SECITEM_SHIM_OSX
1501 SecItemUpdate_ios(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
)
1503 SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
)
1504 #endif // *** END SECITEM_SHIM_OSX ***
1507 __block SecCFDictionaryCOW query
= { inQuery
};
1508 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1510 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1511 return SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1512 if (token
== NULL
) {
1513 return SecItemRawUpdate(query
, attributes
, error
);
1515 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1520 CFReleaseSafe(query
.mutable_dictionary
);
1521 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1525 #ifndef SECITEM_SHIM_OSX
1526 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1528 OSStatus status
= errSecSuccess
;
1529 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1531 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
)
1532 && CFEqual(class, kSecClassIdentity
)) {
1533 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1534 const void *vals
[] = { kCFBooleanTrue
, persist
};
1535 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1536 vals
, (array_size(keys
)), NULL
, NULL
);
1537 CFTypeRef item_query
= NULL
;
1538 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1539 CFReleaseNull(persistent_query
);
1543 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1544 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1545 CFRelease(item_query
);
1553 #if SECITEM_SHIM_OSX
1554 SecItemDelete_ios(CFDictionaryRef inQuery
)
1556 SecItemDelete(CFDictionaryRef inQuery
)
1557 #endif // *** END SECITEM_SHIM_OSX ***
1560 __block SecCFDictionaryCOW query
= { inQuery
};
1562 os_activity_t trace_activity
= os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1564 #ifndef SECITEM_SHIM_OSX
1565 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1566 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1567 #endif // *** END SECITEM_SHIM_OSX ***
1569 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1570 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1571 if (token
== NULL
) {
1572 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1574 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1577 // Delete item from the token.
1578 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1579 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1580 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1582 // Delete the item from the keychain.
1583 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1584 SecSecurityClientGet(), error
), out
);
1594 #ifndef SECITEM_SHIM_OSX
1598 CFReleaseSafe(query
.mutable_dictionary
);
1600 os_activity_end(trace_activity
);
1606 SecItemDeleteAll(void)
1608 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1612 #ifndef SECITEM_SHIM_OSX
1613 SecTrustStoreRef ts
= SecTrustStoreForDomain(kSecTrustStoreDomainUser
);
1614 if (!gSecurityd
->sec_truststore_remove_all(ts
, error
))
1615 ok
= SecError(errSecInternal
, error
, CFSTR("sec_truststore_remove_all is NULL"));
1616 #endif // *** END SECITEM_SHIM_OSX ***
1617 if (!gSecurityd
->sec_item_delete_all(error
))
1618 ok
= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1620 ok
= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1627 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
1628 __block CFArrayRef result
;
1629 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1630 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
1635 #ifndef SECITEM_SHIM_OSX
1636 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1638 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
)
1640 return -1; /* this is only on OS X currently */
1645 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1649 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1651 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
1653 do_if_registered(sec_roll_keys
, force
, error
);
1655 __block
bool result
= false;
1657 secdebug("secitem","enter - %s", __FUNCTION__
);
1658 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
1659 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1660 xpc_dictionary_set_bool(message
, "force", force
);
1663 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
1664 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);