2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
30 #include <Security/SecBasePriv.h>
31 #include <Security/SecItem.h>
32 #include <Security/SecItemPriv.h>
33 #include <Security/SecItemInternal.h>
34 #include <Security/SecItemShim.h>
35 #include <Security/SecAccessControl.h>
36 #include <Security/SecAccessControlPriv.h>
37 #include <Security/SecKey.h>
38 #include <Security/SecKeyPriv.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecIdentity.h>
41 #include <Security/SecIdentityPriv.h>
42 #include <Security/SecRandom.h>
43 #include <Security/SecBasePriv.h>
44 #include <Security/SecCTKKeyPriv.h>
45 #include <Security/SecTask.h>
46 #include <Security/SecPolicyInternal.h>
53 #include <sys/param.h>
55 #include <Security/SecBase.h>
56 #include <CoreFoundation/CFData.h>
57 #include <CoreFoundation/CFDate.h>
58 #include <CoreFoundation/CFDictionary.h>
59 #include <CoreFoundation/CFNumber.h>
60 #include <CoreFoundation/CFString.h>
61 #include <CoreFoundation/CFURL.h>
62 #include <CommonCrypto/CommonDigest.h>
63 #include <libkern/OSByteOrder.h>
64 #include <corecrypto/ccder.h>
65 #include <utilities/array_size.h>
66 #include <utilities/debugging.h>
67 #include <utilities/SecCFError.h>
68 #include <utilities/SecCFWrappers.h>
69 #include <utilities/SecIOFormat.h>
70 #include <utilities/SecXPCError.h>
71 #include <utilities/der_plist.h>
72 #include <utilities/der_plist_internal.h>
75 #include <libaks_acl_cf_keys.h>
76 #include <os/activity.h>
80 #include <Security/SecInternal.h>
81 #include "keychain/SecureObjectSync/SOSInternal.h"
82 #include <TargetConditionals.h>
83 #include <ipc/securityd_client.h>
84 #include <Security/SecuritydXPC.h>
85 #include <AssertMacros.h>
87 #include <sys/types.h>
91 #include <libDER/asn1Types.h>
93 #include <utilities/SecDb.h>
94 #include <IOKit/IOReturn.h>
96 #include <coreauthd_spi.h>
97 #include <LocalAuthentication/LAPrivateDefines.h>
98 #include <LocalAuthentication/LACFSupport.h>
100 #include <ctkclient/ctkclient.h>
103 * See corresponding definition in SecDbKeychainItemV7. This is the unserialized
104 * maximum, so the daemon's limit is not exactly the same.
106 #define REASONABLE_DATA_SIZE 4096
108 const CFStringRef kSecNetworkExtensionAccessGroupSuffix
= CFSTR("com.apple.networkextensionsharing");
110 /* Return an OSStatus for a sqlite3 error code. */
111 static OSStatus
osstatus_for_s3e(int s3e
)
117 return errSecSuccess
;
118 case SQLITE_READONLY
:
119 return errSecReadOnly
;
120 case SQLITE_CONSTRAINT
:
121 return errSecDuplicateItem
;
122 case SQLITE_ABORT
: // There is no errSecOperationCancelled
124 case SQLITE_MISMATCH
:
125 return errSecNoSuchAttr
;
127 return errSecAllocate
;
130 case SQLITE_INTERNAL
:
131 return errSecInternalComponent
;
132 case SQLITE_FULL
: // Happens if we run out of uniqueids or disk is full (TODO: replace with better code)
133 case SQLITE_PERM
: // No acess permission
134 case SQLITE_AUTH
: // No authorization (e.g. no class key for file)
135 case SQLITE_CANTOPEN
: // can be several reasons for this. Caller should sqlite3_system_errno()
136 case SQLITE_EMPTY
: // SQLite does not seem to use this. Was already here, so keeping
139 return errSecNotAvailable
;
143 static OSStatus
osstatus_for_kern_return(CFIndex kernResult
)
148 return errSecSuccess
;
149 case kIOReturnNotReadable
:
150 case kIOReturnNotWritable
:
151 return errSecAuthFailed
;
152 case kIOReturnNotPermitted
:
153 case kIOReturnNotPrivileged
:
154 case kIOReturnLockedRead
:
155 case kIOReturnLockedWrite
:
156 return errSecInteractionNotAllowed
;
159 case kIOReturnBadArgument
:
162 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
166 static OSStatus
osstatus_for_xpc_error(CFIndex xpcError
) {
169 case kSecXPCErrorSuccess
:
170 return errSecSuccess
;
171 case kSecXPCErrorUnexpectedType
:
172 case kSecXPCErrorUnexpectedNull
:
174 case kSecXPCErrorConnectionFailed
:
175 return errSecNotAvailable
;
176 case kSecXPCErrorUnknown
:
178 return errSecInternal
;
182 static OSStatus
osstatus_for_der_error(CFIndex derError
) {
185 case kSecDERErrorUnknownEncoding
:
186 case kSecDERErrorUnsupportedDERType
:
187 case kSecDERErrorUnsupportedNumberType
:
189 case kSecDERErrorUnsupportedCFObject
:
191 case kSecDERErrorAllocationFailure
:
192 return errSecAllocate
;
194 return errSecInternal
;
198 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
199 // Wrap LA error in Sec error.
201 case kLAErrorUserCancel
:
202 return errSecUserCanceled
;
203 case kLAErrorParameter
:
205 case kLAErrorNotInteractive
:
206 return errSecInteractionNotAllowed
;
208 return errSecAuthFailed
;
212 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
214 case kTKErrorCodeBadParameter
:
216 case kTKErrorCodeNotImplemented
:
217 return errSecUnimplemented
;
218 case kTKErrorCodeCanceledByUser
:
219 return errSecUserCanceled
;
220 case kTKErrorCodeCorruptedData
:
223 return errSecInternal
;
228 // Convert from securityd error codes to OSStatus for legacy API.
229 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
232 status
= errSecSuccess
;
234 CFStringRef domain
= CFErrorGetDomain(error
);
235 if (domain
== NULL
) {
236 secerror("No error domain for error: %@", error
);
237 status
= errSecInternal
;
238 } else if (CFEqual(kSecErrorDomain
, domain
)) {
239 status
= (OSStatus
)CFErrorGetCode(error
);
240 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
241 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
242 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
243 status
= (OSStatus
)CFErrorGetCode(error
);
244 } else if (CFEqual(kSecKernDomain
, domain
)) {
245 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
246 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
247 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
248 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
249 status
= osstatus_for_der_error(CFErrorGetCode(error
));
250 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
251 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
252 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
253 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
254 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
255 status
= errSecInternal
;
257 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
258 status
= errSecInternal
;
265 lastErrorReleaseError(void *value
)
272 getLastErrorKey(pthread_key_t
*kv
)
274 static pthread_key_t key
;
275 static bool haveKey
= false;
276 static dispatch_once_t onceToken
;
277 dispatch_once(&onceToken
, ^{
278 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
286 SetLastError(CFErrorRef newError
)
289 if (!getLastErrorKey(&key
))
291 CFErrorRef oldError
= pthread_getspecific(key
);
296 pthread_setspecific(key
, newError
);
300 SecCopyLastError(OSStatus status
)
305 if (!getLastErrorKey(&key
))
308 error
= pthread_getspecific(key
);
310 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
319 // Wrapper to provide a CFErrorRef for legacy API.
320 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
321 CFErrorRef error
= NULL
;
323 if (perform(&error
)) {
324 assert(error
== NULL
);
326 status
= errSecSuccess
;
330 status
= SecErrorGetOSStatus(error
);
331 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
332 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
333 CFReleaseNull(error
);
339 logUnreasonableDataLength(CFDictionaryRef attributes
)
344 if (isDictionary(attributes
)) {
345 data
= CFDictionaryGetValue(attributes
, kSecValueData
);
347 length
= CFDataGetLength(data
);
348 if (length
> REASONABLE_DATA_SIZE
) {
349 // This log message is vague, as we may not know anything else about the item.
350 // securityd logging (correlate by activity ID) will have more information.
351 secwarning("keychain item data exceeds reasonable size (%lu bytes)", (unsigned long)length
);
357 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
358 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
361 static CFDictionaryRef
362 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
364 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
365 if (filtered
== NULL
)
367 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
368 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
369 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
370 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
371 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
372 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
373 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
374 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
375 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
376 CFDictionaryRemoveValue(filtered
, kSecAttrIsPermanent
);
382 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
383 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
385 Currently in need of conversion below:
386 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
387 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
388 currently implemented at all, but when it is needs to short circuit to
389 local evaluation, different from the sql query abilities
392 static CFDictionaryRef
393 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
394 CFDictionaryRef refDictionary
= NULL
;
395 CFTypeID typeID
= CFGetTypeID(ref
);
396 if (typeID
== SecKeyGetTypeID()) {
397 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
398 if (refDictionary
&& forQuery
) {
399 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
400 CFAssignRetained(refDictionary
, filtered
);
402 } else if (typeID
== SecCertificateGetTypeID()) {
403 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
404 } else if (typeID
== SecIdentityGetTypeID()) {
406 SecIdentityRef identity
= (SecIdentityRef
)ref
;
407 SecCertificateRef cert
= NULL
;
408 SecKeyRef key
= NULL
;
409 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
410 !SecIdentityCopyPrivateKey(identity
, &key
))
412 CFDataRef data
= SecCertificateCopyData(cert
);
413 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
415 if (key_dict
&& data
) {
416 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
417 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
419 CFReleaseNull(key_dict
);
425 return refDictionary
;
428 #ifdef SECITEM_SHIM_OSX
429 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
433 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
434 CFTypeRef ref
= NULL
;
435 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
436 if (CFEqual(class, kSecClassKey
)) {
437 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
438 } else if (CFEqual(class, kSecClassCertificate
)) {
439 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
440 } else if (CFEqual(class, kSecClassIdentity
)) {
441 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
442 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
443 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
445 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
448 secerror("SecItem: failed to create identity");
453 #ifdef SECITEM_SHIM_OSX
455 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
463 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
466 return -1 /* errSecUnimplemented */;
468 #endif // TARGET_OS_OSX
470 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
472 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
473 OSStatus
*return_status
, CFTypeRef
*return_result
)
475 bool handled
= false;
476 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
478 CFTypeID typeID
= CFGetTypeID(value
);
479 if (typeID
== SecIdentityGetTypeID()) {
481 OSStatus status
= errSecSuccess
;
482 SecIdentityRef identity
= (SecIdentityRef
)value
;
483 SecCertificateRef cert
= NULL
;
484 SecKeyRef key
= NULL
;
485 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
486 !SecIdentityCopyPrivateKey(identity
, &key
))
488 CFMutableDictionaryRef partial_query
=
489 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
490 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
491 CFTypeRef result
= NULL
;
492 bool duplicate_cert
= false;
493 /* an identity is first and foremost a key, but it can have multiple
494 certs associated with it: so we identify it by the cert */
495 status
= operation(partial_query
, return_result
? &result
: NULL
);
496 if ((operation
== (secitem_operation
)SecItemAdd
) &&
497 (status
== errSecDuplicateItem
)) {
498 duplicate_cert
= true;
499 status
= errSecSuccess
;
502 if (!status
|| status
== errSecItemNotFound
) {
503 bool skip_key_operation
= false;
505 /* if the key is still in use, skip deleting it */
506 if (operation
== (secitem_operation
)SecItemDelete
) {
507 // find certs with cert.pkhh == keys.klbl
508 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
509 CFDataRef pkhh
= NULL
;
511 key_dict
= SecKeyCopyAttributeDictionary(key
);
513 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
514 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
515 const void *vals
[] = { kSecClassCertificate
, pkhh
};
517 query_dict
= CFDictionaryCreate(NULL
, keys
,
518 vals
, (array_size(keys
)),
521 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
522 skip_key_operation
= true;
523 CFReleaseSafe(query_dict
);
524 CFReleaseSafe(key_dict
);
527 if (!skip_key_operation
) {
528 /* now perform the operation for the key */
529 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
530 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
532 status
= operation(partial_query
, NULL
);
533 if ((operation
== (secitem_operation
)SecItemAdd
) &&
534 (status
== errSecDuplicateItem
) &&
536 status
= errSecSuccess
;
539 /* add and copy matching for an identityref have a persistent ref result */
542 /* result is a persistent ref to a cert */
544 CFDictionaryRef tokenAttrs
= NULL
;
545 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
, &tokenAttrs
)) {
546 *return_result
= _SecItemCreatePersistentRef(kSecClassIdentity
, rowid
, tokenAttrs
);
548 CFReleaseNull(tokenAttrs
);
553 CFReleaseNull(partial_query
);
556 status
= errSecInvalidItemRef
;
560 *return_status
= status
;
563 value
= CFDictionaryGetValue(attributes
, kSecClass
);
564 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
565 (operation
== (secitem_operation
)SecItemDelete
)) {
566 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
567 CFDictionaryRemoveValue(dict
, kSecClass
);
568 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
569 OSStatus status
= SecItemDelete(dict
);
571 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
572 status
= SecItemDelete(dict
);
575 *return_status
= status
;
583 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
586 CFErrorRef lastError
= SecCopyLastError(status
);
588 CFErrorPropagate(lastError
, error
);
590 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
597 handleUpdateIdentity(CFDictionaryRef query
,
598 CFDictionaryRef update
,
602 CFMutableDictionaryRef updatedQuery
= NULL
;
603 SecCertificateRef cert
= NULL
;
604 SecKeyRef key
= NULL
;
605 bool handled
= false;
609 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
611 CFTypeID typeID
= CFGetTypeID(value
);
612 if (typeID
== SecIdentityGetTypeID()) {
613 SecIdentityRef identity
= (SecIdentityRef
)value
;
618 status
= SecIdentityCopyCertificate(identity
, &cert
);
619 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
621 status
= SecIdentityCopyPrivateKey(identity
, &key
);
622 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
624 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
625 require_action_quiet(updatedQuery
, errOut
, *result
= false);
627 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
628 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
630 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
631 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
635 value
= CFDictionaryGetValue(query
, kSecClass
);
636 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
639 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
640 require_action_quiet(updatedQuery
, errOut
, *result
= false);
642 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
643 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
645 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
646 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
648 CFReleaseNull(updatedQuery
);
653 CFReleaseNull(updatedQuery
);
659 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
661 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
662 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
663 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
664 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
665 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
667 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
668 CFReleaseNull(label
);
674 static CFDataRef
CreateTokenPersistentRefData(CFTypeRef
class, CFDictionaryRef attributes
)
676 CFDataRef tokenPersistentRef
= NULL
;
677 CFStringRef tokenId
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
678 CFDictionaryRef itemValue
= NULL
;
679 if (CFEqual(class, kSecClassIdentity
)) {
680 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecAttrIdentityCertificateData
), NULL
);
682 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecValueData
), NULL
);
684 require(itemValue
, out
);
685 CFDataRef oid
= CFDictionaryGetValue(itemValue
, kSecTokenValueObjectIDKey
);
687 CFArrayRef array
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, class, tokenId
, oid
, NULL
);
688 tokenPersistentRef
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, NULL
);
691 CFReleaseNull(itemValue
);
692 return tokenPersistentRef
;
695 static const uint8_t tk_persistent_ref_id
[] = {'t', 'k', 'p', 'r'};
696 /* A persistent ref is just the class and the rowid of the record.
697 Persistent ref for token items is a der blob with class, tokenID and objectId. */
698 CFDataRef
_SecItemCreatePersistentRef(CFTypeRef
class, sqlite_int64 rowid
, CFDictionaryRef attributes
)
700 CFDataRef result
= NULL
;
701 if (attributes
&& CFDictionaryContainsKey(attributes
, CFEqual(class, kSecClassIdentity
) ? kSecAttrIdentityCertificateTokenID
: kSecAttrTokenID
)) {
702 CFDataRef tokenPersistentRef
= CreateTokenPersistentRefData(class, attributes
);
703 require(tokenPersistentRef
, out
);
704 CFMutableDataRef tmpData
= CFDataCreateMutable(kCFAllocatorDefault
, sizeof(tk_persistent_ref_id
) + CFDataGetLength(tokenPersistentRef
));
705 CFDataAppendBytes(tmpData
, tk_persistent_ref_id
, sizeof(tk_persistent_ref_id
));
706 CFDataAppend(tmpData
, tokenPersistentRef
);
707 CFReleaseNull(tokenPersistentRef
);
710 require(rowid
>= 0, out
);
711 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
712 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
713 kCFStringEncodingUTF8
))
715 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
716 result
= CFDataCreate(NULL
, bytes
, sizeof(bytes
));
723 static Boolean
isValidClass(CFStringRef
class, CFStringRef
*return_class
) {
724 const void *valid_classes
[] = { kSecClassGenericPassword
,
725 kSecClassInternetPassword
,
726 kSecClassAppleSharePassword
,
727 kSecClassCertificate
,
731 for (size_t i
= 0; i
< array_size(valid_classes
); i
++) {
732 if (CFEqual(valid_classes
[i
], class)) {
734 *return_class
= valid_classes
[i
];
742 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref
, CFStringRef
*return_class
, CFDictionaryRef
*return_token_attrs
) {
743 bool valid_ref
= false;
744 CFPropertyListRef pl
= NULL
;
745 const uint8_t *der
= CFDataGetBytePtr(persistent_ref
) + sizeof(tk_persistent_ref_id
);
746 const uint8_t *der_end
= der
+ (CFDataGetLength(persistent_ref
) - sizeof(tk_persistent_ref_id
));
747 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &pl
, NULL
, der
, der_end
), out
);
748 require_quiet(der
== der_end
, out
);
749 require_quiet(CFGetTypeID(pl
) == CFArrayGetTypeID(), out
);
750 require_quiet(CFArrayGetCount(pl
) == 3, out
);
751 require_quiet(valid_ref
= isValidClass(CFArrayGetValueAtIndex(pl
, 0), return_class
), out
);
752 if (return_token_attrs
) {
753 *return_token_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
754 kSecAttrTokenID
, CFArrayGetValueAtIndex(pl
, 1),
755 kSecAttrTokenOID
, CFArrayGetValueAtIndex(pl
, 2), NULL
);
762 /* AUDIT[securityd](done):
763 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
765 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
, CFDictionaryRef
*return_token_attrs
)
767 bool valid_ref
= false;
768 require(CFGetTypeID(persistent_ref
) == CFDataGetTypeID(), out
);
770 if (CFDataGetLength(persistent_ref
) > (CFIndex
)sizeof(tk_persistent_ref_id
) &&
771 memcmp(tk_persistent_ref_id
, CFDataGetBytePtr(persistent_ref
), sizeof(tk_persistent_ref_id
)) == 0) {
772 valid_ref
= ParseTokenPersistentRefData(persistent_ref
, return_class
, return_token_attrs
);
773 } else if (CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
774 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
775 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
777 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
778 bytes
, CFStringGetLength(kSecClassGenericPassword
),
779 kCFStringEncodingUTF8
, true);
781 if ((valid_ref
= isValidClass(class, return_class
))) {
783 *return_rowid
= rowid
;
791 static bool cf_bool_value(CFTypeRef cf_bool
) {
792 return cf_bool
&& CFBooleanGetValue(cf_bool
);
795 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
796 if (cow_dictionary
->mutable_dictionary
== NULL
) {
797 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
798 if (cow_dictionary
->dictionary
!= NULL
) {
799 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
800 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
803 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
806 return cow_dictionary
->mutable_dictionary
;
809 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
810 // access_control and optionally of the data value.
811 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
812 CFMutableDictionaryRef value
= NULL
;
813 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
814 kSecTokenValueObjectIDKey
, oid
,
815 kSecTokenValueAccessControlKey
, access_control
,
817 if (object_value
!= NULL
) {
818 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
821 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
826 CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
827 CFPropertyListRef plist
= NULL
;
828 const uint8_t *der
= CFDataGetBytePtr(db_value
);
829 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
830 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
831 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
832 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
833 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
839 TKTokenRef
SecTokenCreate(CFStringRef token_id
, SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
) {
840 CFMutableDictionaryRef token_attrs
= NULL
;
841 TKTokenRef token
= NULL
;
843 static CFMutableDictionaryRef sharedLAContexts
= NULL
;
844 static dispatch_once_t onceToken
;
845 static os_unfair_lock lock
= OS_UNFAIR_LOCK_INIT
;
846 if ((auth_params
->dictionary
== NULL
|| CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
) == NULL
) && !CFStringHasPrefix(token_id
, kSecAttrTokenIDSecureEnclave
)) {
847 dispatch_once(&onceToken
, ^{
848 sharedLAContexts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
851 os_unfair_lock_lock(&lock
);
852 CFTypeRef ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
854 ctx
= LACreateNewContextWithACMContext(NULL
, error
);
856 os_unfair_lock_unlock(&lock
);
857 secerror("Failed to create authentication context %@", *error
);
860 CFDictionarySetValue(sharedLAContexts
, token_id
, ctx
);
862 ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
865 CFDataRef credRef
= NULL
;
867 credRef
= LACopyACMContext(ctx
, NULL
);
871 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, ctx
);
872 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, credRef
);
875 os_unfair_lock_unlock(&lock
);
878 token_attrs
= (auth_params
->dictionary
!= NULL
) ?
879 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
->dictionary
) :
880 CFDictionaryCreateMutableForCFTypes(NULL
);
881 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
883 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
884 token
= TKTokenCreate(token_attrs
, error
);
886 CFReleaseSafe(token_attrs
);
890 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params_dict
,
891 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
893 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
894 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
895 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
896 if (token_id
!= NULL
&& object_id
!= NULL
) {
897 if (CFRetainSafe(token
) == NULL
) {
898 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
901 if (auth_params
.dictionary
!= NULL
) {
902 CFDictionaryForEach(auth_params
.dictionary
, ^(const void *key
, const void *value
) {
903 CFDictionaryAddValue(attrs
, key
, value
);
906 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
907 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
910 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
914 CFReleaseSafe(attrs
);
915 CFReleaseSafe(auth_params
.mutable_dictionary
);
920 /* Turn the returned single value or dictionary that contains all the attributes to create a
921 ref into the exact result the client asked for */
922 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
923 CFDictionaryRef query
, CFDictionaryRef auth_params_dict
,
924 CFTypeRef
*result
, CFErrorRef
*error
) {
926 CFDataRef ac_data
= NULL
;
927 CFDataRef value
= NULL
;
928 CFTypeRef persistent_ref
= NULL
;
929 CFStringRef token_id
= NULL
;
930 CFStringRef cert_token_id
= NULL
;
931 CFDataRef object_id
= NULL
;
932 CFMutableDictionaryRef attrs
= NULL
;
933 CFDataRef cert_data
= NULL
;
934 CFDataRef cert_object_id
= NULL
;
935 TKTokenRef cert_token
= NULL
;
936 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
938 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
939 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
940 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
941 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
943 // Get token value if not provided by the caller.
944 bool token_item
= false;
945 bool cert_token_item
= false;
947 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
948 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
949 token_item
= (token_id
!= NULL
);
951 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
952 cert_token_item
= (cert_token_id
!= NULL
);
956 cert_token_item
= true;
958 CFRetainAssign(cert_token
, token
);
961 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
963 cert_token_item
= false;
966 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
967 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
968 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
969 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
971 value
= CFRetainSafe(raw_result
);
972 if (token_item
&& value
!= NULL
) {
973 // Parse token-based item's data field.
974 CFDataRef object_value
= NULL
;
975 CFDictionaryRef parsed_value
= NULL
;
976 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
977 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
978 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
979 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
980 CFRelease(parsed_value
);
981 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
982 // Retrieve value directly from the token.
984 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
986 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
987 if (CFEqual(object_value
, kCFNull
))
988 CFReleaseNull(object_value
);
990 CFAssignRetained(value
, object_value
);
993 // If only thing requested is data, return them directly.
994 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
995 *result
= CFRetainSafe(value
);
1001 // Extract persistent_ref, if caller wants it.
1002 if (wants_persistent_ref
) {
1003 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
1004 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
1006 persistent_ref
= CFRetainSafe(raw_result
);
1008 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
1009 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
1010 *result
= CFRetainSafe(persistent_ref
);
1016 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
1022 // For other cases we need an output dictionary.
1023 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
1024 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
1026 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
1027 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
1029 if ((wants_data
|| wants_ref
) && value
!= NULL
)
1030 CFDictionarySetValue(output
, kSecValueData
, value
);
1032 CFDictionaryRemoveValue(output
, kSecValueData
);
1034 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
1035 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
1037 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
1039 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
1040 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
1041 // Decode also certdata field of the identity.
1042 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
1044 CFDictionaryRef parsed_value
;
1045 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
1046 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
1047 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
1048 CFRelease(parsed_value
);
1049 if (cert_data
== NULL
) {
1050 // Retrieve value directly from the token.
1051 if (cert_token
== NULL
) {
1052 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, &auth_params
, error
), out
);
1054 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1055 if (CFEqual(cert_data
, kCFNull
))
1056 CFReleaseNull(cert_data
);
1058 if (cert_data
!= NULL
) {
1059 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1061 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1066 if (wants_ref
|| wants_attributes
) {
1067 // Convert serialized form of access control to object form.
1069 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1072 if (ac_data
!= NULL
) {
1073 SecAccessControlRef ac
;
1074 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1075 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1082 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
.dictionary
, token
, object_id
, &ref
, error
), out
);
1083 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1084 CFAssignRetained(*result
, ref
);
1085 } else if (ref
!= NULL
) {
1086 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1089 // We could have stored data value previously to make ref creation succeed.
1090 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1091 CFDictionaryRemoveValue(output
, kSecValueData
);
1099 CFReleaseSafe(cert_object_id
);
1100 CFReleaseSafe(cert_data
);
1101 CFReleaseSafe(ac_data
);
1102 CFReleaseSafe(value
);
1103 CFReleaseSafe(persistent_ref
);
1104 CFReleaseSafe(object_id
);
1105 CFReleaseSafe(attrs
);
1106 CFReleaseSafe(token
);
1107 CFReleaseSafe(cert_token
);
1108 CFReleaseSafe(auth_params
.mutable_dictionary
);
1112 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1113 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1115 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1116 require_action_quiet(result
!= NULL
, out
, ok
= true);
1118 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1119 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1120 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1121 for (i
= 0; i
< count
; i
++) {
1123 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1124 token
, query
, auth_params
, &ref
, error
), out
);
1126 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1131 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1140 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1141 void *la_lib
= NULL
;
1142 CFDataRef acm_context
= NULL
;
1143 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1144 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1145 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1146 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1147 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1148 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1149 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1151 if (la_lib
!= NULL
) {
1157 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1159 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1160 void *la_lib
= NULL
;
1162 // If a ref was specified we get its attribute dictionary and parse it.
1163 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1165 CFDictionaryRef ref_attributes
;
1166 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1167 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1169 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1170 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1171 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1172 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1173 // so add only those attributes from 'ref' which are missing in attrs.
1174 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1176 CFRelease(ref_attributes
);
1179 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1182 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1183 // another roundtrip to token driver.
1184 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1185 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1189 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1190 if (access_control
!= NULL
) {
1191 require_action_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
,
1192 SecError(errSecParam
, error
, CFSTR("unsupported kSecAttrAccessControl in query")));
1193 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1196 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1198 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1199 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1200 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1201 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1202 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1205 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1207 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1208 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1210 CFTypeRef values
[] = { policy
};
1211 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1212 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1213 CFReleaseSafe(policiesArray
);
1214 require_action_quiet(policiesArrayXPC
, out
,
1215 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1217 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1218 xpc_release(policiesArrayXPC
);
1219 require_action_quiet(objectReadyForXPC
, out
,
1220 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1222 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1223 CFRelease(objectReadyForXPC
);
1225 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1227 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1228 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1229 DERDecodedInfo content
;
1230 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1231 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1232 if (canonical_issuer
) {
1233 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1234 CFRelease(canonical_issuer
);
1239 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1240 // This use flag is client-only, securityd does not understand it.
1241 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1247 if (la_lib
!= NULL
) {
1250 CFReleaseSafe(ac_data
);
1251 CFReleaseSafe(acm_context
);
1255 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1257 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1259 CFArrayForEachC(ac_pairs
, ac_pair
) {
1260 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1261 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1262 CFStringAppend(log_string
, str
);
1263 CFRelease(acl_hex_string
);
1267 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1268 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1269 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1271 CFRelease(log_string
);
1275 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1276 void (^newCredentialRefAdded
)(void)) {
1278 CFArrayRef ac_pairs
= NULL
;
1279 SecCFDictionaryCOW auth_options
= { NULL
};
1281 for (uint32_t i
= 0;; ++i
) {
1282 // If the operation succeeded or failed with other than auth-needed error, just leave.
1283 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1284 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1285 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1287 // If auth_params were not created up to now, do create them because we will definitely need them.
1288 SecCFDictionaryCOWGetMutable(auth_params
);
1290 // Retrieve or create authentication handle and/or ACM context.
1291 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1292 if (auth_handle
== NULL
) {
1293 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1294 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1295 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1296 CFRelease(auth_handle
);
1297 if (acm_context
== NULL
) {
1298 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1299 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1300 CFRelease(acm_context
);
1301 if (newCredentialRefAdded
) {
1302 newCredentialRefAdded();
1307 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1308 // user retry limit.
1309 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1311 // Prepare auth options dictionary.
1312 if (auth_options
.dictionary
== NULL
) {
1313 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1314 if (operation_prompt
!= NULL
) {
1315 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1316 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1320 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1321 if (caller_name
!= NULL
) {
1322 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1323 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1327 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1328 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1329 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1330 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1335 // Go through all access_control-operation pairs and evaluate them.
1337 CFArrayForEachC(ac_pairs
, ac_pair
) {
1338 CFDataRef updated_acl
= NULL
;
1339 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1340 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1341 auth_options
.dictionary
, &updated_acl
, error
), out
);
1343 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1344 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1345 SecAccessControlRef ac
= NULL
;
1346 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1347 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1348 SecAccessControlSetBound(ac
, true);
1349 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1350 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1351 CFRelease(updated_acl
);
1360 CFReleaseSafe(auth_options
.mutable_dictionary
);
1361 CFReleaseSafe(ac_pairs
);
1365 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1366 // Store operation prompt.
1367 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1368 if (operation_prompt
!= NULL
) {
1369 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1370 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1373 // Store caller name.
1374 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1375 if (caller_name
!= NULL
) {
1376 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1377 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1380 // Find out whether we are allowed to pop up a UI.
1381 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1382 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1383 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1384 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1385 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1386 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1387 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1388 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1391 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1392 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1395 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1396 if (acm_context
!= NULL
) {
1397 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1401 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1403 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1404 // Extract ACLs to be verified from the error.
1405 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1406 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1407 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1408 if (*ac_pairs
== NULL
)
1409 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1412 CFRelease(user_info
);
1413 CFReleaseNull(*error
);
1414 return kSecItemAuthResultNeedAuth
;
1416 return kSecItemAuthResultError
;
1419 // Wrapper to handle automatic authentication and token/secd case switching.
1420 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1421 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1423 __block SecCFDictionaryCOW auth_params
= { NULL
};
1424 SecAccessControlRef access_control
= NULL
;
1425 __block TKTokenRef token
= NULL
;
1427 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1428 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1429 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1430 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1431 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1432 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1435 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1436 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1438 secItemOperation
== SecItemCopyMatching
||
1439 secItemOperation
== SecItemUpdate
||
1440 secItemOperation
== SecItemDelete
;
1442 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1443 if (attributes
!= NULL
)
1444 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1446 // Populate auth_params dictionary according to initial query contents.
1447 SecItemAuthCopyParams(&auth_params
, query
);
1449 if (secItemOperation
!= SecItemCopyMatching
) {
1450 // UISkip is allowed only for CopyMatching.
1451 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1452 SecError(errSecParam
, error
,
1453 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1456 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1457 SecItemAuthResult result
= kSecItemAuthResultError
;
1459 // Propagate actual credential reference to the query.
1460 if (auth_params
.dictionary
!= NULL
) {
1461 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1462 if (acm_context
!= NULL
) {
1463 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1466 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1467 if (acl_data_ref
!= NULL
) {
1468 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1472 // Prepare connection to target token if it is present.
1473 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1474 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1475 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, &auth_params
, error
)), out
);
1478 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1479 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1480 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1483 result
= kSecItemAuthResultOK
;
1488 require_quiet(ok
, out
);
1493 CFReleaseSafe(token
);
1494 CFReleaseSafe(auth_params
.mutable_dictionary
);
1498 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1500 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1501 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1502 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1504 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1510 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1512 CFArrayRef result
= NULL
;
1513 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1514 if(success
&& !isArray(result
)){
1515 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1516 CFReleaseNull(result
);
1521 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1522 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1525 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1527 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1528 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1532 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1534 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1536 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1541 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1549 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1551 return dict_to_error_request(op
, query
, error
);
1554 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1555 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1556 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1557 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1558 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1559 keys
, ac_pairs
, 1));
1561 CFRelease(ac_pairs
[0]);
1566 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1567 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1568 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationNeeded
) {
1569 // Replace error with the one which is augmented with access control and operation which failed,
1570 // which will cause SecItemDoWithAuth to throw UI.
1571 // Create array containing tuple (array) with error and requested operation.
1572 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
);
1573 if (access_control
!= NULL
) {
1574 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1575 CFRelease(access_control
);
1581 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1582 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
, result
= NULL
;
1583 SecAccessControlRef ac
= NULL
;
1584 CFDictionaryRef old_attrs
= NULL
;
1586 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1587 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1588 if (ac_data
!= NULL
) {
1589 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1590 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1591 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1594 // Create or update the object on the token.
1595 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1596 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1597 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1598 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1599 if (!CFEqual(key
, kSecValueData
)) {
1600 CFDictionaryAddValue(attributes
, key
, value
);
1604 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1605 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1606 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1607 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1608 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1610 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1611 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1612 CFRetainAssign(result
, new_object_id
);
1616 CFReleaseSafe(access_control
);
1617 CFReleaseSafe(db_value
);
1618 CFReleaseSafe(old_attrs
);
1619 CFReleaseSafe(new_object_id
);
1623 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1624 CFTypeRef
*result
, CFErrorRef
*error
) {
1626 CFTypeRef object_id
= NULL
, ref
= NULL
;
1627 CFDictionaryRef ref_attrs
= NULL
;
1628 CFTypeRef db_result
= NULL
;
1629 CFDataRef db_value
= NULL
;
1630 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1632 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1633 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1634 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1635 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1636 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1637 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1638 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1639 // the ref from the dictionary since it is of no use any more.
1640 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1642 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1643 // by creating ref and getting back its attributes.
1644 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1646 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1647 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1648 if (!CFEqual(key
, kSecValueData
)) {
1649 CFDictionaryAddValue(attrs
, key
, value
);
1656 // Make sure that both attributes and data are returned.
1657 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1658 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1660 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1661 // IsPermanent is not present or is true, so add item to the db.
1662 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1663 SecSecurityClientGet(), &db_result
, error
), out
);
1665 // Process directly result of token call.
1666 db_result
= CFRetain(attrs
);
1668 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1672 CFReleaseSafe(db_result
);
1673 CFReleaseSafe(db_value
);
1674 CFReleaseSafe(attrs
);
1675 CFReleaseSafe(ref_attrs
);
1676 CFReleaseSafe(object_id
);
1681 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1682 __block SecCFDictionaryCOW attrs
= { attributes
};
1685 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1686 os_activity_scope(activity
);
1687 os_release(activity
);
1689 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1690 infer_cert_label(&attrs
);
1692 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1693 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1694 if (token
== NULL
) {
1695 CFTypeRef raw_result
= NULL
;
1696 logUnreasonableDataLength(attributes
);
1697 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1700 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1701 CFReleaseSafe(raw_result
);
1704 // Send request to an appropriate token instead of secd.
1705 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1711 CFReleaseSafe(attrs
.mutable_dictionary
);
1712 secdebug("secitem", "SecItemAdd returned: %d", (int)status
);
1718 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1720 __block SecCFDictionaryCOW query
= { inQuery
};
1722 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1723 os_activity_scope(activity
);
1724 os_release(activity
);
1726 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1728 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1729 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1730 if ((wants_data
&& !wants_attributes
)) {
1731 // When either attributes or data are requested, we need to query both, because for token based items,
1732 // both are needed in order to generate proper data and/or attributes results.
1733 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1736 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1737 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1738 CFTypeRef raw_result
= NULL
;
1739 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1742 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1743 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1744 // to currently processed item.
1745 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1746 CFReleaseSafe(raw_result
);
1752 secdebug("secitem", "SecItemCopyMatching_ios returned: %d", (int)status
);
1753 CFReleaseSafe(query
.mutable_dictionary
);
1757 // Invokes token-object handler for each item matching specified query.
1758 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1759 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1760 CFErrorRef
*error
)) {
1762 CFMutableDictionaryRef list_query
= NULL
;
1763 CFTypeRef items
= NULL
;
1764 CFArrayRef ref_array
= NULL
;
1765 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1767 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1768 // items in the keychain.
1769 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1770 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1771 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1773 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1774 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1775 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1776 SecSecurityClientGet(), &items
, error
), out
);
1777 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1778 // Wrap single returned item into the array.
1779 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1780 CFAssignRetained(items
, item_array
);
1784 CFArrayForEachC(items
, item
) {
1785 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1786 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1788 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1789 require_quiet(item_data
, out
);
1791 CFAssignRetained(item_query
,
1792 CFDictionaryCreateForCFTypes(NULL
,
1793 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1795 require_quiet(perform(item_data
, item_query
, error
), out
);
1801 CFReleaseSafe(list_query
);
1802 CFReleaseSafe(items
);
1803 CFReleaseSafe(item_data
);
1804 CFReleaseSafe(ref_array
);
1805 CFReleaseSafe(item_query
);
1809 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1812 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1813 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1814 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1815 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1818 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1820 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1821 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1822 logUnreasonableDataLength(attributesToUpdate
);
1823 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1825 ok
= securityd_message_no_error(reply
, error
);
1829 xpc_release(message
);
1835 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1836 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1838 CFDataRef object_id
= NULL
;
1839 CFMutableDictionaryRef db_value
= NULL
;
1841 // Update attributes on the token.
1842 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1843 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1844 attributes
, error
), out
);
1846 // Update attributes in the database.
1847 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1852 CFReleaseSafe(object_id
);
1853 CFReleaseSafe(attributes
);
1854 CFReleaseSafe(db_value
);
1859 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1860 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1861 os_activity_scope(activity
);
1862 os_release(activity
);
1864 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1865 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1870 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1871 CFDictionaryRef inAttributesToUpdate
,
1874 __block SecCFDictionaryCOW query
= { inQuery
};
1875 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1876 bool result
= false;
1878 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1881 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1882 if (token
== NULL
) {
1883 return SecItemRawUpdate(query
, attributes
, error
);
1885 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1890 CFReleaseSafe(query
.mutable_dictionary
);
1891 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1892 secdebug("secitem", "SecItemUpdateWithError returned: %d", (int)result
);
1896 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1898 OSStatus status
= errSecSuccess
;
1899 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1901 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1902 && CFEqual(class, kSecClassIdentity
)) {
1903 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1904 const void *vals
[] = { kCFBooleanTrue
, persist
};
1905 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1906 vals
, (array_size(keys
)), NULL
, NULL
);
1907 CFTypeRef item_query
= NULL
;
1908 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1909 CFReleaseNull(persistent_query
);
1912 if (item_query
== NULL
)
1913 return errSecItemNotFound
;
1915 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1916 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1917 CFRelease(item_query
);
1923 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1925 __block SecCFDictionaryCOW query
= { inQuery
};
1927 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1928 os_activity_scope(activity
);
1929 os_release(activity
);
1931 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1932 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1934 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1935 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1936 if (token
== NULL
) {
1937 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1939 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1942 // Delete item from the token.
1943 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1944 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1945 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1947 // Delete the item from the keychain.
1948 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1949 SecSecurityClientGet(), error
), out
);
1960 CFReleaseSafe(query
.mutable_dictionary
);
1961 secdebug("secitem", "SecItemDelete returned: %d", (int)status
);
1967 SecItemDeleteAll(void)
1969 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1972 if (!gSecurityd
->sec_item_delete_all(error
))
1973 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1975 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1983 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1985 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1986 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1991 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1993 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1994 os_activity_scope(activity
);
1995 os_release(activity
);
1997 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1998 SecSecurityClientGet(), error
);
2005 #if SECITEM_SHIM_OSX
2006 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
2008 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
2013 os_activity_t activity
= os_activity_create("SecItemUpdateTokenItems_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2014 os_activity_scope(activity
);
2015 os_release(activity
);
2017 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
2018 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
2019 if (tokenItemsAttributes
) {
2020 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
2021 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
2022 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
2023 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
2024 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
2025 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
2026 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
2027 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
2029 CFRelease(tokenItems
);
2033 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
2034 CFDictionarySetValue(attributes
, kSecValueData
, data
);
2035 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
2036 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2037 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2038 CFArrayAppendValue(tokenItems
, attributes
);
2039 CFRelease(attributes
);
2043 CFArrayAppendValue(tokenItems
, itemAttributes
);
2046 tmpArrayRef
= tokenItems
;
2049 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2055 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2056 __block CFArrayRef result
;
2057 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2058 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2063 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2065 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2067 do_if_registered(sec_roll_keys
, force
, error
);
2069 __block
bool result
= false;
2071 secdebug("secitem","enter - %s", __FUNCTION__
);
2072 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2073 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2074 xpc_dictionary_set_bool(message
, "force", force
);
2077 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2078 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2084 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2085 __block CFArrayRef results
= NULL
;
2086 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2087 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2088 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2090 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2091 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2096 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2097 __block
bool result
= false;
2098 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2099 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2100 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2101 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2103 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2104 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2110 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2111 CFArrayRef results
= NULL
;
2113 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2114 os_activity_scope(activity
);
2115 os_release(activity
);
2117 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2122 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2123 bool results
= false;
2125 os_activity_t activity
= os_activity_create("SecItemCertificateExists", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2126 os_activity_scope(activity
);
2127 os_release(activity
);
2129 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);