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 "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.h>
102 const CFStringRef kSecNetworkExtensionAccessGroupSuffix
= CFSTR("com.apple.networkextensionsharing");
104 /* Return an OSStatus for a sqlite3 error code. */
105 static OSStatus
osstatus_for_s3e(int s3e
)
111 return errSecSuccess
;
112 case SQLITE_READONLY
:
113 return errSecReadOnly
;
114 case SQLITE_CONSTRAINT
:
115 return errSecDuplicateItem
;
116 case SQLITE_ABORT
: // There is no errSecOperationCancelled
118 case SQLITE_MISMATCH
:
119 return errSecNoSuchAttr
;
121 return errSecAllocate
;
124 case SQLITE_INTERNAL
:
125 return errSecInternalComponent
;
126 case SQLITE_FULL
: // Happens if we run out of uniqueids or disk is full (TODO: replace with better code)
127 case SQLITE_PERM
: // No acess permission
128 case SQLITE_AUTH
: // No authorization (e.g. no class key for file)
129 case SQLITE_CANTOPEN
: // can be several reasons for this. Caller should sqlite3_system_errno()
130 case SQLITE_EMPTY
: // SQLite does not seem to use this. Was already here, so keeping
133 return errSecNotAvailable
;
137 static OSStatus
osstatus_for_kern_return(CFIndex kernResult
)
142 return errSecSuccess
;
143 case kIOReturnNotReadable
:
144 case kIOReturnNotWritable
:
145 return errSecAuthFailed
;
146 case kIOReturnNotPermitted
:
147 case kIOReturnNotPrivileged
:
148 case kIOReturnLockedRead
:
149 case kIOReturnLockedWrite
:
150 return errSecInteractionNotAllowed
;
153 case kIOReturnBadArgument
:
156 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
160 static OSStatus
osstatus_for_xpc_error(CFIndex xpcError
) {
163 case kSecXPCErrorSuccess
:
164 return errSecSuccess
;
165 case kSecXPCErrorUnexpectedType
:
166 case kSecXPCErrorUnexpectedNull
:
168 case kSecXPCErrorConnectionFailed
:
169 return errSecNotAvailable
;
170 case kSecXPCErrorUnknown
:
172 return errSecInternal
;
176 static OSStatus
osstatus_for_der_error(CFIndex derError
) {
179 case kSecDERErrorUnknownEncoding
:
180 case kSecDERErrorUnsupportedDERType
:
181 case kSecDERErrorUnsupportedNumberType
:
183 case kSecDERErrorUnsupportedCFObject
:
185 case kSecDERErrorAllocationFailure
:
186 return errSecAllocate
;
188 return errSecInternal
;
192 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
193 // Wrap LA error in Sec error.
195 case kLAErrorUserCancel
:
196 return errSecUserCanceled
;
197 case kLAErrorParameter
:
199 case kLAErrorNotInteractive
:
200 return errSecInteractionNotAllowed
;
202 return errSecAuthFailed
;
206 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
208 case kTKErrorCodeBadParameter
:
210 case kTKErrorCodeNotImplemented
:
211 return errSecUnimplemented
;
212 case kTKErrorCodeCanceledByUser
:
213 return errSecUserCanceled
;
214 case kTKErrorCodeCorruptedData
:
217 return errSecInternal
;
222 // Convert from securityd error codes to OSStatus for legacy API.
223 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
226 status
= errSecSuccess
;
228 CFStringRef domain
= CFErrorGetDomain(error
);
229 if (domain
== NULL
) {
230 secerror("No error domain for error: %@", error
);
231 status
= errSecInternal
;
232 } else if (CFEqual(kSecErrorDomain
, domain
)) {
233 status
= (OSStatus
)CFErrorGetCode(error
);
234 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
235 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
236 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
237 status
= (OSStatus
)CFErrorGetCode(error
);
238 } else if (CFEqual(kSecKernDomain
, domain
)) {
239 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
240 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
241 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
242 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
243 status
= osstatus_for_der_error(CFErrorGetCode(error
));
244 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
245 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
246 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
247 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
248 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
249 status
= errSecInternal
;
251 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
252 status
= errSecInternal
;
259 lastErrorReleaseError(void *value
)
266 getLastErrorKey(pthread_key_t
*kv
)
268 static pthread_key_t key
;
269 static bool haveKey
= false;
270 static dispatch_once_t onceToken
;
271 dispatch_once(&onceToken
, ^{
272 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
280 SetLastError(CFErrorRef newError
)
283 if (!getLastErrorKey(&key
))
285 CFErrorRef oldError
= pthread_getspecific(key
);
290 pthread_setspecific(key
, newError
);
294 SecCopyLastError(OSStatus status
)
299 if (!getLastErrorKey(&key
))
302 error
= pthread_getspecific(key
);
304 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
313 // Wrapper to provide a CFErrorRef for legacy API.
314 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
315 CFErrorRef error
= NULL
;
317 if (perform(&error
)) {
318 assert(error
== NULL
);
320 status
= errSecSuccess
;
324 status
= SecErrorGetOSStatus(error
);
325 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
326 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
327 CFReleaseNull(error
);
332 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
333 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
336 static CFDictionaryRef
337 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
339 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
340 if (filtered
== NULL
)
342 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
343 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
344 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
345 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
346 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
347 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
348 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
349 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
350 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
351 CFDictionaryRemoveValue(filtered
, kSecAttrIsPermanent
);
357 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
358 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
360 Currently in need of conversion below:
361 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
362 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
363 currently implemented at all, but when it is needs to short circuit to
364 local evaluation, different from the sql query abilities
367 static CFDictionaryRef
368 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
369 CFDictionaryRef refDictionary
= NULL
;
370 CFTypeID typeID
= CFGetTypeID(ref
);
371 if (typeID
== SecKeyGetTypeID()) {
372 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
373 if (refDictionary
&& forQuery
) {
374 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
375 CFAssignRetained(refDictionary
, filtered
);
377 } else if (typeID
== SecCertificateGetTypeID()) {
378 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
379 } else if (typeID
== SecIdentityGetTypeID()) {
381 SecIdentityRef identity
= (SecIdentityRef
)ref
;
382 SecCertificateRef cert
= NULL
;
383 SecKeyRef key
= NULL
;
384 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
385 !SecIdentityCopyPrivateKey(identity
, &key
))
387 CFDataRef data
= SecCertificateCopyData(cert
);
388 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
390 if (key_dict
&& data
) {
391 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
392 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
394 CFReleaseNull(key_dict
);
400 return refDictionary
;
403 #ifdef SECITEM_SHIM_OSX
404 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
408 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
409 CFTypeRef ref
= NULL
;
410 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
411 if (CFEqual(class, kSecClassKey
)) {
412 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
413 } else if (CFEqual(class, kSecClassCertificate
)) {
414 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
415 } else if (CFEqual(class, kSecClassIdentity
)) {
416 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
417 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
418 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
420 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
423 secerror("SecItem: failed to create identity");
428 #ifdef SECITEM_SHIM_OSX
430 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
438 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
441 return -1 /* errSecUnimplemented */;
443 #endif // TARGET_OS_OSX
445 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
447 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
448 OSStatus
*return_status
, CFTypeRef
*return_result
)
450 bool handled
= false;
451 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
453 CFTypeID typeID
= CFGetTypeID(value
);
454 if (typeID
== SecIdentityGetTypeID()) {
456 OSStatus status
= errSecSuccess
;
457 SecIdentityRef identity
= (SecIdentityRef
)value
;
458 SecCertificateRef cert
= NULL
;
459 SecKeyRef key
= NULL
;
460 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
461 !SecIdentityCopyPrivateKey(identity
, &key
))
463 CFMutableDictionaryRef partial_query
=
464 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
465 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
466 CFTypeRef result
= NULL
;
467 bool duplicate_cert
= false;
468 /* an identity is first and foremost a key, but it can have multiple
469 certs associated with it: so we identify it by the cert */
470 status
= operation(partial_query
, return_result
? &result
: NULL
);
471 if ((operation
== (secitem_operation
)SecItemAdd
) &&
472 (status
== errSecDuplicateItem
)) {
473 duplicate_cert
= true;
474 status
= errSecSuccess
;
477 if (!status
|| status
== errSecItemNotFound
) {
478 bool skip_key_operation
= false;
480 /* if the key is still in use, skip deleting it */
481 if (operation
== (secitem_operation
)SecItemDelete
) {
482 // find certs with cert.pkhh == keys.klbl
483 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
484 CFDataRef pkhh
= NULL
;
486 key_dict
= SecKeyCopyAttributeDictionary(key
);
488 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
489 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
490 const void *vals
[] = { kSecClassCertificate
, pkhh
};
492 query_dict
= CFDictionaryCreate(NULL
, keys
,
493 vals
, (array_size(keys
)),
496 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
497 skip_key_operation
= true;
498 CFReleaseSafe(query_dict
);
499 CFReleaseSafe(key_dict
);
502 if (!skip_key_operation
) {
503 /* now perform the operation for the key */
504 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
505 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
507 status
= operation(partial_query
, NULL
);
508 if ((operation
== (secitem_operation
)SecItemAdd
) &&
509 (status
== errSecDuplicateItem
) &&
511 status
= errSecSuccess
;
514 /* add and copy matching for an identityref have a persistent ref result */
517 /* result is a persistent ref to a cert */
519 CFDictionaryRef tokenAttrs
= NULL
;
520 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
, &tokenAttrs
)) {
521 *return_result
= _SecItemCreatePersistentRef(kSecClassIdentity
, rowid
, tokenAttrs
);
523 CFReleaseNull(tokenAttrs
);
528 CFReleaseNull(partial_query
);
531 status
= errSecInvalidItemRef
;
535 *return_status
= status
;
538 value
= CFDictionaryGetValue(attributes
, kSecClass
);
539 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
540 (operation
== (secitem_operation
)SecItemDelete
)) {
541 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
542 CFDictionaryRemoveValue(dict
, kSecClass
);
543 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
544 OSStatus status
= SecItemDelete(dict
);
546 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
547 status
= SecItemDelete(dict
);
550 *return_status
= status
;
558 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
561 CFErrorRef lastError
= SecCopyLastError(status
);
563 CFErrorPropagate(lastError
, error
);
565 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
572 handleUpdateIdentity(CFDictionaryRef query
,
573 CFDictionaryRef update
,
577 CFMutableDictionaryRef updatedQuery
= NULL
;
578 SecCertificateRef cert
= NULL
;
579 SecKeyRef key
= NULL
;
580 bool handled
= false;
584 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
586 CFTypeID typeID
= CFGetTypeID(value
);
587 if (typeID
== SecIdentityGetTypeID()) {
588 SecIdentityRef identity
= (SecIdentityRef
)value
;
593 status
= SecIdentityCopyCertificate(identity
, &cert
);
594 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
596 status
= SecIdentityCopyPrivateKey(identity
, &key
);
597 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
599 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
600 require_action_quiet(updatedQuery
, errOut
, *result
= false);
602 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
603 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
605 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
606 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
610 value
= CFDictionaryGetValue(query
, kSecClass
);
611 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
614 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
615 require_action_quiet(updatedQuery
, errOut
, *result
= false);
617 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
618 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
620 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
621 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
623 CFReleaseNull(updatedQuery
);
628 CFReleaseNull(updatedQuery
);
634 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
636 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
637 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
638 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
639 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
640 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
642 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
643 CFReleaseNull(label
);
649 static CFDataRef
CreateTokenPersistentRefData(CFTypeRef
class, CFDictionaryRef attributes
)
651 CFDataRef tokenPersistentRef
= NULL
;
652 CFStringRef tokenId
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
653 CFDictionaryRef itemValue
= NULL
;
654 if (CFEqual(class, kSecClassIdentity
)) {
655 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecAttrIdentityCertificateData
), NULL
);
657 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecValueData
), NULL
);
659 require(itemValue
, out
);
660 CFDataRef oid
= CFDictionaryGetValue(itemValue
, kSecTokenValueObjectIDKey
);
662 CFArrayRef array
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, class, tokenId
, oid
, NULL
);
663 tokenPersistentRef
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, NULL
);
666 CFReleaseNull(itemValue
);
667 return tokenPersistentRef
;
670 static const uint8_t tk_persistent_ref_id
[] = {'t', 'k', 'p', 'r'};
671 /* A persistent ref is just the class and the rowid of the record.
672 Persistent ref for token items is a der blob with class, tokenID and objectId. */
673 CFDataRef
_SecItemCreatePersistentRef(CFTypeRef
class, sqlite_int64 rowid
, CFDictionaryRef attributes
)
675 CFDataRef result
= NULL
;
676 if (attributes
&& CFDictionaryContainsKey(attributes
, CFEqual(class, kSecClassIdentity
) ? kSecAttrIdentityCertificateTokenID
: kSecAttrTokenID
)) {
677 CFDataRef tokenPersistentRef
= CreateTokenPersistentRefData(class, attributes
);
678 require(tokenPersistentRef
, out
);
679 CFMutableDataRef tmpData
= CFDataCreateMutable(kCFAllocatorDefault
, sizeof(tk_persistent_ref_id
) + CFDataGetLength(tokenPersistentRef
));
680 CFDataAppendBytes(tmpData
, tk_persistent_ref_id
, sizeof(tk_persistent_ref_id
));
681 CFDataAppend(tmpData
, tokenPersistentRef
);
682 CFReleaseNull(tokenPersistentRef
);
685 require(rowid
>= 0, out
);
686 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
687 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
688 kCFStringEncodingUTF8
))
690 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
691 result
= CFDataCreate(NULL
, bytes
, sizeof(bytes
));
698 static Boolean
isValidClass(CFStringRef
class, CFStringRef
*return_class
) {
699 const void *valid_classes
[] = { kSecClassGenericPassword
,
700 kSecClassInternetPassword
,
701 kSecClassAppleSharePassword
,
702 kSecClassCertificate
,
706 for (size_t i
= 0; i
< array_size(valid_classes
); i
++) {
707 if (CFEqual(valid_classes
[i
], class)) {
709 *return_class
= valid_classes
[i
];
717 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref
, CFStringRef
*return_class
, CFDictionaryRef
*return_token_attrs
) {
718 bool valid_ref
= false;
719 CFPropertyListRef pl
= NULL
;
720 const uint8_t *der
= CFDataGetBytePtr(persistent_ref
) + sizeof(tk_persistent_ref_id
);
721 const uint8_t *der_end
= der
+ (CFDataGetLength(persistent_ref
) - sizeof(tk_persistent_ref_id
));
722 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &pl
, NULL
, der
, der_end
), out
);
723 require_quiet(der
== der_end
, out
);
724 require_quiet(CFGetTypeID(pl
) == CFArrayGetTypeID(), out
);
725 require_quiet(CFArrayGetCount(pl
) == 3, out
);
726 require_quiet(valid_ref
= isValidClass(CFArrayGetValueAtIndex(pl
, 0), return_class
), out
);
727 if (return_token_attrs
) {
728 *return_token_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
729 kSecAttrTokenID
, CFArrayGetValueAtIndex(pl
, 1),
730 kSecAttrTokenOID
, CFArrayGetValueAtIndex(pl
, 2), NULL
);
737 /* AUDIT[securityd](done):
738 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
740 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
, CFDictionaryRef
*return_token_attrs
)
742 bool valid_ref
= false;
743 require(CFGetTypeID(persistent_ref
) == CFDataGetTypeID(), out
);
745 if (CFDataGetLength(persistent_ref
) > (CFIndex
)sizeof(tk_persistent_ref_id
) &&
746 memcmp(tk_persistent_ref_id
, CFDataGetBytePtr(persistent_ref
), sizeof(tk_persistent_ref_id
)) == 0) {
747 valid_ref
= ParseTokenPersistentRefData(persistent_ref
, return_class
, return_token_attrs
);
748 } else if (CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
749 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
750 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
752 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
753 bytes
, CFStringGetLength(kSecClassGenericPassword
),
754 kCFStringEncodingUTF8
, true);
756 if ((valid_ref
= isValidClass(class, return_class
))) {
758 *return_rowid
= rowid
;
766 static bool cf_bool_value(CFTypeRef cf_bool
) {
767 return cf_bool
&& CFBooleanGetValue(cf_bool
);
770 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
771 if (cow_dictionary
->mutable_dictionary
== NULL
) {
772 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
773 if (cow_dictionary
->dictionary
!= NULL
) {
774 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
775 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
778 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
781 return cow_dictionary
->mutable_dictionary
;
784 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
785 // access_control and optionally of the data value.
786 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
787 CFMutableDictionaryRef value
= NULL
;
788 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
789 kSecTokenValueObjectIDKey
, oid
,
790 kSecTokenValueAccessControlKey
, access_control
,
792 if (object_value
!= NULL
) {
793 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
796 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
801 CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
802 CFPropertyListRef plist
= NULL
;
803 const uint8_t *der
= CFDataGetBytePtr(db_value
);
804 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
805 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
806 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
807 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
808 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
814 TKTokenRef
SecTokenCreate(CFStringRef token_id
, SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
) {
815 CFMutableDictionaryRef token_attrs
= NULL
;
816 TKTokenRef token
= NULL
;
818 static CFMutableDictionaryRef sharedLAContexts
= NULL
;
819 static dispatch_once_t onceToken
;
820 static os_unfair_lock lock
= OS_UNFAIR_LOCK_INIT
;
821 if ((auth_params
->dictionary
== NULL
|| CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
) == NULL
) && !CFStringHasPrefix(token_id
, kSecAttrTokenIDSecureEnclave
)) {
822 dispatch_once(&onceToken
, ^{
823 sharedLAContexts
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
826 os_unfair_lock_lock(&lock
);
827 CFTypeRef ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
829 ctx
= LACreateNewContextWithACMContext(NULL
, error
);
831 os_unfair_lock_unlock(&lock
);
832 secerror("Failed to create authentication context %@", *error
);
835 CFDictionarySetValue(sharedLAContexts
, token_id
, ctx
);
837 ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
840 CFDataRef credRef
= NULL
;
842 credRef
= LACopyACMContext(ctx
, NULL
);
846 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, ctx
);
847 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, credRef
);
850 os_unfair_lock_unlock(&lock
);
853 token_attrs
= (auth_params
->dictionary
!= NULL
) ?
854 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
->dictionary
) :
855 CFDictionaryCreateMutableForCFTypes(NULL
);
856 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
858 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
859 token
= TKTokenCreate(token_attrs
, error
);
861 CFReleaseSafe(token_attrs
);
865 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params_dict
,
866 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
868 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
869 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
870 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
871 if (token_id
!= NULL
&& object_id
!= NULL
) {
872 if (CFRetainSafe(token
) == NULL
) {
873 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
876 if (auth_params
.dictionary
!= NULL
) {
877 CFDictionaryForEach(auth_params
.dictionary
, ^(const void *key
, const void *value
) {
878 CFDictionaryAddValue(attrs
, key
, value
);
881 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
882 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
885 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
889 CFReleaseSafe(attrs
);
890 CFReleaseSafe(auth_params
.mutable_dictionary
);
895 /* Turn the returned single value or dictionary that contains all the attributes to create a
896 ref into the exact result the client asked for */
897 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
898 CFDictionaryRef query
, CFDictionaryRef auth_params_dict
,
899 CFTypeRef
*result
, CFErrorRef
*error
) {
901 CFDataRef ac_data
= NULL
;
902 CFDataRef value
= NULL
;
903 CFTypeRef persistent_ref
= NULL
;
904 CFStringRef token_id
= NULL
;
905 CFStringRef cert_token_id
= NULL
;
906 CFDataRef object_id
= NULL
;
907 CFMutableDictionaryRef attrs
= NULL
;
908 CFDataRef cert_data
= NULL
;
909 CFDataRef cert_object_id
= NULL
;
910 TKTokenRef cert_token
= NULL
;
911 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
913 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
914 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
915 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
916 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
918 // Get token value if not provided by the caller.
919 bool token_item
= false;
920 bool cert_token_item
= false;
922 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
923 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
924 token_item
= (token_id
!= NULL
);
926 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
927 cert_token_item
= (cert_token_id
!= NULL
);
931 cert_token_item
= true;
933 CFRetainAssign(cert_token
, token
);
936 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
938 cert_token_item
= false;
941 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
942 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
943 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
944 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
946 value
= CFRetainSafe(raw_result
);
947 if (token_item
&& value
!= NULL
) {
948 // Parse token-based item's data field.
949 CFDataRef object_value
= NULL
;
950 CFDictionaryRef parsed_value
= NULL
;
951 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
952 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
953 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
954 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
955 CFRelease(parsed_value
);
956 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
957 // Retrieve value directly from the token.
959 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
961 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
962 if (CFEqual(object_value
, kCFNull
))
963 CFReleaseNull(object_value
);
965 CFAssignRetained(value
, object_value
);
968 // If only thing requested is data, return them directly.
969 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
970 *result
= CFRetainSafe(value
);
976 // Extract persistent_ref, if caller wants it.
977 if (wants_persistent_ref
) {
978 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
979 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
981 persistent_ref
= CFRetainSafe(raw_result
);
983 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
984 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
985 *result
= CFRetainSafe(persistent_ref
);
991 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
997 // For other cases we need an output dictionary.
998 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
999 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
1001 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
1002 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
1004 if ((wants_data
|| wants_ref
) && value
!= NULL
)
1005 CFDictionarySetValue(output
, kSecValueData
, value
);
1007 CFDictionaryRemoveValue(output
, kSecValueData
);
1009 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
1010 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
1012 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
1014 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
1015 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
1016 // Decode also certdata field of the identity.
1017 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
1019 CFDictionaryRef parsed_value
;
1020 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
1021 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
1022 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
1023 CFRelease(parsed_value
);
1024 if (cert_data
== NULL
) {
1025 // Retrieve value directly from the token.
1026 if (cert_token
== NULL
) {
1027 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, &auth_params
, error
), out
);
1029 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1030 if (CFEqual(cert_data
, kCFNull
))
1031 CFReleaseNull(cert_data
);
1033 if (cert_data
!= NULL
) {
1034 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1036 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1041 if (wants_ref
|| wants_attributes
) {
1042 // Convert serialized form of access control to object form.
1044 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1047 if (ac_data
!= NULL
) {
1048 SecAccessControlRef ac
;
1049 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1050 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1057 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
.dictionary
, token
, object_id
, &ref
, error
), out
);
1058 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1059 CFAssignRetained(*result
, ref
);
1060 } else if (ref
!= NULL
) {
1061 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1064 // We could have stored data value previously to make ref creation succeed.
1065 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1066 CFDictionaryRemoveValue(output
, kSecValueData
);
1074 CFReleaseSafe(cert_object_id
);
1075 CFReleaseSafe(cert_data
);
1076 CFReleaseSafe(ac_data
);
1077 CFReleaseSafe(value
);
1078 CFReleaseSafe(persistent_ref
);
1079 CFReleaseSafe(object_id
);
1080 CFReleaseSafe(attrs
);
1081 CFReleaseSafe(token
);
1082 CFReleaseSafe(cert_token
);
1083 CFReleaseSafe(auth_params
.mutable_dictionary
);
1087 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1088 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1090 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1091 require_action_quiet(result
!= NULL
, out
, ok
= true);
1093 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1094 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1095 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1096 for (i
= 0; i
< count
; i
++) {
1098 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1099 token
, query
, auth_params
, &ref
, error
), out
);
1101 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1106 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1115 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1116 void *la_lib
= NULL
;
1117 CFDataRef acm_context
= NULL
;
1118 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1119 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1120 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1121 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1122 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1123 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1124 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1126 if (la_lib
!= NULL
) {
1132 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1134 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1135 void *la_lib
= NULL
;
1137 // If a ref was specified we get its attribute dictionary and parse it.
1138 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1140 CFDictionaryRef ref_attributes
;
1141 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1142 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1144 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1145 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1146 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1147 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1148 // so add only those attributes from 'ref' which are missing in attrs.
1149 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1151 CFRelease(ref_attributes
);
1154 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1157 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1158 // another roundtrip to token driver.
1159 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1160 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1164 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1165 if (access_control
!= NULL
) {
1166 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
1167 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1170 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1172 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1173 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1174 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1175 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1176 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1179 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1181 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1182 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1184 CFTypeRef values
[] = { policy
};
1185 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1186 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1187 CFReleaseSafe(policiesArray
);
1188 require_action_quiet(policiesArrayXPC
, out
,
1189 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1191 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1192 xpc_release(policiesArrayXPC
);
1193 require_action_quiet(objectReadyForXPC
, out
,
1194 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1196 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1197 CFRelease(objectReadyForXPC
);
1199 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1201 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1202 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1203 DERDecodedInfo content
;
1204 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1205 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1206 if (canonical_issuer
) {
1207 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1208 CFRelease(canonical_issuer
);
1213 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1214 // This use flag is client-only, securityd does not understand it.
1215 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1221 if (la_lib
!= NULL
) {
1224 CFReleaseSafe(ac_data
);
1225 CFReleaseSafe(acm_context
);
1229 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1231 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1233 CFArrayForEachC(ac_pairs
, ac_pair
) {
1234 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1235 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1236 CFStringAppend(log_string
, str
);
1237 CFRelease(acl_hex_string
);
1241 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1242 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1243 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1245 CFRelease(log_string
);
1249 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1250 void (^newCredentialRefAdded
)(void)) {
1252 CFArrayRef ac_pairs
= NULL
;
1253 SecCFDictionaryCOW auth_options
= { NULL
};
1255 for (uint32_t i
= 0;; ++i
) {
1256 // If the operation succeeded or failed with other than auth-needed error, just leave.
1257 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1258 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1259 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1261 // If auth_params were not created up to now, do create them because we will definitely need them.
1262 SecCFDictionaryCOWGetMutable(auth_params
);
1264 // Retrieve or create authentication handle and/or ACM context.
1265 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1266 if (auth_handle
== NULL
) {
1267 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1268 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1269 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1270 CFRelease(auth_handle
);
1271 if (acm_context
== NULL
) {
1272 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1273 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1274 CFRelease(acm_context
);
1275 if (newCredentialRefAdded
) {
1276 newCredentialRefAdded();
1281 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1282 // user retry limit.
1283 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1285 // Prepare auth options dictionary.
1286 if (auth_options
.dictionary
== NULL
) {
1287 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1288 if (operation_prompt
!= NULL
) {
1289 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1290 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1294 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1295 if (caller_name
!= NULL
) {
1296 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1297 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1301 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1302 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1303 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1304 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1309 // Go through all access_control-operation pairs and evaluate them.
1311 CFArrayForEachC(ac_pairs
, ac_pair
) {
1312 CFDataRef updated_acl
= NULL
;
1313 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1314 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1315 auth_options
.dictionary
, &updated_acl
, error
), out
);
1317 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1318 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1319 SecAccessControlRef ac
= NULL
;
1320 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1321 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1322 SecAccessControlSetBound(ac
, true);
1323 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1324 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1325 CFRelease(updated_acl
);
1334 CFReleaseSafe(auth_options
.mutable_dictionary
);
1335 CFReleaseSafe(ac_pairs
);
1339 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1340 // Store operation prompt.
1341 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1342 if (operation_prompt
!= NULL
) {
1343 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1344 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1347 // Store caller name.
1348 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1349 if (caller_name
!= NULL
) {
1350 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1351 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1354 // Find out whether we are allowed to pop up a UI.
1355 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1356 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1357 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1358 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1359 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1360 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1361 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1362 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1365 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1366 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1369 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1370 if (acm_context
!= NULL
) {
1371 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1375 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1377 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1378 // Extract ACLs to be verified from the error.
1379 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1380 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1381 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1382 if (*ac_pairs
== NULL
)
1383 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1386 CFRelease(user_info
);
1387 CFReleaseNull(*error
);
1388 return kSecItemAuthResultNeedAuth
;
1390 return kSecItemAuthResultError
;
1393 // Wrapper to handle automatic authentication and token/secd case switching.
1394 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1395 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1397 __block SecCFDictionaryCOW auth_params
= { NULL
};
1398 SecAccessControlRef access_control
= NULL
;
1399 __block TKTokenRef token
= NULL
;
1401 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1402 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1403 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1404 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1405 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1406 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1409 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1410 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1412 secItemOperation
== SecItemCopyMatching
||
1413 secItemOperation
== SecItemUpdate
||
1414 secItemOperation
== SecItemDelete
;
1416 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1417 if (attributes
!= NULL
)
1418 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1420 // Populate auth_params dictionary according to initial query contents.
1421 SecItemAuthCopyParams(&auth_params
, query
);
1423 if (secItemOperation
!= SecItemCopyMatching
) {
1424 // UISkip is allowed only for CopyMatching.
1425 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1426 SecError(errSecParam
, error
,
1427 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1430 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1431 SecItemAuthResult result
= kSecItemAuthResultError
;
1433 // Propagate actual credential reference to the query.
1434 if (auth_params
.dictionary
!= NULL
) {
1435 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1436 if (acm_context
!= NULL
) {
1437 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1440 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1441 if (acl_data_ref
!= NULL
) {
1442 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1446 // Prepare connection to target token if it is present.
1447 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1448 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1449 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, &auth_params
, error
)), out
);
1452 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1453 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1454 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1457 result
= kSecItemAuthResultOK
;
1462 require_quiet(ok
, out
);
1467 CFReleaseSafe(token
);
1468 CFReleaseSafe(auth_params
.mutable_dictionary
);
1472 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1474 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1475 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1476 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1478 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1484 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1486 CFArrayRef result
= NULL
;
1487 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1488 if(success
&& !isArray(result
)){
1489 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1490 CFReleaseNull(result
);
1495 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1496 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1499 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1501 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1502 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1506 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1508 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1510 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1515 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1523 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1525 return dict_to_error_request(op
, query
, error
);
1528 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1529 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1530 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1531 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1532 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1533 keys
, ac_pairs
, 1));
1535 CFRelease(ac_pairs
[0]);
1540 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1541 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1542 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1543 // Replace error with the one which is augmented with access control and operation which failed,
1544 // which will cause SecItemDoWithAuth to throw UI.
1545 // Create array containing tuple (array) with error and requested operation.
1546 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
);
1547 if (access_control
!= NULL
) {
1548 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1549 CFRelease(access_control
);
1555 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1556 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1557 SecAccessControlRef ac
= NULL
;
1558 CFDictionaryRef old_attrs
= NULL
;
1560 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1561 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1562 if (ac_data
!= NULL
) {
1563 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1564 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1565 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1568 // Create or update the object on the token.
1569 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1570 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1571 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1572 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1573 if (!CFEqual(key
, kSecValueData
)) {
1574 CFDictionaryAddValue(attributes
, key
, value
);
1578 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1579 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1580 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1581 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1582 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1584 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1585 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1589 CFReleaseSafe(access_control
);
1590 CFReleaseSafe(db_value
);
1591 CFReleaseSafe(old_attrs
);
1592 return new_object_id
;
1595 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1596 CFTypeRef
*result
, CFErrorRef
*error
) {
1598 CFTypeRef object_id
= NULL
, ref
= NULL
;
1599 CFDictionaryRef ref_attrs
= NULL
;
1600 CFTypeRef db_result
= NULL
;
1601 CFDataRef db_value
= NULL
;
1602 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1604 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1605 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1606 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1607 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1608 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1609 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1610 // the ref from the dictionary since it is of no use any more.
1611 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1613 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1614 // by creating ref and getting back its attributes.
1615 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1617 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1618 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1619 if (!CFEqual(key
, kSecValueData
)) {
1620 CFDictionaryAddValue(attrs
, key
, value
);
1627 // Make sure that both attributes and data are returned.
1628 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1629 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1631 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1632 // IsPermanent is not present or is true, so add item to the db.
1633 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1634 SecSecurityClientGet(), &db_result
, error
), out
);
1636 // Process directly result of token call.
1637 db_result
= CFRetain(attrs
);
1639 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1643 CFReleaseSafe(db_result
);
1644 CFReleaseSafe(db_value
);
1645 CFReleaseSafe(attrs
);
1646 CFReleaseSafe(ref_attrs
);
1647 CFReleaseSafe(object_id
);
1652 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1653 __block SecCFDictionaryCOW attrs
= { attributes
};
1656 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1657 os_activity_scope(activity
);
1658 os_release(activity
);
1660 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1661 infer_cert_label(&attrs
);
1663 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1664 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1665 if (token
== NULL
) {
1666 CFTypeRef raw_result
= NULL
;
1667 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1670 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1671 CFReleaseSafe(raw_result
);
1674 // Send request to an appropriate token instead of secd.
1675 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1681 CFReleaseSafe(attrs
.mutable_dictionary
);
1687 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1689 __block SecCFDictionaryCOW query
= { inQuery
};
1691 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1692 os_activity_scope(activity
);
1693 os_release(activity
);
1695 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1697 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1698 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1699 if ((wants_data
&& !wants_attributes
)) {
1700 // When either attributes or data are requested, we need to query both, because for token based items,
1701 // both are needed in order to generate proper data and/or attributes results.
1702 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1705 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1706 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1707 CFTypeRef raw_result
= NULL
;
1708 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1711 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1712 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1713 // to currently processed item.
1714 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1715 CFReleaseSafe(raw_result
);
1722 CFReleaseSafe(query
.mutable_dictionary
);
1726 // Invokes token-object handler for each item matching specified query.
1727 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1728 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1729 CFErrorRef
*error
)) {
1731 CFMutableDictionaryRef list_query
= NULL
;
1732 CFTypeRef items
= NULL
;
1733 CFArrayRef ref_array
= NULL
;
1734 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1736 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1737 // items in the keychain.
1738 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1739 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1740 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1742 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1743 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1744 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1745 SecSecurityClientGet(), &items
, error
), out
);
1746 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1747 // Wrap single returned item into the array.
1748 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1749 CFAssignRetained(items
, item_array
);
1753 CFArrayForEachC(items
, item
) {
1754 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1755 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1757 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1758 require_quiet(item_data
, out
);
1760 CFAssignRetained(item_query
,
1761 CFDictionaryCreateForCFTypes(NULL
,
1762 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1764 require_quiet(perform(item_data
, item_query
, error
), out
);
1770 CFReleaseSafe(list_query
);
1771 CFReleaseSafe(items
);
1772 CFReleaseSafe(item_data
);
1773 CFReleaseSafe(ref_array
);
1774 CFReleaseSafe(item_query
);
1778 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1781 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1782 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1783 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1784 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1787 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1789 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1790 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1791 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1793 ok
= securityd_message_no_error(reply
, error
);
1797 xpc_release(message
);
1803 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1804 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1806 CFDataRef object_id
= NULL
;
1807 CFMutableDictionaryRef db_value
= NULL
;
1809 // Update attributes on the token.
1810 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1811 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1812 attributes
, error
), out
);
1814 // Update attributes in the database.
1815 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1820 CFReleaseSafe(object_id
);
1821 CFReleaseSafe(attributes
);
1822 CFReleaseSafe(db_value
);
1827 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1828 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1829 os_activity_scope(activity
);
1830 os_release(activity
);
1832 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1833 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1838 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1839 CFDictionaryRef inAttributesToUpdate
,
1842 __block SecCFDictionaryCOW query
= { inQuery
};
1843 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1844 bool result
= false;
1846 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1849 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1850 if (token
== NULL
) {
1851 return SecItemRawUpdate(query
, attributes
, error
);
1853 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1858 CFReleaseSafe(query
.mutable_dictionary
);
1859 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1863 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1865 OSStatus status
= errSecSuccess
;
1866 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1868 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1869 && CFEqual(class, kSecClassIdentity
)) {
1870 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1871 const void *vals
[] = { kCFBooleanTrue
, persist
};
1872 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1873 vals
, (array_size(keys
)), NULL
, NULL
);
1874 CFTypeRef item_query
= NULL
;
1875 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1876 CFReleaseNull(persistent_query
);
1879 if (item_query
== NULL
)
1880 return errSecItemNotFound
;
1882 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1883 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1884 CFRelease(item_query
);
1890 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1892 __block SecCFDictionaryCOW query
= { inQuery
};
1894 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1895 os_activity_scope(activity
);
1896 os_release(activity
);
1898 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1899 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1901 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1902 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1903 if (token
== NULL
) {
1904 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1906 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1909 // Delete item from the token.
1910 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1911 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1912 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1914 // Delete the item from the keychain.
1915 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1916 SecSecurityClientGet(), error
), out
);
1927 CFReleaseSafe(query
.mutable_dictionary
);
1934 SecItemDeleteAll(void)
1936 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1939 if (!gSecurityd
->sec_item_delete_all(error
))
1940 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1942 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1950 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1952 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1953 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1958 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1960 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1961 os_activity_scope(activity
);
1962 os_release(activity
);
1964 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1965 SecSecurityClientGet(), error
);
1972 #if SECITEM_SHIM_OSX
1973 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1975 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1980 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1981 os_activity_scope(activity
);
1982 os_release(activity
);
1984 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1985 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
1986 if (tokenItemsAttributes
) {
1987 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1988 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
1989 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
1990 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
1991 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
1992 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
1993 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
1994 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
1996 CFRelease(tokenItems
);
2000 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
2001 CFDictionarySetValue(attributes
, kSecValueData
, data
);
2002 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
2003 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2004 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2005 CFArrayAppendValue(tokenItems
, attributes
);
2006 CFRelease(attributes
);
2010 CFArrayAppendValue(tokenItems
, itemAttributes
);
2013 tmpArrayRef
= tokenItems
;
2016 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2022 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2023 __block CFArrayRef result
;
2024 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2025 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2030 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2032 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2034 do_if_registered(sec_roll_keys
, force
, error
);
2036 __block
bool result
= false;
2038 secdebug("secitem","enter - %s", __FUNCTION__
);
2039 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2040 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2041 xpc_dictionary_set_bool(message
, "force", force
);
2044 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2045 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2051 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2052 __block CFArrayRef results
= NULL
;
2053 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2054 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2055 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2057 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2058 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2063 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2064 __block
bool result
= false;
2065 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2066 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2067 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2068 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2070 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2071 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2077 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2078 CFArrayRef results
= NULL
;
2080 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2081 os_activity_scope(activity
);
2082 os_release(activity
);
2084 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2089 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2090 bool results
= false;
2092 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2093 os_activity_scope(activity
);
2094 os_release(activity
);
2096 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);