]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecItem.c
Security-58286.230.21.tar.gz
[apple/security.git] / OSX / sec / Security / SecItem.c
1 /*
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
27 passwords.)
28 */
29
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>
47 #include <errno.h>
48 #include <limits.h>
49 #include <sqlite3.h>
50 #include <stdint.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <sys/param.h>
54 #include <sys/stat.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>
73 #include <assert.h>
74 #include <dlfcn.h>
75 #include <libaks_acl_cf_keys.h>
76 #include <os/activity.h>
77 #include <pthread.h>
78 #include <os/lock.h>
79
80 #include <Security/SecInternal.h>
81 #include "SOSInternal.h"
82 #include <TargetConditionals.h>
83 #include <ipc/securityd_client.h>
84 #include <Security/SecuritydXPC.h>
85 #include <AssertMacros.h>
86 #include <asl.h>
87 #include <sys/types.h>
88 #include <pwd.h>
89 #include <grp.h>
90 #include <unistd.h>
91 #include <libDER/asn1Types.h>
92
93 #include <utilities/SecDb.h>
94 #include <IOKit/IOReturn.h>
95
96 #include <coreauthd_spi.h>
97 #include <LocalAuthentication/LAPrivateDefines.h>
98 #include <LocalAuthentication/LACFSupport.h>
99
100 #include <ctkclient.h>
101
102 const CFStringRef kSecNetworkExtensionAccessGroupSuffix = CFSTR("com.apple.networkextensionsharing");
103
104 /* Return an OSStatus for a sqlite3 error code. */
105 static OSStatus osstatus_for_s3e(int s3e)
106 {
107 switch (s3e)
108 {
109 case SQLITE_OK:
110 case SQLITE_DONE:
111 return errSecSuccess;
112 case SQLITE_READONLY:
113 return errSecReadOnly;
114 case SQLITE_CONSTRAINT:
115 return errSecDuplicateItem;
116 case SQLITE_ABORT: // There is no errSecOperationCancelled
117 return -1;
118 case SQLITE_MISMATCH:
119 return errSecNoSuchAttr;
120 case SQLITE_NOMEM:
121 return errSecAllocate;
122 case SQLITE_IOERR:
123 return errSecIO;
124 case SQLITE_INTERNAL:
125 return errSecInternalComponent;
126 case SQLITE_FULL: // Happens if we run out of uniqueids or disk is full (TODO: replace with better code)
127 case SQLITE_PERM: // No acess permission
128 case SQLITE_AUTH: // No authorization (e.g. no class key for file)
129 case SQLITE_CANTOPEN: // can be several reasons for this. Caller should sqlite3_system_errno()
130 case SQLITE_EMPTY: // SQLite does not seem to use this. Was already here, so keeping
131 case SQLITE_ERROR:
132 default:
133 return errSecNotAvailable;
134 }
135 }
136
137 static OSStatus osstatus_for_kern_return(CFIndex kernResult)
138 {
139 switch (kernResult)
140 {
141 case KERN_SUCCESS:
142 return errSecSuccess;
143 case kIOReturnNotReadable:
144 case kIOReturnNotWritable:
145 return errSecAuthFailed;
146 case kIOReturnNotPermitted:
147 case kIOReturnNotPrivileged:
148 case kIOReturnLockedRead:
149 case kIOReturnLockedWrite:
150 return errSecInteractionNotAllowed;
151 case kIOReturnError:
152 return errSecDecode;
153 case kIOReturnBadArgument:
154 return errSecParam;
155 default:
156 return errSecNotAvailable; /* TODO: Replace with a real error code. */
157 }
158 }
159
160 static OSStatus osstatus_for_xpc_error(CFIndex xpcError) {
161 switch (xpcError)
162 {
163 case kSecXPCErrorSuccess:
164 return errSecSuccess;
165 case kSecXPCErrorUnexpectedType:
166 case kSecXPCErrorUnexpectedNull:
167 return errSecParam;
168 case kSecXPCErrorConnectionFailed:
169 return errSecNotAvailable;
170 case kSecXPCErrorUnknown:
171 default:
172 return errSecInternal;
173 }
174 }
175
176 static OSStatus osstatus_for_der_error(CFIndex derError) {
177 switch (derError)
178 {
179 case kSecDERErrorUnknownEncoding:
180 case kSecDERErrorUnsupportedDERType:
181 case kSecDERErrorUnsupportedNumberType:
182 return errSecDecode;
183 case kSecDERErrorUnsupportedCFObject:
184 return errSecParam;
185 case kSecDERErrorAllocationFailure:
186 return errSecAllocate;
187 default:
188 return errSecInternal;
189 }
190 }
191
192 static OSStatus osstatus_for_localauthentication_error(CFIndex laError) {
193 // Wrap LA error in Sec error.
194 switch (laError) {
195 case kLAErrorUserCancel:
196 return errSecUserCanceled;
197 case kLAErrorParameter:
198 return errSecParam;
199 case kLAErrorNotInteractive:
200 return errSecInteractionNotAllowed;
201 default:
202 return errSecAuthFailed;
203 }
204 }
205
206 static OSStatus osstatus_for_ctk_error(CFIndex ctkError) {
207 switch (ctkError) {
208 case kTKErrorCodeBadParameter:
209 return errSecParam;
210 case kTKErrorCodeNotImplemented:
211 return errSecUnimplemented;
212 case kTKErrorCodeCanceledByUser:
213 return errSecUserCanceled;
214 case kTKErrorCodeCorruptedData:
215 return errSecDecode;
216 default:
217 return errSecInternal;
218 }
219 }
220
221
222 // Convert from securityd error codes to OSStatus for legacy API.
223 OSStatus SecErrorGetOSStatus(CFErrorRef error) {
224 OSStatus status;
225 if (error == NULL) {
226 status = errSecSuccess;
227 } else {
228 CFStringRef domain = CFErrorGetDomain(error);
229 if (domain == NULL) {
230 secerror("No error domain for error: %@", error);
231 status = errSecInternal;
232 } else if (CFEqual(kSecErrorDomain, domain)) {
233 status = (OSStatus)CFErrorGetCode(error);
234 } else if (CFEqual(kSecDbErrorDomain, domain)) {
235 status = osstatus_for_s3e((int)CFErrorGetCode(error));
236 } else if (CFEqual(kSecErrnoDomain, domain)) {
237 status = (OSStatus)CFErrorGetCode(error);
238 } else if (CFEqual(kSecKernDomain, domain)) {
239 status = osstatus_for_kern_return(CFErrorGetCode(error));
240 } else if (CFEqual(sSecXPCErrorDomain, domain)) {
241 status = osstatus_for_xpc_error(CFErrorGetCode(error));
242 } else if (CFEqual(sSecDERErrorDomain, domain)) {
243 status = osstatus_for_der_error(CFErrorGetCode(error));
244 } else if (CFEqual(CFSTR(kLAErrorDomain), domain)) {
245 status = osstatus_for_localauthentication_error(CFErrorGetCode(error));
246 } else if (CFEqual(CFSTR(kTKErrorDomain), domain)) {
247 status = osstatus_for_ctk_error(CFErrorGetCode(error));
248 } else if (CFEqual(kSOSErrorDomain, domain)) {
249 status = errSecInternal;
250 } else {
251 secnotice("securityd", "unknown error domain: %@ for error: %@", domain, error);
252 status = errSecInternal;
253 }
254 }
255 return status;
256 }
257
258 static void
259 lastErrorReleaseError(void *value)
260 {
261 if (value)
262 CFRelease(value);
263 }
264
265 static bool
266 getLastErrorKey(pthread_key_t *kv)
267 {
268 static pthread_key_t key;
269 static bool haveKey = false;
270 static dispatch_once_t onceToken;
271 dispatch_once(&onceToken, ^{
272 if (pthread_key_create(&key, lastErrorReleaseError) == 0)
273 haveKey = true;
274 });
275 *kv = key;
276 return haveKey;
277 }
278
279 static void
280 SetLastError(CFErrorRef newError)
281 {
282 pthread_key_t key;
283 if (!getLastErrorKey(&key))
284 return;
285 CFErrorRef oldError = pthread_getspecific(key);
286 if (oldError)
287 CFRelease(oldError);
288 if (newError)
289 CFRetain(newError);
290 pthread_setspecific(key, newError);
291 }
292
293 CFErrorRef
294 SecCopyLastError(OSStatus status)
295 {
296 pthread_key_t key;
297 CFErrorRef error;
298
299 if (!getLastErrorKey(&key))
300 return NULL;
301
302 error = pthread_getspecific(key);
303 if (error) {
304 if (status && status != SecErrorGetOSStatus(error)) {
305 error = NULL;
306 } else {
307 CFRetain(error);
308 }
309 }
310 return error;
311 }
312
313 // Wrapper to provide a CFErrorRef for legacy API.
314 OSStatus SecOSStatusWith(bool (^perform)(CFErrorRef *error)) {
315 CFErrorRef error = NULL;
316 OSStatus status;
317 if (perform(&error)) {
318 assert(error == NULL);
319 SetLastError(NULL);
320 status = errSecSuccess;
321 } else {
322 assert(error);
323 SetLastError(error);
324 status = SecErrorGetOSStatus(error);
325 if (status != errSecItemNotFound) // Occurs in normal operation, so exclude
326 secinfo("OSStatus", "error:[%" PRIdOSStatus "] %@", status, error);
327 CFReleaseNull(error);
328 }
329 return status;
330 }
331
332 /* Drop assorted kSecAttrCanXxxx attributes from the query, because these attributes are generated
333 by SecKey implementation and may differ between OS versions, see <rdar://problem/27095761>.
334 */
335
336 static CFDictionaryRef
337 AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes)
338 {
339 CFMutableDictionaryRef filtered = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
340 if (filtered == NULL)
341 return NULL;
342 CFDictionaryRemoveValue(filtered, kSecAttrCanSign);
343 CFDictionaryRemoveValue(filtered, kSecAttrCanVerify);
344 CFDictionaryRemoveValue(filtered, kSecAttrCanEncrypt);
345 CFDictionaryRemoveValue(filtered, kSecAttrCanDecrypt);
346 CFDictionaryRemoveValue(filtered, kSecAttrCanDerive);
347 CFDictionaryRemoveValue(filtered, kSecAttrCanWrap);
348 CFDictionaryRemoveValue(filtered, kSecAttrCanUnwrap);
349 CFDictionaryRemoveValue(filtered, kSecAttrCanSignRecover);
350 CFDictionaryRemoveValue(filtered, kSecAttrCanVerifyRecover);
351 CFDictionaryRemoveValue(filtered, kSecAttrIsPermanent);
352
353 return filtered;
354 }
355
356
357 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
358 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
359
360 Currently in need of conversion below:
361 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
362 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
363 currently implemented at all, but when it is needs to short circuit to
364 local evaluation, different from the sql query abilities
365 */
366
367 static CFDictionaryRef
368 SecItemCopyAttributeDictionary(CFTypeRef ref, bool forQuery) {
369 CFDictionaryRef refDictionary = NULL;
370 CFTypeID typeID = CFGetTypeID(ref);
371 if (typeID == SecKeyGetTypeID()) {
372 refDictionary = SecKeyCopyAttributeDictionary((SecKeyRef)ref);
373 if (refDictionary && forQuery) {
374 CFDictionaryRef filtered = AttributeCreateFilteredOutSecAttrs(refDictionary);
375 CFAssignRetained(refDictionary, filtered);
376 }
377 } else if (typeID == SecCertificateGetTypeID()) {
378 refDictionary = SecCertificateCopyAttributeDictionary((SecCertificateRef)ref);
379 } else if (typeID == SecIdentityGetTypeID()) {
380 assert(false);
381 SecIdentityRef identity = (SecIdentityRef)ref;
382 SecCertificateRef cert = NULL;
383 SecKeyRef key = NULL;
384 if (!SecIdentityCopyCertificate(identity, &cert) &&
385 !SecIdentityCopyPrivateKey(identity, &key))
386 {
387 CFDataRef data = SecCertificateCopyData(cert);
388 CFDictionaryRef key_dict = SecKeyCopyAttributeDictionary(key);
389
390 if (key_dict && data) {
391 refDictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, key_dict);
392 CFDictionarySetValue((CFMutableDictionaryRef)refDictionary, kSecAttrIdentityCertificateData, data);
393 }
394 CFReleaseNull(key_dict);
395 CFReleaseNull(data);
396 }
397 CFReleaseNull(cert);
398 CFReleaseNull(key);
399 }
400 return refDictionary;
401 }
402
403 #ifdef SECITEM_SHIM_OSX
404 extern CFTypeRef SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes);
405 #endif
406
407 static CFTypeRef
408 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
409 CFTypeRef ref = NULL;
410 CFStringRef class = CFDictionaryGetValue(refAttributes, kSecClass);
411 if (CFEqual(class, kSecClassKey)) {
412 ref = SecKeyCreateFromAttributeDictionary(refAttributes);
413 } else if (CFEqual(class, kSecClassCertificate)) {
414 ref = SecCertificateCreateFromAttributeDictionary(refAttributes);
415 } else if (CFEqual(class, kSecClassIdentity)) {
416 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecAttrIdentityCertificateData);
417 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, data);
418 SecKeyRef key = SecKeyCreateFromAttributeDictionary(refAttributes);
419 if (key && cert) {
420 ref = SecIdentityCreate(kCFAllocatorDefault, cert, key);
421 }
422 else {
423 secerror("SecItem: failed to create identity");
424 }
425
426 CFReleaseSafe(key);
427 CFReleaseSafe(cert);
428 #ifdef SECITEM_SHIM_OSX
429 } else {
430 ref = SecItemCreateFromAttributeDictionary_osx(refAttributes);
431 #endif
432 }
433 return ref;
434 }
435
436 #if !TARGET_OS_OSX
437 OSStatus
438 SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames)
439 {
440 // @@@ TBI
441 return -1 /* errSecUnimplemented */;
442 }
443 #endif // TARGET_OS_OSX
444
445 typedef OSStatus (*secitem_operation)(CFDictionaryRef attributes, CFTypeRef *result);
446
447 static bool explode_identity(CFDictionaryRef attributes, secitem_operation operation,
448 OSStatus *return_status, CFTypeRef *return_result)
449 {
450 bool handled = false;
451 CFTypeRef value = CFDictionaryGetValue(attributes, kSecValueRef);
452 if (value) {
453 CFTypeID typeID = CFGetTypeID(value);
454 if (typeID == SecIdentityGetTypeID()) {
455 handled = true;
456 OSStatus status = errSecSuccess;
457 SecIdentityRef identity = (SecIdentityRef)value;
458 SecCertificateRef cert = NULL;
459 SecKeyRef key = NULL;
460 if (!SecIdentityCopyCertificate(identity, &cert) &&
461 !SecIdentityCopyPrivateKey(identity, &key))
462 {
463 CFMutableDictionaryRef partial_query =
464 CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
465 CFDictionarySetValue(partial_query, kSecValueRef, cert);
466 CFTypeRef result = NULL;
467 bool duplicate_cert = false;
468 /* an identity is first and foremost a key, but it can have multiple
469 certs associated with it: so we identify it by the cert */
470 status = operation(partial_query, return_result ? &result : NULL);
471 if ((operation == (secitem_operation)SecItemAdd) &&
472 (status == errSecDuplicateItem)) {
473 duplicate_cert = true;
474 status = errSecSuccess;
475 }
476
477 if (!status || status == errSecItemNotFound) {
478 bool skip_key_operation = false;
479
480 /* if the key is still in use, skip deleting it */
481 if (operation == (secitem_operation)SecItemDelete) {
482 // find certs with cert.pkhh == keys.klbl
483 CFDictionaryRef key_dict = NULL, query_dict = NULL;
484 CFDataRef pkhh = NULL;
485
486 key_dict = SecKeyCopyAttributeDictionary(key);
487 if (key_dict)
488 pkhh = (CFDataRef)CFDictionaryGetValue(key_dict, kSecAttrApplicationLabel);
489 const void *keys[] = { kSecClass, kSecAttrPublicKeyHash };
490 const void *vals[] = { kSecClassCertificate, pkhh };
491 if (pkhh)
492 query_dict = CFDictionaryCreate(NULL, keys,
493 vals, (array_size(keys)),
494 NULL, NULL);
495 if (query_dict)
496 if (errSecSuccess == SecItemCopyMatching(query_dict, NULL))
497 skip_key_operation = true;
498 CFReleaseSafe(query_dict);
499 CFReleaseSafe(key_dict);
500 }
501
502 if (!skip_key_operation) {
503 /* now perform the operation for the key */
504 CFDictionarySetValue(partial_query, kSecValueRef, key);
505 CFDictionarySetValue(partial_query, kSecReturnPersistentRef, kCFBooleanFalse);
506
507 status = operation(partial_query, NULL);
508 if ((operation == (secitem_operation)SecItemAdd) &&
509 (status == errSecDuplicateItem) &&
510 !duplicate_cert)
511 status = errSecSuccess;
512 }
513
514 /* add and copy matching for an identityref have a persistent ref result */
515 if (result) {
516 if (!status) {
517 /* result is a persistent ref to a cert */
518 sqlite_int64 rowid;
519 CFDictionaryRef tokenAttrs = NULL;
520 if (_SecItemParsePersistentRef(result, NULL, &rowid, &tokenAttrs)) {
521 *return_result = _SecItemCreatePersistentRef(kSecClassIdentity, rowid, tokenAttrs);
522 }
523 CFReleaseNull(tokenAttrs);
524 }
525 CFRelease(result);
526 }
527 }
528 CFReleaseNull(partial_query);
529 }
530 else
531 status = errSecInvalidItemRef;
532
533 CFReleaseNull(cert);
534 CFReleaseNull(key);
535 *return_status = status;
536 }
537 } else {
538 value = CFDictionaryGetValue(attributes, kSecClass);
539 if (value && CFEqual(kSecClassIdentity, value) &&
540 (operation == (secitem_operation)SecItemDelete)) {
541 CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
542 CFDictionaryRemoveValue(dict, kSecClass);
543 CFDictionarySetValue(dict, kSecClass, kSecClassCertificate);
544 OSStatus status = SecItemDelete(dict);
545 if (!status) {
546 CFDictionarySetValue(dict, kSecClass, kSecClassKey);
547 status = SecItemDelete(dict);
548 }
549 CFRelease(dict);
550 *return_status = status;
551 handled = true;
552 }
553 }
554 return handled;
555 }
556
557 static bool
558 SecErrorPropagateLastError(OSStatus status, CFErrorRef *error)
559 {
560 if (status) {
561 CFErrorRef lastError = SecCopyLastError(status);
562 if (lastError)
563 CFErrorPropagate(lastError, error);
564 else
565 SecError(status, error, CFSTR("SecError: error not captured, OSStatus was: %d"), (int)status);
566 return false;
567 }
568 return true;
569 }
570
571 static bool
572 handleUpdateIdentity(CFDictionaryRef query,
573 CFDictionaryRef update,
574 bool *result,
575 CFErrorRef *error)
576 {
577 CFMutableDictionaryRef updatedQuery = NULL;
578 SecCertificateRef cert = NULL;
579 SecKeyRef key = NULL;
580 bool handled = false;
581
582 *result = false;
583
584 CFTypeRef value = CFDictionaryGetValue(query, kSecValueRef);
585 if (value) {
586 CFTypeID typeID = CFGetTypeID(value);
587 if (typeID == SecIdentityGetTypeID()) {
588 SecIdentityRef identity = (SecIdentityRef)value;
589 OSStatus status;
590
591 handled = true;
592
593 status = SecIdentityCopyCertificate(identity, &cert);
594 require_noerr_action_quiet(status, errOut, SecErrorPropagateLastError(status, error));
595
596 status = SecIdentityCopyPrivateKey(identity, &key);
597 require_noerr_action_quiet(status, errOut, SecErrorPropagateLastError(status, error));
598
599 updatedQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
600 require_action_quiet(updatedQuery, errOut, *result = false);
601
602 CFDictionarySetValue(updatedQuery, kSecValueRef, cert);
603 require_quiet(SecItemUpdateWithError(updatedQuery, update, error), errOut);
604
605 CFDictionarySetValue(updatedQuery, kSecValueRef, key);
606 require_quiet(SecItemUpdateWithError(updatedQuery, update, error), errOut);
607
608 }
609 } else {
610 value = CFDictionaryGetValue(query, kSecClass);
611 if (value && CFEqual(kSecClassIdentity, value)) {
612 handled = true;
613
614 updatedQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
615 require_action_quiet(updatedQuery, errOut, *result = false);
616
617 CFDictionarySetValue(updatedQuery, kSecClass, kSecClassCertificate);
618 require_quiet(SecItemUpdateWithError(updatedQuery, update, error), errOut);
619
620 CFDictionarySetValue(updatedQuery, kSecClass, kSecClassKey);
621 require_quiet(SecItemUpdateWithError(updatedQuery, update, error), errOut);
622
623 CFReleaseNull(updatedQuery);
624 }
625 }
626 *result = true;
627 errOut:
628 CFReleaseNull(updatedQuery);
629 CFReleaseNull(cert);
630 CFReleaseNull(key);
631 return handled;
632 }
633
634 static void infer_cert_label(SecCFDictionaryCOW *attributes)
635 {
636 if (!CFDictionaryContainsKey(attributes->dictionary, kSecAttrLabel)) {
637 CFTypeRef value_ref = CFDictionaryGetValue(attributes->dictionary, kSecValueRef);
638 if (value_ref && CFGetTypeID(value_ref) == SecCertificateGetTypeID()) {
639 SecCertificateRef certificate = (SecCertificateRef)value_ref;
640 CFStringRef label = SecCertificateCopySubjectSummary(certificate);
641 if (label) {
642 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes), kSecAttrLabel, label);
643 CFReleaseNull(label);
644 }
645 }
646 }
647 }
648
649 static CFDataRef CreateTokenPersistentRefData(CFTypeRef class, CFDictionaryRef attributes)
650 {
651 CFDataRef tokenPersistentRef = NULL;
652 CFStringRef tokenId = CFDictionaryGetValue(attributes, kSecAttrTokenID);
653 CFDictionaryRef itemValue = NULL;
654 if (CFEqual(class, kSecClassIdentity)) {
655 itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecAttrIdentityCertificateData), NULL);
656 } else {
657 itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecValueData), NULL);
658 }
659 require(itemValue, out);
660 CFDataRef oid = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey);
661 require(oid, out);
662 CFArrayRef array = CFArrayCreateForCFTypes(kCFAllocatorDefault, class, tokenId, oid, NULL);
663 tokenPersistentRef = CFPropertyListCreateDERData(kCFAllocatorDefault, array, NULL);
664 CFRelease(array);
665 out:
666 CFReleaseNull(itemValue);
667 return tokenPersistentRef;
668 }
669
670 static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'};
671 /* A persistent ref is just the class and the rowid of the record.
672 Persistent ref for token items is a der blob with class, tokenID and objectId. */
673 CFDataRef _SecItemCreatePersistentRef(CFTypeRef class, sqlite_int64 rowid, CFDictionaryRef attributes)
674 {
675 CFDataRef result = NULL;
676 if (attributes && CFDictionaryContainsKey(attributes, CFEqual(class, kSecClassIdentity) ? kSecAttrIdentityCertificateTokenID : kSecAttrTokenID)) {
677 CFDataRef tokenPersistentRef = CreateTokenPersistentRefData(class, attributes);
678 require(tokenPersistentRef, out);
679 CFMutableDataRef tmpData = CFDataCreateMutable(kCFAllocatorDefault, sizeof(tk_persistent_ref_id) + CFDataGetLength(tokenPersistentRef));
680 CFDataAppendBytes(tmpData, tk_persistent_ref_id, sizeof(tk_persistent_ref_id));
681 CFDataAppend(tmpData, tokenPersistentRef);
682 CFReleaseNull(tokenPersistentRef);
683 result = tmpData;
684 } else {
685 require(rowid >= 0, out);
686 uint8_t bytes[sizeof(sqlite_int64) + 4];
687 if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/,
688 kCFStringEncodingUTF8))
689 {
690 OSWriteBigInt64(bytes + 4, 0, rowid);
691 result = CFDataCreate(NULL, bytes, sizeof(bytes));
692 }
693 }
694 out:
695 return result;
696 }
697
698 static Boolean isValidClass(CFStringRef class, CFStringRef *return_class) {
699 const void *valid_classes[] = { kSecClassGenericPassword,
700 kSecClassInternetPassword,
701 kSecClassAppleSharePassword,
702 kSecClassCertificate,
703 kSecClassKey,
704 kSecClassIdentity };
705
706 for (size_t i = 0; i < array_size(valid_classes); i++) {
707 if (CFEqual(valid_classes[i], class)) {
708 if (return_class)
709 *return_class = valid_classes[i];
710 return true;
711 }
712 }
713
714 return false;
715 }
716
717 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref, CFStringRef *return_class, CFDictionaryRef *return_token_attrs) {
718 bool valid_ref = false;
719 CFPropertyListRef pl = NULL;
720 const uint8_t *der = CFDataGetBytePtr(persistent_ref) + sizeof(tk_persistent_ref_id);
721 const uint8_t *der_end = der + (CFDataGetLength(persistent_ref) - sizeof(tk_persistent_ref_id));
722 require_quiet(der = der_decode_plist(0, kCFPropertyListImmutable, &pl, NULL, der, der_end), out);
723 require_quiet(der == der_end, out);
724 require_quiet(CFGetTypeID(pl) == CFArrayGetTypeID(), out);
725 require_quiet(CFArrayGetCount(pl) == 3, out);
726 require_quiet(valid_ref = isValidClass(CFArrayGetValueAtIndex(pl, 0), return_class), out);
727 if (return_token_attrs) {
728 *return_token_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
729 kSecAttrTokenID, CFArrayGetValueAtIndex(pl, 1),
730 kSecAttrTokenOID, CFArrayGetValueAtIndex(pl, 2), NULL);
731 }
732 out:
733 CFReleaseNull(pl);
734 return valid_ref;
735 }
736
737 /* AUDIT[securityd](done):
738 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
739 */
740 bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid, CFDictionaryRef *return_token_attrs)
741 {
742 bool valid_ref = false;
743 require(CFGetTypeID(persistent_ref) == CFDataGetTypeID(), out);
744
745 if (CFDataGetLength(persistent_ref) > (CFIndex)sizeof(tk_persistent_ref_id) &&
746 memcmp(tk_persistent_ref_id, CFDataGetBytePtr(persistent_ref), sizeof(tk_persistent_ref_id)) == 0) {
747 valid_ref = ParseTokenPersistentRefData(persistent_ref, return_class, return_token_attrs);
748 } else if (CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) {
749 const uint8_t *bytes = CFDataGetBytePtr(persistent_ref);
750 sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0);
751
752 CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault,
753 bytes, CFStringGetLength(kSecClassGenericPassword),
754 kCFStringEncodingUTF8, true);
755
756 if ((valid_ref = isValidClass(class, return_class))) {
757 if (return_rowid)
758 *return_rowid = rowid;
759 }
760 CFRelease(class);
761 }
762 out:
763 return valid_ref;
764 }
765
766 static bool cf_bool_value(CFTypeRef cf_bool) {
767 return cf_bool && CFBooleanGetValue(cf_bool);
768 }
769
770 CFMutableDictionaryRef SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW *cow_dictionary) {
771 if (cow_dictionary->mutable_dictionary == NULL) {
772 cow_dictionary->mutable_dictionary = CFDictionaryCreateMutableForCFTypes(NULL);
773 if (cow_dictionary->dictionary != NULL) {
774 CFDictionaryForEach(cow_dictionary->dictionary, ^(const void *key, const void *value) {
775 CFDictionarySetValue(cow_dictionary->mutable_dictionary, key, value);
776 });
777 }
778 cow_dictionary->dictionary = cow_dictionary->mutable_dictionary;
779 }
780
781 return cow_dictionary->mutable_dictionary;
782 }
783
784 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
785 // access_control and optionally of the data value.
786 static CFDataRef SecTokenItemValueCreate(CFDataRef oid, CFDataRef access_control, CFDataRef object_value, CFErrorRef *error) {
787 CFMutableDictionaryRef value = NULL;
788 value = CFDictionaryCreateMutableForCFTypesWith(NULL,
789 kSecTokenValueObjectIDKey, oid,
790 kSecTokenValueAccessControlKey, access_control,
791 NULL);
792 if (object_value != NULL) {
793 CFDictionarySetValue(value, kSecTokenValueDataKey, object_value);
794 }
795
796 CFDataRef value_data = CFPropertyListCreateDERData(NULL, value, error);
797 CFRelease(value);
798 return value_data;
799 }
800
801 CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error) {
802 CFPropertyListRef plist = NULL;
803 const uint8_t *der = CFDataGetBytePtr(db_value);
804 const uint8_t *der_end = der + CFDataGetLength(db_value);
805 require_quiet(der = der_decode_plist(0, kCFPropertyListImmutable, &plist, error, der, der_end), out);
806 require_action_quiet(der == der_end, out, SecError(errSecDecode, error, CFSTR("trailing garbage at end of token data field")));
807 require_action_quiet(CFDictionaryGetValue(plist, kSecTokenValueObjectIDKey) != NULL, out,
808 SecError(errSecInternal, error, CFSTR("token based item data does not have OID")));
809
810 out:
811 return plist;
812 }
813
814 TKTokenRef SecTokenCreate(CFStringRef token_id, SecCFDictionaryCOW *auth_params, CFErrorRef *error) {
815 CFMutableDictionaryRef token_attrs = NULL;
816 TKTokenRef token = NULL;
817
818 static CFMutableDictionaryRef sharedLAContexts = NULL;
819 static dispatch_once_t onceToken;
820 static os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
821 if ((auth_params->dictionary == NULL || CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference) == NULL) && !CFStringHasPrefix(token_id, kSecAttrTokenIDSecureEnclave)) {
822 dispatch_once(&onceToken, ^{
823 sharedLAContexts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
824 });
825
826 os_unfair_lock_lock(&lock);
827 CFTypeRef ctx = CFDictionaryGetValue(sharedLAContexts, token_id);
828 if (ctx == nil) {
829 ctx = LACreateNewContextWithACMContext(NULL, error);
830 if (!ctx) {
831 secerror("Failed to create authentication context %@", *error);
832 return token;
833 }
834 CFDictionarySetValue(sharedLAContexts, token_id, ctx);
835 CFRelease(ctx);
836 ctx = CFDictionaryGetValue(sharedLAContexts, token_id);
837 }
838
839 CFDataRef credRef = NULL;
840 if (ctx != nil) {
841 credRef = LACopyACMContext(ctx, NULL);
842 }
843
844 if (credRef) {
845 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, ctx);
846 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, credRef);
847 CFRelease(credRef);
848 }
849 os_unfair_lock_unlock(&lock);
850 }
851
852 token_attrs = (auth_params->dictionary != NULL) ?
853 CFDictionaryCreateMutableCopy(NULL, 0, auth_params->dictionary) :
854 CFDictionaryCreateMutableForCFTypes(NULL);
855 CFDictionarySetValue(token_attrs, kSecAttrTokenID, token_id);
856
857 CFDictionaryRemoveValue(token_attrs, kSecUseAuthenticationContext);
858 token = TKTokenCreate(token_attrs, error);
859
860 CFReleaseSafe(token_attrs);
861 return token;
862 }
863
864 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes, CFDictionaryRef auth_params_dict,
865 TKTokenRef token, CFDataRef object_id, CFTypeRef *ref, CFErrorRef *error) {
866 bool ok = false;
867 SecCFDictionaryCOW auth_params = { auth_params_dict };
868 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
869 CFTypeRef token_id = CFDictionaryGetValue(attributes, kSecAttrTokenID);
870 if (token_id != NULL && object_id != NULL) {
871 if (CFRetainSafe(token) == NULL) {
872 require_quiet(token = SecTokenCreate(token_id, &auth_params, error), out);
873 }
874
875 if (auth_params.dictionary != NULL) {
876 CFDictionaryForEach(auth_params.dictionary, ^(const void *key, const void *value) {
877 CFDictionaryAddValue(attrs, key, value);
878 });
879 }
880 CFDictionarySetValue(attrs, kSecUseToken, token);
881 CFDictionarySetValue(attrs, kSecAttrTokenOID, object_id);
882 CFRelease(token);
883 }
884 *ref = SecItemCreateFromAttributeDictionary(attrs);
885 ok = true;
886
887 out:
888 CFReleaseSafe(attrs);
889 CFReleaseSafe(auth_params.mutable_dictionary);
890 return ok;
891 }
892
893
894 /* Turn the returned single value or dictionary that contains all the attributes to create a
895 ref into the exact result the client asked for */
896 static bool SecItemResultCopyPrepared(CFTypeRef raw_result, TKTokenRef token,
897 CFDictionaryRef query, CFDictionaryRef auth_params_dict,
898 CFTypeRef *result, CFErrorRef *error) {
899 bool ok = false;
900 CFDataRef ac_data = NULL;
901 CFDataRef value = NULL;
902 CFTypeRef persistent_ref = NULL;
903 CFStringRef token_id = NULL;
904 CFStringRef cert_token_id = NULL;
905 CFDataRef object_id = NULL;
906 CFMutableDictionaryRef attrs = NULL;
907 CFDataRef cert_data = NULL;
908 CFDataRef cert_object_id = NULL;
909 TKTokenRef cert_token = NULL;
910 SecCFDictionaryCOW auth_params = { auth_params_dict };
911
912 bool wants_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef));
913 bool wants_data = cf_bool_value(CFDictionaryGetValue(query, kSecReturnData));
914 bool wants_attributes = cf_bool_value(CFDictionaryGetValue(query, kSecReturnAttributes));
915 bool wants_persistent_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnPersistentRef));
916
917 // Get token value if not provided by the caller.
918 bool token_item = false;
919 bool cert_token_item = false;
920 if (token == NULL) {
921 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID()) {
922 token_id = CFDictionaryGetValue(raw_result, kSecAttrTokenID);
923 token_item = (token_id != NULL);
924
925 cert_token_id = CFDictionaryGetValue(raw_result, kSecAttrIdentityCertificateTokenID);
926 cert_token_item = (cert_token_id != NULL);
927 }
928 } else {
929 token_item = true;
930 cert_token_item = true;
931 CFRetain(token);
932 CFRetainAssign(cert_token, token);
933 }
934
935 if ((token_item || cert_token_item) && cf_bool_value(CFDictionaryGetValue(query, kSecUseTokenRawItems))) {
936 token_item = false;
937 cert_token_item = false;
938 }
939
940 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
941 if (wants_data || wants_ref || (token_item && wants_attributes)) {
942 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID())
943 value = CFRetainSafe(CFDictionaryGetValue(raw_result, kSecValueData));
944 else
945 value = CFRetainSafe(raw_result);
946 if (token_item && value != NULL) {
947 // Parse token-based item's data field.
948 CFDataRef object_value = NULL;
949 CFDictionaryRef parsed_value = NULL;
950 require_quiet(parsed_value = SecTokenItemValueCopy(value, error), out);
951 object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey));
952 ac_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueAccessControlKey));
953 object_value = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey));
954 CFRelease(parsed_value);
955 if ((wants_data || wants_ref) && object_value == NULL) {
956 // Retrieve value directly from the token.
957 if (token == NULL) {
958 require_quiet(token = SecTokenCreate(token_id, &auth_params, error), out);
959 }
960 require_quiet(object_value = TKTokenCopyObjectData(token, object_id, error), out);
961 if (CFEqual(object_value, kCFNull))
962 CFReleaseNull(object_value);
963 }
964 CFAssignRetained(value, object_value);
965 }
966
967 // If only thing requested is data, return them directly.
968 if (!(wants_attributes || wants_persistent_ref || wants_ref)) {
969 *result = CFRetainSafe(value);
970 ok = true;
971 goto out;
972 }
973 }
974
975 // Extract persistent_ref, if caller wants it.
976 if (wants_persistent_ref) {
977 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID())
978 persistent_ref = CFRetainSafe(CFDictionaryGetValue(raw_result, kSecValuePersistentRef));
979 else
980 persistent_ref = CFRetainSafe(raw_result);
981
982 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
983 if (!(wants_attributes || wants_data || wants_ref)) {
984 *result = CFRetainSafe(persistent_ref);
985 ok = true;
986 goto out;
987 }
988 }
989
990 if (!wants_ref && !wants_attributes && (!wants_data || !wants_persistent_ref)) {
991 *result = NULL;
992 ok = true;
993 goto out;
994 }
995
996 // For other cases we need an output dictionary.
997 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID())
998 *result = CFDictionaryCreateMutableCopy(NULL, 0, raw_result);
999 else
1000 *result = CFDictionaryCreateForCFTypes(NULL, NULL);
1001 CFMutableDictionaryRef output = (CFMutableDictionaryRef)*result;
1002
1003 if ((wants_data || wants_ref) && value != NULL)
1004 CFDictionarySetValue(output, kSecValueData, value);
1005 else
1006 CFDictionaryRemoveValue(output, kSecValueData);
1007
1008 if (wants_persistent_ref && persistent_ref != NULL)
1009 CFDictionarySetValue(output, kSecValuePersistentRef, persistent_ref);
1010 else
1011 CFDictionaryRemoveValue(output, kSecValuePersistentRef);
1012
1013 if ((wants_ref || wants_attributes) && cert_token_item &&
1014 CFEqualSafe(CFDictionaryGetValue(output, kSecClass), kSecClassIdentity)) {
1015 // Decode also certdata field of the identity.
1016 CFDataRef data = CFDictionaryGetValue(output, kSecAttrIdentityCertificateData);
1017 if (data != NULL) {
1018 CFDictionaryRef parsed_value;
1019 require_quiet(parsed_value = SecTokenItemValueCopy(data, error), out);
1020 cert_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey));
1021 cert_object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey));
1022 CFRelease(parsed_value);
1023 if (cert_data == NULL) {
1024 // Retrieve value directly from the token.
1025 if (cert_token == NULL) {
1026 require_quiet(cert_token = SecTokenCreate(cert_token_id, &auth_params, error), out);
1027 }
1028 require_quiet(cert_data = TKTokenCopyObjectData(cert_token, cert_object_id, error), out);
1029 if (CFEqual(cert_data, kCFNull))
1030 CFReleaseNull(cert_data);
1031 }
1032 if (cert_data != NULL) {
1033 CFDictionarySetValue(output, kSecAttrIdentityCertificateData, cert_data);
1034 } else {
1035 CFDictionaryRemoveValue(output, kSecAttrIdentityCertificateData);
1036 }
1037 }
1038 }
1039
1040 if (wants_ref || wants_attributes) {
1041 // Convert serialized form of access control to object form.
1042 if (!token_item) {
1043 CFRetainAssign(ac_data, CFDictionaryGetValue(output, kSecAttrAccessControl));
1044 }
1045
1046 if (ac_data != NULL) {
1047 SecAccessControlRef ac;
1048 require_quiet(ac = SecAccessControlCreateFromData(kCFAllocatorDefault, ac_data, error), out);
1049 CFDictionarySetValue(output, kSecAttrAccessControl, ac);
1050 CFRelease(ac);
1051 }
1052 }
1053
1054 if (wants_ref) {
1055 CFTypeRef ref;
1056 require_quiet(SecTokenItemCreateFromAttributes(output, auth_params.dictionary, token, object_id, &ref, error), out);
1057 if (!(wants_attributes || wants_data || wants_persistent_ref)) {
1058 CFAssignRetained(*result, ref);
1059 } else if (ref != NULL) {
1060 CFDictionarySetValue(output, kSecValueRef, ref);
1061 CFRelease(ref);
1062 if (!wants_data) {
1063 // We could have stored data value previously to make ref creation succeed.
1064 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1065 CFDictionaryRemoveValue(output, kSecValueData);
1066 }
1067 }
1068 }
1069
1070 ok = true;
1071
1072 out:
1073 CFReleaseSafe(cert_object_id);
1074 CFReleaseSafe(cert_data);
1075 CFReleaseSafe(ac_data);
1076 CFReleaseSafe(value);
1077 CFReleaseSafe(persistent_ref);
1078 CFReleaseSafe(object_id);
1079 CFReleaseSafe(attrs);
1080 CFReleaseSafe(token);
1081 CFReleaseSafe(cert_token);
1082 CFReleaseSafe(auth_params.mutable_dictionary);
1083 return ok;
1084 }
1085
1086 bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TKTokenRef token,
1087 CFTypeRef raw_result, CFTypeRef *result, CFErrorRef *error) {
1088 bool ok = false;
1089 require_action_quiet(raw_result != NULL, out, ok = true);
1090 require_action_quiet(result != NULL, out, ok = true);
1091
1092 if (CFGetTypeID(raw_result) == CFArrayGetTypeID()) {
1093 CFIndex i, count = CFArrayGetCount(raw_result);
1094 *result = CFArrayCreateMutableForCFTypes(NULL);
1095 for (i = 0; i < count; i++) {
1096 CFTypeRef ref;
1097 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result, i),
1098 token, query, auth_params, &ref, error), out);
1099 if (ref != NULL) {
1100 CFArrayAppendValue((CFMutableArrayRef)*result, ref);
1101 CFRelease(ref);
1102 }
1103 }
1104 } else {
1105 require_quiet(SecItemResultCopyPrepared(raw_result, token, query, auth_params, result, error), out);
1106 }
1107
1108 ok = true;
1109
1110 out:
1111 return ok;
1112 }
1113
1114 CFDataRef SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context, CFErrorRef *error) {
1115 void *la_lib = NULL;
1116 CFDataRef acm_context = NULL;
1117 require_action_quiet(la_lib = dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY), out,
1118 SecError(errSecInternal, error, CFSTR("failed to open LocalAuthentication.framework")));
1119 LAFunctionCopyExternalizedContext fnCopyExternalizedContext = NULL;
1120 require_action_quiet(fnCopyExternalizedContext = dlsym(la_lib, "LACopyExternalizedContext"), out,
1121 SecError(errSecInternal, error, CFSTR("failed to obtain LACopyExternalizedContext")));
1122 require_action_quiet(acm_context = fnCopyExternalizedContext(la_context), out,
1123 SecError(errSecInternal, error, CFSTR("failed to get ACM handle from LAContext")));
1124 out:
1125 if (la_lib != NULL) {
1126 dlclose(la_lib);
1127 }
1128 return acm_context;
1129 }
1130
1131 static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, CFErrorRef *error) {
1132 bool ok = false;
1133 CFDataRef ac_data = NULL, acm_context = NULL;
1134 void *la_lib = NULL;
1135
1136 // If a ref was specified we get its attribute dictionary and parse it.
1137 CFTypeRef value = CFDictionaryGetValue(attrs->dictionary, kSecValueRef);
1138 if (value) {
1139 CFDictionaryRef ref_attributes;
1140 require_action_quiet(ref_attributes = SecItemCopyAttributeDictionary(value, forQuery), out,
1141 SecError(errSecValueRefUnsupported, error, CFSTR("unsupported kSecValueRef in query")));
1142
1143 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1144 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1145 CFDictionaryForEach(ref_attributes, ^(const void *key, const void *value) {
1146 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1147 // so add only those attributes from 'ref' which are missing in attrs.
1148 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs), key, value);
1149 });
1150 CFRelease(ref_attributes);
1151
1152 if (forQuery) {
1153 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrTokenOID);
1154 }
1155
1156 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1157 // another roundtrip to token driver.
1158 if (forQuery || !CFDictionaryContainsKey(attrs->dictionary, kSecAttrTokenID)) {
1159 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecValueRef);
1160 }
1161 }
1162
1163 SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(attrs->dictionary, kSecAttrAccessControl);
1164 if (access_control != NULL) {
1165 require_quiet(ac_data = SecAccessControlCopyData(access_control), out);
1166 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrAccessControl, ac_data);
1167 }
1168
1169 const CFTypeRef la_context = CFDictionaryGetValue(attrs->dictionary, kSecUseAuthenticationContext);
1170 if (la_context) {
1171 require_action_quiet(!CFDictionaryContainsKey(attrs->dictionary, kSecUseCredentialReference), out,
1172 SecError(errSecParam, error, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1173 require_quiet(acm_context = SecItemAttributesCopyPreparedAuthContext(la_context, error), out);
1174 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseAuthenticationContext);
1175 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseCredentialReference, acm_context);
1176 }
1177
1178 CFTypeRef policy = CFDictionaryGetValue(attrs->dictionary, kSecMatchPolicy);
1179 if (policy) {
1180 require_action_quiet(CFGetTypeID(policy) == SecPolicyGetTypeID(), out,
1181 SecError(errSecParam, error, CFSTR("unsupported kSecMatchPolicy in query")));
1182
1183 CFTypeRef values[] = { policy };
1184 CFArrayRef policiesArray = CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks);
1185 xpc_object_t policiesArrayXPC = SecPolicyArrayCopyXPCArray(policiesArray, error);
1186 CFReleaseSafe(policiesArray);
1187 require_action_quiet(policiesArrayXPC, out,
1188 SecError(errSecInternal, error, CFSTR("Failed to copy XPC policy")));
1189
1190 CFTypeRef objectReadyForXPC = _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC);
1191 xpc_release(policiesArrayXPC);
1192 require_action_quiet(objectReadyForXPC, out,
1193 SecError(errSecInternal, error, CFSTR("Failed to create CFObject from XPC policy")));
1194
1195 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecMatchPolicy, objectReadyForXPC);
1196 CFRelease(objectReadyForXPC);
1197 }
1198 value = CFDictionaryGetValue(attrs->dictionary, kSecAttrIssuer);
1199 if (value) {
1200 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1201 const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) };
1202 DERDecodedInfo content;
1203 if (DERDecodeItem(&name, &content) == DR_Success && content.tag == ASN1_CONSTR_SEQUENCE) {
1204 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content);
1205 if (canonical_issuer) {
1206 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrIssuer, canonical_issuer);
1207 CFRelease(canonical_issuer);
1208 }
1209 }
1210 }
1211
1212 if (CFDictionaryContainsKey(attrs->dictionary, kSecUseTokenRawItems)) {
1213 // This use flag is client-only, securityd does not understand it.
1214 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseTokenRawItems);
1215 }
1216
1217 ok = true;
1218
1219 out:
1220 if (la_lib != NULL) {
1221 dlclose(la_lib);
1222 }
1223 CFReleaseSafe(ac_data);
1224 CFReleaseSafe(acm_context);
1225 return ok;
1226 }
1227
1228 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs, CFErrorRef *error)
1229 {
1230 CFMutableStringRef log_string = CFStringCreateMutable(kCFAllocatorDefault, 0);
1231 CFArrayRef ac_pair;
1232 CFArrayForEachC(ac_pairs, ac_pair) {
1233 CFStringRef acl_hex_string = CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair, 0));
1234 CFStringRef str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair, 1), acl_hex_string);
1235 CFStringAppend(log_string, str);
1236 CFRelease(acl_hex_string);
1237 CFRelease(str);
1238 }
1239
1240 CFStringRef reason = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string);
1241 SecError(errSecAuthFailed, error, CFSTR("%@"), reason);
1242 __security_simulatecrash(reason, __sec_exception_code_AuthLoop);
1243 CFRelease(reason);
1244 CFRelease(log_string);
1245 return false;
1246 }
1247
1248 bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFArrayRef *ac_pairs, CFErrorRef *error),
1249 void (^newCredentialRefAdded)(void)) {
1250 bool ok = false;
1251 CFArrayRef ac_pairs = NULL;
1252 SecCFDictionaryCOW auth_options = { NULL };
1253
1254 for (uint32_t i = 0;; ++i) {
1255 // If the operation succeeded or failed with other than auth-needed error, just leave.
1256 SecItemAuthResult auth_result = perform(&ac_pairs, error);
1257 require_quiet(auth_result != kSecItemAuthResultError, out);
1258 require_action_quiet(auth_result == kSecItemAuthResultNeedAuth, out, ok = true);
1259
1260 // If auth_params were not created up to now, do create them because we will definitely need them.
1261 SecCFDictionaryCOWGetMutable(auth_params);
1262
1263 // Retrieve or create authentication handle and/or ACM context.
1264 CFTypeRef auth_handle = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationContext);
1265 if (auth_handle == NULL) {
1266 CFDataRef acm_context = CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference);
1267 require_quiet(auth_handle = LACreateNewContextWithACMContext(acm_context, error), out);
1268 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, auth_handle);
1269 CFRelease(auth_handle);
1270 if (acm_context == NULL) {
1271 require_quiet(acm_context = LACopyACMContext(auth_handle, error), out);
1272 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1273 CFRelease(acm_context);
1274 if (newCredentialRefAdded) {
1275 newCredentialRefAdded();
1276 }
1277 }
1278 }
1279
1280 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1281 // user retry limit.
1282 require_action(i < 20, out, SecItemAuthMaxAttemptsReached(ac_pairs, error));
1283
1284 // Prepare auth options dictionary.
1285 if (auth_options.dictionary == NULL) {
1286 CFStringRef operation_prompt = CFDictionaryGetValue(auth_params->dictionary, kSecUseOperationPrompt);
1287 if (operation_prompt != NULL) {
1288 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionAuthenticationReason);
1289 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, operation_prompt);
1290 CFRelease(key);
1291 }
1292
1293 CFStringRef caller_name = CFDictionaryGetValue(auth_params->dictionary, kSecUseCallerName);
1294 if (caller_name != NULL) {
1295 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionCallerName);
1296 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, caller_name);
1297 CFRelease(key);
1298 }
1299
1300 CFTypeRef auth_ui = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationUI);
1301 if (CFEqualSafe(auth_ui, kSecUseAuthenticationUIFail)) {
1302 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionNotInteractive);
1303 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, kCFBooleanTrue);
1304 CFRelease(key);
1305 }
1306 }
1307
1308 // Go through all access_control-operation pairs and evaluate them.
1309 CFArrayRef ac_pair;
1310 CFArrayForEachC(ac_pairs, ac_pair) {
1311 CFDataRef updated_acl = NULL;
1312 require_quiet(LAEvaluateAndUpdateACL(auth_handle,
1313 CFArrayGetValueAtIndex(ac_pair, 0), CFArrayGetValueAtIndex(ac_pair, 1),
1314 auth_options.dictionary, &updated_acl, error), out);
1315
1316 if (updated_acl || CFEqual(CFArrayGetValueAtIndex(ac_pair, 1), CFSTR(""))) {
1317 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1318 SecAccessControlRef ac = NULL;
1319 require(ac = SecAccessControlCreateFromData(kCFAllocatorDefault,
1320 updated_acl ? updated_acl : CFArrayGetValueAtIndex(ac_pair, 0), error), out);
1321 SecAccessControlSetBound(ac, true);
1322 CFAssignRetained(updated_acl, SecAccessControlCopyData(ac));
1323 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecAttrAccessControl, updated_acl);
1324 CFRelease(updated_acl);
1325 CFRelease(ac);
1326 }
1327 }
1328 }
1329
1330 ok = true;
1331
1332 out:
1333 CFReleaseSafe(auth_options.mutable_dictionary);
1334 CFReleaseSafe(ac_pairs);
1335 return ok;
1336 }
1337
1338 void SecItemAuthCopyParams(SecCFDictionaryCOW *auth_params, SecCFDictionaryCOW *query) {
1339 // Store operation prompt.
1340 CFStringRef operation_prompt = CFDictionaryGetValue(query->dictionary, kSecUseOperationPrompt);
1341 if (operation_prompt != NULL) {
1342 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseOperationPrompt, operation_prompt);
1343 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseOperationPrompt);
1344 }
1345
1346 // Store caller name.
1347 CFStringRef caller_name = CFDictionaryGetValue(query->dictionary, kSecUseCallerName);
1348 if (caller_name != NULL) {
1349 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCallerName, caller_name);
1350 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseCallerName);
1351 }
1352
1353 // Find out whether we are allowed to pop up a UI.
1354 CFTypeRef auth_ui = CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI) ?:
1355 (CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI), kCFBooleanTrue) ?
1356 kSecUseAuthenticationUIFail : kSecUseAuthenticationUIAllow);
1357 if (!CFEqual(auth_ui, kSecUseAuthenticationUISkip) || CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI)) {
1358 if (CFDictionaryContainsKey(query->dictionary, kSecUseNoAuthenticationUI))
1359 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseNoAuthenticationUI);
1360 if (!CFEqualSafe(auth_ui, kSecUseAuthenticationUISkip) && CFDictionaryContainsKey(query->dictionary, kSecUseAuthenticationUI))
1361 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseAuthenticationUI);
1362 }
1363
1364 if (!CFEqual(auth_ui, kSecUseAuthenticationUIAllow)) {
1365 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationUI, auth_ui);
1366 }
1367
1368 CFDataRef acm_context = CFDictionaryGetValue(query->dictionary, kSecUseCredentialReference);
1369 if (acm_context != NULL) {
1370 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1371 }
1372 }
1373
1374 static SecItemAuthResult SecItemCreatePairsFromError(CFErrorRef *error, CFArrayRef *ac_pairs)
1375 {
1376 if (error && *error && CFErrorGetCode(*error) == errSecAuthNeeded && CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain)) {
1377 // Extract ACLs to be verified from the error.
1378 CFDictionaryRef user_info = CFErrorCopyUserInfo(*error);
1379 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
1380 CFRetainAssign(*ac_pairs, CFDictionaryGetValue(user_info, key));
1381 if (*ac_pairs == NULL)
1382 CFAssignRetained(*ac_pairs, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
1383
1384 CFRelease(key);
1385 CFRelease(user_info);
1386 CFReleaseNull(*error);
1387 return kSecItemAuthResultNeedAuth;
1388 }
1389 return kSecItemAuthResultError;
1390 }
1391
1392 // Wrapper to handle automatic authentication and token/secd case switching.
1393 bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error,
1394 bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) {
1395 bool ok = false;
1396 __block SecCFDictionaryCOW auth_params = { NULL };
1397 SecAccessControlRef access_control = NULL;
1398 __block TKTokenRef token = NULL;
1399
1400 if (secItemOperation == SecItemAdd || secItemOperation == SecItemUpdate) {
1401 CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary;
1402 access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl);
1403 if (access_control && SecAccessControlGetConstraints(access_control) &&
1404 CFEqualSafe(CFDictionaryGetValue(dict, kSecAttrSynchronizable), kCFBooleanTrue))
1405 require_quiet(SecError(errSecParam, error, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out);
1406 }
1407
1408 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1409 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1410 bool forQuery =
1411 secItemOperation == SecItemCopyMatching ||
1412 secItemOperation == SecItemUpdate ||
1413 secItemOperation == SecItemDelete;
1414
1415 require_quiet(SecItemAttributesPrepare(query, forQuery, error), out);
1416 if (attributes != NULL)
1417 require_quiet(SecItemAttributesPrepare(attributes, false, error), out);
1418
1419 // Populate auth_params dictionary according to initial query contents.
1420 SecItemAuthCopyParams(&auth_params, query);
1421
1422 if (secItemOperation != SecItemCopyMatching) {
1423 // UISkip is allowed only for CopyMatching.
1424 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI), kSecUseAuthenticationUISkip), out,
1425 SecError(errSecParam, error,
1426 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1427 }
1428
1429 ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFArrayRef *ac_pairs, CFErrorRef *error) {
1430 SecItemAuthResult result = kSecItemAuthResultError;
1431
1432 // Propagate actual credential reference to the query.
1433 if (auth_params.dictionary != NULL) {
1434 CFDataRef acm_context = CFDictionaryGetValue(auth_params.dictionary, kSecUseCredentialReference);
1435 if (acm_context != NULL) {
1436 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecUseCredentialReference, acm_context);
1437 }
1438
1439 CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params.dictionary, kSecAttrAccessControl);
1440 if (acl_data_ref != NULL) {
1441 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes ?: query), kSecAttrAccessControl, acl_data_ref);
1442 }
1443 }
1444
1445 // Prepare connection to target token if it is present.
1446 CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID);
1447 if (secItemOperation != SecItemCopyMatching && token_id != NULL) {
1448 require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, &auth_params, error)), out);
1449 }
1450
1451 CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL;
1452 if(!perform(token, query->dictionary, attrs, auth_params.dictionary, error)) {
1453 require_quiet((result = SecItemCreatePairsFromError(error, ac_pairs)) == kSecItemAuthResultOK, out);
1454 }
1455
1456 result = kSecItemAuthResultOK;
1457
1458 out:
1459 return result;
1460 }, NULL);
1461 require_quiet(ok, out);
1462
1463 ok = true;
1464
1465 out:
1466 CFReleaseSafe(token);
1467 CFReleaseSafe(auth_params.mutable_dictionary);
1468 return ok;
1469 }
1470
1471 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error)
1472 {
1473 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1474 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error);
1475 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1476 if (result) {
1477 return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error);
1478 }
1479 return true;
1480 });
1481 }
1482
1483 static CFArrayRef dict_to_array_error_request(enum SecXPCOperation op, CFDictionaryRef attributes, CFErrorRef *error)
1484 {
1485 CFArrayRef result = NULL;
1486 bool success = cftype_to_bool_cftype_error_request(op, attributes, (CFTypeRef*)&result, error);
1487 if(success && !isArray(result)){
1488 SecError(errSecUnimplemented, error, CFSTR("Unexpected nonarray returned: %@"), result);
1489 CFReleaseNull(result);
1490 }
1491 return result;
1492 }
1493
1494 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused SecurityClient *client, CFTypeRef *result, CFErrorRef *error) {
1495 return cftype_to_bool_cftype_error_request(op, attributes, result, error);
1496 }
1497
1498 static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error)
1499 {
1500 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1501 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error);
1502 }, NULL);
1503 }
1504
1505 static bool cfstring_array_to_error_request(enum SecXPCOperation op, CFStringRef string, CFArrayRef attributes, __unused SecurityClient *client, CFErrorRef *error)
1506 {
1507 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1508 if (string) {
1509 if (!SecXPCDictionarySetString(message, kSecXPCKeyString, string, error))
1510 return false;
1511 }
1512
1513 if (attributes) {
1514 if (!SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error))
1515 return false;
1516 }
1517
1518 return true;
1519 }, NULL);
1520 }
1521
1522 static bool dict_client_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused SecurityClient *client, CFErrorRef *error)
1523 {
1524 return dict_to_error_request(op, query, error);
1525 }
1526
1527 static bool SecTokenCreateAccessControlError(CFStringRef operation, CFDataRef access_control, CFErrorRef *error) {
1528 CFArrayRef ac_pair = CFArrayCreateForCFTypes(NULL, access_control, operation, NULL);
1529 const void *ac_pairs[] = { CFArrayCreateForCFTypes(NULL, ac_pair, NULL) };
1530 const void *keys[] = { CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded) };
1531 CFAssignRetained(*error, CFErrorCreateWithUserInfoKeysAndValues(NULL, kSecErrorDomain, errSecAuthNeeded,
1532 keys, ac_pairs, 1));
1533 CFRelease(keys[0]);
1534 CFRelease(ac_pairs[0]);
1535 CFRelease(ac_pair);
1536 return false;
1537 }
1538
1539 static bool SecTokenProcessError(CFStringRef operation, TKTokenRef token, CFTypeRef object_or_attrs, CFErrorRef *error) {
1540 if (CFEqualSafe(CFErrorGetDomain(*error), CFSTR(kTKErrorDomain)) &&
1541 CFErrorGetCode(*error) == kTKErrorCodeAuthenticationFailed) {
1542 // Replace error with the one which is augmented with access control and operation which failed,
1543 // which will cause SecItemDoWithAuth to throw UI.
1544 // Create array containing tuple (array) with error and requested operation.
1545 CFDataRef access_control = (CFGetTypeID(object_or_attrs) == CFDataGetTypeID()) ?
1546 TKTokenCopyObjectAccessControl(token, object_or_attrs, error) :
1547 TKTokenCopyObjectCreationAccessControl(token, object_or_attrs, error);
1548 if (access_control != NULL) {
1549 SecTokenCreateAccessControlError(operation, access_control, error);
1550 CFRelease(access_control);
1551 }
1552 }
1553 return false;
1554 }
1555
1556 static CFTypeRef SecTokenCopyUpdatedObjectID(TKTokenRef token, CFDataRef object_id, CFMutableDictionaryRef attributes, CFErrorRef *error) {
1557 CFDataRef access_control = NULL, db_value = NULL, new_object_id = NULL;
1558 SecAccessControlRef ac = NULL;
1559 CFDictionaryRef old_attrs = NULL;
1560
1561 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1562 CFDataRef ac_data = CFDictionaryGetValue(attributes, kSecAttrAccessControl);
1563 if (ac_data != NULL) {
1564 require_quiet(ac = SecAccessControlCreateFromData(NULL, ac_data, error), out);
1565 require_action_quiet(SecAccessControlIsBound(ac), out,
1566 SecTokenCreateAccessControlError(CFSTR(""), ac_data, error));
1567 }
1568
1569 // Create or update the object on the token.
1570 old_attrs = CFDictionaryCreateCopy(kCFAllocatorDefault, attributes);
1571 require_action_quiet(new_object_id = TKTokenCreateOrUpdateObject(token, object_id, attributes, error), out,
1572 SecTokenProcessError(kAKSKeyOpEncrypt, token, object_id ?: (CFTypeRef)attributes, error));
1573 CFDictionaryForEach(old_attrs, ^(const void *key, const void *value) {
1574 if (!CFEqual(key, kSecValueData)) {
1575 CFDictionaryAddValue(attributes, key, value);
1576 }
1577 });
1578
1579 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1580 require_quiet(access_control = TKTokenCopyObjectAccessControl(token, new_object_id, error), out);
1581 require_quiet(db_value = SecTokenItemValueCreate(new_object_id, access_control,
1582 CFDictionaryGetValue(attributes, kSecValueData), error), out);
1583 CFDictionarySetValue(attributes, kSecValueData, db_value);
1584
1585 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1586 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
1587
1588 out:
1589 CFReleaseSafe(ac);
1590 CFReleaseSafe(access_control);
1591 CFReleaseSafe(db_value);
1592 CFReleaseSafe(old_attrs);
1593 return new_object_id;
1594 }
1595
1596 static bool SecTokenItemAdd(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef auth_params,
1597 CFTypeRef *result, CFErrorRef *error) {
1598 bool ok = false;
1599 CFTypeRef object_id = NULL, ref = NULL;
1600 CFDictionaryRef ref_attrs = NULL;
1601 CFTypeRef db_result = NULL;
1602 CFDataRef db_value = NULL;
1603 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
1604
1605 CFDictionarySetValue(attrs, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); //token items should be accesible always because have own ACL encoded in OID
1606 object_id = CFRetainSafe(CFDictionaryGetValue(attrs, kSecAttrTokenOID));
1607 CFDictionaryRemoveValue(attrs, kSecAttrTokenOID);
1608 require_quiet(CFAssignRetained(object_id, SecTokenCopyUpdatedObjectID(token, object_id, attrs, error)), out);
1609 if (CFDictionaryContainsKey(attrs, kSecValueRef)) {
1610 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1611 // the ref from the dictionary since it is of no use any more.
1612 CFDictionaryRemoveValue(attrs, kSecValueRef);
1613 } else {
1614 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1615 // by creating ref and getting back its attributes.
1616 require_quiet(SecTokenItemCreateFromAttributes(attrs, auth_params, token, object_id, &ref, error), out);
1617 if (ref != NULL) {
1618 if ((ref_attrs = SecItemCopyAttributeDictionary(ref, false)) != NULL) {
1619 CFDictionaryForEach(ref_attrs, ^(const void *key, const void *value) {
1620 if (!CFEqual(key, kSecValueData)) {
1621 CFDictionaryAddValue(attrs, key, value);
1622 }
1623 });
1624 }
1625 }
1626 }
1627
1628 // Make sure that both attributes and data are returned.
1629 CFDictionarySetValue(attrs, kSecReturnAttributes, kCFBooleanTrue);
1630 CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue);
1631
1632 if (!CFEqualSafe(CFDictionaryGetValue(attrs, kSecAttrIsPermanent), kCFBooleanFalse)) {
1633 // IsPermanent is not present or is true, so add item to the db.
1634 require_quiet(SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attrs,
1635 SecSecurityClientGet(), &db_result, error), out);
1636 } else {
1637 // Process directly result of token call.
1638 db_result = CFRetain(attrs);
1639 }
1640 require_quiet(SecItemResultProcess(attributes, auth_params, token, db_result, result, error), out);
1641 ok = true;
1642
1643 out:
1644 CFReleaseSafe(db_result);
1645 CFReleaseSafe(db_value);
1646 CFReleaseSafe(attrs);
1647 CFReleaseSafe(ref_attrs);
1648 CFReleaseSafe(object_id);
1649 CFReleaseSafe(ref);
1650 return ok;
1651 }
1652
1653 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
1654 __block SecCFDictionaryCOW attrs = { attributes };
1655 OSStatus status;
1656
1657 os_activity_t activity = os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1658 os_activity_scope(activity);
1659 os_release(activity);
1660
1661 require_quiet(!explode_identity(attrs.dictionary, (secitem_operation)SecItemAdd, &status, result), errOut);
1662 infer_cert_label(&attrs);
1663
1664 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1665 return SecItemAuthDoQuery(&attrs, NULL, SecItemAdd, error, ^bool(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef unused, CFDictionaryRef auth_params, CFErrorRef *error) {
1666 if (token == NULL) {
1667 CFTypeRef raw_result = NULL;
1668 if (!SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attributes, SecSecurityClientGet(), &raw_result, error))
1669 return false;
1670
1671 bool ok = SecItemResultProcess(attributes, auth_params, token, raw_result, result, error);
1672 CFReleaseSafe(raw_result);
1673 return ok;
1674 } else {
1675 // Send request to an appropriate token instead of secd.
1676 return SecTokenItemAdd(token, attributes, auth_params, result, error);
1677 }
1678 });
1679 });
1680
1681 errOut:
1682 CFReleaseSafe(attrs.mutable_dictionary);
1683
1684 return status;
1685 }
1686
1687
1688 OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) {
1689 OSStatus status;
1690 __block SecCFDictionaryCOW query = { inQuery };
1691
1692 os_activity_t activity = os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1693 os_activity_scope(activity);
1694 os_release(activity);
1695
1696 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemCopyMatching, &status, result), errOut);
1697
1698 bool wants_data = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnData));
1699 bool wants_attributes = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnAttributes));
1700 if ((wants_data && !wants_attributes)) {
1701 // When either attributes or data are requested, we need to query both, because for token based items,
1702 // both are needed in order to generate proper data and/or attributes results.
1703 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query), kSecReturnAttributes, kCFBooleanTrue);
1704 }
1705
1706 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1707 return SecItemAuthDoQuery(&query, NULL, SecItemCopyMatching, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1708 CFTypeRef raw_result = NULL;
1709 if (!SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, query, SecSecurityClientGet(), &raw_result, error))
1710 return false;
1711
1712 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1713 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1714 // to currently processed item.
1715 bool ok = SecItemResultProcess(inQuery, auth_params, NULL, raw_result, result, error);
1716 CFReleaseSafe(raw_result);
1717 return ok;
1718 });
1719 });
1720
1721 errOut:
1722
1723 CFReleaseSafe(query.mutable_dictionary);
1724 return status;
1725 }
1726
1727 // Invokes token-object handler for each item matching specified query.
1728 static bool SecTokenItemForEachMatching(CFDictionaryRef query, CFErrorRef *error,
1729 bool (^perform)(CFDictionaryRef item_value, CFDictionaryRef item_query,
1730 CFErrorRef *error)) {
1731 bool ok = false;
1732 CFMutableDictionaryRef list_query = NULL;
1733 CFTypeRef items = NULL;
1734 CFArrayRef ref_array = NULL;
1735 CFDictionaryRef item_query = NULL, item_data = NULL;
1736
1737 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1738 // items in the keychain.
1739 list_query = CFDictionaryCreateMutableCopy(NULL, 0, query);
1740 if (CFDictionaryGetValue(list_query, kSecMatchLimit) == NULL) {
1741 CFDictionarySetValue(list_query, kSecMatchLimit, kSecMatchLimitAll);
1742 }
1743 CFDictionarySetValue(list_query, kSecReturnData, kCFBooleanTrue);
1744 CFDictionarySetValue(list_query, kSecReturnPersistentRef, kCFBooleanTrue);
1745 require_quiet(SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, list_query,
1746 SecSecurityClientGet(), &items, error), out);
1747 if (CFGetTypeID(items) != CFArrayGetTypeID()) {
1748 // Wrap single returned item into the array.
1749 CFArrayRef item_array = CFArrayCreateForCFTypes(NULL, items, NULL);
1750 CFAssignRetained(items, item_array);
1751 }
1752
1753 CFTypeRef item;
1754 CFArrayForEachC(items, item) {
1755 CFDataRef data = CFDictionaryGetValue(item, kSecValueData);
1756 require_action_quiet(data != NULL, out, SecError(errSecInternal, error, CFSTR("value not present for token item")));
1757
1758 CFAssignRetained(item_data, SecTokenItemValueCopy(data, error));
1759 require_quiet(item_data, out);
1760
1761 CFAssignRetained(item_query,
1762 CFDictionaryCreateForCFTypes(NULL,
1763 kSecValuePersistentRef, CFDictionaryGetValue(item, kSecValuePersistentRef),
1764 NULL));
1765 require_quiet(perform(item_data, item_query, error), out);
1766 }
1767
1768 ok = true;
1769
1770 out:
1771 CFReleaseSafe(list_query);
1772 CFReleaseSafe(items);
1773 CFReleaseSafe(item_data);
1774 CFReleaseSafe(ref_array);
1775 CFReleaseSafe(item_query);
1776 return ok;
1777 }
1778
1779 static bool SecItemRawUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1780 bool ok = false;
1781 if (gSecurityd) {
1782 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1783 CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
1784 CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); });
1785 ok = gSecurityd->sec_item_update(query, tmp, SecSecurityClientGet(), error);
1786 CFRelease(tmp);
1787 } else {
1788 xpc_object_t message = securityd_create_message(sec_item_update_id, error);
1789 if (message) {
1790 if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) &&
1791 SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) {
1792 xpc_object_t reply = securityd_message_with_reply_sync(message, error);
1793 if (reply) {
1794 ok = securityd_message_no_error(reply, error);
1795 xpc_release(reply);
1796 }
1797 }
1798 xpc_release(message);
1799 }
1800 }
1801 return ok;
1802 }
1803
1804 static bool SecTokenItemUpdate(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1805 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1806 bool ok = false;
1807 CFDataRef object_id = NULL;
1808 CFMutableDictionaryRef db_value = NULL;
1809
1810 // Update attributes on the token.
1811 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(NULL, 0, attributesToUpdate);
1812 require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey),
1813 attributes, error), out);
1814
1815 // Update attributes in the database.
1816 require_quiet(SecItemRawUpdate(item_query, attributes, error), out);
1817
1818 ok = true;
1819
1820 out:
1821 CFReleaseSafe(object_id);
1822 CFReleaseSafe(attributes);
1823 CFReleaseSafe(db_value);
1824 return ok;
1825 });
1826 }
1827
1828 OSStatus SecItemUpdate(CFDictionaryRef inQuery, CFDictionaryRef inAttributesToUpdate) {
1829 os_activity_t activity = os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1830 os_activity_scope(activity);
1831 os_release(activity);
1832
1833 return SecOSStatusWith(^bool(CFErrorRef *error) {
1834 return SecItemUpdateWithError(inQuery, inAttributesToUpdate, error);
1835 });
1836 }
1837
1838 bool
1839 SecItemUpdateWithError(CFDictionaryRef inQuery,
1840 CFDictionaryRef inAttributesToUpdate,
1841 CFErrorRef *error)
1842 {
1843 __block SecCFDictionaryCOW query = { inQuery };
1844 __block SecCFDictionaryCOW attributesToUpdate = { inAttributesToUpdate };
1845 bool result = false;
1846
1847 if (handleUpdateIdentity(inQuery, inAttributesToUpdate, &result, error))
1848 goto errOut;
1849
1850 result = SecItemAuthDoQuery(&query, &attributesToUpdate, SecItemUpdate, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1851 if (token == NULL) {
1852 return SecItemRawUpdate(query, attributes, error);
1853 } else {
1854 return SecTokenItemUpdate(token, query, attributes, error);
1855 }
1856 });
1857
1858 errOut:
1859 CFReleaseSafe(query.mutable_dictionary);
1860 CFReleaseSafe(attributesToUpdate.mutable_dictionary);
1861 return result;
1862 }
1863
1864 static OSStatus explode_persistent_identity_ref(SecCFDictionaryCOW *query)
1865 {
1866 OSStatus status = errSecSuccess;
1867 CFTypeRef persist = CFDictionaryGetValue(query->dictionary, kSecValuePersistentRef);
1868 CFStringRef class;
1869 if (persist && _SecItemParsePersistentRef(persist, &class, NULL, NULL)
1870 && CFEqual(class, kSecClassIdentity)) {
1871 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef };
1872 const void *vals[] = { kCFBooleanTrue, persist };
1873 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys,
1874 vals, (array_size(keys)), NULL, NULL);
1875 CFTypeRef item_query = NULL;
1876 status = SecItemCopyMatching(persistent_query, &item_query);
1877 CFReleaseNull(persistent_query);
1878 if (status)
1879 return status;
1880 if (item_query == NULL)
1881 return errSecItemNotFound;
1882
1883 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecValuePersistentRef);
1884 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecValueRef, item_query);
1885 CFRelease(item_query);
1886 }
1887
1888 return status;
1889 }
1890
1891 OSStatus SecItemDelete(CFDictionaryRef inQuery) {
1892 OSStatus status;
1893 __block SecCFDictionaryCOW query = { inQuery };
1894
1895 os_activity_t activity = os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1896 os_activity_scope(activity);
1897 os_release(activity);
1898
1899 require_noerr_quiet(status = explode_persistent_identity_ref(&query), errOut);
1900 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemDelete, &status, NULL), errOut);
1901
1902 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1903 return SecItemAuthDoQuery(&query, NULL, SecItemDelete, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1904 if (token == NULL) {
1905 return SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, query, SecSecurityClientGet(), error);
1906 } else {
1907 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1908 bool ok = false;
1909
1910 // Delete item from the token.
1911 CFDataRef object_id = CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey);
1912 require_action_quiet(TKTokenDeleteObject(token, object_id, error), out,
1913 SecTokenProcessError(kAKSKeyOpDelete, token, object_id, error));
1914
1915 // Delete the item from the keychain.
1916 require_quiet(SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, item_query,
1917 SecSecurityClientGet(), error), out);
1918 ok = true;
1919
1920 out:
1921 return ok;
1922 });
1923 }
1924 });
1925 });
1926
1927 errOut:
1928 CFReleaseSafe(query.mutable_dictionary);
1929
1930
1931 return status;
1932 }
1933
1934 OSStatus
1935 SecItemDeleteAll(void)
1936 {
1937 return SecOSStatusWith(^bool (CFErrorRef *error) {
1938 bool ok = true;
1939 if (gSecurityd) {
1940 if (!gSecurityd->sec_item_delete_all(error))
1941 ok &= SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL"));
1942 } else {
1943 ok &= securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL);
1944 }
1945 return ok;
1946 });
1947 }
1948
1949 #if 0
1950 static bool
1951 agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unused SecurityClient *client, CFErrorRef *error)
1952 {
1953 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1954 return SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, agrps, error);
1955 }, NULL);
1956 }
1957 #endif
1958
1959 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error) {
1960 #if 0
1961 os_activity_t activity = os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1962 os_activity_scope(activity);
1963 os_release(activity);
1964
1965 return SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups,
1966 SecSecurityClientGet(), error);
1967 #else
1968 return true;
1969 #endif
1970 }
1971
1972 OSStatus
1973 #if SECITEM_SHIM_OSX
1974 SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
1975 #else
1976 SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
1977 #endif
1978 {
1979 OSStatus status;
1980
1981 os_activity_t activity = os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1982 os_activity_scope(activity);
1983 os_release(activity);
1984
1985 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1986 CFArrayRef tmpArrayRef = tokenItemsAttributes;
1987 if (tokenItemsAttributes) {
1988 CFMutableArrayRef tokenItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1989 for (CFIndex i = 0; i < CFArrayGetCount(tokenItemsAttributes); ++i) {
1990 CFDictionaryRef itemAttributes = CFArrayGetValueAtIndex(tokenItemsAttributes, i);
1991 CFTypeRef accessControl = CFDictionaryGetValue(itemAttributes, kSecAttrAccessControl);
1992 CFTypeRef tokenOID = CFDictionaryGetValue(itemAttributes, kSecAttrTokenOID);
1993 CFTypeRef valueData = CFDictionaryGetValue(itemAttributes, kSecValueData);
1994 if (tokenOID != NULL && accessControl != NULL && CFDataGetTypeID() == CFGetTypeID(accessControl)) {
1995 CFDataRef data = SecTokenItemValueCreate(tokenOID, accessControl, valueData, error);
1996 if (!data) {
1997 CFRelease(tokenItems);
1998 return false;
1999 }
2000
2001 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, itemAttributes);
2002 CFDictionarySetValue(attributes, kSecValueData, data);
2003 CFDictionarySetValue(attributes, kSecAttrTokenID, tokenID);
2004 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
2005 CFDictionaryRemoveValue(attributes, kSecAttrTokenOID);
2006 CFArrayAppendValue(tokenItems, attributes);
2007 CFRelease(attributes);
2008 CFRelease(data);
2009 }
2010 else
2011 CFArrayAppendValue(tokenItems, itemAttributes);
2012 }
2013
2014 tmpArrayRef = tokenItems;
2015 }
2016
2017 return SECURITYD_XPC(sec_item_update_token_items, cfstring_array_to_error_request, tokenID, tmpArrayRef, SecSecurityClientGet(), error);
2018 });
2019
2020 return status;
2021 }
2022
2023 CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) {
2024 __block CFArrayRef result;
2025 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT, ^{
2026 result = SECURITYD_XPC(sec_keychain_sync_update_message, dict_to_array_error_request, updates, error);
2027 });
2028 return result;
2029 }
2030
2031 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2032
2033 bool _SecKeychainRollKeys(bool force, CFErrorRef *error)
2034 {
2035 do_if_registered(sec_roll_keys, force, error);
2036
2037 __block bool result = false;
2038
2039 secdebug("secitem","enter - %s", __FUNCTION__);
2040 securityd_send_sync_and_do(kSecXPCOpRollKeys, error,
2041 ^bool(xpc_object_t message, CFErrorRef *error) {
2042 xpc_dictionary_set_bool(message, "force", force);
2043 return true;
2044 },
2045 ^bool(xpc_object_t response, __unused CFErrorRef *error) {
2046 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
2047 return result;
2048 });
2049 return result;
2050 }
2051
2052 static CFArrayRef data_array_to_array_error_request(enum SecXPCOperation op, CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) {
2053 __block CFArrayRef results = NULL;
2054 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
2055 SecXPCDictionarySetData(message, kSecXPCKeyNormalizedIssuer, normalizedIssuer, error);
2056 SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, accessGroups, error);
2057 return true;
2058 }, ^bool(xpc_object_t response, CFErrorRef *error) {
2059 return SecXPCDictionaryCopyArrayOptional(response, kSecXPCKeyResult, &results, error);
2060 });
2061 return results;
2062 }
2063
2064 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op, CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) {
2065 __block bool result = false;
2066 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
2067 SecXPCDictionarySetData(message, kSecXPCKeyNormalizedIssuer, normalizedIssuer, error);
2068 SecXPCDictionarySetData(message, kSecXPCKeySerialNumber, serialNumber, error);
2069 SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, accessGroups, error);
2070 return true;
2071 }, ^bool(xpc_object_t response, CFErrorRef *error) {
2072 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
2073 return result;
2074 });
2075 return result;
2076 }
2077
2078 CFArrayRef SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) {
2079 CFArrayRef results = NULL;
2080
2081 os_activity_t activity = os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2082 os_activity_scope(activity);
2083 os_release(activity);
2084
2085 results = SECURITYD_XPC(sec_item_copy_parent_certificates, data_array_to_array_error_request, normalizedIssuer, accessGroups, error);
2086
2087 return results;
2088 }
2089
2090 bool SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) {
2091 bool results = false;
2092
2093 os_activity_t activity = os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2094 os_activity_scope(activity);
2095 os_release(activity);
2096
2097 results = SECURITYD_XPC(sec_item_certificate_exists, data_data_array_to_bool_error_request, normalizedIssuer, serialNumber, accessGroups, error);
2098
2099 return results;
2100 }