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 secerror("Failed to create authentication context %@", *error
);
834 CFDictionarySetValue(sharedLAContexts
, token_id
, ctx
);
836 ctx
= CFDictionaryGetValue(sharedLAContexts
, token_id
);
839 CFDataRef credRef
= NULL
;
841 credRef
= LACopyACMContext(ctx
, NULL
);
845 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, ctx
);
846 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, credRef
);
849 os_unfair_lock_unlock(&lock
);
852 token_attrs
= (auth_params
->dictionary
!= NULL
) ?
853 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
->dictionary
) :
854 CFDictionaryCreateMutableForCFTypes(NULL
);
855 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
857 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
858 token
= TKTokenCreate(token_attrs
, error
);
860 CFReleaseSafe(token_attrs
);
864 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params_dict
,
865 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
867 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
868 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
869 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
870 if (token_id
!= NULL
&& object_id
!= NULL
) {
871 if (CFRetainSafe(token
) == NULL
) {
872 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
875 if (auth_params
.dictionary
!= NULL
) {
876 CFDictionaryForEach(auth_params
.dictionary
, ^(const void *key
, const void *value
) {
877 CFDictionaryAddValue(attrs
, key
, value
);
880 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
881 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
884 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
888 CFReleaseSafe(attrs
);
889 CFReleaseSafe(auth_params
.mutable_dictionary
);
894 /* Turn the returned single value or dictionary that contains all the attributes to create a
895 ref into the exact result the client asked for */
896 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
897 CFDictionaryRef query
, CFDictionaryRef auth_params_dict
,
898 CFTypeRef
*result
, CFErrorRef
*error
) {
900 CFDataRef ac_data
= NULL
;
901 CFDataRef value
= NULL
;
902 CFTypeRef persistent_ref
= NULL
;
903 CFStringRef token_id
= NULL
;
904 CFStringRef cert_token_id
= NULL
;
905 CFDataRef object_id
= NULL
;
906 CFMutableDictionaryRef attrs
= NULL
;
907 CFDataRef cert_data
= NULL
;
908 CFDataRef cert_object_id
= NULL
;
909 TKTokenRef cert_token
= NULL
;
910 SecCFDictionaryCOW auth_params
= { auth_params_dict
};
912 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
913 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
914 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
915 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
917 // Get token value if not provided by the caller.
918 bool token_item
= false;
919 bool cert_token_item
= false;
921 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
922 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
923 token_item
= (token_id
!= NULL
);
925 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
926 cert_token_item
= (cert_token_id
!= NULL
);
930 cert_token_item
= true;
932 CFRetainAssign(cert_token
, token
);
935 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
937 cert_token_item
= false;
940 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
941 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
942 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
943 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
945 value
= CFRetainSafe(raw_result
);
946 if (token_item
&& value
!= NULL
) {
947 // Parse token-based item's data field.
948 CFDataRef object_value
= NULL
;
949 CFDictionaryRef parsed_value
= NULL
;
950 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
951 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
952 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
953 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
954 CFRelease(parsed_value
);
955 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
956 // Retrieve value directly from the token.
958 require_quiet(token
= SecTokenCreate(token_id
, &auth_params
, error
), out
);
960 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
961 if (CFEqual(object_value
, kCFNull
))
962 CFReleaseNull(object_value
);
964 CFAssignRetained(value
, object_value
);
967 // If only thing requested is data, return them directly.
968 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
969 *result
= CFRetainSafe(value
);
975 // Extract persistent_ref, if caller wants it.
976 if (wants_persistent_ref
) {
977 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
978 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
980 persistent_ref
= CFRetainSafe(raw_result
);
982 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
983 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
984 *result
= CFRetainSafe(persistent_ref
);
990 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
996 // For other cases we need an output dictionary.
997 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
998 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
1000 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
1001 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
1003 if ((wants_data
|| wants_ref
) && value
!= NULL
)
1004 CFDictionarySetValue(output
, kSecValueData
, value
);
1006 CFDictionaryRemoveValue(output
, kSecValueData
);
1008 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
1009 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
1011 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
1013 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
1014 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
1015 // Decode also certdata field of the identity.
1016 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
1018 CFDictionaryRef parsed_value
;
1019 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
1020 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
1021 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
1022 CFRelease(parsed_value
);
1023 if (cert_data
== NULL
) {
1024 // Retrieve value directly from the token.
1025 if (cert_token
== NULL
) {
1026 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, &auth_params
, error
), out
);
1028 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1029 if (CFEqual(cert_data
, kCFNull
))
1030 CFReleaseNull(cert_data
);
1032 if (cert_data
!= NULL
) {
1033 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1035 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1040 if (wants_ref
|| wants_attributes
) {
1041 // Convert serialized form of access control to object form.
1043 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1046 if (ac_data
!= NULL
) {
1047 SecAccessControlRef ac
;
1048 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1049 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1056 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
.dictionary
, token
, object_id
, &ref
, error
), out
);
1057 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1058 CFAssignRetained(*result
, ref
);
1059 } else if (ref
!= NULL
) {
1060 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1063 // We could have stored data value previously to make ref creation succeed.
1064 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1065 CFDictionaryRemoveValue(output
, kSecValueData
);
1073 CFReleaseSafe(cert_object_id
);
1074 CFReleaseSafe(cert_data
);
1075 CFReleaseSafe(ac_data
);
1076 CFReleaseSafe(value
);
1077 CFReleaseSafe(persistent_ref
);
1078 CFReleaseSafe(object_id
);
1079 CFReleaseSafe(attrs
);
1080 CFReleaseSafe(token
);
1081 CFReleaseSafe(cert_token
);
1082 CFReleaseSafe(auth_params
.mutable_dictionary
);
1086 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1087 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1089 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1090 require_action_quiet(result
!= NULL
, out
, ok
= true);
1092 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1093 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1094 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1095 for (i
= 0; i
< count
; i
++) {
1097 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1098 token
, query
, auth_params
, &ref
, error
), out
);
1100 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1105 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1114 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1115 void *la_lib
= NULL
;
1116 CFDataRef acm_context
= NULL
;
1117 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1118 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1119 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1120 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1121 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1122 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1123 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1125 if (la_lib
!= NULL
) {
1131 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1133 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1134 void *la_lib
= NULL
;
1136 // If a ref was specified we get its attribute dictionary and parse it.
1137 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1139 CFDictionaryRef ref_attributes
;
1140 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1141 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1143 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1144 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1145 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1146 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1147 // so add only those attributes from 'ref' which are missing in attrs.
1148 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1150 CFRelease(ref_attributes
);
1153 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1156 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1157 // another roundtrip to token driver.
1158 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1159 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1163 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1164 if (access_control
!= NULL
) {
1165 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
1166 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1169 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1171 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1172 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1173 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1174 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1175 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1178 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1180 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1181 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1183 CFTypeRef values
[] = { policy
};
1184 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1185 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1186 CFReleaseSafe(policiesArray
);
1187 require_action_quiet(policiesArrayXPC
, out
,
1188 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1190 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1191 xpc_release(policiesArrayXPC
);
1192 require_action_quiet(objectReadyForXPC
, out
,
1193 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1195 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1196 CFRelease(objectReadyForXPC
);
1198 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1200 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1201 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1202 DERDecodedInfo content
;
1203 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1204 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1205 if (canonical_issuer
) {
1206 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1207 CFRelease(canonical_issuer
);
1212 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1213 // This use flag is client-only, securityd does not understand it.
1214 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1220 if (la_lib
!= NULL
) {
1223 CFReleaseSafe(ac_data
);
1224 CFReleaseSafe(acm_context
);
1228 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1230 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1232 CFArrayForEachC(ac_pairs
, ac_pair
) {
1233 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1234 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1235 CFStringAppend(log_string
, str
);
1236 CFRelease(acl_hex_string
);
1240 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1241 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1242 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1244 CFRelease(log_string
);
1248 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1249 void (^newCredentialRefAdded
)(void)) {
1251 CFArrayRef ac_pairs
= NULL
;
1252 SecCFDictionaryCOW auth_options
= { NULL
};
1254 for (uint32_t i
= 0;; ++i
) {
1255 // If the operation succeeded or failed with other than auth-needed error, just leave.
1256 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1257 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1258 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1260 // If auth_params were not created up to now, do create them because we will definitely need them.
1261 SecCFDictionaryCOWGetMutable(auth_params
);
1263 // Retrieve or create authentication handle and/or ACM context.
1264 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1265 if (auth_handle
== NULL
) {
1266 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1267 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1268 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1269 CFRelease(auth_handle
);
1270 if (acm_context
== NULL
) {
1271 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1272 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1273 CFRelease(acm_context
);
1274 if (newCredentialRefAdded
) {
1275 newCredentialRefAdded();
1280 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1281 // user retry limit.
1282 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1284 // Prepare auth options dictionary.
1285 if (auth_options
.dictionary
== NULL
) {
1286 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1287 if (operation_prompt
!= NULL
) {
1288 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1289 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1293 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1294 if (caller_name
!= NULL
) {
1295 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1296 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1300 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1301 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1302 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1303 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1308 // Go through all access_control-operation pairs and evaluate them.
1310 CFArrayForEachC(ac_pairs
, ac_pair
) {
1311 CFDataRef updated_acl
= NULL
;
1312 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1313 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1314 auth_options
.dictionary
, &updated_acl
, error
), out
);
1316 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1317 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1318 SecAccessControlRef ac
= NULL
;
1319 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1320 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1321 SecAccessControlSetBound(ac
, true);
1322 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1323 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1324 CFRelease(updated_acl
);
1333 CFReleaseSafe(auth_options
.mutable_dictionary
);
1334 CFReleaseSafe(ac_pairs
);
1338 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1339 // Store operation prompt.
1340 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1341 if (operation_prompt
!= NULL
) {
1342 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1343 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1346 // Store caller name.
1347 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1348 if (caller_name
!= NULL
) {
1349 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1350 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1353 // Find out whether we are allowed to pop up a UI.
1354 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1355 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1356 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1357 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1358 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1359 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1360 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1361 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1364 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1365 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1368 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1369 if (acm_context
!= NULL
) {
1370 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1374 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1376 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1377 // Extract ACLs to be verified from the error.
1378 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1379 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1380 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1381 if (*ac_pairs
== NULL
)
1382 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1385 CFRelease(user_info
);
1386 CFReleaseNull(*error
);
1387 return kSecItemAuthResultNeedAuth
;
1389 return kSecItemAuthResultError
;
1392 // Wrapper to handle automatic authentication and token/secd case switching.
1393 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1394 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1396 __block SecCFDictionaryCOW auth_params
= { NULL
};
1397 SecAccessControlRef access_control
= NULL
;
1398 __block TKTokenRef token
= NULL
;
1400 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1401 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1402 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1403 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1404 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1405 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1408 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1409 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1411 secItemOperation
== SecItemCopyMatching
||
1412 secItemOperation
== SecItemUpdate
||
1413 secItemOperation
== SecItemDelete
;
1415 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1416 if (attributes
!= NULL
)
1417 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1419 // Populate auth_params dictionary according to initial query contents.
1420 SecItemAuthCopyParams(&auth_params
, query
);
1422 if (secItemOperation
!= SecItemCopyMatching
) {
1423 // UISkip is allowed only for CopyMatching.
1424 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1425 SecError(errSecParam
, error
,
1426 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1429 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1430 SecItemAuthResult result
= kSecItemAuthResultError
;
1432 // Propagate actual credential reference to the query.
1433 if (auth_params
.dictionary
!= NULL
) {
1434 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1435 if (acm_context
!= NULL
) {
1436 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1439 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1440 if (acl_data_ref
!= NULL
) {
1441 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1445 // Prepare connection to target token if it is present.
1446 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1447 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1448 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, &auth_params
, error
)), out
);
1451 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1452 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1453 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1456 result
= kSecItemAuthResultOK
;
1461 require_quiet(ok
, out
);
1466 CFReleaseSafe(token
);
1467 CFReleaseSafe(auth_params
.mutable_dictionary
);
1471 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1473 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1474 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1475 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1477 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1483 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1485 CFArrayRef result
= NULL
;
1486 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1487 if(success
&& !isArray(result
)){
1488 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1489 CFReleaseNull(result
);
1494 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1495 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1498 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1500 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1501 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1505 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1507 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1509 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1514 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1522 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1524 return dict_to_error_request(op
, query
, error
);
1527 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1528 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1529 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1530 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1531 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1532 keys
, ac_pairs
, 1));
1534 CFRelease(ac_pairs
[0]);
1539 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1540 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1541 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1542 // Replace error with the one which is augmented with access control and operation which failed,
1543 // which will cause SecItemDoWithAuth to throw UI.
1544 // Create array containing tuple (array) with error and requested operation.
1545 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1546 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1547 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1548 if (access_control
!= NULL
) {
1549 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1550 CFRelease(access_control
);
1556 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1557 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1558 SecAccessControlRef ac
= NULL
;
1559 CFDictionaryRef old_attrs
= NULL
;
1561 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1562 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1563 if (ac_data
!= NULL
) {
1564 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1565 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1566 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1569 // Create or update the object on the token.
1570 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1571 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1572 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1573 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1574 if (!CFEqual(key
, kSecValueData
)) {
1575 CFDictionaryAddValue(attributes
, key
, value
);
1579 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1580 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1581 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1582 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1583 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1585 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1586 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1590 CFReleaseSafe(access_control
);
1591 CFReleaseSafe(db_value
);
1592 CFReleaseSafe(old_attrs
);
1593 return new_object_id
;
1596 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1597 CFTypeRef
*result
, CFErrorRef
*error
) {
1599 CFTypeRef object_id
= NULL
, ref
= NULL
;
1600 CFDictionaryRef ref_attrs
= NULL
;
1601 CFTypeRef db_result
= NULL
;
1602 CFDataRef db_value
= NULL
;
1603 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1605 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1606 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1607 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1608 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1609 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1610 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1611 // the ref from the dictionary since it is of no use any more.
1612 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1614 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1615 // by creating ref and getting back its attributes.
1616 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1618 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1619 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1620 if (!CFEqual(key
, kSecValueData
)) {
1621 CFDictionaryAddValue(attrs
, key
, value
);
1628 // Make sure that both attributes and data are returned.
1629 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1630 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1632 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1633 // IsPermanent is not present or is true, so add item to the db.
1634 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1635 SecSecurityClientGet(), &db_result
, error
), out
);
1637 // Process directly result of token call.
1638 db_result
= CFRetain(attrs
);
1640 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1644 CFReleaseSafe(db_result
);
1645 CFReleaseSafe(db_value
);
1646 CFReleaseSafe(attrs
);
1647 CFReleaseSafe(ref_attrs
);
1648 CFReleaseSafe(object_id
);
1653 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1654 __block SecCFDictionaryCOW attrs
= { attributes
};
1657 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1658 os_activity_scope(activity
);
1659 os_release(activity
);
1661 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1662 infer_cert_label(&attrs
);
1664 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1665 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1666 if (token
== NULL
) {
1667 CFTypeRef raw_result
= NULL
;
1668 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1671 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1672 CFReleaseSafe(raw_result
);
1675 // Send request to an appropriate token instead of secd.
1676 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1682 CFReleaseSafe(attrs
.mutable_dictionary
);
1688 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1690 __block SecCFDictionaryCOW query
= { inQuery
};
1692 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1693 os_activity_scope(activity
);
1694 os_release(activity
);
1696 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1698 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1699 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1700 if ((wants_data
&& !wants_attributes
)) {
1701 // When either attributes or data are requested, we need to query both, because for token based items,
1702 // both are needed in order to generate proper data and/or attributes results.
1703 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1706 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1707 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1708 CFTypeRef raw_result
= NULL
;
1709 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1712 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1713 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1714 // to currently processed item.
1715 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1716 CFReleaseSafe(raw_result
);
1723 CFReleaseSafe(query
.mutable_dictionary
);
1727 // Invokes token-object handler for each item matching specified query.
1728 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1729 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1730 CFErrorRef
*error
)) {
1732 CFMutableDictionaryRef list_query
= NULL
;
1733 CFTypeRef items
= NULL
;
1734 CFArrayRef ref_array
= NULL
;
1735 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1737 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1738 // items in the keychain.
1739 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1740 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1741 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1743 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1744 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1745 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1746 SecSecurityClientGet(), &items
, error
), out
);
1747 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1748 // Wrap single returned item into the array.
1749 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1750 CFAssignRetained(items
, item_array
);
1754 CFArrayForEachC(items
, item
) {
1755 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1756 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1758 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1759 require_quiet(item_data
, out
);
1761 CFAssignRetained(item_query
,
1762 CFDictionaryCreateForCFTypes(NULL
,
1763 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1765 require_quiet(perform(item_data
, item_query
, error
), out
);
1771 CFReleaseSafe(list_query
);
1772 CFReleaseSafe(items
);
1773 CFReleaseSafe(item_data
);
1774 CFReleaseSafe(ref_array
);
1775 CFReleaseSafe(item_query
);
1779 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1782 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1783 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1784 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1785 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1788 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1790 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1791 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1792 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1794 ok
= securityd_message_no_error(reply
, error
);
1798 xpc_release(message
);
1804 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1805 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1807 CFDataRef object_id
= NULL
;
1808 CFMutableDictionaryRef db_value
= NULL
;
1810 // Update attributes on the token.
1811 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1812 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1813 attributes
, error
), out
);
1815 // Update attributes in the database.
1816 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1821 CFReleaseSafe(object_id
);
1822 CFReleaseSafe(attributes
);
1823 CFReleaseSafe(db_value
);
1828 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1829 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1830 os_activity_scope(activity
);
1831 os_release(activity
);
1833 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1834 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1839 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1840 CFDictionaryRef inAttributesToUpdate
,
1843 __block SecCFDictionaryCOW query
= { inQuery
};
1844 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1845 bool result
= false;
1847 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1850 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1851 if (token
== NULL
) {
1852 return SecItemRawUpdate(query
, attributes
, error
);
1854 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1859 CFReleaseSafe(query
.mutable_dictionary
);
1860 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1864 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1866 OSStatus status
= errSecSuccess
;
1867 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1869 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1870 && CFEqual(class, kSecClassIdentity
)) {
1871 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1872 const void *vals
[] = { kCFBooleanTrue
, persist
};
1873 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1874 vals
, (array_size(keys
)), NULL
, NULL
);
1875 CFTypeRef item_query
= NULL
;
1876 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1877 CFReleaseNull(persistent_query
);
1880 if (item_query
== NULL
)
1881 return errSecItemNotFound
;
1883 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1884 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1885 CFRelease(item_query
);
1891 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1893 __block SecCFDictionaryCOW query
= { inQuery
};
1895 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1896 os_activity_scope(activity
);
1897 os_release(activity
);
1899 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1900 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1902 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1903 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1904 if (token
== NULL
) {
1905 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1907 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1910 // Delete item from the token.
1911 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1912 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1913 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1915 // Delete the item from the keychain.
1916 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1917 SecSecurityClientGet(), error
), out
);
1928 CFReleaseSafe(query
.mutable_dictionary
);
1935 SecItemDeleteAll(void)
1937 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1940 if (!gSecurityd
->sec_item_delete_all(error
))
1941 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1943 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1951 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1953 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1954 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1959 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1961 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1962 os_activity_scope(activity
);
1963 os_release(activity
);
1965 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1966 SecSecurityClientGet(), error
);
1973 #if SECITEM_SHIM_OSX
1974 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1976 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1981 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1982 os_activity_scope(activity
);
1983 os_release(activity
);
1985 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1986 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
1987 if (tokenItemsAttributes
) {
1988 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1989 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
1990 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
1991 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
1992 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
1993 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
1994 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
1995 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
1997 CFRelease(tokenItems
);
2001 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
2002 CFDictionarySetValue(attributes
, kSecValueData
, data
);
2003 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
2004 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2005 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2006 CFArrayAppendValue(tokenItems
, attributes
);
2007 CFRelease(attributes
);
2011 CFArrayAppendValue(tokenItems
, itemAttributes
);
2014 tmpArrayRef
= tokenItems
;
2017 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2023 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2024 __block CFArrayRef result
;
2025 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2026 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2031 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2033 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2035 do_if_registered(sec_roll_keys
, force
, error
);
2037 __block
bool result
= false;
2039 secdebug("secitem","enter - %s", __FUNCTION__
);
2040 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2041 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2042 xpc_dictionary_set_bool(message
, "force", force
);
2045 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2046 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2052 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2053 __block CFArrayRef results
= NULL
;
2054 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2055 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2056 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2058 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2059 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2064 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2065 __block
bool result
= false;
2066 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2067 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2068 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2069 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2071 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2072 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2078 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2079 CFArrayRef results
= NULL
;
2081 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2082 os_activity_scope(activity
);
2083 os_release(activity
);
2085 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2090 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2091 bool results
= false;
2093 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2094 os_activity_scope(activity
);
2095 os_release(activity
);
2097 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);