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>
79 #include <Security/SecInternal.h>
80 #include "SOSInternal.h"
81 #include <TargetConditionals.h>
82 #include <ipc/securityd_client.h>
83 #include <Security/SecuritydXPC.h>
84 #include <AssertMacros.h>
86 #include <sys/types.h>
90 #include <libDER/asn1Types.h>
92 #include <utilities/SecDb.h>
93 #include <IOKit/IOReturn.h>
95 #include <coreauthd_spi.h>
96 #include <LocalAuthentication/LAPrivateDefines.h>
97 #include <LocalAuthentication/LACFSupport.h>
99 #include <ctkclient.h>
101 const CFStringRef kSecNetworkExtensionAccessGroupSuffix
= CFSTR("com.apple.networkextensionsharing");
103 /* Return an OSStatus for a sqlite3 error code. */
104 static OSStatus
osstatus_for_s3e(int s3e
)
110 return errSecSuccess
;
111 case SQLITE_READONLY
:
112 return errSecReadOnly
;
113 case SQLITE_CONSTRAINT
:
114 return errSecDuplicateItem
;
115 case SQLITE_ABORT
: // There is no errSecOperationCancelled
117 case SQLITE_MISMATCH
:
118 return errSecNoSuchAttr
;
120 return errSecAllocate
;
123 case SQLITE_INTERNAL
:
124 return errSecInternalComponent
;
125 case SQLITE_FULL
: // Happens if we run out of uniqueids or disk is full (TODO: replace with better code)
126 case SQLITE_PERM
: // No acess permission
127 case SQLITE_AUTH
: // No authorization (e.g. no class key for file)
128 case SQLITE_CANTOPEN
: // can be several reasons for this. Caller should sqlite3_system_errno()
129 case SQLITE_EMPTY
: // SQLite does not seem to use this. Was already here, so keeping
132 return errSecNotAvailable
;
136 static OSStatus
osstatus_for_kern_return(CFIndex kernResult
)
141 return errSecSuccess
;
142 case kIOReturnNotReadable
:
143 case kIOReturnNotWritable
:
144 return errSecAuthFailed
;
145 case kIOReturnNotPermitted
:
146 case kIOReturnNotPrivileged
:
147 case kIOReturnLockedRead
:
148 case kIOReturnLockedWrite
:
149 return errSecInteractionNotAllowed
;
152 case kIOReturnBadArgument
:
155 return errSecNotAvailable
; /* TODO: Replace with a real error code. */
159 static OSStatus
osstatus_for_xpc_error(CFIndex xpcError
) {
162 case kSecXPCErrorSuccess
:
163 return errSecSuccess
;
164 case kSecXPCErrorUnexpectedType
:
165 case kSecXPCErrorUnexpectedNull
:
167 case kSecXPCErrorConnectionFailed
:
168 return errSecNotAvailable
;
169 case kSecXPCErrorUnknown
:
171 return errSecInternal
;
175 static OSStatus
osstatus_for_der_error(CFIndex derError
) {
178 case kSecDERErrorUnknownEncoding
:
179 case kSecDERErrorUnsupportedDERType
:
180 case kSecDERErrorUnsupportedNumberType
:
182 case kSecDERErrorUnsupportedCFObject
:
184 case kSecDERErrorAllocationFailure
:
185 return errSecAllocate
;
187 return errSecInternal
;
191 static OSStatus
osstatus_for_ids_error(CFIndex idsError
) {
194 case kSecIDSErrorNoDeviceID
:
195 return errSecDeviceIDNeeded
;
196 case kSecIDSErrorNotRegistered
:
197 return errSecIDSNotRegistered
;
198 case kSecIDSErrorFailedToSend
:
199 return errSecFailedToSendIDSMessage
;
200 case kSecIDSErrorCouldNotFindMatchingAuthToken
:
201 return errSecDeviceIDNoMatch
;
202 case kSecIDSErrorNoPeersAvailable
:
203 return errSecPeersNotAvailable
;
205 return errSecInternal
;
209 static OSStatus
osstatus_for_localauthentication_error(CFIndex laError
) {
210 // Wrap LA error in Sec error.
212 case kLAErrorUserCancel
:
213 return errSecUserCanceled
;
214 case kLAErrorParameter
:
216 case kLAErrorNotInteractive
:
217 return errSecInteractionNotAllowed
;
219 return errSecAuthFailed
;
223 static OSStatus
osstatus_for_ctk_error(CFIndex ctkError
) {
225 case kTKErrorCodeBadParameter
:
227 case kTKErrorCodeNotImplemented
:
228 return errSecUnimplemented
;
229 case kTKErrorCodeCanceledByUser
:
230 return errSecUserCanceled
;
231 case kTKErrorCodeCorruptedData
:
234 return errSecInternal
;
239 // Convert from securityd error codes to OSStatus for legacy API.
240 OSStatus
SecErrorGetOSStatus(CFErrorRef error
) {
243 status
= errSecSuccess
;
245 CFStringRef domain
= CFErrorGetDomain(error
);
246 if (domain
== NULL
) {
247 secerror("No error domain for error: %@", error
);
248 status
= errSecInternal
;
249 } else if (CFEqual(kSecErrorDomain
, domain
)) {
250 status
= (OSStatus
)CFErrorGetCode(error
);
251 } else if (CFEqual(kSecDbErrorDomain
, domain
)) {
252 status
= osstatus_for_s3e((int)CFErrorGetCode(error
));
253 } else if (CFEqual(kSecErrnoDomain
, domain
)) {
254 status
= (OSStatus
)CFErrorGetCode(error
);
255 } else if (CFEqual(kSecKernDomain
, domain
)) {
256 status
= osstatus_for_kern_return(CFErrorGetCode(error
));
257 } else if (CFEqual(sSecXPCErrorDomain
, domain
)) {
258 status
= osstatus_for_xpc_error(CFErrorGetCode(error
));
259 } else if (CFEqual(sSecDERErrorDomain
, domain
)) {
260 status
= osstatus_for_der_error(CFErrorGetCode(error
));
261 }else if (CFEqual(kSecIDSErrorDomain
, domain
)) {
262 status
= osstatus_for_ids_error(CFErrorGetCode(error
));
263 } else if (CFEqual(CFSTR(kLAErrorDomain
), domain
)) {
264 status
= osstatus_for_localauthentication_error(CFErrorGetCode(error
));
265 } else if (CFEqual(CFSTR(kTKErrorDomain
), domain
)) {
266 status
= osstatus_for_ctk_error(CFErrorGetCode(error
));
267 } else if (CFEqual(kSOSErrorDomain
, domain
)) {
268 status
= errSecInternal
;
270 secnotice("securityd", "unknown error domain: %@ for error: %@", domain
, error
);
271 status
= errSecInternal
;
278 lastErrorReleaseError(void *value
)
285 getLastErrorKey(pthread_key_t
*kv
)
287 static pthread_key_t key
;
288 static bool haveKey
= false;
289 static dispatch_once_t onceToken
;
290 dispatch_once(&onceToken
, ^{
291 if (pthread_key_create(&key
, lastErrorReleaseError
) == 0)
299 SetLastError(CFErrorRef newError
)
302 if (!getLastErrorKey(&key
))
304 CFErrorRef oldError
= pthread_getspecific(key
);
309 pthread_setspecific(key
, newError
);
313 SecCopyLastError(OSStatus status
)
318 if (!getLastErrorKey(&key
))
321 error
= pthread_getspecific(key
);
323 if (status
&& status
!= SecErrorGetOSStatus(error
)) {
332 // Wrapper to provide a CFErrorRef for legacy API.
333 OSStatus
SecOSStatusWith(bool (^perform
)(CFErrorRef
*error
)) {
334 CFErrorRef error
= NULL
;
336 if (perform(&error
)) {
337 assert(error
== NULL
);
339 status
= errSecSuccess
;
343 status
= SecErrorGetOSStatus(error
);
344 if (status
!= errSecItemNotFound
) // Occurs in normal operation, so exclude
345 secinfo("OSStatus", "error:[%" PRIdOSStatus
"] %@", status
, error
);
346 CFReleaseNull(error
);
351 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
352 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
355 static CFDictionaryRef
356 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes
)
358 CFMutableDictionaryRef filtered
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
359 if (filtered
== NULL
)
361 CFDictionaryRemoveValue(filtered
, kSecAttrCanSign
);
362 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerify
);
363 CFDictionaryRemoveValue(filtered
, kSecAttrCanEncrypt
);
364 CFDictionaryRemoveValue(filtered
, kSecAttrCanDecrypt
);
365 CFDictionaryRemoveValue(filtered
, kSecAttrCanDerive
);
366 CFDictionaryRemoveValue(filtered
, kSecAttrCanWrap
);
367 CFDictionaryRemoveValue(filtered
, kSecAttrCanUnwrap
);
368 CFDictionaryRemoveValue(filtered
, kSecAttrCanSignRecover
);
369 CFDictionaryRemoveValue(filtered
, kSecAttrCanVerifyRecover
);
370 CFDictionaryRemoveValue(filtered
, kSecAttrIsPermanent
);
376 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
377 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
379 Currently in need of conversion below:
380 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
381 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
382 currently implemented at all, but when it is needs to short circuit to
383 local evaluation, different from the sql query abilities
386 static CFDictionaryRef
387 SecItemCopyAttributeDictionary(CFTypeRef ref
, bool forQuery
) {
388 CFDictionaryRef refDictionary
= NULL
;
389 CFTypeID typeID
= CFGetTypeID(ref
);
390 if (typeID
== SecKeyGetTypeID()) {
391 refDictionary
= SecKeyCopyAttributeDictionary((SecKeyRef
)ref
);
392 if (refDictionary
&& forQuery
) {
393 CFDictionaryRef filtered
= AttributeCreateFilteredOutSecAttrs(refDictionary
);
394 CFAssignRetained(refDictionary
, filtered
);
396 } else if (typeID
== SecCertificateGetTypeID()) {
397 refDictionary
= SecCertificateCopyAttributeDictionary((SecCertificateRef
)ref
);
398 } else if (typeID
== SecIdentityGetTypeID()) {
400 SecIdentityRef identity
= (SecIdentityRef
)ref
;
401 SecCertificateRef cert
= NULL
;
402 SecKeyRef key
= NULL
;
403 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
404 !SecIdentityCopyPrivateKey(identity
, &key
))
406 CFDataRef data
= SecCertificateCopyData(cert
);
407 CFDictionaryRef key_dict
= SecKeyCopyAttributeDictionary(key
);
409 if (key_dict
&& data
) {
410 refDictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, key_dict
);
411 CFDictionarySetValue((CFMutableDictionaryRef
)refDictionary
, kSecAttrIdentityCertificateData
, data
);
413 CFReleaseNull(key_dict
);
419 return refDictionary
;
422 #ifdef SECITEM_SHIM_OSX
423 extern CFTypeRef
SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
);
427 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
428 CFTypeRef ref
= NULL
;
429 CFStringRef
class = CFDictionaryGetValue(refAttributes
, kSecClass
);
430 if (CFEqual(class, kSecClassKey
)) {
431 ref
= SecKeyCreateFromAttributeDictionary(refAttributes
);
432 } else if (CFEqual(class, kSecClassCertificate
)) {
433 ref
= SecCertificateCreateFromAttributeDictionary(refAttributes
);
434 } else if (CFEqual(class, kSecClassIdentity
)) {
435 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecAttrIdentityCertificateData
);
436 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
437 SecKeyRef key
= SecKeyCreateFromAttributeDictionary(refAttributes
);
439 ref
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
442 #ifdef SECITEM_SHIM_OSX
444 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
451 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
454 return -1 /* errSecUnimplemented */;
457 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
459 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
460 OSStatus
*return_status
, CFTypeRef
*return_result
)
462 bool handled
= false;
463 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
465 CFTypeID typeID
= CFGetTypeID(value
);
466 if (typeID
== SecIdentityGetTypeID()) {
468 OSStatus status
= errSecSuccess
;
469 SecIdentityRef identity
= (SecIdentityRef
)value
;
470 SecCertificateRef cert
= NULL
;
471 SecKeyRef key
= NULL
;
472 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
473 !SecIdentityCopyPrivateKey(identity
, &key
))
475 CFMutableDictionaryRef partial_query
=
476 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
477 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
478 CFTypeRef result
= NULL
;
479 bool duplicate_cert
= false;
480 /* an identity is first and foremost a key, but it can have multiple
481 certs associated with it: so we identify it by the cert */
482 status
= operation(partial_query
, return_result
? &result
: NULL
);
483 if ((operation
== (secitem_operation
)SecItemAdd
) &&
484 (status
== errSecDuplicateItem
)) {
485 duplicate_cert
= true;
486 status
= errSecSuccess
;
489 if (!status
|| status
== errSecItemNotFound
) {
490 bool skip_key_operation
= false;
492 /* if the key is still in use, skip deleting it */
493 if (operation
== (secitem_operation
)SecItemDelete
) {
494 // find certs with cert.pkhh == keys.klbl
495 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
496 CFDataRef pkhh
= NULL
;
498 key_dict
= SecKeyCopyAttributeDictionary(key
);
500 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
501 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
502 const void *vals
[] = { kSecClassCertificate
, pkhh
};
504 query_dict
= CFDictionaryCreate(NULL
, keys
,
505 vals
, (array_size(keys
)),
508 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
509 skip_key_operation
= true;
510 CFReleaseSafe(query_dict
);
511 CFReleaseSafe(key_dict
);
514 if (!skip_key_operation
) {
515 /* now perform the operation for the key */
516 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
517 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
519 status
= operation(partial_query
, NULL
);
520 if ((operation
== (secitem_operation
)SecItemAdd
) &&
521 (status
== errSecDuplicateItem
) &&
523 status
= errSecSuccess
;
526 /* add and copy matching for an identityref have a persistent ref result */
529 /* result is a persistent ref to a cert */
531 CFDictionaryRef tokenAttrs
= NULL
;
532 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
, &tokenAttrs
)) {
533 *return_result
= _SecItemCreatePersistentRef(kSecClassIdentity
, rowid
, tokenAttrs
);
535 CFReleaseNull(tokenAttrs
);
540 CFReleaseNull(partial_query
);
543 status
= errSecInvalidItemRef
;
547 *return_status
= status
;
550 value
= CFDictionaryGetValue(attributes
, kSecClass
);
551 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
552 (operation
== (secitem_operation
)SecItemDelete
)) {
553 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
554 CFDictionaryRemoveValue(dict
, kSecClass
);
555 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
556 OSStatus status
= SecItemDelete(dict
);
558 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
559 status
= SecItemDelete(dict
);
562 *return_status
= status
;
570 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
573 CFErrorRef lastError
= SecCopyLastError(status
);
575 CFErrorPropagate(lastError
, error
);
577 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
584 handleUpdateIdentity(CFDictionaryRef query
,
585 CFDictionaryRef update
,
589 CFMutableDictionaryRef updatedQuery
= NULL
;
590 SecCertificateRef cert
= NULL
;
591 SecKeyRef key
= NULL
;
592 bool handled
= false;
596 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
598 CFTypeID typeID
= CFGetTypeID(value
);
599 if (typeID
== SecIdentityGetTypeID()) {
600 SecIdentityRef identity
= (SecIdentityRef
)value
;
605 status
= SecIdentityCopyCertificate(identity
, &cert
);
606 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
608 status
= SecIdentityCopyPrivateKey(identity
, &key
);
609 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
611 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
612 require_action_quiet(updatedQuery
, errOut
, *result
= false);
614 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
615 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
617 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
618 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
622 value
= CFDictionaryGetValue(query
, kSecClass
);
623 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
626 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
627 require_action_quiet(updatedQuery
, errOut
, *result
= false);
629 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
630 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
632 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
633 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
635 CFReleaseNull(updatedQuery
);
640 CFReleaseNull(updatedQuery
);
646 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
648 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
649 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
650 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
651 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
652 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
654 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
655 CFReleaseNull(label
);
661 static CFDataRef
CreateTokenPersistentRefData(CFTypeRef
class, CFDictionaryRef attributes
)
663 CFDataRef tokenPersistentRef
= NULL
;
664 CFStringRef tokenId
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
665 CFDictionaryRef itemValue
= NULL
;
666 if (CFEqual(class, kSecClassIdentity
)) {
667 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecAttrIdentityCertificateData
), NULL
);
669 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecValueData
), NULL
);
671 require(itemValue
, out
);
672 CFDataRef oid
= CFDictionaryGetValue(itemValue
, kSecTokenValueObjectIDKey
);
674 CFArrayRef array
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, class, tokenId
, oid
, NULL
);
675 tokenPersistentRef
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, NULL
);
678 CFReleaseNull(itemValue
);
679 return tokenPersistentRef
;
682 static const uint8_t tk_persistent_ref_id
[] = {'t', 'k', 'p', 'r'};
683 /* A persistent ref is just the class and the rowid of the record.
684 Persistent ref for token items is a der blob with class, tokenID and objectId. */
685 CFDataRef
_SecItemCreatePersistentRef(CFTypeRef
class, sqlite_int64 rowid
, CFDictionaryRef attributes
)
687 CFDataRef result
= NULL
;
688 if (attributes
&& CFDictionaryContainsKey(attributes
, CFEqual(class, kSecClassIdentity
) ? kSecAttrIdentityCertificateTokenID
: kSecAttrTokenID
)) {
689 CFDataRef tokenPersistentRef
= CreateTokenPersistentRefData(class, attributes
);
690 require(tokenPersistentRef
, out
);
691 CFMutableDataRef tmpData
= CFDataCreateMutable(kCFAllocatorDefault
, sizeof(tk_persistent_ref_id
) + CFDataGetLength(tokenPersistentRef
));
692 CFDataAppendBytes(tmpData
, tk_persistent_ref_id
, sizeof(tk_persistent_ref_id
));
693 CFDataAppend(tmpData
, tokenPersistentRef
);
694 CFReleaseNull(tokenPersistentRef
);
697 require(rowid
>= 0, out
);
698 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
699 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
700 kCFStringEncodingUTF8
))
702 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
703 result
= CFDataCreate(NULL
, bytes
, sizeof(bytes
));
710 static Boolean
isValidClass(CFStringRef
class, CFStringRef
*return_class
) {
711 const void *valid_classes
[] = { kSecClassGenericPassword
,
712 kSecClassInternetPassword
,
713 kSecClassAppleSharePassword
,
714 kSecClassCertificate
,
718 for (size_t i
= 0; i
< array_size(valid_classes
); i
++) {
719 if (CFEqual(valid_classes
[i
], class)) {
721 *return_class
= valid_classes
[i
];
729 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref
, CFStringRef
*return_class
, CFDictionaryRef
*return_token_attrs
) {
730 bool valid_ref
= false;
731 CFPropertyListRef pl
= NULL
;
732 const uint8_t *der
= CFDataGetBytePtr(persistent_ref
) + sizeof(tk_persistent_ref_id
);
733 const uint8_t *der_end
= der
+ (CFDataGetLength(persistent_ref
) - sizeof(tk_persistent_ref_id
));
734 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &pl
, NULL
, der
, der_end
), out
);
735 require_quiet(der
== der_end
, out
);
736 require_quiet(CFGetTypeID(pl
) == CFArrayGetTypeID(), out
);
737 require_quiet(CFArrayGetCount(pl
) == 3, out
);
738 require_quiet(valid_ref
= isValidClass(CFArrayGetValueAtIndex(pl
, 0), return_class
), out
);
739 if (return_token_attrs
) {
740 *return_token_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
741 kSecAttrTokenID
, CFArrayGetValueAtIndex(pl
, 1),
742 kSecAttrTokenOID
, CFArrayGetValueAtIndex(pl
, 2), NULL
);
749 /* AUDIT[securityd](done):
750 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
752 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
, CFDictionaryRef
*return_token_attrs
)
754 bool valid_ref
= false;
755 require(CFGetTypeID(persistent_ref
) == CFDataGetTypeID(), out
);
757 if (CFDataGetLength(persistent_ref
) > (CFIndex
)sizeof(tk_persistent_ref_id
) &&
758 memcmp(tk_persistent_ref_id
, CFDataGetBytePtr(persistent_ref
), sizeof(tk_persistent_ref_id
)) == 0) {
759 valid_ref
= ParseTokenPersistentRefData(persistent_ref
, return_class
, return_token_attrs
);
760 } else if (CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
761 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
762 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
764 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
765 bytes
, CFStringGetLength(kSecClassGenericPassword
),
766 kCFStringEncodingUTF8
, true);
768 if ((valid_ref
= isValidClass(class, return_class
))) {
770 *return_rowid
= rowid
;
778 static bool cf_bool_value(CFTypeRef cf_bool
) {
779 return cf_bool
&& CFBooleanGetValue(cf_bool
);
782 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
783 if (cow_dictionary
->mutable_dictionary
== NULL
) {
784 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
785 if (cow_dictionary
->dictionary
!= NULL
) {
786 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
787 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
790 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
793 return cow_dictionary
->mutable_dictionary
;
796 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
797 // access_control and optionally of the data value.
798 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
799 CFMutableDictionaryRef value
= NULL
;
800 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
801 kSecTokenValueObjectIDKey
, oid
,
802 kSecTokenValueAccessControlKey
, access_control
,
804 if (object_value
!= NULL
) {
805 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
808 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
813 CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
814 CFPropertyListRef plist
= NULL
;
815 const uint8_t *der
= CFDataGetBytePtr(db_value
);
816 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
817 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
818 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
819 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
820 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
826 TKTokenRef
SecTokenCreate(CFStringRef token_id
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
827 CFMutableDictionaryRef token_attrs
= NULL
;
828 TKTokenRef token
= NULL
;
829 token_attrs
= (auth_params
!= NULL
) ?
830 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
) :
831 CFDictionaryCreateMutableForCFTypes(NULL
);
832 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
834 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
835 token
= TKTokenCreate(token_attrs
, error
);
837 CFReleaseSafe(token_attrs
);
841 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
842 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
844 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
845 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
846 if (token_id
!= NULL
&& object_id
!= NULL
) {
847 if (CFRetainSafe(token
) == NULL
) {
848 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
851 if (auth_params
!= NULL
) {
852 CFDictionaryForEach(auth_params
, ^(const void *key
, const void *value
) {
853 CFDictionaryAddValue(attrs
, key
, value
);
856 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
857 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
860 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
864 CFReleaseSafe(attrs
);
869 /* Turn the returned single value or dictionary that contains all the attributes to create a
870 ref into the exact result the client asked for */
871 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
872 CFDictionaryRef query
, CFDictionaryRef auth_params
,
873 CFTypeRef
*result
, CFErrorRef
*error
) {
875 CFDataRef ac_data
= NULL
;
876 CFDataRef value
= NULL
;
877 CFTypeRef persistent_ref
= NULL
;
878 CFStringRef token_id
= NULL
;
879 CFStringRef cert_token_id
= NULL
;
880 CFDataRef object_id
= NULL
;
881 CFMutableDictionaryRef attrs
= NULL
;
882 CFDataRef cert_data
= NULL
;
883 CFDataRef cert_object_id
= NULL
;
884 TKTokenRef cert_token
= NULL
;
886 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
887 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
888 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
889 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
891 // Get token value if not provided by the caller.
892 bool token_item
= false;
893 bool cert_token_item
= false;
895 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
896 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
897 token_item
= (token_id
!= NULL
);
899 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
900 cert_token_item
= (cert_token_id
!= NULL
);
904 cert_token_item
= true;
906 CFRetainAssign(cert_token
, token
);
909 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
911 cert_token_item
= false;
914 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
915 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
916 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
917 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
919 value
= CFRetainSafe(raw_result
);
920 if (token_item
&& value
!= NULL
) {
921 // Parse token-based item's data field.
922 CFDataRef object_value
= NULL
;
923 CFDictionaryRef parsed_value
= NULL
;
924 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
925 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
926 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
927 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
928 CFRelease(parsed_value
);
929 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
930 // Retrieve value directly from the token.
932 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
934 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
935 if (CFEqual(object_value
, kCFNull
))
936 CFReleaseNull(object_value
);
938 CFAssignRetained(value
, object_value
);
941 // If only thing requested is data, return them directly.
942 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
943 *result
= CFRetainSafe(value
);
949 // Extract persistent_ref, if caller wants it.
950 if (wants_persistent_ref
) {
951 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
952 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
954 persistent_ref
= CFRetainSafe(raw_result
);
956 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
957 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
958 *result
= CFRetainSafe(persistent_ref
);
964 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
970 // For other cases we need an output dictionary.
971 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
972 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
974 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
975 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
977 if ((wants_data
|| wants_ref
) && value
!= NULL
)
978 CFDictionarySetValue(output
, kSecValueData
, value
);
980 CFDictionaryRemoveValue(output
, kSecValueData
);
982 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
983 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
985 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
987 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
988 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
989 // Decode also certdata field of the identity.
990 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
992 CFDictionaryRef parsed_value
;
993 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
994 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
995 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
996 CFRelease(parsed_value
);
997 if (cert_data
== NULL
) {
998 // Retrieve value directly from the token.
999 if (cert_token
== NULL
) {
1000 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, auth_params
, error
), out
);
1002 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1003 if (CFEqual(cert_data
, kCFNull
))
1004 CFReleaseNull(cert_data
);
1006 if (cert_data
!= NULL
) {
1007 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1009 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1014 if (wants_ref
|| wants_attributes
) {
1015 // Convert serialized form of access control to object form.
1017 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1020 if (ac_data
!= NULL
) {
1021 SecAccessControlRef ac
;
1022 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1023 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1030 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
, token
, object_id
, &ref
, error
), out
);
1031 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1032 CFAssignRetained(*result
, ref
);
1033 } else if (ref
!= NULL
) {
1034 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1037 // We could have stored data value previously to make ref creation succeed.
1038 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1039 CFDictionaryRemoveValue(output
, kSecValueData
);
1047 CFReleaseSafe(cert_object_id
);
1048 CFReleaseSafe(cert_data
);
1049 CFReleaseSafe(ac_data
);
1050 CFReleaseSafe(value
);
1051 CFReleaseSafe(persistent_ref
);
1052 CFReleaseSafe(object_id
);
1053 CFReleaseSafe(attrs
);
1054 CFReleaseSafe(token
);
1055 CFReleaseSafe(cert_token
);
1059 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1060 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1062 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1063 require_action_quiet(result
!= NULL
, out
, ok
= true);
1065 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1066 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1067 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1068 for (i
= 0; i
< count
; i
++) {
1070 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1071 token
, query
, auth_params
, &ref
, error
), out
);
1073 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1078 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1087 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1088 void *la_lib
= NULL
;
1089 CFDataRef acm_context
= NULL
;
1090 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1091 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1092 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1093 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1094 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1095 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1096 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1098 if (la_lib
!= NULL
) {
1104 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1106 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1107 void *la_lib
= NULL
;
1109 // If a ref was specified we get its attribute dictionary and parse it.
1110 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1112 CFDictionaryRef ref_attributes
;
1113 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1114 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1116 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1117 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1118 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1119 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1120 // so add only those attributes from 'ref' which are missing in attrs.
1121 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1123 CFRelease(ref_attributes
);
1126 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1129 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1130 // another roundtrip to token driver.
1131 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1132 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1136 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1137 if (access_control
!= NULL
) {
1138 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
1139 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1142 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1144 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1145 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1146 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1147 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1148 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1151 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1153 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1154 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1156 CFTypeRef values
[] = { policy
};
1157 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1158 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1159 CFReleaseSafe(policiesArray
);
1160 require_action_quiet(policiesArrayXPC
, out
,
1161 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1163 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1164 xpc_release(policiesArrayXPC
);
1165 require_action_quiet(objectReadyForXPC
, out
,
1166 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1168 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1169 CFRelease(objectReadyForXPC
);
1171 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1173 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1174 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1175 DERDecodedInfo content
;
1176 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1177 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1178 if (canonical_issuer
) {
1179 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1180 CFRelease(canonical_issuer
);
1185 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1186 // This use flag is client-only, securityd does not understand it.
1187 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1193 if (la_lib
!= NULL
) {
1196 CFReleaseSafe(ac_data
);
1197 CFReleaseSafe(acm_context
);
1201 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1203 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1205 CFArrayForEachC(ac_pairs
, ac_pair
) {
1206 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1207 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1208 CFStringAppend(log_string
, str
);
1209 CFRelease(acl_hex_string
);
1213 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1214 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1215 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1217 CFRelease(log_string
);
1221 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1222 void (^newCredentialRefAdded
)()) {
1224 CFArrayRef ac_pairs
= NULL
;
1225 SecCFDictionaryCOW auth_options
= { NULL
};
1226 // We need to create shared LAContext for Mail to reduce popups with Auth UI.
1227 // This app-hack will be removed by:<rdar://problem/28305552>
1228 // Similar workaround is for Safari, will be removed by fixing <rdar://problem/29683072>
1229 static CFTypeRef sharedLAContext
= NULL
;
1230 static CFDataRef sharedACMContext
= NULL
;
1231 static dispatch_once_t onceToken
;
1232 dispatch_once(&onceToken
, ^{
1233 CFBundleRef bundle
= CFBundleGetMainBundle();
1234 CFStringRef bundleName
= (bundle
!= NULL
) ? CFBundleGetIdentifier(bundle
) : NULL
;
1235 if (CFEqualSafe(bundleName
, CFSTR("com.apple.mail")) ||
1236 CFEqualSafe(bundleName
, CFSTR("com.apple.WebKit.Networking"))) {
1237 sharedLAContext
= LACreateNewContextWithACMContext(NULL
, error
);
1238 sharedACMContext
= (sharedLAContext
!= NULL
) ? LACopyACMContext(sharedLAContext
, error
) : NULL
;
1241 if (sharedLAContext
&& sharedACMContext
&&
1242 (auth_params
->dictionary
== NULL
|| (CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
) == NULL
&&
1243 CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
) == NULL
))) {
1244 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, sharedLAContext
);
1245 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, sharedACMContext
);
1248 for (uint32_t i
= 0;; ++i
) {
1249 // If the operation succeeded or failed with other than auth-needed error, just leave.
1250 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1251 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1252 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1254 // If auth_params were not created up to now, do create them because we will definitely need them.
1255 SecCFDictionaryCOWGetMutable(auth_params
);
1257 // Retrieve or create authentication handle and/or ACM context.
1258 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1259 if (auth_handle
== NULL
) {
1260 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1261 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1262 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1263 CFRelease(auth_handle
);
1264 if (acm_context
== NULL
) {
1265 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1266 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1267 CFRelease(acm_context
);
1268 if (newCredentialRefAdded
) {
1269 newCredentialRefAdded();
1274 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1275 // user retry limit.
1276 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1278 // Prepare auth options dictionary.
1279 if (auth_options
.dictionary
== NULL
) {
1280 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1281 if (operation_prompt
!= NULL
) {
1282 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1283 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1287 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1288 if (caller_name
!= NULL
) {
1289 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1290 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1294 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1295 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1296 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1297 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1302 // Go through all access_control-operation pairs and evaluate them.
1304 CFArrayForEachC(ac_pairs
, ac_pair
) {
1305 CFDataRef updated_acl
= NULL
;
1306 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1307 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1308 auth_options
.dictionary
, &updated_acl
, error
), out
);
1310 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1311 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1312 SecAccessControlRef ac
= NULL
;
1313 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1314 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1315 SecAccessControlSetBound(ac
, true);
1316 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1317 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1318 CFRelease(updated_acl
);
1327 CFReleaseSafe(auth_options
.mutable_dictionary
);
1328 CFReleaseSafe(ac_pairs
);
1332 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1333 // Store operation prompt.
1334 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1335 if (operation_prompt
!= NULL
) {
1336 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1337 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1340 // Store caller name.
1341 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1342 if (caller_name
!= NULL
) {
1343 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1344 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1347 // Find out whether we are allowed to pop up a UI.
1348 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1349 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1350 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1351 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1352 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1353 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1354 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1355 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1358 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1359 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1362 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1363 if (acm_context
!= NULL
) {
1364 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1368 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1370 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1371 // Extract ACLs to be verified from the error.
1372 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1373 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1374 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1375 if (*ac_pairs
== NULL
)
1376 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1379 CFRelease(user_info
);
1380 CFReleaseNull(*error
);
1381 return kSecItemAuthResultNeedAuth
;
1383 return kSecItemAuthResultError
;
1386 // Wrapper to handle automatic authentication and token/secd case switching.
1387 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1388 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1390 __block SecCFDictionaryCOW auth_params
= { NULL
};
1391 SecAccessControlRef access_control
= NULL
;
1392 __block TKTokenRef token
= NULL
;
1394 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1395 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1396 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1397 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1398 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1399 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1402 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1403 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1405 secItemOperation
== SecItemCopyMatching
||
1406 secItemOperation
== SecItemUpdate
||
1407 secItemOperation
== SecItemDelete
;
1409 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1410 if (attributes
!= NULL
)
1411 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1413 // Populate auth_params dictionary according to initial query contents.
1414 SecItemAuthCopyParams(&auth_params
, query
);
1416 if (secItemOperation
!= SecItemCopyMatching
) {
1417 // UISkip is allowed only for CopyMatching.
1418 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1419 SecError(errSecParam
, error
,
1420 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1423 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1424 SecItemAuthResult result
= kSecItemAuthResultError
;
1426 // Propagate actual credential reference to the query.
1427 if (auth_params
.dictionary
!= NULL
) {
1428 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1429 if (acm_context
!= NULL
) {
1430 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1433 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1434 if (acl_data_ref
!= NULL
) {
1435 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1439 // Prepare connection to target token if it is present.
1440 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1441 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1442 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, auth_params
.dictionary
, error
)), out
);
1445 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1446 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1447 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1450 result
= kSecItemAuthResultOK
;
1455 require_quiet(ok
, out
);
1460 CFReleaseSafe(token
);
1461 CFReleaseSafe(auth_params
.mutable_dictionary
);
1465 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1467 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1468 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1469 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1471 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1477 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1479 CFArrayRef result
= NULL
;
1480 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1481 if(success
&& !isArray(result
)){
1482 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1483 CFReleaseNull(result
);
1488 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1489 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1492 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1494 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1495 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1499 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1501 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1503 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1508 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1516 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1518 return dict_to_error_request(op
, query
, error
);
1521 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1522 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1523 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1524 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1525 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1526 keys
, ac_pairs
, 1));
1528 CFRelease(ac_pairs
[0]);
1533 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1534 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1535 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1536 // Replace error with the one which is augmented with access control and operation which failed,
1537 // which will cause SecItemDoWithAuth to throw UI.
1538 // Create array containing tuple (array) with error and requested operation.
1539 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1540 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1541 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1542 if (access_control
!= NULL
) {
1543 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1544 CFRelease(access_control
);
1550 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1551 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1552 SecAccessControlRef ac
= NULL
;
1553 CFDictionaryRef old_attrs
= NULL
;
1555 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1556 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1557 if (ac_data
!= NULL
) {
1558 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1559 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1560 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1563 // Create or update the object on the token.
1564 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1565 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1566 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1567 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1568 if (!CFEqual(key
, kSecValueData
)) {
1569 CFDictionaryAddValue(attributes
, key
, value
);
1573 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1574 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1575 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1576 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1577 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1579 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1580 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1584 CFReleaseSafe(access_control
);
1585 CFReleaseSafe(db_value
);
1586 CFReleaseSafe(old_attrs
);
1587 return new_object_id
;
1590 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1591 CFTypeRef
*result
, CFErrorRef
*error
) {
1593 CFTypeRef object_id
= NULL
, ref
= NULL
;
1594 CFDictionaryRef ref_attrs
= NULL
;
1595 CFTypeRef db_result
= NULL
;
1596 CFDataRef db_value
= NULL
;
1597 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1599 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1600 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1601 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1602 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1603 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1604 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1605 // the ref from the dictionary since it is of no use any more.
1606 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1608 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1609 // by creating ref and getting back its attributes.
1610 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1612 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1613 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1614 if (!CFEqual(key
, kSecValueData
)) {
1615 CFDictionaryAddValue(attrs
, key
, value
);
1622 // Make sure that both attributes and data are returned.
1623 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1624 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1626 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1627 // IsPermanent is not present or is true, so add item to the db.
1628 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1629 SecSecurityClientGet(), &db_result
, error
), out
);
1631 // Process directly result of token call.
1632 db_result
= CFRetain(attrs
);
1634 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1638 CFReleaseSafe(db_result
);
1639 CFReleaseSafe(db_value
);
1640 CFReleaseSafe(attrs
);
1641 CFReleaseSafe(ref_attrs
);
1642 CFReleaseSafe(object_id
);
1647 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1648 __block SecCFDictionaryCOW attrs
= { attributes
};
1651 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1652 os_activity_scope(activity
);
1653 os_release(activity
);
1655 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1656 infer_cert_label(&attrs
);
1658 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1659 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1660 if (token
== NULL
) {
1661 CFTypeRef raw_result
= NULL
;
1662 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1665 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1666 CFReleaseSafe(raw_result
);
1669 // Send request to an appropriate token instead of secd.
1670 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1676 CFReleaseSafe(attrs
.mutable_dictionary
);
1682 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1684 __block SecCFDictionaryCOW query
= { inQuery
};
1686 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1687 os_activity_scope(activity
);
1688 os_release(activity
);
1690 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1692 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1693 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1694 if ((wants_data
&& !wants_attributes
) || (!wants_data
&& wants_attributes
)) {
1695 // When either attributes or data are requested, we need to query both, because for token based items,
1696 // both are needed in order to generate proper data and/or attributes results.
1697 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1698 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnData
, kCFBooleanTrue
);
1701 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1702 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1703 CFTypeRef raw_result
= NULL
;
1704 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1707 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1708 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1709 // to currently processed item.
1710 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1711 CFReleaseSafe(raw_result
);
1718 CFReleaseSafe(query
.mutable_dictionary
);
1722 // Invokes token-object handler for each item matching specified query.
1723 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1724 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1725 CFErrorRef
*error
)) {
1727 CFMutableDictionaryRef list_query
= NULL
;
1728 CFTypeRef items
= NULL
;
1729 CFArrayRef ref_array
= NULL
;
1730 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1732 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1733 // items in the keychain.
1734 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1735 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1736 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1738 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1739 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1740 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1741 SecSecurityClientGet(), &items
, error
), out
);
1742 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1743 // Wrap single returned item into the array.
1744 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1745 CFAssignRetained(items
, item_array
);
1749 CFArrayForEachC(items
, item
) {
1750 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1751 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1753 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1754 require_quiet(item_data
, out
);
1756 CFAssignRetained(item_query
,
1757 CFDictionaryCreateForCFTypes(NULL
,
1758 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1760 require_quiet(perform(item_data
, item_query
, error
), out
);
1766 CFReleaseSafe(list_query
);
1767 CFReleaseSafe(items
);
1768 CFReleaseSafe(item_data
);
1769 CFReleaseSafe(ref_array
);
1770 CFReleaseSafe(item_query
);
1774 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1777 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1778 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1779 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1780 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1783 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1785 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1786 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1787 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1789 ok
= securityd_message_no_error(reply
, error
);
1793 xpc_release(message
);
1799 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1800 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1802 CFDataRef object_id
= NULL
;
1803 CFMutableDictionaryRef db_value
= NULL
;
1805 // Update attributes on the token.
1806 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1807 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1808 attributes
, error
), out
);
1810 // Update attributes in the database.
1811 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1816 CFReleaseSafe(object_id
);
1817 CFReleaseSafe(attributes
);
1818 CFReleaseSafe(db_value
);
1823 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1824 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1825 os_activity_scope(activity
);
1826 os_release(activity
);
1828 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1829 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1834 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1835 CFDictionaryRef inAttributesToUpdate
,
1838 __block SecCFDictionaryCOW query
= { inQuery
};
1839 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1840 bool result
= false;
1842 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1845 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1846 if (token
== NULL
) {
1847 return SecItemRawUpdate(query
, attributes
, error
);
1849 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1854 CFReleaseSafe(query
.mutable_dictionary
);
1855 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1859 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1861 OSStatus status
= errSecSuccess
;
1862 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1864 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1865 && CFEqual(class, kSecClassIdentity
)) {
1866 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1867 const void *vals
[] = { kCFBooleanTrue
, persist
};
1868 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1869 vals
, (array_size(keys
)), NULL
, NULL
);
1870 CFTypeRef item_query
= NULL
;
1871 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1872 CFReleaseNull(persistent_query
);
1875 if (item_query
== NULL
)
1876 return errSecItemNotFound
;
1878 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1879 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1880 CFRelease(item_query
);
1886 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1888 __block SecCFDictionaryCOW query
= { inQuery
};
1890 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1891 os_activity_scope(activity
);
1892 os_release(activity
);
1894 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1895 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1897 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1898 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1899 if (token
== NULL
) {
1900 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1902 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1905 // Delete item from the token.
1906 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1907 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1908 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1910 // Delete the item from the keychain.
1911 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1912 SecSecurityClientGet(), error
), out
);
1923 CFReleaseSafe(query
.mutable_dictionary
);
1930 SecItemDeleteAll(void)
1932 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1935 if (!gSecurityd
->sec_item_delete_all(error
))
1936 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1938 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1946 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1948 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1949 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1954 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1956 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1957 os_activity_scope(activity
);
1958 os_release(activity
);
1960 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1961 SecSecurityClientGet(), error
);
1968 #if SECITEM_SHIM_OSX
1969 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1971 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1976 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1977 os_activity_scope(activity
);
1978 os_release(activity
);
1980 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1981 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
1982 if (tokenItemsAttributes
) {
1983 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1984 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
1985 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
1986 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
1987 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
1988 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
1989 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
1990 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
1992 CFRelease(tokenItems
);
1996 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
1997 CFDictionarySetValue(attributes
, kSecValueData
, data
);
1998 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
1999 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2000 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2001 CFArrayAppendValue(tokenItems
, attributes
);
2002 CFRelease(attributes
);
2006 CFArrayAppendValue(tokenItems
, itemAttributes
);
2009 tmpArrayRef
= tokenItems
;
2012 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2018 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2019 __block CFArrayRef result
;
2020 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2021 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2026 #ifndef SECITEM_SHIM_OSX
2027 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2029 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
)
2031 return -1; /* this is only on OS X currently */
2036 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2040 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2042 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2044 do_if_registered(sec_roll_keys
, force
, error
);
2046 __block
bool result
= false;
2048 secdebug("secitem","enter - %s", __FUNCTION__
);
2049 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2050 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2051 xpc_dictionary_set_bool(message
, "force", force
);
2054 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2055 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2061 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2062 __block CFArrayRef results
= NULL
;
2063 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2064 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2065 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2067 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2068 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2073 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2074 __block
bool result
= false;
2075 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2076 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2077 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2078 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2080 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2081 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2087 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2088 CFArrayRef results
= NULL
;
2090 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2091 os_activity_scope(activity
);
2092 os_release(activity
);
2094 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2099 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2100 bool results
= false;
2102 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2103 os_activity_scope(activity
);
2104 os_release(activity
);
2106 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);