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
;
235 return errSecInternal
;
240 // Convert from securityd error codes to OSStatus for legacy API.
241 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
244 status
= errSecSuccess
;
246 CFStringRef domain
= CFErrorGetDomain(error
);
247 if (domain
== NULL
) {
248 secerror("No error domain for error: %@", error
);
249 status
= errSecInternal
;
250 } else if (CFEqual(kSecErrorDomain
, domain
)) {
251 status
= (OSStatus
)CFErrorGetCode(error
);
252 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
253 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
254 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
255 status
= (OSStatus
)CFErrorGetCode(error
);
256 } else if (CFEqual(kSecKernDomain
, domain
)) {
257 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
258 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
259 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
260 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
261 status
= osstatus_for_der_error(CFErrorGetCode(error
));
262 } else if (CFEqual(kSecIDSErrorDomain
, domain
)) {
263 status
= osstatus_for_ids_error(CFErrorGetCode(error
));
264 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
265 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
266 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
267 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
268 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
269 status
= errSecInternal
;
271 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
272 status
= errSecInternal
;
279 lastErrorReleaseError(void *value
)
286 getLastErrorKey(pthread_key_t
*kv
)
288 static pthread_key_t key
;
289 static bool haveKey
= false;
290 static dispatch_once_t onceToken
;
291 dispatch_once(&onceToken
, ^{
292 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
300 SetLastError(CFErrorRef newError
)
303 if (!getLastErrorKey(&key
))
305 CFErrorRef oldError
= pthread_getspecific(key
);
310 pthread_setspecific(key
, newError
);
314 SecCopyLastError(OSStatus status
)
319 if (!getLastErrorKey(&key
))
322 error
= pthread_getspecific(key
);
324 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
333 // Wrapper to provide a CFErrorRef for legacy API.
334 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
335 CFErrorRef error
= NULL
;
337 if (perform(&error
)) {
338 assert(error
== NULL
);
340 status
= errSecSuccess
;
344 status
= SecErrorGetOSStatus(error
);
345 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
346 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
347 CFReleaseNull(error
);
352 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
353 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
356 static CFDictionaryRef
357 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
359 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
360 if (filtered
== NULL
)
362 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
363 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
364 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
365 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
366 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
367 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
368 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
369 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
370 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
376 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
377 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
379 Currently in need of conversion below:
380 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
381 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
382 currently implemented at all, but when it is needs to short circuit to
383 local evaluation, different from the sql query abilities
386 static CFDictionaryRef
387 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
388 CFDictionaryRef refDictionary
= NULL
;
389 CFTypeID typeID
= CFGetTypeID(ref
);
390 if (typeID
== SecKeyGetTypeID()) {
391 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
392 if (refDictionary
&& forQuery
) {
393 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
394 CFAssignRetained(refDictionary
, filtered
);
396 } else if (typeID
== SecCertificateGetTypeID()) {
397 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
398 } else if (typeID
== SecIdentityGetTypeID()) {
400 SecIdentityRef identity
= (SecIdentityRef
)ref
;
401 SecCertificateRef cert
= NULL
;
402 SecKeyRef key
= NULL
;
403 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
404 !SecIdentityCopyPrivateKey(identity
, &key
))
406 CFDataRef data
= SecCertificateCopyData(cert
);
407 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
409 if (key_dict
&& data
) {
410 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
411 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
413 CFReleaseNull(key_dict
);
419 return refDictionary
;
422 #ifdef SECITEM_SHIM_OSX
423 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
427 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
428 CFTypeRef ref
= NULL
;
429 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
430 if (CFEqual(class, kSecClassKey
)) {
431 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
432 } else if (CFEqual(class, kSecClassCertificate
)) {
433 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
434 } else if (CFEqual(class, kSecClassIdentity
)) {
435 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
436 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
437 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
439 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
442 #ifdef SECITEM_SHIM_OSX
444 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
451 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
454 return -1 /* errSecUnimplemented */;
457 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
459 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
460 OSStatus
*return_status
, CFTypeRef
*return_result
)
462 bool handled
= false;
463 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
465 CFTypeID typeID
= CFGetTypeID(value
);
466 if (typeID
== SecIdentityGetTypeID()) {
468 OSStatus status
= errSecSuccess
;
469 SecIdentityRef identity
= (SecIdentityRef
)value
;
470 SecCertificateRef cert
= NULL
;
471 SecKeyRef key
= NULL
;
472 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
473 !SecIdentityCopyPrivateKey(identity
, &key
))
475 CFMutableDictionaryRef partial_query
=
476 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
477 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
478 CFTypeRef result
= NULL
;
479 bool duplicate_cert
= false;
480 /* an identity is first and foremost a key, but it can have multiple
481 certs associated with it: so we identify it by the cert */
482 status
= operation(partial_query
, return_result
? &result
: NULL
);
483 if ((operation
== (secitem_operation
)SecItemAdd
) &&
484 (status
== errSecDuplicateItem
)) {
485 duplicate_cert
= true;
486 status
= errSecSuccess
;
489 if (!status
|| status
== errSecItemNotFound
) {
490 bool skip_key_operation
= false;
492 /* if the key is still in use, skip deleting it */
493 if (operation
== (secitem_operation
)SecItemDelete
) {
494 // find certs with cert.pkhh == keys.klbl
495 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
496 CFDataRef pkhh
= NULL
;
498 key_dict
= SecKeyCopyAttributeDictionary(key
);
500 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
501 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
502 const void *vals
[] = { kSecClassCertificate
, pkhh
};
504 query_dict
= CFDictionaryCreate(NULL
, keys
,
505 vals
, (array_size(keys
)),
508 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
509 skip_key_operation
= true;
510 CFReleaseSafe(query_dict
);
511 CFReleaseSafe(key_dict
);
514 if (!skip_key_operation
) {
515 /* now perform the operation for the key */
516 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
517 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
519 status
= operation(partial_query
, NULL
);
520 if ((operation
== (secitem_operation
)SecItemAdd
) &&
521 (status
== errSecDuplicateItem
) &&
523 status
= errSecSuccess
;
526 /* add and copy matching for an identityref have a persistent ref result */
529 /* result is a persistent ref to a cert */
531 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
)) {
532 *return_result
= _SecItemMakePersistentRef(kSecClassIdentity
, rowid
);
538 CFReleaseNull(partial_query
);
541 status
= errSecInvalidItemRef
;
545 *return_status
= status
;
548 value
= CFDictionaryGetValue(attributes
, kSecClass
);
549 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
550 (operation
== (secitem_operation
)SecItemDelete
)) {
551 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
552 CFDictionaryRemoveValue(dict
, kSecClass
);
553 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
554 OSStatus status
= SecItemDelete(dict
);
556 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
557 status
= SecItemDelete(dict
);
560 *return_status
= status
;
568 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
571 CFErrorRef lastError
= SecCopyLastError(status
);
573 CFErrorPropagate(lastError
, error
);
575 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
582 handleUpdateIdentity(CFDictionaryRef query
,
583 CFDictionaryRef update
,
587 CFMutableDictionaryRef updatedQuery
= NULL
;
588 SecCertificateRef cert
= NULL
;
589 SecKeyRef key
= NULL
;
590 bool handled
= false;
594 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
596 CFTypeID typeID
= CFGetTypeID(value
);
597 if (typeID
== SecIdentityGetTypeID()) {
598 SecIdentityRef identity
= (SecIdentityRef
)value
;
603 status
= SecIdentityCopyCertificate(identity
, &cert
);
604 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
606 status
= SecIdentityCopyPrivateKey(identity
, &key
);
607 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
609 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
610 require_action_quiet(updatedQuery
, errOut
, *result
= false);
612 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
613 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
615 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
616 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
620 value
= CFDictionaryGetValue(query
, kSecClass
);
621 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
624 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
625 require_action_quiet(updatedQuery
, errOut
, *result
= false);
627 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
628 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
630 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
631 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
633 CFReleaseNull(updatedQuery
);
638 CFReleaseNull(updatedQuery
);
644 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
646 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
647 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
648 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
649 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
650 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
652 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
653 CFReleaseNull(label
);
659 /* A persistent ref is just the class and the rowid of the record. */
660 CF_RETURNS_RETAINED CFDataRef
_SecItemMakePersistentRef(CFTypeRef
class, sqlite_int64 rowid
)
662 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
665 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
666 kCFStringEncodingUTF8
))
668 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
669 return CFDataCreate(NULL
, bytes
, sizeof(bytes
));
674 /* AUDIT[securityd](done):
675 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
677 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
)
679 bool valid_ref
= false;
680 if (CFGetTypeID(persistent_ref
) == CFDataGetTypeID() &&
681 CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
682 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
683 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
685 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
686 bytes
, CFStringGetLength(kSecClassGenericPassword
),
687 kCFStringEncodingUTF8
, true);
688 const void *valid_classes
[] = { kSecClassGenericPassword
,
689 kSecClassInternetPassword
,
690 kSecClassAppleSharePassword
,
691 kSecClassCertificate
,
696 for (i
=0; i
< array_size(valid_classes
); i
++) {
697 if (CFEqual(valid_classes
[i
], class)) {
699 *return_class
= valid_classes
[i
];
701 *return_rowid
= rowid
;
711 static bool cf_bool_value(CFTypeRef cf_bool
)
713 return (cf_bool
&& CFEqual(kCFBooleanTrue
, cf_bool
));
716 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
717 if (cow_dictionary
->mutable_dictionary
== NULL
) {
718 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
719 if (cow_dictionary
->dictionary
!= NULL
) {
720 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
721 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
724 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
727 return cow_dictionary
->mutable_dictionary
;
730 // Keys for dictionary of kSecvalueData of token-based items.
731 static const CFStringRef kSecTokenValueObjectIDKey
= CFSTR("oid");
732 static const CFStringRef kSecTokenValueAccessControlKey
= CFSTR("ac");
733 static const CFStringRef kSecTokenValueDataKey
= CFSTR("data");
735 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
736 // access_control and optionally of the data value.
737 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
738 CFMutableDictionaryRef value
= NULL
;
739 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
740 kSecTokenValueObjectIDKey
, oid
,
741 kSecTokenValueAccessControlKey
, access_control
,
743 if (object_value
!= NULL
) {
744 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
747 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
752 static CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
753 CFPropertyListRef plist
= NULL
;
754 const uint8_t *der
= CFDataGetBytePtr(db_value
);
755 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
756 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
757 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
758 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
759 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
765 CFDataRef
_SecTokenItemCopyValueData(CFDataRef db_value
, CFErrorRef
*error
) {
766 CFDataRef valueData
= NULL
;
767 CFDictionaryRef itemDict
= NULL
;
768 require_quiet(itemDict
= SecTokenItemValueCopy(db_value
, error
), out
);
769 CFRetainAssign(valueData
, CFDictionaryGetValue(itemDict
, kSecTokenValueDataKey
));
770 require_action_quiet(valueData
, out
, SecError(errSecInternal
, error
, CFSTR("token item does not contain value data")));
773 CFReleaseSafe(itemDict
);
777 TKTokenRef
SecTokenCreate(CFStringRef token_id
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
778 CFMutableDictionaryRef token_attrs
= NULL
;
779 TKTokenRef token
= NULL
;
780 token_attrs
= (auth_params
!= NULL
) ?
781 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
) :
782 CFDictionaryCreateMutableForCFTypes(NULL
);
783 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
785 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
786 token
= TKTokenCreate(token_attrs
, error
);
788 CFReleaseSafe(token_attrs
);
792 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
793 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
795 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
796 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
797 if (token_id
!= NULL
&& object_id
!= NULL
) {
798 if (CFRetainSafe(token
) == NULL
) {
799 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
802 if (auth_params
!= NULL
) {
803 CFDictionaryForEach(auth_params
, ^(const void *key
, const void *value
) {
804 CFDictionarySetValue(attrs
, key
, value
);
807 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
808 CFDictionarySetValue(attrs
, kSecUseTokenObjectID
, object_id
);
811 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
815 CFReleaseSafe(attrs
);
820 /* Turn the returned single value or dictionary that contains all the attributes to create a
821 ref into the exact result the client asked for */
822 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
823 CFDictionaryRef query
, CFDictionaryRef auth_params
,
824 CFTypeRef
*result
, CFErrorRef
*error
) {
826 CFDataRef ac_data
= NULL
;
827 CFDataRef value
= NULL
;
828 CFTypeRef persistent_ref
= NULL
;
829 CFStringRef token_id
= NULL
;
830 CFStringRef cert_token_id
= NULL
;
831 CFDataRef object_id
= NULL
;
832 CFMutableDictionaryRef attrs
= NULL
;
833 CFDataRef cert_data
= NULL
;
834 CFDataRef cert_object_id
= NULL
;
835 TKTokenRef cert_token
= NULL
;
837 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
838 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
839 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
840 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
842 // Get token value if not provided by the caller.
843 bool token_item
= false;
844 bool cert_token_item
= false;
846 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
847 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
848 token_item
= (token_id
!= NULL
);
850 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
851 cert_token_item
= (cert_token_id
!= NULL
);
855 cert_token_item
= true;
857 CFRetainAssign(cert_token
, token
);
860 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
861 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
862 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
863 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
865 value
= CFRetainSafe(raw_result
);
866 if (token_item
&& value
!= NULL
) {
867 // Parse token-based item's data field.
868 CFDataRef object_value
= NULL
;
869 CFDictionaryRef parsed_value
= NULL
;
870 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
871 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
872 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
873 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
874 CFRelease(parsed_value
);
875 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
876 // Retrieve value directly from the token.
878 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
880 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
881 if (CFEqual(object_value
, kCFNull
))
882 CFReleaseNull(object_value
);
884 CFAssignRetained(value
, object_value
);
887 // If only thing requested is data, return them directly.
888 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
889 *result
= CFRetainSafe(value
);
895 // Extract persistent_ref, if caller wants it.
896 if (wants_persistent_ref
) {
897 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
898 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
900 persistent_ref
= CFRetainSafe(raw_result
);
902 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
903 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
904 *result
= CFRetainSafe(persistent_ref
);
910 if (wants_ref
|| wants_attributes
|| (wants_data
&& wants_persistent_ref
)) {
911 // For these cases we need output dictionary.
912 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
913 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
915 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
916 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
918 if ((wants_data
|| wants_ref
) && value
!= NULL
)
919 CFDictionarySetValue(output
, kSecValueData
, value
);
921 CFDictionaryRemoveValue(output
, kSecValueData
);
923 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
924 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
926 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
928 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
929 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
930 // Decode also certdata field of the identity.
931 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
933 CFDictionaryRef parsed_value
;
934 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
935 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
936 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
937 CFRelease(parsed_value
);
938 if (cert_data
== NULL
) {
939 // Retrieve value directly from the token.
940 if (cert_token
== NULL
) {
941 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, auth_params
, error
), out
);
943 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
944 if (CFEqual(cert_data
, kCFNull
))
945 CFReleaseNull(cert_data
);
947 if (cert_data
!= NULL
) {
948 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
950 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
957 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
, token
, object_id
, &ref
, error
), out
);
958 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
959 CFAssignRetained(*result
, ref
);
960 } else if (ref
!= NULL
) {
961 CFDictionarySetValue(output
, kSecValueRef
, ref
);
964 // We could have stored data value previously to make ref creation succeed.
965 // They are not needed any more and in case that caller did not want the data, avoid returning them.
966 CFDictionaryRemoveValue(output
, kSecValueData
);
971 if (wants_attributes
) {
972 // Convert serialized form of access control to object form.
974 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
977 if (ac_data
!= NULL
) {
978 SecAccessControlRef ac
;
979 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
980 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
991 CFReleaseSafe(cert_object_id
);
992 CFReleaseSafe(cert_data
);
993 CFReleaseSafe(ac_data
);
994 CFReleaseSafe(value
);
995 CFReleaseSafe(persistent_ref
);
996 CFReleaseSafe(object_id
);
997 CFReleaseSafe(attrs
);
998 CFReleaseSafe(token
);
999 CFReleaseSafe(cert_token
);
1003 static bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1004 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1006 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1007 require_action_quiet(result
!= NULL
, out
, ok
= true);
1009 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1010 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1011 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1012 for (i
= 0; i
< count
; i
++) {
1014 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1015 token
, query
, auth_params
, &ref
, error
), out
);
1017 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1022 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1031 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1033 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1034 void *la_lib
= NULL
;
1036 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1037 if (access_control
!= NULL
) {
1038 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
1039 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1042 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1044 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1045 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1046 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1047 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1048 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1049 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1050 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1051 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1052 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1053 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1054 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1057 // If a ref was specified we get its attribute dictionary and parse it.
1058 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1060 CFDictionaryRef ref_attributes
;
1061 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1062 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1064 /* Replace any attributes we already got from the ref with the ones
1065 from the attributes dictionary the caller passed us. This allows
1066 a caller to add an item using attributes from the ref and still
1067 override some of them in the dictionary directly. */
1068 CFMutableDictionaryRef new_query
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, ref_attributes
);
1069 CFRelease(ref_attributes
);
1070 CFDictionaryForEach(attrs
->dictionary
, ^(const void *key
, const void *value
) {
1071 if (!CFEqual(key
, kSecValueRef
))
1072 CFDictionarySetValue(new_query
, key
, value
);
1074 CFAssignRetained(attrs
->mutable_dictionary
, new_query
);
1075 attrs
->dictionary
= attrs
->mutable_dictionary
;
1078 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1080 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1081 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1083 CFTypeRef values
[] = { policy
};
1084 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1085 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1086 CFReleaseSafe(policiesArray
);
1087 require_action_quiet(policiesArrayXPC
, out
,
1088 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1090 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1091 xpc_release(policiesArrayXPC
);
1092 require_action_quiet(objectReadyForXPC
, out
,
1093 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1095 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1096 CFRelease(objectReadyForXPC
);
1098 #ifndef SECITEM_SHIM_OSX
1099 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1101 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1102 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1103 DERDecodedInfo content
;
1104 if (!DERDecodeItem(&name
, &content
) &&
1105 (content
.tag
== ASN1_CONSTR_SEQUENCE
))
1107 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1108 if (canonical_issuer
) {
1109 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1110 CFRelease(canonical_issuer
);
1119 if (la_lib
!= NULL
) {
1122 CFReleaseSafe(ac_data
);
1123 CFReleaseSafe(acm_context
);
1127 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1129 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1131 CFArrayForEachC(ac_pairs
, ac_pair
) {
1132 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1133 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1134 CFStringAppend(log_string
, str
);
1135 CFRelease(acl_hex_string
);
1139 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1140 SecError(errSecAuthFailed
, error
, reason
);
1141 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1144 CFRelease(log_string
);
1148 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
)) {
1150 CFArrayRef ac_pairs
= NULL
;
1151 SecCFDictionaryCOW auth_options
= { NULL
};
1153 for (uint32_t i
= 0;; ++i
) {
1154 // If the operation succeeded or failed with other than auth-needed error, just leave.
1155 SecItemAuthResult auth_result
= perform(auth_params
->dictionary
, &ac_pairs
, error
);
1156 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1157 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1159 // If auth_params were not created up to now, do create them because we will definitely need them.
1160 SecCFDictionaryCOWGetMutable(auth_params
);
1162 // Retrieve or create authentication handle and/or ACM context.
1163 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1164 if (auth_handle
== NULL
) {
1165 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1166 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1167 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1168 CFRelease(auth_handle
);
1169 if (acm_context
== NULL
) {
1170 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1171 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1172 CFRelease(acm_context
);
1176 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1177 // user retry limit.
1178 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1180 // Prepare auth options dictionary.
1181 if (auth_options
.dictionary
== NULL
) {
1182 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1183 if (operation_prompt
!= NULL
) {
1184 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1185 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1189 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1190 if (caller_name
!= NULL
) {
1191 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1192 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1196 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1197 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1198 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1199 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1204 // Go through all access_control-operation pairs and evaluate them.
1206 CFArrayForEachC(ac_pairs
, ac_pair
) {
1207 CFDataRef updated_acl
= NULL
;
1208 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1209 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1210 auth_options
.dictionary
, &updated_acl
, error
), out
);
1212 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1213 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1214 SecAccessControlRef ac
= NULL
;
1215 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1216 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1217 SecAccessControlSetBound(ac
, true);
1218 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1219 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1220 CFRelease(updated_acl
);
1229 CFReleaseSafe(auth_options
.mutable_dictionary
);
1230 CFReleaseSafe(ac_pairs
);
1234 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1235 // Store operation prompt.
1236 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1237 if (operation_prompt
!= NULL
) {
1238 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1239 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1242 // Store caller name.
1243 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1244 if (caller_name
!= NULL
) {
1245 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1246 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1249 // Find out whether we are allowed to pop up a UI.
1250 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1251 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1252 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1253 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1254 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1255 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1256 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1257 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1260 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1261 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1264 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1265 if (acm_context
!= NULL
) {
1266 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1270 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1272 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1273 // Extract ACLs to be verified from the error.
1274 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1275 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1276 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1277 if (*ac_pairs
== NULL
)
1278 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1281 CFRelease(user_info
);
1282 CFReleaseNull(*error
);
1283 return kSecItemAuthResultNeedAuth
;
1285 return kSecItemAuthResultError
;
1288 // Wrapper to handle automatic authentication and token/secd case switching.
1289 static bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1290 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1292 SecCFDictionaryCOW auth_params
= { NULL
};
1293 SecAccessControlRef access_control
= NULL
;
1294 __block TKTokenRef token
= NULL
;
1296 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1297 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1298 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1299 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1300 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1301 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1304 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1305 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1307 secItemOperation
== SecItemCopyMatching
||
1308 secItemOperation
== SecItemUpdate
||
1309 secItemOperation
== SecItemDelete
;
1311 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1312 if (attributes
!= NULL
)
1313 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1315 // Populate auth_params dictionary according to initial query contents.
1316 SecItemAuthCopyParams(&auth_params
, query
);
1318 if (secItemOperation
!= SecItemCopyMatching
) {
1319 // UISkip is allowed only for CopyMatching.
1320 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1321 SecError(errSecParam
, error
,
1322 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1325 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1326 SecItemAuthResult result
= kSecItemAuthResultError
;
1328 // Propagate actual credential reference to the query.
1329 if (auth_params
!= NULL
) {
1330 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
, kSecUseCredentialReference
);
1331 if (acm_context
!= NULL
) {
1332 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1335 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
, kSecAttrAccessControl
);
1336 if (acl_data_ref
!= NULL
) {
1337 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1341 // Prepare connection to target token if it is present.
1342 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1343 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1344 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, auth_params
, error
)), out
);
1347 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1348 if(!perform(token
, query
->dictionary
, attrs
, auth_params
, error
)) {
1349 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1352 result
= kSecItemAuthResultOK
;
1357 require_quiet(ok
, out
);
1362 CFReleaseSafe(token
);
1363 CFReleaseSafe(auth_params
.mutable_dictionary
);
1367 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1369 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1370 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1371 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1373 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1379 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1381 CFArrayRef result
= NULL
;
1382 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1383 if(success
&& !isArray(result
)){
1384 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1385 CFReleaseNull(result
);
1390 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1391 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1394 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1396 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1397 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1401 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1403 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1405 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1410 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1418 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1420 return dict_to_error_request(op
, query
, error
);
1423 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1424 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1425 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1426 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1427 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1428 keys
, ac_pairs
, 1));
1430 CFRelease(ac_pairs
[0]);
1435 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1436 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1437 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1438 // Replace error with the one which is augmented with access control and operation which failed,
1439 // which will cause SecItemDoWithAuth to throw UI.
1440 // Create array containing tuple (array) with error and requested operation.
1441 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1442 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1443 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1444 if (access_control
!= NULL
) {
1445 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1446 CFRelease(access_control
);
1452 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1453 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1454 SecAccessControlRef ac
= NULL
;
1456 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1457 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1458 if (ac_data
!= NULL
) {
1459 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1460 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1461 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1464 // Create or update the object on the token.
1465 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1466 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1468 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1469 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1470 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1471 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1472 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1474 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1475 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1479 CFReleaseSafe(access_control
);
1480 CFReleaseSafe(db_value
);
1481 return new_object_id
;
1484 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1485 CFTypeRef
*result
, CFErrorRef
*error
) {
1487 CFTypeRef object_id
= NULL
, ref
= NULL
;
1488 CFDictionaryRef ref_attrs
= NULL
;
1489 CFTypeRef db_result
= NULL
;
1491 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1492 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, NULL
, attrs
, error
), out
);
1494 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1495 // by creating ref and getting back its attributes.
1496 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1498 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1499 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1500 if (!CFEqual(key
, kSecValueData
)) {
1501 CFDictionaryAddValue(attrs
, key
, value
);
1507 // Make sure that both attributes and data are returned.
1508 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1509 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1511 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1512 // IsPermanent is not present or is true, so add item to the db.
1513 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1514 SecSecurityClientGet(), &db_result
, error
), out
);
1516 // Process directly result of token call.
1517 db_result
= CFRetain(attrs
);
1519 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1524 CFReleaseSafe(db_result
);
1525 CFReleaseSafe(attrs
);
1526 CFReleaseSafe(ref_attrs
);
1527 CFReleaseSafe(object_id
);
1532 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1533 __block SecCFDictionaryCOW attrs
= { attributes
};
1536 os_activity_t trace_activity
= os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1538 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1539 infer_cert_label(&attrs
);
1541 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1542 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1543 if (token
== NULL
) {
1544 CFTypeRef raw_result
= NULL
;
1545 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1548 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1549 CFReleaseSafe(raw_result
);
1552 // Send request to an appropriate token instead of secd.
1553 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1559 CFReleaseSafe(attrs
.mutable_dictionary
);
1561 os_activity_end(trace_activity
);
1566 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1568 __block SecCFDictionaryCOW query
= { inQuery
};
1570 os_activity_t trace_activity
= os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1572 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1574 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1575 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1576 if ((wants_data
&& !wants_attributes
) || (!wants_data
&& wants_attributes
)) {
1577 // When either attributes or data are requested, we need to query both, because for token based items,
1578 // both are needed in order to generate proper data and/or attributes results.
1579 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1580 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnData
, kCFBooleanTrue
);
1583 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1584 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1585 CFTypeRef raw_result
= NULL
;
1586 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1589 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1590 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1591 // to currently processed item.
1592 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1593 CFReleaseSafe(raw_result
);
1600 CFReleaseSafe(query
.mutable_dictionary
);
1601 os_activity_end(trace_activity
);
1605 // Invokes token-object handler for each item matching specified query.
1606 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1607 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1608 CFErrorRef
*error
)) {
1610 CFMutableDictionaryRef list_query
= NULL
;
1611 CFTypeRef items
= NULL
;
1612 CFArrayRef ref_array
= NULL
;
1613 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1615 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1616 // items in the keychain.
1617 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1618 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1619 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1621 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1622 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1623 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1624 SecSecurityClientGet(), &items
, error
), out
);
1625 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1626 // Wrap single returned item into the array.
1627 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1628 CFAssignRetained(items
, item_array
);
1632 CFArrayForEachC(items
, item
) {
1633 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1634 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1636 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1637 require_quiet(item_data
, out
);
1639 CFAssignRetained(item_query
,
1640 CFDictionaryCreateForCFTypes(NULL
,
1641 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1643 require_quiet(perform(item_data
, item_query
, error
), out
);
1649 CFReleaseSafe(list_query
);
1650 CFReleaseSafe(items
);
1651 CFReleaseSafe(item_data
);
1652 CFReleaseSafe(ref_array
);
1653 CFReleaseSafe(item_query
);
1657 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1660 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1661 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1662 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1663 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1666 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1668 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1669 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1670 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1672 ok
= securityd_message_no_error(reply
, error
);
1676 xpc_release(message
);
1682 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1683 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1685 CFDataRef object_id
= NULL
;
1686 CFMutableDictionaryRef db_value
= NULL
;
1688 // Update attributes on the token.
1689 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1690 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1691 attributes
, error
), out
);
1693 // Update attributes in the database.
1694 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1699 CFReleaseSafe(object_id
);
1700 CFReleaseSafe(attributes
);
1701 CFReleaseSafe(db_value
);
1706 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1707 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1708 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1713 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1714 CFDictionaryRef inAttributesToUpdate
,
1717 __block SecCFDictionaryCOW query
= { inQuery
};
1718 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1719 bool result
= false;
1721 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1724 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1725 if (token
== NULL
) {
1726 return SecItemRawUpdate(query
, attributes
, error
);
1728 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1733 CFReleaseSafe(query
.mutable_dictionary
);
1734 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1738 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1740 OSStatus status
= errSecSuccess
;
1741 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1743 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
)
1744 && CFEqual(class, kSecClassIdentity
)) {
1745 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1746 const void *vals
[] = { kCFBooleanTrue
, persist
};
1747 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1748 vals
, (array_size(keys
)), NULL
, NULL
);
1749 CFTypeRef item_query
= NULL
;
1750 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1751 CFReleaseNull(persistent_query
);
1755 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1756 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1757 CFRelease(item_query
);
1763 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1765 __block SecCFDictionaryCOW query
= { inQuery
};
1767 os_activity_t trace_activity
= os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1769 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1770 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1772 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1773 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1774 if (token
== NULL
) {
1775 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1777 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1780 // Delete item from the token.
1781 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1782 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1783 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1785 // Delete the item from the keychain.
1786 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1787 SecSecurityClientGet(), error
), out
);
1798 CFReleaseSafe(query
.mutable_dictionary
);
1800 os_activity_end(trace_activity
);
1806 SecItemDeleteAll(void)
1808 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1812 #ifndef SECITEM_SHIM_OSX
1813 SecTrustStoreRef ts
= SecTrustStoreForDomain(kSecTrustStoreDomainUser
);
1814 if (!gSecurityd
->sec_truststore_remove_all(ts
, error
))
1815 ok
= SecError(errSecInternal
, error
, CFSTR("sec_truststore_remove_all is NULL"));
1816 #endif // *** END SECITEM_SHIM_OSX ***
1817 if (!gSecurityd
->sec_item_delete_all(error
))
1818 ok
= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1820 ok
= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1827 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1829 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1830 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1834 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1835 os_activity_t trace_activity
= os_activity_start("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_FLAG_DEFAULT
);
1837 bool ok
= SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1838 SecSecurityClientGet(), error
);
1840 os_activity_end(trace_activity
);
1845 #if SECITEM_SHIM_OSX
1846 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1848 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1853 os_activity_t trace_activity
= os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT
);
1855 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1856 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
1857 if (tokenItemsAttributes
) {
1858 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1859 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
1860 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
1861 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
1862 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
1863 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
1864 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
1865 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
1867 CFRelease(tokenItems
);
1871 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
1872 CFDictionarySetValue(attributes
, kSecValueData
, data
);
1873 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
1874 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1875 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
1876 CFArrayAppendValue(tokenItems
, attributes
);
1877 CFRelease(attributes
);
1881 CFArrayAppendValue(tokenItems
, itemAttributes
);
1884 tmpArrayRef
= tokenItems
;
1887 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
1890 os_activity_end(trace_activity
);
1895 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
1896 __block CFArrayRef result
;
1897 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
1898 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
1903 #ifndef SECITEM_SHIM_OSX
1904 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1906 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
)
1908 return -1; /* this is only on OS X currently */
1913 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
1917 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1919 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
1921 do_if_registered(sec_roll_keys
, force
, error
);
1923 __block
bool result
= false;
1925 secdebug("secitem","enter - %s", __FUNCTION__
);
1926 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
1927 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1928 xpc_dictionary_set_bool(message
, "force", force
);
1931 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
1932 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);