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