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 secerror("SecItem: failed to create identity");
447 #ifdef SECITEM_SHIM_OSX
449 ref
= SecItemCreateFromAttributeDictionary_osx(refAttributes
);
456 SecItemCopyDisplayNames(CFArrayRef items
, CFArrayRef
*displayNames
)
459 return -1 /* errSecUnimplemented */;
462 typedef OSStatus (*secitem_operation
)(CFDictionaryRef attributes
, CFTypeRef
*result
);
464 static bool explode_identity(CFDictionaryRef attributes
, secitem_operation operation
,
465 OSStatus
*return_status
, CFTypeRef
*return_result
)
467 bool handled
= false;
468 CFTypeRef value
= CFDictionaryGetValue(attributes
, kSecValueRef
);
470 CFTypeID typeID
= CFGetTypeID(value
);
471 if (typeID
== SecIdentityGetTypeID()) {
473 OSStatus status
= errSecSuccess
;
474 SecIdentityRef identity
= (SecIdentityRef
)value
;
475 SecCertificateRef cert
= NULL
;
476 SecKeyRef key
= NULL
;
477 if (!SecIdentityCopyCertificate(identity
, &cert
) &&
478 !SecIdentityCopyPrivateKey(identity
, &key
))
480 CFMutableDictionaryRef partial_query
=
481 CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
482 CFDictionarySetValue(partial_query
, kSecValueRef
, cert
);
483 CFTypeRef result
= NULL
;
484 bool duplicate_cert
= false;
485 /* an identity is first and foremost a key, but it can have multiple
486 certs associated with it: so we identify it by the cert */
487 status
= operation(partial_query
, return_result
? &result
: NULL
);
488 if ((operation
== (secitem_operation
)SecItemAdd
) &&
489 (status
== errSecDuplicateItem
)) {
490 duplicate_cert
= true;
491 status
= errSecSuccess
;
494 if (!status
|| status
== errSecItemNotFound
) {
495 bool skip_key_operation
= false;
497 /* if the key is still in use, skip deleting it */
498 if (operation
== (secitem_operation
)SecItemDelete
) {
499 // find certs with cert.pkhh == keys.klbl
500 CFDictionaryRef key_dict
= NULL
, query_dict
= NULL
;
501 CFDataRef pkhh
= NULL
;
503 key_dict
= SecKeyCopyAttributeDictionary(key
);
505 pkhh
= (CFDataRef
)CFDictionaryGetValue(key_dict
, kSecAttrApplicationLabel
);
506 const void *keys
[] = { kSecClass
, kSecAttrPublicKeyHash
};
507 const void *vals
[] = { kSecClassCertificate
, pkhh
};
509 query_dict
= CFDictionaryCreate(NULL
, keys
,
510 vals
, (array_size(keys
)),
513 if (errSecSuccess
== SecItemCopyMatching(query_dict
, NULL
))
514 skip_key_operation
= true;
515 CFReleaseSafe(query_dict
);
516 CFReleaseSafe(key_dict
);
519 if (!skip_key_operation
) {
520 /* now perform the operation for the key */
521 CFDictionarySetValue(partial_query
, kSecValueRef
, key
);
522 CFDictionarySetValue(partial_query
, kSecReturnPersistentRef
, kCFBooleanFalse
);
524 status
= operation(partial_query
, NULL
);
525 if ((operation
== (secitem_operation
)SecItemAdd
) &&
526 (status
== errSecDuplicateItem
) &&
528 status
= errSecSuccess
;
531 /* add and copy matching for an identityref have a persistent ref result */
534 /* result is a persistent ref to a cert */
536 CFDictionaryRef tokenAttrs
= NULL
;
537 if (_SecItemParsePersistentRef(result
, NULL
, &rowid
, &tokenAttrs
)) {
538 *return_result
= _SecItemCreatePersistentRef(kSecClassIdentity
, rowid
, tokenAttrs
);
540 CFReleaseNull(tokenAttrs
);
545 CFReleaseNull(partial_query
);
548 status
= errSecInvalidItemRef
;
552 *return_status
= status
;
555 value
= CFDictionaryGetValue(attributes
, kSecClass
);
556 if (value
&& CFEqual(kSecClassIdentity
, value
) &&
557 (operation
== (secitem_operation
)SecItemDelete
)) {
558 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, attributes
);
559 CFDictionaryRemoveValue(dict
, kSecClass
);
560 CFDictionarySetValue(dict
, kSecClass
, kSecClassCertificate
);
561 OSStatus status
= SecItemDelete(dict
);
563 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
564 status
= SecItemDelete(dict
);
567 *return_status
= status
;
575 SecErrorPropagateLastError(OSStatus status
, CFErrorRef
*error
)
578 CFErrorRef lastError
= SecCopyLastError(status
);
580 CFErrorPropagate(lastError
, error
);
582 SecError(status
, error
, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status
);
589 handleUpdateIdentity(CFDictionaryRef query
,
590 CFDictionaryRef update
,
594 CFMutableDictionaryRef updatedQuery
= NULL
;
595 SecCertificateRef cert
= NULL
;
596 SecKeyRef key
= NULL
;
597 bool handled
= false;
601 CFTypeRef value
= CFDictionaryGetValue(query
, kSecValueRef
);
603 CFTypeID typeID
= CFGetTypeID(value
);
604 if (typeID
== SecIdentityGetTypeID()) {
605 SecIdentityRef identity
= (SecIdentityRef
)value
;
610 status
= SecIdentityCopyCertificate(identity
, &cert
);
611 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
613 status
= SecIdentityCopyPrivateKey(identity
, &key
);
614 require_noerr_action_quiet(status
, errOut
, SecErrorPropagateLastError(status
, error
));
616 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
617 require_action_quiet(updatedQuery
, errOut
, *result
= false);
619 CFDictionarySetValue(updatedQuery
, kSecValueRef
, cert
);
620 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
622 CFDictionarySetValue(updatedQuery
, kSecValueRef
, key
);
623 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
627 value
= CFDictionaryGetValue(query
, kSecClass
);
628 if (value
&& CFEqual(kSecClassIdentity
, value
)) {
631 updatedQuery
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
632 require_action_quiet(updatedQuery
, errOut
, *result
= false);
634 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassCertificate
);
635 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
637 CFDictionarySetValue(updatedQuery
, kSecClass
, kSecClassKey
);
638 require_quiet(SecItemUpdateWithError(updatedQuery
, update
, error
), errOut
);
640 CFReleaseNull(updatedQuery
);
645 CFReleaseNull(updatedQuery
);
651 static void infer_cert_label(SecCFDictionaryCOW
*attributes
)
653 if (!CFDictionaryContainsKey(attributes
->dictionary
, kSecAttrLabel
)) {
654 CFTypeRef value_ref
= CFDictionaryGetValue(attributes
->dictionary
, kSecValueRef
);
655 if (value_ref
&& CFGetTypeID(value_ref
) == SecCertificateGetTypeID()) {
656 SecCertificateRef certificate
= (SecCertificateRef
)value_ref
;
657 CFStringRef label
= SecCertificateCopySubjectSummary(certificate
);
659 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
), kSecAttrLabel
, label
);
660 CFReleaseNull(label
);
666 static CFDataRef
CreateTokenPersistentRefData(CFTypeRef
class, CFDictionaryRef attributes
)
668 CFDataRef tokenPersistentRef
= NULL
;
669 CFStringRef tokenId
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
670 CFDictionaryRef itemValue
= NULL
;
671 if (CFEqual(class, kSecClassIdentity
)) {
672 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecAttrIdentityCertificateData
), NULL
);
674 itemValue
= SecTokenItemValueCopy(CFDictionaryGetValue(attributes
, kSecValueData
), NULL
);
676 require(itemValue
, out
);
677 CFDataRef oid
= CFDictionaryGetValue(itemValue
, kSecTokenValueObjectIDKey
);
679 CFArrayRef array
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, class, tokenId
, oid
, NULL
);
680 tokenPersistentRef
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, NULL
);
683 CFReleaseNull(itemValue
);
684 return tokenPersistentRef
;
687 static const uint8_t tk_persistent_ref_id
[] = {'t', 'k', 'p', 'r'};
688 /* A persistent ref is just the class and the rowid of the record.
689 Persistent ref for token items is a der blob with class, tokenID and objectId. */
690 CFDataRef
_SecItemCreatePersistentRef(CFTypeRef
class, sqlite_int64 rowid
, CFDictionaryRef attributes
)
692 CFDataRef result
= NULL
;
693 if (attributes
&& CFDictionaryContainsKey(attributes
, CFEqual(class, kSecClassIdentity
) ? kSecAttrIdentityCertificateTokenID
: kSecAttrTokenID
)) {
694 CFDataRef tokenPersistentRef
= CreateTokenPersistentRefData(class, attributes
);
695 require(tokenPersistentRef
, out
);
696 CFMutableDataRef tmpData
= CFDataCreateMutable(kCFAllocatorDefault
, sizeof(tk_persistent_ref_id
) + CFDataGetLength(tokenPersistentRef
));
697 CFDataAppendBytes(tmpData
, tk_persistent_ref_id
, sizeof(tk_persistent_ref_id
));
698 CFDataAppend(tmpData
, tokenPersistentRef
);
699 CFReleaseNull(tokenPersistentRef
);
702 require(rowid
>= 0, out
);
703 uint8_t bytes
[sizeof(sqlite_int64
) + 4];
704 if (CFStringGetCString(class, (char *)bytes
, 4 + 1 /*null-term*/,
705 kCFStringEncodingUTF8
))
707 OSWriteBigInt64(bytes
+ 4, 0, rowid
);
708 result
= CFDataCreate(NULL
, bytes
, sizeof(bytes
));
715 static Boolean
isValidClass(CFStringRef
class, CFStringRef
*return_class
) {
716 const void *valid_classes
[] = { kSecClassGenericPassword
,
717 kSecClassInternetPassword
,
718 kSecClassAppleSharePassword
,
719 kSecClassCertificate
,
723 for (size_t i
= 0; i
< array_size(valid_classes
); i
++) {
724 if (CFEqual(valid_classes
[i
], class)) {
726 *return_class
= valid_classes
[i
];
734 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref
, CFStringRef
*return_class
, CFDictionaryRef
*return_token_attrs
) {
735 bool valid_ref
= false;
736 CFPropertyListRef pl
= NULL
;
737 const uint8_t *der
= CFDataGetBytePtr(persistent_ref
) + sizeof(tk_persistent_ref_id
);
738 const uint8_t *der_end
= der
+ (CFDataGetLength(persistent_ref
) - sizeof(tk_persistent_ref_id
));
739 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &pl
, NULL
, der
, der_end
), out
);
740 require_quiet(der
== der_end
, out
);
741 require_quiet(CFGetTypeID(pl
) == CFArrayGetTypeID(), out
);
742 require_quiet(CFArrayGetCount(pl
) == 3, out
);
743 require_quiet(valid_ref
= isValidClass(CFArrayGetValueAtIndex(pl
, 0), return_class
), out
);
744 if (return_token_attrs
) {
745 *return_token_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
746 kSecAttrTokenID
, CFArrayGetValueAtIndex(pl
, 1),
747 kSecAttrTokenOID
, CFArrayGetValueAtIndex(pl
, 2), NULL
);
754 /* AUDIT[securityd](done):
755 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
757 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef
*return_class
, sqlite_int64
*return_rowid
, CFDictionaryRef
*return_token_attrs
)
759 bool valid_ref
= false;
760 require(CFGetTypeID(persistent_ref
) == CFDataGetTypeID(), out
);
762 if (CFDataGetLength(persistent_ref
) > (CFIndex
)sizeof(tk_persistent_ref_id
) &&
763 memcmp(tk_persistent_ref_id
, CFDataGetBytePtr(persistent_ref
), sizeof(tk_persistent_ref_id
)) == 0) {
764 valid_ref
= ParseTokenPersistentRefData(persistent_ref
, return_class
, return_token_attrs
);
765 } else if (CFDataGetLength(persistent_ref
) == (CFIndex
)(sizeof(sqlite_int64
) + 4)) {
766 const uint8_t *bytes
= CFDataGetBytePtr(persistent_ref
);
767 sqlite_int64 rowid
= OSReadBigInt64(bytes
+ 4, 0);
769 CFStringRef
class = CFStringCreateWithBytes(kCFAllocatorDefault
,
770 bytes
, CFStringGetLength(kSecClassGenericPassword
),
771 kCFStringEncodingUTF8
, true);
773 if ((valid_ref
= isValidClass(class, return_class
))) {
775 *return_rowid
= rowid
;
783 static bool cf_bool_value(CFTypeRef cf_bool
) {
784 return cf_bool
&& CFBooleanGetValue(cf_bool
);
787 CFMutableDictionaryRef
SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW
*cow_dictionary
) {
788 if (cow_dictionary
->mutable_dictionary
== NULL
) {
789 cow_dictionary
->mutable_dictionary
= CFDictionaryCreateMutableForCFTypes(NULL
);
790 if (cow_dictionary
->dictionary
!= NULL
) {
791 CFDictionaryForEach(cow_dictionary
->dictionary
, ^(const void *key
, const void *value
) {
792 CFDictionarySetValue(cow_dictionary
->mutable_dictionary
, key
, value
);
795 cow_dictionary
->dictionary
= cow_dictionary
->mutable_dictionary
;
798 return cow_dictionary
->mutable_dictionary
;
801 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
802 // access_control and optionally of the data value.
803 static CFDataRef
SecTokenItemValueCreate(CFDataRef oid
, CFDataRef access_control
, CFDataRef object_value
, CFErrorRef
*error
) {
804 CFMutableDictionaryRef value
= NULL
;
805 value
= CFDictionaryCreateMutableForCFTypesWith(NULL
,
806 kSecTokenValueObjectIDKey
, oid
,
807 kSecTokenValueAccessControlKey
, access_control
,
809 if (object_value
!= NULL
) {
810 CFDictionarySetValue(value
, kSecTokenValueDataKey
, object_value
);
813 CFDataRef value_data
= CFPropertyListCreateDERData(NULL
, value
, error
);
818 CFDictionaryRef
SecTokenItemValueCopy(CFDataRef db_value
, CFErrorRef
*error
) {
819 CFPropertyListRef plist
= NULL
;
820 const uint8_t *der
= CFDataGetBytePtr(db_value
);
821 const uint8_t *der_end
= der
+ CFDataGetLength(db_value
);
822 require_quiet(der
= der_decode_plist(0, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
), out
);
823 require_action_quiet(der
== der_end
, out
, SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of token data field")));
824 require_action_quiet(CFDictionaryGetValue(plist
, kSecTokenValueObjectIDKey
) != NULL
, out
,
825 SecError(errSecInternal
, error
, CFSTR("token based item data does not have OID")));
831 TKTokenRef
SecTokenCreate(CFStringRef token_id
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
832 CFMutableDictionaryRef token_attrs
= NULL
;
833 TKTokenRef token
= NULL
;
834 token_attrs
= (auth_params
!= NULL
) ?
835 CFDictionaryCreateMutableCopy(NULL
, 0, auth_params
) :
836 CFDictionaryCreateMutableForCFTypes(NULL
);
837 CFDictionarySetValue(token_attrs
, kSecAttrTokenID
, token_id
);
839 CFDictionaryRemoveValue(token_attrs
, kSecUseAuthenticationContext
);
840 token
= TKTokenCreate(token_attrs
, error
);
842 CFReleaseSafe(token_attrs
);
846 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
847 TKTokenRef token
, CFDataRef object_id
, CFTypeRef
*ref
, CFErrorRef
*error
) {
849 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
850 CFTypeRef token_id
= CFDictionaryGetValue(attributes
, kSecAttrTokenID
);
851 if (token_id
!= NULL
&& object_id
!= NULL
) {
852 if (CFRetainSafe(token
) == NULL
) {
853 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
856 if (auth_params
!= NULL
) {
857 CFDictionaryForEach(auth_params
, ^(const void *key
, const void *value
) {
858 CFDictionaryAddValue(attrs
, key
, value
);
861 CFDictionarySetValue(attrs
, kSecUseToken
, token
);
862 CFDictionarySetValue(attrs
, kSecAttrTokenOID
, object_id
);
865 *ref
= SecItemCreateFromAttributeDictionary(attrs
);
869 CFReleaseSafe(attrs
);
874 /* Turn the returned single value or dictionary that contains all the attributes to create a
875 ref into the exact result the client asked for */
876 static bool SecItemResultCopyPrepared(CFTypeRef raw_result
, TKTokenRef token
,
877 CFDictionaryRef query
, CFDictionaryRef auth_params
,
878 CFTypeRef
*result
, CFErrorRef
*error
) {
880 CFDataRef ac_data
= NULL
;
881 CFDataRef value
= NULL
;
882 CFTypeRef persistent_ref
= NULL
;
883 CFStringRef token_id
= NULL
;
884 CFStringRef cert_token_id
= NULL
;
885 CFDataRef object_id
= NULL
;
886 CFMutableDictionaryRef attrs
= NULL
;
887 CFDataRef cert_data
= NULL
;
888 CFDataRef cert_object_id
= NULL
;
889 TKTokenRef cert_token
= NULL
;
891 bool wants_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnRef
));
892 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnData
));
893 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnAttributes
));
894 bool wants_persistent_ref
= cf_bool_value(CFDictionaryGetValue(query
, kSecReturnPersistentRef
));
896 // Get token value if not provided by the caller.
897 bool token_item
= false;
898 bool cert_token_item
= false;
900 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID()) {
901 token_id
= CFDictionaryGetValue(raw_result
, kSecAttrTokenID
);
902 token_item
= (token_id
!= NULL
);
904 cert_token_id
= CFDictionaryGetValue(raw_result
, kSecAttrIdentityCertificateTokenID
);
905 cert_token_item
= (cert_token_id
!= NULL
);
909 cert_token_item
= true;
911 CFRetainAssign(cert_token
, token
);
914 if ((token_item
|| cert_token_item
) && cf_bool_value(CFDictionaryGetValue(query
, kSecUseTokenRawItems
))) {
916 cert_token_item
= false;
919 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
920 if (wants_data
|| wants_ref
|| (token_item
&& wants_attributes
)) {
921 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
922 value
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValueData
));
924 value
= CFRetainSafe(raw_result
);
925 if (token_item
&& value
!= NULL
) {
926 // Parse token-based item's data field.
927 CFDataRef object_value
= NULL
;
928 CFDictionaryRef parsed_value
= NULL
;
929 require_quiet(parsed_value
= SecTokenItemValueCopy(value
, error
), out
);
930 object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
931 ac_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueAccessControlKey
));
932 object_value
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
933 CFRelease(parsed_value
);
934 if ((wants_data
|| wants_ref
) && object_value
== NULL
) {
935 // Retrieve value directly from the token.
937 require_quiet(token
= SecTokenCreate(token_id
, auth_params
, error
), out
);
939 require_quiet(object_value
= TKTokenCopyObjectData(token
, object_id
, error
), out
);
940 if (CFEqual(object_value
, kCFNull
))
941 CFReleaseNull(object_value
);
943 CFAssignRetained(value
, object_value
);
946 // If only thing requested is data, return them directly.
947 if (!(wants_attributes
|| wants_persistent_ref
|| wants_ref
)) {
948 *result
= CFRetainSafe(value
);
954 // Extract persistent_ref, if caller wants it.
955 if (wants_persistent_ref
) {
956 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
957 persistent_ref
= CFRetainSafe(CFDictionaryGetValue(raw_result
, kSecValuePersistentRef
));
959 persistent_ref
= CFRetainSafe(raw_result
);
961 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
962 if (!(wants_attributes
|| wants_data
|| wants_ref
)) {
963 *result
= CFRetainSafe(persistent_ref
);
969 if (!wants_ref
&& !wants_attributes
&& (!wants_data
|| !wants_persistent_ref
)) {
975 // For other cases we need an output dictionary.
976 if (CFGetTypeID(raw_result
) == CFDictionaryGetTypeID())
977 *result
= CFDictionaryCreateMutableCopy(NULL
, 0, raw_result
);
979 *result
= CFDictionaryCreateForCFTypes(NULL
, NULL
);
980 CFMutableDictionaryRef output
= (CFMutableDictionaryRef
)*result
;
982 if ((wants_data
|| wants_ref
) && value
!= NULL
)
983 CFDictionarySetValue(output
, kSecValueData
, value
);
985 CFDictionaryRemoveValue(output
, kSecValueData
);
987 if (wants_persistent_ref
&& persistent_ref
!= NULL
)
988 CFDictionarySetValue(output
, kSecValuePersistentRef
, persistent_ref
);
990 CFDictionaryRemoveValue(output
, kSecValuePersistentRef
);
992 if ((wants_ref
|| wants_attributes
) && cert_token_item
&&
993 CFEqualSafe(CFDictionaryGetValue(output
, kSecClass
), kSecClassIdentity
)) {
994 // Decode also certdata field of the identity.
995 CFDataRef data
= CFDictionaryGetValue(output
, kSecAttrIdentityCertificateData
);
997 CFDictionaryRef parsed_value
;
998 require_quiet(parsed_value
= SecTokenItemValueCopy(data
, error
), out
);
999 cert_data
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueDataKey
));
1000 cert_object_id
= CFRetainSafe(CFDictionaryGetValue(parsed_value
, kSecTokenValueObjectIDKey
));
1001 CFRelease(parsed_value
);
1002 if (cert_data
== NULL
) {
1003 // Retrieve value directly from the token.
1004 if (cert_token
== NULL
) {
1005 require_quiet(cert_token
= SecTokenCreate(cert_token_id
, auth_params
, error
), out
);
1007 require_quiet(cert_data
= TKTokenCopyObjectData(cert_token
, cert_object_id
, error
), out
);
1008 if (CFEqual(cert_data
, kCFNull
))
1009 CFReleaseNull(cert_data
);
1011 if (cert_data
!= NULL
) {
1012 CFDictionarySetValue(output
, kSecAttrIdentityCertificateData
, cert_data
);
1014 CFDictionaryRemoveValue(output
, kSecAttrIdentityCertificateData
);
1019 if (wants_ref
|| wants_attributes
) {
1020 // Convert serialized form of access control to object form.
1022 CFRetainAssign(ac_data
, CFDictionaryGetValue(output
, kSecAttrAccessControl
));
1025 if (ac_data
!= NULL
) {
1026 SecAccessControlRef ac
;
1027 require_quiet(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
, ac_data
, error
), out
);
1028 CFDictionarySetValue(output
, kSecAttrAccessControl
, ac
);
1035 require_quiet(SecTokenItemCreateFromAttributes(output
, auth_params
, token
, object_id
, &ref
, error
), out
);
1036 if (!(wants_attributes
|| wants_data
|| wants_persistent_ref
)) {
1037 CFAssignRetained(*result
, ref
);
1038 } else if (ref
!= NULL
) {
1039 CFDictionarySetValue(output
, kSecValueRef
, ref
);
1042 // We could have stored data value previously to make ref creation succeed.
1043 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1044 CFDictionaryRemoveValue(output
, kSecValueData
);
1052 CFReleaseSafe(cert_object_id
);
1053 CFReleaseSafe(cert_data
);
1054 CFReleaseSafe(ac_data
);
1055 CFReleaseSafe(value
);
1056 CFReleaseSafe(persistent_ref
);
1057 CFReleaseSafe(object_id
);
1058 CFReleaseSafe(attrs
);
1059 CFReleaseSafe(token
);
1060 CFReleaseSafe(cert_token
);
1064 bool SecItemResultProcess(CFDictionaryRef query
, CFDictionaryRef auth_params
, TKTokenRef token
,
1065 CFTypeRef raw_result
, CFTypeRef
*result
, CFErrorRef
*error
) {
1067 require_action_quiet(raw_result
!= NULL
, out
, ok
= true);
1068 require_action_quiet(result
!= NULL
, out
, ok
= true);
1070 if (CFGetTypeID(raw_result
) == CFArrayGetTypeID()) {
1071 CFIndex i
, count
= CFArrayGetCount(raw_result
);
1072 *result
= CFArrayCreateMutableForCFTypes(NULL
);
1073 for (i
= 0; i
< count
; i
++) {
1075 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result
, i
),
1076 token
, query
, auth_params
, &ref
, error
), out
);
1078 CFArrayAppendValue((CFMutableArrayRef
)*result
, ref
);
1083 require_quiet(SecItemResultCopyPrepared(raw_result
, token
, query
, auth_params
, result
, error
), out
);
1092 CFDataRef
SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context
, CFErrorRef
*error
) {
1093 void *la_lib
= NULL
;
1094 CFDataRef acm_context
= NULL
;
1095 require_action_quiet(la_lib
= dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY
), out
,
1096 SecError(errSecInternal
, error
, CFSTR("failed to open LocalAuthentication.framework")));
1097 LAFunctionCopyExternalizedContext fnCopyExternalizedContext
= NULL
;
1098 require_action_quiet(fnCopyExternalizedContext
= dlsym(la_lib
, "LACopyExternalizedContext"), out
,
1099 SecError(errSecInternal
, error
, CFSTR("failed to obtain LACopyExternalizedContext")));
1100 require_action_quiet(acm_context
= fnCopyExternalizedContext(la_context
), out
,
1101 SecError(errSecInternal
, error
, CFSTR("failed to get ACM handle from LAContext")));
1103 if (la_lib
!= NULL
) {
1109 static bool SecItemAttributesPrepare(SecCFDictionaryCOW
*attrs
, bool forQuery
, CFErrorRef
*error
) {
1111 CFDataRef ac_data
= NULL
, acm_context
= NULL
;
1112 void *la_lib
= NULL
;
1114 // If a ref was specified we get its attribute dictionary and parse it.
1115 CFTypeRef value
= CFDictionaryGetValue(attrs
->dictionary
, kSecValueRef
);
1117 CFDictionaryRef ref_attributes
;
1118 require_action_quiet(ref_attributes
= SecItemCopyAttributeDictionary(value
, forQuery
), out
,
1119 SecError(errSecValueRefUnsupported
, error
, CFSTR("unsupported kSecValueRef in query")));
1121 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1122 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1123 CFDictionaryForEach(ref_attributes
, ^(const void *key
, const void *value
) {
1124 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1125 // so add only those attributes from 'ref' which are missing in attrs.
1126 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs
), key
, value
);
1128 CFRelease(ref_attributes
);
1131 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrTokenOID
);
1134 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1135 // another roundtrip to token driver.
1136 if (forQuery
|| !CFDictionaryContainsKey(attrs
->dictionary
, kSecAttrTokenID
)) {
1137 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecValueRef
);
1141 SecAccessControlRef access_control
= (SecAccessControlRef
)CFDictionaryGetValue(attrs
->dictionary
, kSecAttrAccessControl
);
1142 if (access_control
!= NULL
) {
1143 require_quiet(ac_data
= SecAccessControlCopyData(access_control
), out
);
1144 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrAccessControl
, ac_data
);
1147 const CFTypeRef la_context
= CFDictionaryGetValue(attrs
->dictionary
, kSecUseAuthenticationContext
);
1149 require_action_quiet(!CFDictionaryContainsKey(attrs
->dictionary
, kSecUseCredentialReference
), out
,
1150 SecError(errSecParam
, error
, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1151 require_quiet(acm_context
= SecItemAttributesCopyPreparedAuthContext(la_context
, error
), out
);
1152 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseAuthenticationContext
);
1153 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseCredentialReference
, acm_context
);
1156 CFTypeRef policy
= CFDictionaryGetValue(attrs
->dictionary
, kSecMatchPolicy
);
1158 require_action_quiet(CFGetTypeID(policy
) == SecPolicyGetTypeID(), out
,
1159 SecError(errSecParam
, error
, CFSTR("unsupported kSecMatchPolicy in query")));
1161 CFTypeRef values
[] = { policy
};
1162 CFArrayRef policiesArray
= CFArrayCreate(kCFAllocatorDefault
, values
, 1, &kCFTypeArrayCallBacks
);
1163 xpc_object_t policiesArrayXPC
= SecPolicyArrayCopyXPCArray(policiesArray
, error
);
1164 CFReleaseSafe(policiesArray
);
1165 require_action_quiet(policiesArrayXPC
, out
,
1166 SecError(errSecInternal
, error
, CFSTR("Failed to copy XPC policy")));
1168 CFTypeRef objectReadyForXPC
= _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC
);
1169 xpc_release(policiesArrayXPC
);
1170 require_action_quiet(objectReadyForXPC
, out
,
1171 SecError(errSecInternal
, error
, CFSTR("Failed to create CFObject from XPC policy")));
1173 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecMatchPolicy
, objectReadyForXPC
);
1174 CFRelease(objectReadyForXPC
);
1176 value
= CFDictionaryGetValue(attrs
->dictionary
, kSecAttrIssuer
);
1178 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1179 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(value
), CFDataGetLength(value
) };
1180 DERDecodedInfo content
;
1181 if (DERDecodeItem(&name
, &content
) == DR_Success
&& content
.tag
== ASN1_CONSTR_SEQUENCE
) {
1182 CFDataRef canonical_issuer
= createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1183 if (canonical_issuer
) {
1184 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs
), kSecAttrIssuer
, canonical_issuer
);
1185 CFRelease(canonical_issuer
);
1190 if (CFDictionaryContainsKey(attrs
->dictionary
, kSecUseTokenRawItems
)) {
1191 // This use flag is client-only, securityd does not understand it.
1192 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs
), kSecUseTokenRawItems
);
1198 if (la_lib
!= NULL
) {
1201 CFReleaseSafe(ac_data
);
1202 CFReleaseSafe(acm_context
);
1206 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs
, CFErrorRef
*error
)
1208 CFMutableStringRef log_string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1210 CFArrayForEachC(ac_pairs
, ac_pair
) {
1211 CFStringRef acl_hex_string
= CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair
, 0));
1212 CFStringRef str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair
, 1), acl_hex_string
);
1213 CFStringAppend(log_string
, str
);
1214 CFRelease(acl_hex_string
);
1218 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string
);
1219 SecError(errSecAuthFailed
, error
, CFSTR("%@"), reason
);
1220 __security_simulatecrash(reason
, __sec_exception_code_AuthLoop
);
1222 CFRelease(log_string
);
1226 bool SecItemAuthDo(SecCFDictionaryCOW
*auth_params
, CFErrorRef
*error
, SecItemAuthResult (^perform
)(CFArrayRef
*ac_pairs
, CFErrorRef
*error
),
1227 void (^newCredentialRefAdded
)()) {
1229 CFArrayRef ac_pairs
= NULL
;
1230 SecCFDictionaryCOW auth_options
= { NULL
};
1231 // We need to create shared LAContext for Mail to reduce popups with Auth UI.
1232 // This app-hack will be removed by:<rdar://problem/28305552>
1233 // Similar workaround is for Safari, will be removed by fixing <rdar://problem/29683072>
1234 static CFTypeRef sharedLAContext
= NULL
;
1235 static CFDataRef sharedACMContext
= NULL
;
1236 static dispatch_once_t onceToken
;
1237 dispatch_once(&onceToken
, ^{
1238 CFBundleRef bundle
= CFBundleGetMainBundle();
1239 CFStringRef bundleName
= (bundle
!= NULL
) ? CFBundleGetIdentifier(bundle
) : NULL
;
1240 if (CFEqualSafe(bundleName
, CFSTR("com.apple.mail")) ||
1241 CFEqualSafe(bundleName
, CFSTR("com.apple.WebKit.Networking"))) {
1242 sharedLAContext
= LACreateNewContextWithACMContext(NULL
, error
);
1243 sharedACMContext
= (sharedLAContext
!= NULL
) ? LACopyACMContext(sharedLAContext
, error
) : NULL
;
1246 if (sharedLAContext
&& sharedACMContext
&&
1247 (auth_params
->dictionary
== NULL
|| (CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
) == NULL
&&
1248 CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
) == NULL
))) {
1249 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, sharedLAContext
);
1250 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, sharedACMContext
);
1253 for (uint32_t i
= 0;; ++i
) {
1254 // If the operation succeeded or failed with other than auth-needed error, just leave.
1255 SecItemAuthResult auth_result
= perform(&ac_pairs
, error
);
1256 require_quiet(auth_result
!= kSecItemAuthResultError
, out
);
1257 require_action_quiet(auth_result
== kSecItemAuthResultNeedAuth
, out
, ok
= true);
1259 // If auth_params were not created up to now, do create them because we will definitely need them.
1260 SecCFDictionaryCOWGetMutable(auth_params
);
1262 // Retrieve or create authentication handle and/or ACM context.
1263 CFTypeRef auth_handle
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationContext
);
1264 if (auth_handle
== NULL
) {
1265 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCredentialReference
);
1266 require_quiet(auth_handle
= LACreateNewContextWithACMContext(acm_context
, error
), out
);
1267 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationContext
, auth_handle
);
1268 CFRelease(auth_handle
);
1269 if (acm_context
== NULL
) {
1270 require_quiet(acm_context
= LACopyACMContext(auth_handle
, error
), out
);
1271 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1272 CFRelease(acm_context
);
1273 if (newCredentialRefAdded
) {
1274 newCredentialRefAdded();
1279 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1280 // user retry limit.
1281 require_action(i
< 20, out
, SecItemAuthMaxAttemptsReached(ac_pairs
, error
));
1283 // Prepare auth options dictionary.
1284 if (auth_options
.dictionary
== NULL
) {
1285 CFStringRef operation_prompt
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseOperationPrompt
);
1286 if (operation_prompt
!= NULL
) {
1287 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionAuthenticationReason
);
1288 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, operation_prompt
);
1292 CFStringRef caller_name
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseCallerName
);
1293 if (caller_name
!= NULL
) {
1294 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionCallerName
);
1295 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, caller_name
);
1299 CFTypeRef auth_ui
= CFDictionaryGetValue(auth_params
->dictionary
, kSecUseAuthenticationUI
);
1300 if (CFEqualSafe(auth_ui
, kSecUseAuthenticationUIFail
)) {
1301 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, kLAOptionNotInteractive
);
1302 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options
), key
, kCFBooleanTrue
);
1307 // Go through all access_control-operation pairs and evaluate them.
1309 CFArrayForEachC(ac_pairs
, ac_pair
) {
1310 CFDataRef updated_acl
= NULL
;
1311 require_quiet(LAEvaluateAndUpdateACL(auth_handle
,
1312 CFArrayGetValueAtIndex(ac_pair
, 0), CFArrayGetValueAtIndex(ac_pair
, 1),
1313 auth_options
.dictionary
, &updated_acl
, error
), out
);
1315 if (updated_acl
|| CFEqual(CFArrayGetValueAtIndex(ac_pair
, 1), CFSTR(""))) {
1316 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1317 SecAccessControlRef ac
= NULL
;
1318 require(ac
= SecAccessControlCreateFromData(kCFAllocatorDefault
,
1319 updated_acl
? updated_acl
: CFArrayGetValueAtIndex(ac_pair
, 0), error
), out
);
1320 SecAccessControlSetBound(ac
, true);
1321 CFAssignRetained(updated_acl
, SecAccessControlCopyData(ac
));
1322 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecAttrAccessControl
, updated_acl
);
1323 CFRelease(updated_acl
);
1332 CFReleaseSafe(auth_options
.mutable_dictionary
);
1333 CFReleaseSafe(ac_pairs
);
1337 void SecItemAuthCopyParams(SecCFDictionaryCOW
*auth_params
, SecCFDictionaryCOW
*query
) {
1338 // Store operation prompt.
1339 CFStringRef operation_prompt
= CFDictionaryGetValue(query
->dictionary
, kSecUseOperationPrompt
);
1340 if (operation_prompt
!= NULL
) {
1341 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseOperationPrompt
, operation_prompt
);
1342 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseOperationPrompt
);
1345 // Store caller name.
1346 CFStringRef caller_name
= CFDictionaryGetValue(query
->dictionary
, kSecUseCallerName
);
1347 if (caller_name
!= NULL
) {
1348 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCallerName
, caller_name
);
1349 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCallerName
);
1352 // Find out whether we are allowed to pop up a UI.
1353 CFTypeRef auth_ui
= CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
) ?:
1354 (CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
), kCFBooleanTrue
) ?
1355 kSecUseAuthenticationUIFail
: kSecUseAuthenticationUIAllow
);
1356 if (!CFEqual(auth_ui
, kSecUseAuthenticationUISkip
) || CFDictionaryGetValue(query
->dictionary
, kSecUseNoAuthenticationUI
)) {
1357 if (CFDictionaryContainsKey(query
->dictionary
, kSecUseNoAuthenticationUI
))
1358 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseNoAuthenticationUI
);
1359 if (!CFEqualSafe(auth_ui
, kSecUseAuthenticationUISkip
) && CFDictionaryContainsKey(query
->dictionary
, kSecUseAuthenticationUI
))
1360 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecUseAuthenticationUI
);
1363 if (!CFEqual(auth_ui
, kSecUseAuthenticationUIAllow
)) {
1364 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseAuthenticationUI
, auth_ui
);
1367 CFDataRef acm_context
= CFDictionaryGetValue(query
->dictionary
, kSecUseCredentialReference
);
1368 if (acm_context
!= NULL
) {
1369 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params
), kSecUseCredentialReference
, acm_context
);
1373 static SecItemAuthResult
SecItemCreatePairsFromError(CFErrorRef
*error
, CFArrayRef
*ac_pairs
)
1375 if (error
&& *error
&& CFErrorGetCode(*error
) == errSecAuthNeeded
&& CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
)) {
1376 // Extract ACLs to be verified from the error.
1377 CFDictionaryRef user_info
= CFErrorCopyUserInfo(*error
);
1378 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
1379 CFRetainAssign(*ac_pairs
, CFDictionaryGetValue(user_info
, key
));
1380 if (*ac_pairs
== NULL
)
1381 CFAssignRetained(*ac_pairs
, CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
));
1384 CFRelease(user_info
);
1385 CFReleaseNull(*error
);
1386 return kSecItemAuthResultNeedAuth
;
1388 return kSecItemAuthResultError
;
1391 // Wrapper to handle automatic authentication and token/secd case switching.
1392 bool SecItemAuthDoQuery(SecCFDictionaryCOW
*query
, SecCFDictionaryCOW
*attributes
, const void *secItemOperation
, CFErrorRef
*error
,
1393 bool (^perform
)(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
)) {
1395 __block SecCFDictionaryCOW auth_params
= { NULL
};
1396 SecAccessControlRef access_control
= NULL
;
1397 __block TKTokenRef token
= NULL
;
1399 if (secItemOperation
== SecItemAdd
|| secItemOperation
== SecItemUpdate
) {
1400 CFDictionaryRef dict
= attributes
? attributes
->dictionary
: query
->dictionary
;
1401 access_control
= (SecAccessControlRef
)CFDictionaryGetValue(dict
, kSecAttrAccessControl
);
1402 if (access_control
&& SecAccessControlGetConstraints(access_control
) &&
1403 CFEqualSafe(CFDictionaryGetValue(dict
, kSecAttrSynchronizable
), kCFBooleanTrue
))
1404 require_quiet(SecError(errSecParam
, error
, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out
);
1407 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1408 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1410 secItemOperation
== SecItemCopyMatching
||
1411 secItemOperation
== SecItemUpdate
||
1412 secItemOperation
== SecItemDelete
;
1414 require_quiet(SecItemAttributesPrepare(query
, forQuery
, error
), out
);
1415 if (attributes
!= NULL
)
1416 require_quiet(SecItemAttributesPrepare(attributes
, false, error
), out
);
1418 // Populate auth_params dictionary according to initial query contents.
1419 SecItemAuthCopyParams(&auth_params
, query
);
1421 if (secItemOperation
!= SecItemCopyMatching
) {
1422 // UISkip is allowed only for CopyMatching.
1423 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query
->dictionary
, kSecUseAuthenticationUI
), kSecUseAuthenticationUISkip
), out
,
1424 SecError(errSecParam
, error
,
1425 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1428 ok
= SecItemAuthDo(&auth_params
, error
, ^SecItemAuthResult(CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
1429 SecItemAuthResult result
= kSecItemAuthResultError
;
1431 // Propagate actual credential reference to the query.
1432 if (auth_params
.dictionary
!= NULL
) {
1433 CFDataRef acm_context
= CFDictionaryGetValue(auth_params
.dictionary
, kSecUseCredentialReference
);
1434 if (acm_context
!= NULL
) {
1435 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecUseCredentialReference
, acm_context
);
1438 CFDataRef acl_data_ref
= CFDictionaryGetValue(auth_params
.dictionary
, kSecAttrAccessControl
);
1439 if (acl_data_ref
!= NULL
) {
1440 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes
?: query
), kSecAttrAccessControl
, acl_data_ref
);
1444 // Prepare connection to target token if it is present.
1445 CFStringRef token_id
= CFDictionaryGetValue(query
->dictionary
, kSecAttrTokenID
);
1446 if (secItemOperation
!= SecItemCopyMatching
&& token_id
!= NULL
) {
1447 require_quiet(CFAssignRetained(token
, SecTokenCreate(token_id
, auth_params
.dictionary
, error
)), out
);
1450 CFDictionaryRef attrs
= (attributes
!= NULL
) ? attributes
->dictionary
: NULL
;
1451 if(!perform(token
, query
->dictionary
, attrs
, auth_params
.dictionary
, error
)) {
1452 require_quiet((result
= SecItemCreatePairsFromError(error
, ac_pairs
)) == kSecItemAuthResultOK
, out
);
1455 result
= kSecItemAuthResultOK
;
1460 require_quiet(ok
, out
);
1465 CFReleaseSafe(token
);
1466 CFReleaseSafe(auth_params
.mutable_dictionary
);
1470 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, CFTypeRef
*result
, CFErrorRef
*error
)
1472 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1473 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
);
1474 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
1476 return SecXPCDictionaryCopyPListOptional(response
, kSecXPCKeyResult
, result
, error
);
1482 static CFArrayRef
dict_to_array_error_request(enum SecXPCOperation op
, CFDictionaryRef attributes
, CFErrorRef
*error
)
1484 CFArrayRef result
= NULL
;
1485 bool success
= cftype_to_bool_cftype_error_request(op
, attributes
, (CFTypeRef
*)&result
, error
);
1486 if(success
&& !isArray(result
)){
1487 SecError(errSecUnimplemented
, error
, CFSTR("Unexpected nonarray returned: %@"), result
);
1488 CFReleaseNull(result
);
1493 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op
, CFTypeRef attributes
, __unused SecurityClient
*client
, CFTypeRef
*result
, CFErrorRef
*error
) {
1494 return cftype_to_bool_cftype_error_request(op
, attributes
, result
, error
);
1497 static bool dict_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, CFErrorRef
*error
)
1499 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1500 return SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
);
1504 static bool cfstring_array_to_error_request(enum SecXPCOperation op
, CFStringRef string
, CFArrayRef attributes
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1506 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1508 if (!SecXPCDictionarySetString(message
, kSecXPCKeyString
, string
, error
))
1513 if (!SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, attributes
, error
))
1521 static bool dict_client_to_error_request(enum SecXPCOperation op
, CFDictionaryRef query
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1523 return dict_to_error_request(op
, query
, error
);
1526 static bool SecTokenCreateAccessControlError(CFStringRef operation
, CFDataRef access_control
, CFErrorRef
*error
) {
1527 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
1528 const void *ac_pairs
[] = { CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
) };
1529 const void *keys
[] = { CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
) };
1530 CFAssignRetained(*error
, CFErrorCreateWithUserInfoKeysAndValues(NULL
, kSecErrorDomain
, errSecAuthNeeded
,
1531 keys
, ac_pairs
, 1));
1533 CFRelease(ac_pairs
[0]);
1538 static bool SecTokenProcessError(CFStringRef operation
, TKTokenRef token
, CFTypeRef object_or_attrs
, CFErrorRef
*error
) {
1539 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
1540 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
1541 // Replace error with the one which is augmented with access control and operation which failed,
1542 // which will cause SecItemDoWithAuth to throw UI.
1543 // Create array containing tuple (array) with error and requested operation.
1544 CFDataRef access_control
= (CFGetTypeID(object_or_attrs
) == CFDataGetTypeID()) ?
1545 TKTokenCopyObjectAccessControl(token
, object_or_attrs
, error
) :
1546 TKTokenCopyObjectCreationAccessControl(token
, object_or_attrs
, error
);
1547 if (access_control
!= NULL
) {
1548 SecTokenCreateAccessControlError(operation
, access_control
, error
);
1549 CFRelease(access_control
);
1555 static CFTypeRef
SecTokenCopyUpdatedObjectID(TKTokenRef token
, CFDataRef object_id
, CFMutableDictionaryRef attributes
, CFErrorRef
*error
) {
1556 CFDataRef access_control
= NULL
, db_value
= NULL
, new_object_id
= NULL
;
1557 SecAccessControlRef ac
= NULL
;
1558 CFDictionaryRef old_attrs
= NULL
;
1560 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1561 CFDataRef ac_data
= CFDictionaryGetValue(attributes
, kSecAttrAccessControl
);
1562 if (ac_data
!= NULL
) {
1563 require_quiet(ac
= SecAccessControlCreateFromData(NULL
, ac_data
, error
), out
);
1564 require_action_quiet(SecAccessControlIsBound(ac
), out
,
1565 SecTokenCreateAccessControlError(CFSTR(""), ac_data
, error
));
1568 // Create or update the object on the token.
1569 old_attrs
= CFDictionaryCreateCopy(kCFAllocatorDefault
, attributes
);
1570 require_action_quiet(new_object_id
= TKTokenCreateOrUpdateObject(token
, object_id
, attributes
, error
), out
,
1571 SecTokenProcessError(kAKSKeyOpEncrypt
, token
, object_id
?: (CFTypeRef
)attributes
, error
));
1572 CFDictionaryForEach(old_attrs
, ^(const void *key
, const void *value
) {
1573 if (!CFEqual(key
, kSecValueData
)) {
1574 CFDictionaryAddValue(attributes
, key
, value
);
1578 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1579 require_quiet(access_control
= TKTokenCopyObjectAccessControl(token
, new_object_id
, error
), out
);
1580 require_quiet(db_value
= SecTokenItemValueCreate(new_object_id
, access_control
,
1581 CFDictionaryGetValue(attributes
, kSecValueData
), error
), out
);
1582 CFDictionarySetValue(attributes
, kSecValueData
, db_value
);
1584 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1585 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
1589 CFReleaseSafe(access_control
);
1590 CFReleaseSafe(db_value
);
1591 CFReleaseSafe(old_attrs
);
1592 return new_object_id
;
1595 static bool SecTokenItemAdd(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
,
1596 CFTypeRef
*result
, CFErrorRef
*error
) {
1598 CFTypeRef object_id
= NULL
, ref
= NULL
;
1599 CFDictionaryRef ref_attrs
= NULL
;
1600 CFTypeRef db_result
= NULL
;
1601 CFDataRef db_value
= NULL
;
1602 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
1604 CFDictionarySetValue(attrs
, kSecAttrAccessible
, kSecAttrAccessibleAlwaysPrivate
); //token items should be accesible always because have own ACL encoded in OID
1605 object_id
= CFRetainSafe(CFDictionaryGetValue(attrs
, kSecAttrTokenOID
));
1606 CFDictionaryRemoveValue(attrs
, kSecAttrTokenOID
);
1607 require_quiet(CFAssignRetained(object_id
, SecTokenCopyUpdatedObjectID(token
, object_id
, attrs
, error
)), out
);
1608 if (CFDictionaryContainsKey(attrs
, kSecValueRef
)) {
1609 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1610 // the ref from the dictionary since it is of no use any more.
1611 CFDictionaryRemoveValue(attrs
, kSecValueRef
);
1613 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1614 // by creating ref and getting back its attributes.
1615 require_quiet(SecTokenItemCreateFromAttributes(attrs
, auth_params
, token
, object_id
, &ref
, error
), out
);
1617 if ((ref_attrs
= SecItemCopyAttributeDictionary(ref
, false)) != NULL
) {
1618 CFDictionaryForEach(ref_attrs
, ^(const void *key
, const void *value
) {
1619 if (!CFEqual(key
, kSecValueData
)) {
1620 CFDictionaryAddValue(attrs
, key
, value
);
1627 // Make sure that both attributes and data are returned.
1628 CFDictionarySetValue(attrs
, kSecReturnAttributes
, kCFBooleanTrue
);
1629 CFDictionarySetValue(attrs
, kSecReturnData
, kCFBooleanTrue
);
1631 if (!CFEqualSafe(CFDictionaryGetValue(attrs
, kSecAttrIsPermanent
), kCFBooleanFalse
)) {
1632 // IsPermanent is not present or is true, so add item to the db.
1633 require_quiet(SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attrs
,
1634 SecSecurityClientGet(), &db_result
, error
), out
);
1636 // Process directly result of token call.
1637 db_result
= CFRetain(attrs
);
1639 require_quiet(SecItemResultProcess(attributes
, auth_params
, token
, db_result
, result
, error
), out
);
1643 CFReleaseSafe(db_result
);
1644 CFReleaseSafe(db_value
);
1645 CFReleaseSafe(attrs
);
1646 CFReleaseSafe(ref_attrs
);
1647 CFReleaseSafe(object_id
);
1652 OSStatus
SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
) {
1653 __block SecCFDictionaryCOW attrs
= { attributes
};
1656 os_activity_t activity
= os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1657 os_activity_scope(activity
);
1658 os_release(activity
);
1660 require_quiet(!explode_identity(attrs
.dictionary
, (secitem_operation
)SecItemAdd
, &status
, result
), errOut
);
1661 infer_cert_label(&attrs
);
1663 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1664 return SecItemAuthDoQuery(&attrs
, NULL
, SecItemAdd
, error
, ^bool(TKTokenRef token
, CFDictionaryRef attributes
, CFDictionaryRef unused
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1665 if (token
== NULL
) {
1666 CFTypeRef raw_result
= NULL
;
1667 if (!SECURITYD_XPC(sec_item_add
, cftype_client_to_bool_cftype_error_request
, attributes
, SecSecurityClientGet(), &raw_result
, error
))
1670 bool ok
= SecItemResultProcess(attributes
, auth_params
, token
, raw_result
, result
, error
);
1671 CFReleaseSafe(raw_result
);
1674 // Send request to an appropriate token instead of secd.
1675 return SecTokenItemAdd(token
, attributes
, auth_params
, result
, error
);
1681 CFReleaseSafe(attrs
.mutable_dictionary
);
1687 OSStatus
SecItemCopyMatching(CFDictionaryRef inQuery
, CFTypeRef
*result
) {
1689 __block SecCFDictionaryCOW query
= { inQuery
};
1691 os_activity_t activity
= os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1692 os_activity_scope(activity
);
1693 os_release(activity
);
1695 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemCopyMatching
, &status
, result
), errOut
);
1697 bool wants_data
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnData
));
1698 bool wants_attributes
= cf_bool_value(CFDictionaryGetValue(query
.dictionary
, kSecReturnAttributes
));
1699 if ((wants_data
&& !wants_attributes
)) {
1700 // When either attributes or data are requested, we need to query both, because for token based items,
1701 // both are needed in order to generate proper data and/or attributes results.
1702 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query
), kSecReturnAttributes
, kCFBooleanTrue
);
1705 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1706 return SecItemAuthDoQuery(&query
, NULL
, SecItemCopyMatching
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1707 CFTypeRef raw_result
= NULL
;
1708 if (!SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, query
, SecSecurityClientGet(), &raw_result
, error
))
1711 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1712 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1713 // to currently processed item.
1714 bool ok
= SecItemResultProcess(inQuery
, auth_params
, NULL
, raw_result
, result
, error
);
1715 CFReleaseSafe(raw_result
);
1722 CFReleaseSafe(query
.mutable_dictionary
);
1726 // Invokes token-object handler for each item matching specified query.
1727 static bool SecTokenItemForEachMatching(CFDictionaryRef query
, CFErrorRef
*error
,
1728 bool (^perform
)(CFDictionaryRef item_value
, CFDictionaryRef item_query
,
1729 CFErrorRef
*error
)) {
1731 CFMutableDictionaryRef list_query
= NULL
;
1732 CFTypeRef items
= NULL
;
1733 CFArrayRef ref_array
= NULL
;
1734 CFDictionaryRef item_query
= NULL
, item_data
= NULL
;
1736 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1737 // items in the keychain.
1738 list_query
= CFDictionaryCreateMutableCopy(NULL
, 0, query
);
1739 if (CFDictionaryGetValue(list_query
, kSecMatchLimit
) == NULL
) {
1740 CFDictionarySetValue(list_query
, kSecMatchLimit
, kSecMatchLimitAll
);
1742 CFDictionarySetValue(list_query
, kSecReturnData
, kCFBooleanTrue
);
1743 CFDictionarySetValue(list_query
, kSecReturnPersistentRef
, kCFBooleanTrue
);
1744 require_quiet(SECURITYD_XPC(sec_item_copy_matching
, cftype_client_to_bool_cftype_error_request
, list_query
,
1745 SecSecurityClientGet(), &items
, error
), out
);
1746 if (CFGetTypeID(items
) != CFArrayGetTypeID()) {
1747 // Wrap single returned item into the array.
1748 CFArrayRef item_array
= CFArrayCreateForCFTypes(NULL
, items
, NULL
);
1749 CFAssignRetained(items
, item_array
);
1753 CFArrayForEachC(items
, item
) {
1754 CFDataRef data
= CFDictionaryGetValue(item
, kSecValueData
);
1755 require_action_quiet(data
!= NULL
, out
, SecError(errSecInternal
, error
, CFSTR("value not present for token item")));
1757 CFAssignRetained(item_data
, SecTokenItemValueCopy(data
, error
));
1758 require_quiet(item_data
, out
);
1760 CFAssignRetained(item_query
,
1761 CFDictionaryCreateForCFTypes(NULL
,
1762 kSecValuePersistentRef
, CFDictionaryGetValue(item
, kSecValuePersistentRef
),
1764 require_quiet(perform(item_data
, item_query
, error
), out
);
1770 CFReleaseSafe(list_query
);
1771 CFReleaseSafe(items
);
1772 CFReleaseSafe(item_data
);
1773 CFReleaseSafe(ref_array
);
1774 CFReleaseSafe(item_query
);
1778 static bool SecItemRawUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1781 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1782 CFMutableDictionaryRef tmp
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
1783 CFDictionaryForEach(attributesToUpdate
, ^(const void *key
, const void *value
) { CFDictionaryAddValue(tmp
, key
, value
); });
1784 ok
= gSecurityd
->sec_item_update(query
, tmp
, SecSecurityClientGet(), error
);
1787 xpc_object_t message
= securityd_create_message(sec_item_update_id
, error
);
1789 if (SecXPCDictionarySetPList(message
, kSecXPCKeyQuery
, query
, error
) &&
1790 SecXPCDictionarySetPList(message
, kSecXPCKeyAttributesToUpdate
, attributesToUpdate
, error
)) {
1791 xpc_object_t reply
= securityd_message_with_reply_sync(message
, error
);
1793 ok
= securityd_message_no_error(reply
, error
);
1797 xpc_release(message
);
1803 static bool SecTokenItemUpdate(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
, CFErrorRef
*error
) {
1804 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1806 CFDataRef object_id
= NULL
;
1807 CFMutableDictionaryRef db_value
= NULL
;
1809 // Update attributes on the token.
1810 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(NULL
, 0, attributesToUpdate
);
1811 require_quiet(object_id
= SecTokenCopyUpdatedObjectID(token
, CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
),
1812 attributes
, error
), out
);
1814 // Update attributes in the database.
1815 require_quiet(SecItemRawUpdate(item_query
, attributes
, error
), out
);
1820 CFReleaseSafe(object_id
);
1821 CFReleaseSafe(attributes
);
1822 CFReleaseSafe(db_value
);
1827 OSStatus
SecItemUpdate(CFDictionaryRef inQuery
, CFDictionaryRef inAttributesToUpdate
) {
1828 os_activity_t activity
= os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1829 os_activity_scope(activity
);
1830 os_release(activity
);
1832 return SecOSStatusWith(^bool(CFErrorRef
*error
) {
1833 return SecItemUpdateWithError(inQuery
, inAttributesToUpdate
, error
);
1838 SecItemUpdateWithError(CFDictionaryRef inQuery
,
1839 CFDictionaryRef inAttributesToUpdate
,
1842 __block SecCFDictionaryCOW query
= { inQuery
};
1843 __block SecCFDictionaryCOW attributesToUpdate
= { inAttributesToUpdate
};
1844 bool result
= false;
1846 if (handleUpdateIdentity(inQuery
, inAttributesToUpdate
, &result
, error
))
1849 result
= SecItemAuthDoQuery(&query
, &attributesToUpdate
, SecItemUpdate
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1850 if (token
== NULL
) {
1851 return SecItemRawUpdate(query
, attributes
, error
);
1853 return SecTokenItemUpdate(token
, query
, attributes
, error
);
1858 CFReleaseSafe(query
.mutable_dictionary
);
1859 CFReleaseSafe(attributesToUpdate
.mutable_dictionary
);
1863 static OSStatus
explode_persistent_identity_ref(SecCFDictionaryCOW
*query
)
1865 OSStatus status
= errSecSuccess
;
1866 CFTypeRef persist
= CFDictionaryGetValue(query
->dictionary
, kSecValuePersistentRef
);
1868 if (persist
&& _SecItemParsePersistentRef(persist
, &class, NULL
, NULL
)
1869 && CFEqual(class, kSecClassIdentity
)) {
1870 const void *keys
[] = { kSecReturnRef
, kSecValuePersistentRef
};
1871 const void *vals
[] = { kCFBooleanTrue
, persist
};
1872 CFDictionaryRef persistent_query
= CFDictionaryCreate(NULL
, keys
,
1873 vals
, (array_size(keys
)), NULL
, NULL
);
1874 CFTypeRef item_query
= NULL
;
1875 status
= SecItemCopyMatching(persistent_query
, &item_query
);
1876 CFReleaseNull(persistent_query
);
1879 if (item_query
== NULL
)
1880 return errSecItemNotFound
;
1882 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query
), kSecValuePersistentRef
);
1883 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query
), kSecValueRef
, item_query
);
1884 CFRelease(item_query
);
1890 OSStatus
SecItemDelete(CFDictionaryRef inQuery
) {
1892 __block SecCFDictionaryCOW query
= { inQuery
};
1894 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1895 os_activity_scope(activity
);
1896 os_release(activity
);
1898 require_noerr_quiet(status
= explode_persistent_identity_ref(&query
), errOut
);
1899 require_quiet(!explode_identity(query
.dictionary
, (secitem_operation
)SecItemDelete
, &status
, NULL
), errOut
);
1901 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1902 return SecItemAuthDoQuery(&query
, NULL
, SecItemDelete
, error
, ^bool(TKTokenRef token
, CFDictionaryRef query
, CFDictionaryRef attributes
, CFDictionaryRef auth_params
, CFErrorRef
*error
) {
1903 if (token
== NULL
) {
1904 return SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, query
, SecSecurityClientGet(), error
);
1906 return SecTokenItemForEachMatching(query
, error
, ^bool(CFDictionaryRef object_data
, CFDictionaryRef item_query
, CFErrorRef
*error
) {
1909 // Delete item from the token.
1910 CFDataRef object_id
= CFDictionaryGetValue(object_data
, kSecTokenValueObjectIDKey
);
1911 require_action_quiet(TKTokenDeleteObject(token
, object_id
, error
), out
,
1912 SecTokenProcessError(kAKSKeyOpDelete
, token
, object_id
, error
));
1914 // Delete the item from the keychain.
1915 require_quiet(SECURITYD_XPC(sec_item_delete
, dict_client_to_error_request
, item_query
,
1916 SecSecurityClientGet(), error
), out
);
1927 CFReleaseSafe(query
.mutable_dictionary
);
1934 SecItemDeleteAll(void)
1936 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
1939 if (!gSecurityd
->sec_item_delete_all(error
))
1940 ok
&= SecError(errSecInternal
, error
, CFSTR("sec_item_delete_all is NULL"));
1942 ok
&= securityd_send_sync_and_do(sec_delete_all_id
, error
, NULL
, NULL
);
1950 agrps_client_to_error_request(enum SecXPCOperation op
, CFArrayRef agrps
, __unused SecurityClient
*client
, CFErrorRef
*error
)
1952 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
1953 return SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, agrps
, error
);
1958 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups
, CFErrorRef
*error
) {
1960 os_activity_t activity
= os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1961 os_activity_scope(activity
);
1962 os_release(activity
);
1964 return SECURITYD_XPC(sec_delete_items_with_access_groups
, agrps_client_to_error_request
, accessGroups
,
1965 SecSecurityClientGet(), error
);
1972 #if SECITEM_SHIM_OSX
1973 SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1975 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
)
1980 os_activity_t activity
= os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1981 os_activity_scope(activity
);
1982 os_release(activity
);
1984 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
1985 CFArrayRef tmpArrayRef
= tokenItemsAttributes
;
1986 if (tokenItemsAttributes
) {
1987 CFMutableArrayRef tokenItems
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1988 for (CFIndex i
= 0; i
< CFArrayGetCount(tokenItemsAttributes
); ++i
) {
1989 CFDictionaryRef itemAttributes
= CFArrayGetValueAtIndex(tokenItemsAttributes
, i
);
1990 CFTypeRef accessControl
= CFDictionaryGetValue(itemAttributes
, kSecAttrAccessControl
);
1991 CFTypeRef tokenOID
= CFDictionaryGetValue(itemAttributes
, kSecAttrTokenOID
);
1992 CFTypeRef valueData
= CFDictionaryGetValue(itemAttributes
, kSecValueData
);
1993 if (tokenOID
!= NULL
&& accessControl
!= NULL
&& CFDataGetTypeID() == CFGetTypeID(accessControl
)) {
1994 CFDataRef data
= SecTokenItemValueCreate(tokenOID
, accessControl
, valueData
, error
);
1996 CFRelease(tokenItems
);
2000 CFMutableDictionaryRef attributes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, itemAttributes
);
2001 CFDictionarySetValue(attributes
, kSecValueData
, data
);
2002 CFDictionarySetValue(attributes
, kSecAttrTokenID
, tokenID
);
2003 CFDictionaryRemoveValue(attributes
, kSecAttrAccessControl
);
2004 CFDictionaryRemoveValue(attributes
, kSecAttrTokenOID
);
2005 CFArrayAppendValue(tokenItems
, attributes
);
2006 CFRelease(attributes
);
2010 CFArrayAppendValue(tokenItems
, itemAttributes
);
2013 tmpArrayRef
= tokenItems
;
2016 return SECURITYD_XPC(sec_item_update_token_items
, cfstring_array_to_error_request
, tokenID
, tmpArrayRef
, SecSecurityClientGet(), error
);
2022 CFArrayRef
_SecKeychainSyncUpdateMessage(CFDictionaryRef updates
, CFErrorRef
*error
) {
2023 __block CFArrayRef result
;
2024 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT
, ^{
2025 result
= SECURITYD_XPC(sec_keychain_sync_update_message
, dict_to_array_error_request
, updates
, error
);
2030 #ifndef SECITEM_SHIM_OSX
2031 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2033 OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
)
2035 return -1; /* this is only on OS X currently */
2040 extern OSStatus
SecTaskValidateForRequirement(SecTaskRef task
, CFStringRef requirement
);
2044 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2046 bool _SecKeychainRollKeys(bool force
, CFErrorRef
*error
)
2048 do_if_registered(sec_roll_keys
, force
, error
);
2050 __block
bool result
= false;
2052 secdebug("secitem","enter - %s", __FUNCTION__
);
2053 securityd_send_sync_and_do(kSecXPCOpRollKeys
, error
,
2054 ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2055 xpc_dictionary_set_bool(message
, "force", force
);
2058 ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
2059 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2065 static CFArrayRef
data_array_to_array_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2066 __block CFArrayRef results
= NULL
;
2067 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2068 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2069 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2071 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2072 return SecXPCDictionaryCopyArrayOptional(response
, kSecXPCKeyResult
, &results
, error
);
2077 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op
, CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2078 __block
bool result
= false;
2079 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
2080 SecXPCDictionarySetData(message
, kSecXPCKeyNormalizedIssuer
, normalizedIssuer
, error
);
2081 SecXPCDictionarySetData(message
, kSecXPCKeySerialNumber
, serialNumber
, error
);
2082 SecXPCDictionarySetPList(message
, kSecXPCKeyAccessGroups
, accessGroups
, error
);
2084 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
2085 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
2091 CFArrayRef
SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2092 CFArrayRef results
= NULL
;
2094 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2095 os_activity_scope(activity
);
2096 os_release(activity
);
2098 results
= SECURITYD_XPC(sec_item_copy_parent_certificates
, data_array_to_array_error_request
, normalizedIssuer
, accessGroups
, error
);
2103 bool SecItemCertificateExists(CFDataRef normalizedIssuer
, CFDataRef serialNumber
, CFArrayRef accessGroups
, CFErrorRef
*error
) {
2104 bool results
= false;
2106 os_activity_t activity
= os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
2107 os_activity_scope(activity
);
2108 os_release(activity
);
2110 results
= SECURITYD_XPC(sec_item_certificate_exists
, data_data_array_to_bool_error_request
, normalizedIssuer
, serialNumber
, accessGroups
, error
);