2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
30 #include <Security/SecBasePriv.h>
31 #include <Security/SecItem.h>
32 #include <Security/SecItemPriv.h>
33 #include <Security/SecItemInternal.h>
34 #include <Security/SecItemShim.h>
35 #include <Security/SecAccessControl.h>
36 #include <Security/SecAccessControlPriv.h>
37 #include <Security/SecKey.h>
38 #include <Security/SecKeyPriv.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecIdentity.h>
41 #include <Security/SecIdentityPriv.h>
42 #include <Security/SecRandom.h>
43 #include <Security/SecBasePriv.h>
44 #include <Security/SecCTKKeyPriv.h>
45 #include <Security/SecTask.h>
46 #include <Security/SecPolicyInternal.h>
53 #include <sys/param.h>
55 #include <Security/SecBase.h>
56 #include <CoreFoundation/CFData.h>
57 #include <CoreFoundation/CFDate.h>
58 #include <CoreFoundation/CFDictionary.h>
59 #include <CoreFoundation/CFNumber.h>
60 #include <CoreFoundation/CFString.h>
61 #include <CoreFoundation/CFURL.h>
62 #include <CommonCrypto/CommonDigest.h>
63 #include <libkern/OSByteOrder.h>
64 #include <corecrypto/ccder.h>
65 #include <utilities/array_size.h>
66 #include <utilities/debugging.h>
67 #include <utilities/SecCFError.h>
68 #include <utilities/SecCFWrappers.h>
69 #include <utilities/SecIOFormat.h>
70 #include <utilities/SecXPCError.h>
71 #include <utilities/der_plist.h>
72 #include <utilities/der_plist_internal.h>
75 #include <libaks_acl_cf_keys.h>
76 #include <os/activity.h>
77 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
80 #include <Security/SecInternal.h>
81 #include "SOSInternal.h"
82 #include <TargetConditionals.h>
83 #include <ipc/securityd_client.h>
84 #include <Security/SecuritydXPC.h>
85 #include <AssertMacros.h>
87 #include <sys/types.h>
91 #ifndef SECITEM_SHIM_OSX
92 #include <libDER/asn1Types.h>
93 #endif // *** END SECITEM_SHIM_OSX ***
95 #include <utilities/SecDb.h>
96 #include <IOKit/IOReturn.h>
98 #include <coreauthd_spi.h>
99 #include <LocalAuthentication/LAPrivateDefines.h>
100 #include <LocalAuthentication/LACFSupport.h>
102 #include <ctkclient.h>
104 /* Return an OSStatus for a sqlite3 error code. */
105 static OSStatus
osstatus_for_s3e(int s3e
)
107 if (s3e
> 0 && s3e
<= SQLITE_DONE
) switch (s3e
)
112 return errSecNotAvailable
; /* errSecDuplicateItem; */
113 case SQLITE_FULL
: /* Happens if we run out of uniqueids */
114 return errSecNotAvailable
; /* TODO: Replace with a better error code. */
116 case SQLITE_READONLY
:
117 return errSecNotAvailable
;
118 case SQLITE_CANTOPEN
:
119 return errSecNotAvailable
;
121 return errSecNotAvailable
;
122 case SQLITE_CONSTRAINT
:
123 return errSecDuplicateItem
;
126 case SQLITE_MISMATCH
:
127 return errSecNoSuchAttr
;
129 return errSecNotAvailable
;
131 return -2; /* TODO: Replace with a real error code. */
132 case SQLITE_INTERNAL
:
134 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
139 static OSStatus
osstatus_for_kern_return(CFIndex kernResult
)
144 return errSecSuccess
;
145 case kIOReturnNotReadable
:
146 case kIOReturnNotWritable
:
147 return errSecAuthFailed
;
148 case kIOReturnNotPermitted
:
149 case kIOReturnNotPrivileged
:
150 case kIOReturnLockedRead
:
151 case kIOReturnLockedWrite
:
152 return errSecInteractionNotAllowed
;
155 case kIOReturnBadArgument
:
158 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
162 static OSStatus
osstatus_for_xpc_error(CFIndex xpcError
) {
165 case kSecXPCErrorSuccess
:
166 return errSecSuccess
;
167 case kSecXPCErrorUnexpectedType
:
168 case kSecXPCErrorUnexpectedNull
:
170 case kSecXPCErrorConnectionFailed
:
171 return errSecNotAvailable
;
172 case kSecXPCErrorUnknown
:
174 return errSecInternal
;
178 static OSStatus
osstatus_for_der_error(CFIndex derError
) {
181 case kSecDERErrorUnknownEncoding
:
182 case kSecDERErrorUnsupportedDERType
:
183 case kSecDERErrorUnsupportedNumberType
:
185 case kSecDERErrorUnsupportedCFObject
:
187 case kSecDERErrorAllocationFailure
:
188 return errSecAllocate
;
190 return errSecInternal
;
194 static OSStatus
osstatus_for_ids_error(CFIndex idsError
) {
197 case kSecIDSErrorNoDeviceID
:
198 return errSecDeviceIDNeeded
;
199 case kSecIDSErrorNotRegistered
:
200 return errSecIDSNotRegistered
;
201 case kSecIDSErrorFailedToSend
:
202 return errSecFailedToSendIDSMessage
;
203 case kSecIDSErrorCouldNotFindMatchingAuthToken
:
204 return errSecDeviceIDNoMatch
;
205 case kSecIDSErrorNoPeersAvailable
:
206 return errSecPeersNotAvailable
;
208 return errSecInternal
;
212 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
213 // Wrap LA error in Sec error.
215 case kLAErrorUserCancel
:
216 return errSecUserCanceled
;
217 case kLAErrorParameter
:
219 case kLAErrorNotInteractive
:
220 return errSecInteractionNotAllowed
;
222 return errSecAuthFailed
;
226 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
228 case kTKErrorCodeBadParameter
:
230 case kTKErrorCodeNotImplemented
:
231 return errSecUnimplemented
;
232 case kTKErrorCodeCanceledByUser
:
233 return errSecUserCanceled
;
234 case kTKErrorCodeCorruptedData
:
237 return errSecInternal
;
242 // Convert from securityd error codes to OSStatus for legacy API.
243 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
246 status
= errSecSuccess
;
248 CFStringRef domain
= CFErrorGetDomain(error
);
249 if (domain
== NULL
) {
250 secerror("No error domain for error: %@", error
);
251 status
= errSecInternal
;
252 } else if (CFEqual(kSecErrorDomain
, domain
)) {
253 status
= (OSStatus
)CFErrorGetCode(error
);
254 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
255 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
256 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
257 status
= (OSStatus
)CFErrorGetCode(error
);
258 } else if (CFEqual(kSecKernDomain
, domain
)) {
259 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
260 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
261 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
262 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
263 status
= osstatus_for_der_error(CFErrorGetCode(error
));
264 } else if (CFEqual(kSecIDSErrorDomain
, domain
)) {
265 status
= osstatus_for_ids_error(CFErrorGetCode(error
));
266 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
267 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
268 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
269 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
270 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
271 status
= errSecInternal
;
273 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
274 status
= errSecInternal
;
281 lastErrorReleaseError(void *value
)
288 getLastErrorKey(pthread_key_t
*kv
)
290 static pthread_key_t key
;
291 static bool haveKey
= false;
292 static dispatch_once_t onceToken
;
293 dispatch_once(&onceToken
, ^{
294 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
302 SetLastError(CFErrorRef newError
)
305 if (!getLastErrorKey(&key
))
307 CFErrorRef oldError
= pthread_getspecific(key
);
312 pthread_setspecific(key
, newError
);
316 SecCopyLastError(OSStatus status
)
321 if (!getLastErrorKey(&key
))
324 error
= pthread_getspecific(key
);
326 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
335 // Wrapper to provide a CFErrorRef for legacy API.
336 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
337 CFErrorRef error
= NULL
;
339 if (perform(&error
)) {
340 assert(error
== NULL
);
342 status
= errSecSuccess
;
346 status
= SecErrorGetOSStatus(error
);
347 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
348 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
349 CFReleaseNull(error
);
354 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
355 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
358 static CFDictionaryRef
359 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
361 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
362 if (filtered
== NULL
)
364 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
365 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
366 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
367 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
368 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
369 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
370 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
371 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
372 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
378 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
379 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
381 Currently in need of conversion below:
382 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
383 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
384 currently implemented at all, but when it is needs to short circuit to
385 local evaluation, different from the sql query abilities
388 static CFDictionaryRef
389 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
390 CFDictionaryRef refDictionary
= NULL
;
391 CFTypeID typeID
= CFGetTypeID(ref
);
392 if (typeID
== SecKeyGetTypeID()) {
393 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
394 if (refDictionary
&& forQuery
) {
395 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
396 CFAssignRetained(refDictionary
, filtered
);
398 } else if (typeID
== SecCertificateGetTypeID()) {
399 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
400 } else if (typeID
== SecIdentityGetTypeID()) {
402 SecIdentityRef identity
= (SecIdentityRef
)ref
;
403 SecCertificateRef cert
= NULL
;
404 SecKeyRef key
= NULL
;
405 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
406 !SecIdentityCopyPrivateKey(identity
, &key
))
408 CFDataRef data
= SecCertificateCopyData(cert
);
409 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
411 if (key_dict
&& data
) {
412 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
413 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
415 CFReleaseNull(key_dict
);
421 return refDictionary
;
424 #ifdef SECITEM_SHIM_OSX
425 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
429 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
430 CFTypeRef ref
= NULL
;
431 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
432 if (CFEqual(class, kSecClassKey
)) {
433 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
434 } else if (CFEqual(class, kSecClassCertificate
)) {
435 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
436 } else if (CFEqual(class, kSecClassIdentity
)) {
437 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
438 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
439 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
441 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
444 #ifdef SECITEM_SHIM_OSX
446 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
453 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
456 return -1 /* errSecUnimplemented */;
459 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
461 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
462 OSStatus
*return_status
, CFTypeRef
*return_result
)
464 bool handled
= false;
465 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
467 CFTypeID typeID
= CFGetTypeID(value
);
468 if (typeID
== SecIdentityGetTypeID()) {
470 OSStatus status
= errSecSuccess
;
471 SecIdentityRef identity
= (SecIdentityRef
)value
;
472 SecCertificateRef cert
= NULL
;
473 SecKeyRef key
= NULL
;
474 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
475 !SecIdentityCopyPrivateKey(identity
, &key
))
477 CFMutableDictionaryRef partial_query
=
478 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
479 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
480 CFTypeRef result
= NULL
;
481 bool duplicate_cert
= false;
482 /* an identity is first and foremost a key, but it can have multiple
483 certs associated with it: so we identify it by the cert */
484 status
= operation(partial_query
, return_result
? &result
: NULL
);
485 if ((operation
== (secitem_operation
)SecItemAdd
) &&
486 (status
== errSecDuplicateItem
)) {
487 duplicate_cert
= true;
488 status
= errSecSuccess
;
491 if (!status
|| status
== errSecItemNotFound
) {
492 bool skip_key_operation
= false;
494 /* if the key is still in use, skip deleting it */
495 if (operation
== (secitem_operation
)SecItemDelete
) {
496 // find certs with cert.pkhh == keys.klbl
497 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
498 CFDataRef pkhh
= NULL
;
500 key_dict
= SecKeyCopyAttributeDictionary(key
);
502 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
503 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
504 const void *vals
[] = { kSecClassCertificate
, pkhh
};
506 query_dict
= CFDictionaryCreate(NULL
, keys
,
507 vals
, (array_size(keys
)),
510 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
511 skip_key_operation
= true;
512 CFReleaseSafe(query_dict
);
513 CFReleaseSafe(key_dict
);
516 if (!skip_key_operation
) {
517 /* now perform the operation for the key */
518 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
519 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
521 status
= operation(partial_query
, NULL
);
522 if ((operation
== (secitem_operation
)SecItemAdd
) &&
523 (status
== errSecDuplicateItem
) &&
525 status
= errSecSuccess
;
528 /* add and copy matching for an identityref have a persistent ref result */
531 /* result is a persistent ref to a cert */
533 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
)) {
534 *return_result
= _SecItemMakePersistentRef(kSecClassIdentity
, rowid
);
540 CFReleaseNull(partial_query
);
543 status
= errSecInvalidItemRef
;
547 *return_status
= status
;
550 value
= CFDictionaryGetValue(attributes
, kSecClass
);
551 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
552 (operation
== (secitem_operation
)SecItemDelete
)) {
553 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
554 CFDictionaryRemoveValue(dict
, kSecClass
);
555 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
556 OSStatus status
= SecItemDelete(dict
);
558 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
559 status
= SecItemDelete(dict
);
562 *return_status
= status
;
570 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
573 CFErrorRef lastError
= SecCopyLastError(status
);
575 CFErrorPropagate(lastError
, error
);
577 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
584 handleUpdateIdentity(CFDictionaryRef query
,
585 CFDictionaryRef update
,
589 CFMutableDictionaryRef updatedQuery
= NULL
;
590 SecCertificateRef cert
= NULL
;
591 SecKeyRef key
= NULL
;
592 bool handled
= false;
596 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
598 CFTypeID typeID
= CFGetTypeID(value
);
599 if (typeID
== SecIdentityGetTypeID()) {
600 SecIdentityRef identity
= (SecIdentityRef
)value
;
605 status
= SecIdentityCopyCertificate(identity
, &cert
);
606 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
608 status
= SecIdentityCopyPrivateKey(identity
, &key
);
609 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
611 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
612 require_action_quiet(updatedQuery
, errOut
, *result
= false);
614 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
615 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
617 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
618 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
622 value
= CFDictionaryGetValue(query
, kSecClass
);
623 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
626 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
627 require_action_quiet(updatedQuery
, errOut
, *result
= false);
629 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
630 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
632 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
633 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
635 CFReleaseNull(updatedQuery
);
640 CFReleaseNull(updatedQuery
);
646 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
648 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
649 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
650 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
651 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
652 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
654 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
655 CFReleaseNull(label
);
661 /* A persistent ref is just the class and the rowid of the record. */
662 CF_RETURNS_RETAINED CFDataRef
_SecItemMakePersistentRef(CFTypeRef
class, sqlite_int64 rowid
)
664 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
667 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
668 kCFStringEncodingUTF8
))
670 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
671 return CFDataCreate(NULL
, bytes
, sizeof(bytes
));
676 /* AUDIT[securityd](done):
677 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
679 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
)
681 bool valid_ref
= false;
682 if (CFGetTypeID(persistent_ref
) == CFDataGetTypeID() &&
683 CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
684 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
685 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
687 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
688 bytes
, CFStringGetLength(kSecClassGenericPassword
),
689 kCFStringEncodingUTF8
, true);
690 const void *valid_classes
[] = { kSecClassGenericPassword
,
691 kSecClassInternetPassword
,
692 kSecClassAppleSharePassword
,
693 kSecClassCertificate
,
698 for (i
=0; i
< array_size(valid_classes
); i
++) {
699 if (CFEqual(valid_classes
[i
], class)) {
701 *return_class
= valid_classes
[i
];
703 *return_rowid
= rowid
;
713 static bool cf_bool_value(CFTypeRef cf_bool
)
715 return (cf_bool
&& CFEqual(kCFBooleanTrue
, cf_bool
));
718 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
719 if (cow_dictionary
->mutable_dictionary
== NULL
) {
720 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
721 if (cow_dictionary
->dictionary
!= NULL
) {
722 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
723 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
726 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
729 return cow_dictionary
->mutable_dictionary
;
732 // Keys for dictionary of kSecvalueData of token-based items.
733 static const CFStringRef kSecTokenValueObjectIDKey
= CFSTR("oid");
734 static const CFStringRef kSecTokenValueAccessControlKey
= CFSTR("ac");
735 static const CFStringRef kSecTokenValueDataKey
= CFSTR("data");
737 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
738 // access_control and optionally of the data value.
739 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
740 CFMutableDictionaryRef value
= NULL
;
741 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
742 kSecTokenValueObjectIDKey
, oid
,
743 kSecTokenValueAccessControlKey
, access_control
,
745 if (object_value
!= NULL
) {
746 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
749 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
754 static CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
755 CFPropertyListRef plist
= NULL
;
756 const uint8_t *der
= CFDataGetBytePtr(db_value
);
757 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
758 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
759 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
760 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
761 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
767 CFDataRef
_SecTokenItemCopyValueData(CFDataRef db_value
, CFErrorRef
*error
) {
768 CFDataRef valueData
= NULL
;
769 CFDictionaryRef itemDict
= NULL
;
770 require_quiet(itemDict
= SecTokenItemValueCopy(db_value
, error
), out
);
771 CFRetainAssign(valueData
, CFDictionaryGetValue(itemDict
, kSecTokenValueDataKey
));
772 require_action_quiet(valueData
, out
, SecError(errSecInternal
, error
, CFSTR("token item does not contain value data")));
775 CFReleaseSafe(itemDict
);
779 TKTokenRef
SecTokenCreate(CFStringRef token_id
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
780 CFMutableDictionaryRef token_attrs
= NULL
;
781 TKTokenRef token
= NULL
;
782 token_attrs
= (auth_params
!= NULL
) ?
783 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
) :
784 CFDictionaryCreateMutableForCFTypes(NULL
);
785 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
787 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
788 token
= TKTokenCreate(token_attrs
, error
);
790 CFReleaseSafe(token_attrs
);
794 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
795 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
797 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
798 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
799 if (token_id
!= NULL
&& object_id
!= NULL
) {
800 if (CFRetainSafe(token
) == NULL
) {
801 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
804 if (auth_params
!= NULL
) {
805 CFDictionaryForEach(auth_params
, ^(const void *key
, const void *value
) {
806 CFDictionarySetValue(attrs
, key
, value
);
809 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
810 CFDictionarySetValue(attrs
, kSecUseTokenObjectID
, object_id
);
813 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
817 CFReleaseSafe(attrs
);
822 /* Turn the returned single value or dictionary that contains all the attributes to create a
823 ref into the exact result the client asked for */
824 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
825 CFDictionaryRef query
, CFDictionaryRef auth_params
,
826 CFTypeRef
*result
, CFErrorRef
*error
) {
828 CFDataRef ac_data
= NULL
;
829 CFDataRef value
= NULL
;
830 CFTypeRef persistent_ref
= NULL
;
831 CFStringRef token_id
= NULL
;
832 CFStringRef cert_token_id
= NULL
;
833 CFDataRef object_id
= NULL
;
834 CFMutableDictionaryRef attrs
= NULL
;
835 CFDataRef cert_data
= NULL
;
836 CFDataRef cert_object_id
= NULL
;
837 TKTokenRef cert_token
= NULL
;
839 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
840 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
841 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
842 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
844 // Get token value if not provided by the caller.
845 bool token_item
= false;
846 bool cert_token_item
= false;
848 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
849 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
850 token_item
= (token_id
!= NULL
);
852 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
853 cert_token_item
= (cert_token_id
!= NULL
);
857 cert_token_item
= true;
859 CFRetainAssign(cert_token
, token
);
862 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
863 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
864 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
865 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
867 value
= CFRetainSafe(raw_result
);
868 if (token_item
&& value
!= NULL
) {
869 // Parse token-based item's data field.
870 CFDataRef object_value
= NULL
;
871 CFDictionaryRef parsed_value
= NULL
;
872 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
873 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
874 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
875 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
876 CFRelease(parsed_value
);
877 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
878 // Retrieve value directly from the token.
880 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
882 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
883 if (CFEqual(object_value
, kCFNull
))
884 CFReleaseNull(object_value
);
886 CFAssignRetained(value
, object_value
);
889 // If only thing requested is data, return them directly.
890 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
891 *result
= CFRetainSafe(value
);
897 // Extract persistent_ref, if caller wants it.
898 if (wants_persistent_ref
) {
899 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
900 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
902 persistent_ref
= CFRetainSafe(raw_result
);
904 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
905 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
906 *result
= CFRetainSafe(persistent_ref
);
912 if (wants_ref
|| wants_attributes
|| (wants_data
&& wants_persistent_ref
)) {
913 // For these cases we need output dictionary.
914 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
915 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
917 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
918 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
920 if ((wants_data
|| wants_ref
) && value
!= NULL
)
921 CFDictionarySetValue(output
, kSecValueData
, value
);
923 CFDictionaryRemoveValue(output
, kSecValueData
);
925 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
926 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
928 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
930 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
931 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
932 // Decode also certdata field of the identity.
933 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
935 CFDictionaryRef parsed_value
;
936 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
937 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
938 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
939 CFRelease(parsed_value
);
940 if (cert_data
== NULL
) {
941 // Retrieve value directly from the token.
942 if (cert_token
== NULL
) {
943 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, auth_params
, error
), out
);
945 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
946 if (CFEqual(cert_data
, kCFNull
))
947 CFReleaseNull(cert_data
);
949 if (cert_data
!= NULL
) {
950 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
952 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
959 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
, token
, object_id
, &ref
, error
), out
);
960 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
961 CFAssignRetained(*result
, ref
);
962 } else if (ref
!= NULL
) {
963 CFDictionarySetValue(output
, kSecValueRef
, ref
);
966 // We could have stored data value previously to make ref creation succeed.
967 // They are not needed any more and in case that caller did not want the data, avoid returning them.
968 CFDictionaryRemoveValue(output
, kSecValueData
);
973 if (wants_attributes
) {
974 // Convert serialized form of access control to object form.
976 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
979 if (ac_data
!= NULL
) {
980 SecAccessControlRef ac
;
981 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
982 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
993 CFReleaseSafe(cert_object_id
);
994 CFReleaseSafe(cert_data
);
995 CFReleaseSafe(ac_data
);
996 CFReleaseSafe(value
);
997 CFReleaseSafe(persistent_ref
);
998 CFReleaseSafe(object_id
);
999 CFReleaseSafe(attrs
);
1000 CFReleaseSafe(token
);
1001 CFReleaseSafe(cert_token
);
1005 static bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1006 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1008 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1009 require_action_quiet(result
!= NULL
, out
, ok
= true);
1011 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1012 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1013 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1014 for (i
= 0; i
< count
; i
++) {
1016 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1017 token
, query
, auth_params
, &ref
, error
), out
);
1019 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1024 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1033 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1034 void *la_lib
= NULL
;
1035 CFDataRef acm_context
= NULL
;
1036 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1037 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1038 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1039 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1040 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1041 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1042 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1044 if (la_lib
!= NULL
) {
1050 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1052 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1053 void *la_lib
= NULL
;
1055 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1056 if (access_control
!= NULL
) {
1057 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
1058 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1061 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1063 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1064 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1065 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1066 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1067 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1070 // If a ref was specified we get its attribute dictionary and parse it.
1071 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1073 CFDictionaryRef ref_attributes
;
1074 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1075 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1077 /* Replace any attributes we already got from the ref with the ones
1078 from the attributes dictionary the caller passed us. This allows
1079 a caller to add an item using attributes from the ref and still
1080 override some of them in the dictionary directly. */
1081 CFMutableDictionaryRef new_query
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, ref_attributes
);
1082 CFRelease(ref_attributes
);
1083 CFDictionaryForEach(attrs
->dictionary
, ^(const void *key
, const void *value
) {
1084 if (!CFEqual(key
, kSecValueRef
))
1085 CFDictionarySetValue(new_query
, key
, value
);
1087 CFAssignRetained(attrs
->mutable_dictionary
, new_query
);
1088 attrs
->dictionary
= attrs
->mutable_dictionary
;
1091 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1093 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1094 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1096 CFTypeRef values
[] = { policy
};
1097 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1098 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1099 CFReleaseSafe(policiesArray
);
1100 require_action_quiet(policiesArrayXPC
, out
,
1101 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1103 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1104 xpc_release(policiesArrayXPC
);
1105 require_action_quiet(objectReadyForXPC
, out
,
1106 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1108 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1109 CFRelease(objectReadyForXPC
);
1111 #ifndef SECITEM_SHIM_OSX
1112 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1114 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1115 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1116 DERDecodedInfo content
;
1117 if (!DERDecodeItem(&name
, &content
) &&
1118 (content
.tag
== ASN1_CONSTR_SEQUENCE
))
1120 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1121 if (canonical_issuer
) {
1122 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1123 CFRelease(canonical_issuer
);
1132 if (la_lib
!= NULL
) {
1135 CFReleaseSafe(ac_data
);
1136 CFReleaseSafe(acm_context
);
1140 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1142 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1144 CFArrayForEachC(ac_pairs
, ac_pair
) {
1145 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1146 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1147 CFStringAppend(log_string
, str
);
1148 CFRelease(acl_hex_string
);
1152 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1153 SecError(errSecAuthFailed
, error
, reason
);
1154 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1157 CFRelease(log_string
);
1161 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
)) {
1163 CFArrayRef ac_pairs
= NULL
;
1164 SecCFDictionaryCOW auth_options
= { NULL
};
1166 for (uint32_t i
= 0;; ++i
) {
1167 // If the operation succeeded or failed with other than auth-needed error, just leave.
1168 SecItemAuthResult auth_result
= perform(auth_params
->dictionary
, &ac_pairs
, error
);
1169 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1170 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1172 // If auth_params were not created up to now, do create them because we will definitely need them.
1173 SecCFDictionaryCOWGetMutable(auth_params
);
1175 // Retrieve or create authentication handle and/or ACM context.
1176 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1177 if (auth_handle
== NULL
) {
1178 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1179 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1180 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1181 CFRelease(auth_handle
);
1182 if (acm_context
== NULL
) {
1183 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1184 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1185 CFRelease(acm_context
);
1189 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1190 // user retry limit.
1191 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1193 // Prepare auth options dictionary.
1194 if (auth_options
.dictionary
== NULL
) {
1195 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1196 if (operation_prompt
!= NULL
) {
1197 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1198 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1202 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1203 if (caller_name
!= NULL
) {
1204 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1205 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1209 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1210 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1211 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1212 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1217 // Go through all access_control-operation pairs and evaluate them.
1219 CFArrayForEachC(ac_pairs
, ac_pair
) {
1220 CFDataRef updated_acl
= NULL
;
1221 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1222 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1223 auth_options
.dictionary
, &updated_acl
, error
), out
);
1225 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1226 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1227 SecAccessControlRef ac
= NULL
;
1228 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1229 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1230 SecAccessControlSetBound(ac
, true);
1231 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1232 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1233 CFRelease(updated_acl
);
1242 CFReleaseSafe(auth_options
.mutable_dictionary
);
1243 CFReleaseSafe(ac_pairs
);
1247 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1248 // Store operation prompt.
1249 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1250 if (operation_prompt
!= NULL
) {
1251 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1252 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1255 // Store caller name.
1256 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1257 if (caller_name
!= NULL
) {
1258 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1259 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1262 // Find out whether we are allowed to pop up a UI.
1263 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1264 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1265 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1266 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1267 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1268 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1269 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1270 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1273 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1274 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1277 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1278 if (acm_context
!= NULL
) {
1279 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1283 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1285 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1286 // Extract ACLs to be verified from the error.
1287 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1288 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1289 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1290 if (*ac_pairs
== NULL
)
1291 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1294 CFRelease(user_info
);
1295 CFReleaseNull(*error
);
1296 return kSecItemAuthResultNeedAuth
;
1298 return kSecItemAuthResultError
;
1301 // Wrapper to handle automatic authentication and token/secd case switching.
1302 static bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1303 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1305 SecCFDictionaryCOW auth_params
= { NULL
};
1306 SecAccessControlRef access_control
= NULL
;
1307 __block TKTokenRef token
= NULL
;
1309 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1310 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1311 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1312 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1313 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1314 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1317 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1318 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1320 secItemOperation
== SecItemCopyMatching
||
1321 secItemOperation
== SecItemUpdate
||
1322 secItemOperation
== SecItemDelete
;
1324 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1325 if (attributes
!= NULL
)
1326 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1328 // Populate auth_params dictionary according to initial query contents.
1329 SecItemAuthCopyParams(&auth_params
, query
);
1331 if (secItemOperation
!= SecItemCopyMatching
) {
1332 // UISkip is allowed only for CopyMatching.
1333 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1334 SecError(errSecParam
, error
,
1335 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1338 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1339 SecItemAuthResult result
= kSecItemAuthResultError
;
1341 // Propagate actual credential reference to the query.
1342 if (auth_params
!= NULL
) {
1343 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
, kSecUseCredentialReference
);
1344 if (acm_context
!= NULL
) {
1345 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1348 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
, kSecAttrAccessControl
);
1349 if (acl_data_ref
!= NULL
) {
1350 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1354 // Prepare connection to target token if it is present.
1355 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1356 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1357 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, auth_params
, error
)), out
);
1360 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1361 if(!perform(token
, query
->dictionary
, attrs
, auth_params
, error
)) {
1362 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1365 result
= kSecItemAuthResultOK
;
1370 require_quiet(ok
, out
);
1375 CFReleaseSafe(token
);
1376 CFReleaseSafe(auth_params
.mutable_dictionary
);
1380 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1382 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1383 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1384 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1386 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1392 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1394 CFArrayRef result
= NULL
;
1395 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1396 if(success
&& !isArray(result
)){
1397 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1398 CFReleaseNull(result
);
1403 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1404 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1407 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1409 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1410 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1414 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1416 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1418 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1423 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1431 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1433 return dict_to_error_request(op
, query
, error
);
1436 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1437 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1438 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1439 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1440 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1441 keys
, ac_pairs
, 1));
1443 CFRelease(ac_pairs
[0]);
1448 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1449 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1450 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1451 // Replace error with the one which is augmented with access control and operation which failed,
1452 // which will cause SecItemDoWithAuth to throw UI.
1453 // Create array containing tuple (array) with error and requested operation.
1454 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1455 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1456 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1457 if (access_control
!= NULL
) {
1458 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1459 CFRelease(access_control
);
1465 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1466 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1467 SecAccessControlRef ac
= NULL
;
1469 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1470 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1471 if (ac_data
!= NULL
) {
1472 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1473 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1474 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1477 // Create or update the object on the token.
1478 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1479 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1481 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1482 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1483 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1484 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1485 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1487 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1488 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1492 CFReleaseSafe(access_control
);
1493 CFReleaseSafe(db_value
);
1494 return new_object_id
;
1497 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1498 CFTypeRef
*result
, CFErrorRef
*error
) {
1500 CFTypeRef object_id
= NULL
, ref
= NULL
;
1501 CFDictionaryRef ref_attrs
= NULL
;
1502 CFTypeRef db_result
= NULL
;
1504 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1505 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, NULL
, attrs
, error
), out
);
1507 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1508 // by creating ref and getting back its attributes.
1509 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1511 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1512 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1513 if (!CFEqual(key
, kSecValueData
)) {
1514 CFDictionaryAddValue(attrs
, key
, value
);
1520 // Make sure that both attributes and data are returned.
1521 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1522 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1524 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1525 // IsPermanent is not present or is true, so add item to the db.
1526 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1527 SecSecurityClientGet(), &db_result
, error
), out
);
1529 // Process directly result of token call.
1530 db_result
= CFRetain(attrs
);
1532 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1537 CFReleaseSafe(db_result
);
1538 CFReleaseSafe(attrs
);
1539 CFReleaseSafe(ref_attrs
);
1540 CFReleaseSafe(object_id
);
1545 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1546 __block SecCFDictionaryCOW attrs
= { attributes
};
1549 os_activity_t trace_activity
= os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1551 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1552 infer_cert_label(&attrs
);
1554 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1555 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1556 if (token
== NULL
) {
1557 CFTypeRef raw_result
= NULL
;
1558 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1561 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1562 CFReleaseSafe(raw_result
);
1565 // Send request to an appropriate token instead of secd.
1566 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1572 CFReleaseSafe(attrs
.mutable_dictionary
);
1574 os_activity_end(trace_activity
);
1579 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1581 __block SecCFDictionaryCOW query
= { inQuery
};
1583 os_activity_t trace_activity
= os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1585 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1587 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1588 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1589 if ((wants_data
&& !wants_attributes
) || (!wants_data
&& wants_attributes
)) {
1590 // When either attributes or data are requested, we need to query both, because for token based items,
1591 // both are needed in order to generate proper data and/or attributes results.
1592 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1593 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnData
, kCFBooleanTrue
);
1596 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1597 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1598 CFTypeRef raw_result
= NULL
;
1599 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1602 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1603 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1604 // to currently processed item.
1605 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1606 CFReleaseSafe(raw_result
);
1613 CFReleaseSafe(query
.mutable_dictionary
);
1614 os_activity_end(trace_activity
);
1618 // Invokes token-object handler for each item matching specified query.
1619 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1620 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1621 CFErrorRef
*error
)) {
1623 CFMutableDictionaryRef list_query
= NULL
;
1624 CFTypeRef items
= NULL
;
1625 CFArrayRef ref_array
= NULL
;
1626 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1628 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1629 // items in the keychain.
1630 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1631 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1632 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1634 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1635 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1636 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1637 SecSecurityClientGet(), &items
, error
), out
);
1638 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1639 // Wrap single returned item into the array.
1640 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1641 CFAssignRetained(items
, item_array
);
1645 CFArrayForEachC(items
, item
) {
1646 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1647 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1649 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1650 require_quiet(item_data
, out
);
1652 CFAssignRetained(item_query
,
1653 CFDictionaryCreateForCFTypes(NULL
,
1654 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1656 require_quiet(perform(item_data
, item_query
, error
), out
);
1662 CFReleaseSafe(list_query
);
1663 CFReleaseSafe(items
);
1664 CFReleaseSafe(item_data
);
1665 CFReleaseSafe(ref_array
);
1666 CFReleaseSafe(item_query
);
1670 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1673 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1674 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1675 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1676 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1679 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1681 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1682 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1683 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1685 ok
= securityd_message_no_error(reply
, error
);
1689 xpc_release(message
);
1695 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1696 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1698 CFDataRef object_id
= NULL
;
1699 CFMutableDictionaryRef db_value
= NULL
;
1701 // Update attributes on the token.
1702 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1703 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1704 attributes
, error
), out
);
1706 // Update attributes in the database.
1707 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1712 CFReleaseSafe(object_id
);
1713 CFReleaseSafe(attributes
);
1714 CFReleaseSafe(db_value
);
1719 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1720 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1721 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1726 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1727 CFDictionaryRef inAttributesToUpdate
,
1730 __block SecCFDictionaryCOW query
= { inQuery
};
1731 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1732 bool result
= false;
1734 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1737 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1738 if (token
== NULL
) {
1739 return SecItemRawUpdate(query
, attributes
, error
);
1741 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1746 CFReleaseSafe(query
.mutable_dictionary
);
1747 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1751 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1753 OSStatus status
= errSecSuccess
;
1754 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1756 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
)
1757 && CFEqual(class, kSecClassIdentity
)) {
1758 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1759 const void *vals
[] = { kCFBooleanTrue
, persist
};
1760 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1761 vals
, (array_size(keys
)), NULL
, NULL
);
1762 CFTypeRef item_query
= NULL
;
1763 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1764 CFReleaseNull(persistent_query
);
1768 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1769 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1770 CFRelease(item_query
);
1776 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1778 __block SecCFDictionaryCOW query
= { inQuery
};
1780 os_activity_t trace_activity
= os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1782 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1783 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1785 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1786 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1787 if (token
== NULL
) {
1788 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1790 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1793 // Delete item from the token.
1794 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1795 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1796 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1798 // Delete the item from the keychain.
1799 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1800 SecSecurityClientGet(), error
), out
);
1811 CFReleaseSafe(query
.mutable_dictionary
);
1813 os_activity_end(trace_activity
);
1819 SecItemDeleteAll(void)
1821 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1825 #ifndef SECITEM_SHIM_OSX
1826 SecTrustStoreRef ts
= SecTrustStoreForDomain(kSecTrustStoreDomainUser
);
1827 if (!gSecurityd
->sec_truststore_remove_all(ts
, error
))
1828 ok
= SecError(errSecInternal
, error
, CFSTR("sec_truststore_remove_all is NULL"));
1829 #endif // *** END SECITEM_SHIM_OSX ***
1830 if (!gSecurityd
->sec_item_delete_all(error
))
1831 ok
= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1833 ok
= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1840 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1842 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1843 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1847 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1848 os_activity_t trace_activity
= os_activity_start("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_FLAG_DEFAULT
);
1850 bool ok
= SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1851 SecSecurityClientGet(), error
);
1853 os_activity_end(trace_activity
);
1858 #if SECITEM_SHIM_OSX
1859 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1861 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1866 os_activity_t trace_activity
= os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1868 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1869 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
1870 if (tokenItemsAttributes
) {
1871 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1872 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
1873 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
1874 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
1875 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
1876 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
1877 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
1878 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
1880 CFRelease(tokenItems
);
1884 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
1885 CFDictionarySetValue(attributes
, kSecValueData
, data
);
1886 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
1887 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1888 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
1889 CFArrayAppendValue(tokenItems
, attributes
);
1890 CFRelease(attributes
);
1894 CFArrayAppendValue(tokenItems
, itemAttributes
);
1897 tmpArrayRef
= tokenItems
;
1900 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
1903 os_activity_end(trace_activity
);
1908 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
1909 __block CFArrayRef result
;
1910 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1911 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
1916 #ifndef SECITEM_SHIM_OSX
1917 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1919 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
)
1921 return -1; /* this is only on OS X currently */
1926 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1930 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1932 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
1934 do_if_registered(sec_roll_keys
, force
, error
);
1936 __block
bool result
= false;
1938 secdebug("secitem","enter - %s", __FUNCTION__
);
1939 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
1940 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1941 xpc_dictionary_set_bool(message
, "force", force
);
1944 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
1945 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);