]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecItem.c
433acca771b978036e6d493d34e9b9241ba905e6
[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(ac_data = SecAccessControlCopyData(access_control), out,
1192 SecError(errSecParam, error, CFSTR("unsupported kSecAttrAccessControl in query")));
1193 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrAccessControl, ac_data);
1194 }
1195
1196 const CFTypeRef la_context = CFDictionaryGetValue(attrs->dictionary, kSecUseAuthenticationContext);
1197 if (la_context) {
1198 require_action_quiet(!CFDictionaryContainsKey(attrs->dictionary, kSecUseCredentialReference), out,
1199 SecError(errSecParam, error, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1200 require_quiet(acm_context = SecItemAttributesCopyPreparedAuthContext(la_context, error), out);
1201 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseAuthenticationContext);
1202 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseCredentialReference, acm_context);
1203 }
1204
1205 CFTypeRef policy = CFDictionaryGetValue(attrs->dictionary, kSecMatchPolicy);
1206 if (policy) {
1207 require_action_quiet(CFGetTypeID(policy) == SecPolicyGetTypeID(), out,
1208 SecError(errSecParam, error, CFSTR("unsupported kSecMatchPolicy in query")));
1209
1210 CFTypeRef values[] = { policy };
1211 CFArrayRef policiesArray = CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks);
1212 xpc_object_t policiesArrayXPC = SecPolicyArrayCopyXPCArray(policiesArray, error);
1213 CFReleaseSafe(policiesArray);
1214 require_action_quiet(policiesArrayXPC, out,
1215 SecError(errSecInternal, error, CFSTR("Failed to copy XPC policy")));
1216
1217 CFTypeRef objectReadyForXPC = _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC);
1218 xpc_release(policiesArrayXPC);
1219 require_action_quiet(objectReadyForXPC, out,
1220 SecError(errSecInternal, error, CFSTR("Failed to create CFObject from XPC policy")));
1221
1222 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecMatchPolicy, objectReadyForXPC);
1223 CFRelease(objectReadyForXPC);
1224 }
1225 value = CFDictionaryGetValue(attrs->dictionary, kSecAttrIssuer);
1226 if (value) {
1227 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1228 const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) };
1229 DERDecodedInfo content;
1230 if (DERDecodeItem(&name, &content) == DR_Success && content.tag == ASN1_CONSTR_SEQUENCE) {
1231 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content);
1232 if (canonical_issuer) {
1233 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrIssuer, canonical_issuer);
1234 CFRelease(canonical_issuer);
1235 }
1236 }
1237 }
1238
1239 if (CFDictionaryContainsKey(attrs->dictionary, kSecUseTokenRawItems)) {
1240 // This use flag is client-only, securityd does not understand it.
1241 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseTokenRawItems);
1242 }
1243
1244 ok = true;
1245
1246 out:
1247 if (la_lib != NULL) {
1248 dlclose(la_lib);
1249 }
1250 CFReleaseSafe(ac_data);
1251 CFReleaseSafe(acm_context);
1252 return ok;
1253 }
1254
1255 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs, CFErrorRef *error)
1256 {
1257 CFMutableStringRef log_string = CFStringCreateMutable(kCFAllocatorDefault, 0);
1258 CFArrayRef ac_pair;
1259 CFArrayForEachC(ac_pairs, ac_pair) {
1260 CFStringRef acl_hex_string = CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair, 0));
1261 CFStringRef str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair, 1), acl_hex_string);
1262 CFStringAppend(log_string, str);
1263 CFRelease(acl_hex_string);
1264 CFRelease(str);
1265 }
1266
1267 CFStringRef reason = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string);
1268 SecError(errSecAuthFailed, error, CFSTR("%@"), reason);
1269 __security_simulatecrash(reason, __sec_exception_code_AuthLoop);
1270 CFRelease(reason);
1271 CFRelease(log_string);
1272 return false;
1273 }
1274
1275 bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFArrayRef *ac_pairs, CFErrorRef *error),
1276 void (^newCredentialRefAdded)(void)) {
1277 bool ok = false;
1278 CFArrayRef ac_pairs = NULL;
1279 SecCFDictionaryCOW auth_options = { NULL };
1280
1281 for (uint32_t i = 0;; ++i) {
1282 // If the operation succeeded or failed with other than auth-needed error, just leave.
1283 SecItemAuthResult auth_result = perform(&ac_pairs, error);
1284 require_quiet(auth_result != kSecItemAuthResultError, out);
1285 require_action_quiet(auth_result == kSecItemAuthResultNeedAuth, out, ok = true);
1286
1287 // If auth_params were not created up to now, do create them because we will definitely need them.
1288 SecCFDictionaryCOWGetMutable(auth_params);
1289
1290 // Retrieve or create authentication handle and/or ACM context.
1291 CFTypeRef auth_handle = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationContext);
1292 if (auth_handle == NULL) {
1293 CFDataRef acm_context = CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference);
1294 require_quiet(auth_handle = LACreateNewContextWithACMContext(acm_context, error), out);
1295 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, auth_handle);
1296 CFRelease(auth_handle);
1297 if (acm_context == NULL) {
1298 require_quiet(acm_context = LACopyACMContext(auth_handle, error), out);
1299 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1300 CFRelease(acm_context);
1301 if (newCredentialRefAdded) {
1302 newCredentialRefAdded();
1303 }
1304 }
1305 }
1306
1307 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1308 // user retry limit.
1309 require_action(i < 20, out, SecItemAuthMaxAttemptsReached(ac_pairs, error));
1310
1311 // Prepare auth options dictionary.
1312 if (auth_options.dictionary == NULL) {
1313 CFStringRef operation_prompt = CFDictionaryGetValue(auth_params->dictionary, kSecUseOperationPrompt);
1314 if (operation_prompt != NULL) {
1315 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionAuthenticationReason);
1316 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, operation_prompt);
1317 CFRelease(key);
1318 }
1319
1320 CFStringRef caller_name = CFDictionaryGetValue(auth_params->dictionary, kSecUseCallerName);
1321 if (caller_name != NULL) {
1322 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionCallerName);
1323 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, caller_name);
1324 CFRelease(key);
1325 }
1326
1327 CFTypeRef auth_ui = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationUI);
1328 if (CFEqualSafe(auth_ui, kSecUseAuthenticationUIFail)) {
1329 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionNotInteractive);
1330 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, kCFBooleanTrue);
1331 CFRelease(key);
1332 }
1333 }
1334
1335 // Go through all access_control-operation pairs and evaluate them.
1336 CFArrayRef ac_pair;
1337 CFArrayForEachC(ac_pairs, ac_pair) {
1338 CFDataRef updated_acl = NULL;
1339 require_quiet(LAEvaluateAndUpdateACL(auth_handle,
1340 CFArrayGetValueAtIndex(ac_pair, 0), CFArrayGetValueAtIndex(ac_pair, 1),
1341 auth_options.dictionary, &updated_acl, error), out);
1342
1343 if (updated_acl || CFEqual(CFArrayGetValueAtIndex(ac_pair, 1), CFSTR(""))) {
1344 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1345 SecAccessControlRef ac = NULL;
1346 require(ac = SecAccessControlCreateFromData(kCFAllocatorDefault,
1347 updated_acl ? updated_acl : CFArrayGetValueAtIndex(ac_pair, 0), error), out);
1348 SecAccessControlSetBound(ac, true);
1349 CFAssignRetained(updated_acl, SecAccessControlCopyData(ac));
1350 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecAttrAccessControl, updated_acl);
1351 CFRelease(updated_acl);
1352 CFRelease(ac);
1353 }
1354 }
1355 }
1356
1357 ok = true;
1358
1359 out:
1360 CFReleaseSafe(auth_options.mutable_dictionary);
1361 CFReleaseSafe(ac_pairs);
1362 return ok;
1363 }
1364
1365 void SecItemAuthCopyParams(SecCFDictionaryCOW *auth_params, SecCFDictionaryCOW *query) {
1366 // Store operation prompt.
1367 CFStringRef operation_prompt = CFDictionaryGetValue(query->dictionary, kSecUseOperationPrompt);
1368 if (operation_prompt != NULL) {
1369 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseOperationPrompt, operation_prompt);
1370 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseOperationPrompt);
1371 }
1372
1373 // Store caller name.
1374 CFStringRef caller_name = CFDictionaryGetValue(query->dictionary, kSecUseCallerName);
1375 if (caller_name != NULL) {
1376 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCallerName, caller_name);
1377 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseCallerName);
1378 }
1379
1380 // Find out whether we are allowed to pop up a UI.
1381 CFTypeRef auth_ui = CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI) ?:
1382 (CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI), kCFBooleanTrue) ?
1383 kSecUseAuthenticationUIFail : kSecUseAuthenticationUIAllow);
1384 if (!CFEqual(auth_ui, kSecUseAuthenticationUISkip) || CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI)) {
1385 if (CFDictionaryContainsKey(query->dictionary, kSecUseNoAuthenticationUI))
1386 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseNoAuthenticationUI);
1387 if (!CFEqualSafe(auth_ui, kSecUseAuthenticationUISkip) && CFDictionaryContainsKey(query->dictionary, kSecUseAuthenticationUI))
1388 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseAuthenticationUI);
1389 }
1390
1391 if (!CFEqual(auth_ui, kSecUseAuthenticationUIAllow)) {
1392 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationUI, auth_ui);
1393 }
1394
1395 CFDataRef acm_context = CFDictionaryGetValue(query->dictionary, kSecUseCredentialReference);
1396 if (acm_context != NULL) {
1397 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1398 }
1399 }
1400
1401 static SecItemAuthResult SecItemCreatePairsFromError(CFErrorRef *error, CFArrayRef *ac_pairs)
1402 {
1403 if (error && *error && CFErrorGetCode(*error) == errSecAuthNeeded && CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain)) {
1404 // Extract ACLs to be verified from the error.
1405 CFDictionaryRef user_info = CFErrorCopyUserInfo(*error);
1406 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
1407 CFRetainAssign(*ac_pairs, CFDictionaryGetValue(user_info, key));
1408 if (*ac_pairs == NULL)
1409 CFAssignRetained(*ac_pairs, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
1410
1411 CFRelease(key);
1412 CFRelease(user_info);
1413 CFReleaseNull(*error);
1414 return kSecItemAuthResultNeedAuth;
1415 }
1416 return kSecItemAuthResultError;
1417 }
1418
1419 // Wrapper to handle automatic authentication and token/secd case switching.
1420 bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error,
1421 bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) {
1422 bool ok = false;
1423 __block SecCFDictionaryCOW auth_params = { NULL };
1424 SecAccessControlRef access_control = NULL;
1425 __block TKTokenRef token = NULL;
1426
1427 if (secItemOperation == SecItemAdd || secItemOperation == SecItemUpdate) {
1428 CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary;
1429 access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl);
1430 if (access_control && SecAccessControlGetConstraints(access_control) &&
1431 CFEqualSafe(CFDictionaryGetValue(dict, kSecAttrSynchronizable), kCFBooleanTrue))
1432 require_quiet(SecError(errSecParam, error, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out);
1433 }
1434
1435 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1436 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1437 bool forQuery =
1438 secItemOperation == SecItemCopyMatching ||
1439 secItemOperation == SecItemUpdate ||
1440 secItemOperation == SecItemDelete;
1441
1442 require_quiet(SecItemAttributesPrepare(query, forQuery, error), out);
1443 if (attributes != NULL)
1444 require_quiet(SecItemAttributesPrepare(attributes, false, error), out);
1445
1446 // Populate auth_params dictionary according to initial query contents.
1447 SecItemAuthCopyParams(&auth_params, query);
1448
1449 if (secItemOperation != SecItemCopyMatching) {
1450 // UISkip is allowed only for CopyMatching.
1451 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI), kSecUseAuthenticationUISkip), out,
1452 SecError(errSecParam, error,
1453 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1454 }
1455
1456 ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFArrayRef *ac_pairs, CFErrorRef *error) {
1457 SecItemAuthResult result = kSecItemAuthResultError;
1458
1459 // Propagate actual credential reference to the query.
1460 if (auth_params.dictionary != NULL) {
1461 CFDataRef acm_context = CFDictionaryGetValue(auth_params.dictionary, kSecUseCredentialReference);
1462 if (acm_context != NULL) {
1463 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecUseCredentialReference, acm_context);
1464 }
1465
1466 CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params.dictionary, kSecAttrAccessControl);
1467 if (acl_data_ref != NULL) {
1468 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes ?: query), kSecAttrAccessControl, acl_data_ref);
1469 }
1470 }
1471
1472 // Prepare connection to target token if it is present.
1473 CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID);
1474 if (secItemOperation != SecItemCopyMatching && token_id != NULL) {
1475 require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, &auth_params, error)), out);
1476 }
1477
1478 CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL;
1479 if(!perform(token, query->dictionary, attrs, auth_params.dictionary, error)) {
1480 require_quiet((result = SecItemCreatePairsFromError(error, ac_pairs)) == kSecItemAuthResultOK, out);
1481 }
1482
1483 result = kSecItemAuthResultOK;
1484
1485 out:
1486 return result;
1487 }, NULL);
1488 require_quiet(ok, out);
1489
1490 ok = true;
1491
1492 out:
1493 CFReleaseSafe(token);
1494 CFReleaseSafe(auth_params.mutable_dictionary);
1495 return ok;
1496 }
1497
1498 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error)
1499 {
1500 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1501 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error);
1502 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1503 if (result) {
1504 return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error);
1505 }
1506 return true;
1507 });
1508 }
1509
1510 static CFArrayRef dict_to_array_error_request(enum SecXPCOperation op, CFDictionaryRef attributes, CFErrorRef *error)
1511 {
1512 CFArrayRef result = NULL;
1513 bool success = cftype_to_bool_cftype_error_request(op, attributes, (CFTypeRef*)&result, error);
1514 if(success && !isArray(result)){
1515 SecError(errSecUnimplemented, error, CFSTR("Unexpected nonarray returned: %@"), result);
1516 CFReleaseNull(result);
1517 }
1518 return result;
1519 }
1520
1521 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused SecurityClient *client, CFTypeRef *result, CFErrorRef *error) {
1522 return cftype_to_bool_cftype_error_request(op, attributes, result, error);
1523 }
1524
1525 static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error)
1526 {
1527 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1528 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error);
1529 }, NULL);
1530 }
1531
1532 static bool cfstring_array_to_error_request(enum SecXPCOperation op, CFStringRef string, CFArrayRef attributes, __unused SecurityClient *client, CFErrorRef *error)
1533 {
1534 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1535 if (string) {
1536 if (!SecXPCDictionarySetString(message, kSecXPCKeyString, string, error))
1537 return false;
1538 }
1539
1540 if (attributes) {
1541 if (!SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error))
1542 return false;
1543 }
1544
1545 return true;
1546 }, NULL);
1547 }
1548
1549 static bool dict_client_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused SecurityClient *client, CFErrorRef *error)
1550 {
1551 return dict_to_error_request(op, query, error);
1552 }
1553
1554 static bool SecTokenCreateAccessControlError(CFStringRef operation, CFDataRef access_control, CFErrorRef *error) {
1555 CFArrayRef ac_pair = CFArrayCreateForCFTypes(NULL, access_control, operation, NULL);
1556 const void *ac_pairs[] = { CFArrayCreateForCFTypes(NULL, ac_pair, NULL) };
1557 const void *keys[] = { CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded) };
1558 CFAssignRetained(*error, CFErrorCreateWithUserInfoKeysAndValues(NULL, kSecErrorDomain, errSecAuthNeeded,
1559 keys, ac_pairs, 1));
1560 CFRelease(keys[0]);
1561 CFRelease(ac_pairs[0]);
1562 CFRelease(ac_pair);
1563 return false;
1564 }
1565
1566 static bool SecTokenProcessError(CFStringRef operation, TKTokenRef token, CFTypeRef object_or_attrs, CFErrorRef *error) {
1567 if (CFEqualSafe(CFErrorGetDomain(*error), CFSTR(kTKErrorDomain)) &&
1568 CFErrorGetCode(*error) == kTKErrorCodeAuthenticationNeeded) {
1569 // Replace error with the one which is augmented with access control and operation which failed,
1570 // which will cause SecItemDoWithAuth to throw UI.
1571 // Create array containing tuple (array) with error and requested operation.
1572 CFDataRef access_control = TKTokenCopyObjectAccessControl(token, object_or_attrs, error);
1573 if (access_control != NULL) {
1574 SecTokenCreateAccessControlError(operation, access_control, error);
1575 CFRelease(access_control);
1576 }
1577 }
1578 return false;
1579 }
1580
1581 static CFTypeRef SecTokenCopyUpdatedObjectID(TKTokenRef token, CFDataRef object_id, CFMutableDictionaryRef attributes, CFErrorRef *error) {
1582 CFDataRef access_control = NULL, db_value = NULL, new_object_id = NULL, result = NULL;
1583 SecAccessControlRef ac = NULL;
1584 CFDictionaryRef old_attrs = NULL;
1585
1586 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1587 CFDataRef ac_data = CFDictionaryGetValue(attributes, kSecAttrAccessControl);
1588 if (ac_data != NULL) {
1589 require_quiet(ac = SecAccessControlCreateFromData(NULL, ac_data, error), out);
1590 require_action_quiet(SecAccessControlIsBound(ac), out,
1591 SecTokenCreateAccessControlError(CFSTR(""), ac_data, error));
1592 }
1593
1594 // Create or update the object on the token.
1595 old_attrs = CFDictionaryCreateCopy(kCFAllocatorDefault, attributes);
1596 require_action_quiet(new_object_id = TKTokenCreateOrUpdateObject(token, object_id, attributes, error), out,
1597 SecTokenProcessError(kAKSKeyOpEncrypt, token, object_id ?: (CFTypeRef)attributes, error));
1598 CFDictionaryForEach(old_attrs, ^(const void *key, const void *value) {
1599 if (!CFEqual(key, kSecValueData)) {
1600 CFDictionaryAddValue(attributes, key, value);
1601 }
1602 });
1603
1604 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1605 require_quiet(access_control = TKTokenCopyObjectAccessControl(token, new_object_id, error), out);
1606 require_quiet(db_value = SecTokenItemValueCreate(new_object_id, access_control,
1607 CFDictionaryGetValue(attributes, kSecValueData), error), out);
1608 CFDictionarySetValue(attributes, kSecValueData, db_value);
1609
1610 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1611 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
1612 CFRetainAssign(result, new_object_id);
1613
1614 out:
1615 CFReleaseSafe(ac);
1616 CFReleaseSafe(access_control);
1617 CFReleaseSafe(db_value);
1618 CFReleaseSafe(old_attrs);
1619 CFReleaseSafe(new_object_id);
1620 return result;
1621 }
1622
1623 static bool SecTokenItemAdd(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef auth_params,
1624 CFTypeRef *result, CFErrorRef *error) {
1625 bool ok = false;
1626 CFTypeRef object_id = NULL, ref = NULL;
1627 CFDictionaryRef ref_attrs = NULL;
1628 CFTypeRef db_result = NULL;
1629 CFDataRef db_value = NULL;
1630 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
1631
1632 CFDictionarySetValue(attrs, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); //token items should be accesible always because have own ACL encoded in OID
1633 object_id = CFRetainSafe(CFDictionaryGetValue(attrs, kSecAttrTokenOID));
1634 CFDictionaryRemoveValue(attrs, kSecAttrTokenOID);
1635 require_quiet(CFAssignRetained(object_id, SecTokenCopyUpdatedObjectID(token, object_id, attrs, error)), out);
1636 CFDictionaryRemoveValue(attrs, kSecAttrTokenOID);
1637 if (CFDictionaryContainsKey(attrs, kSecValueRef)) {
1638 // All attributes already had been extracted from valueRef, so do not go through that step again, just remove
1639 // the ref from the dictionary since it is of no use any more.
1640 CFDictionaryRemoveValue(attrs, kSecValueRef);
1641 } else {
1642 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1643 // by creating ref and getting back its attributes.
1644 require_quiet(SecTokenItemCreateFromAttributes(attrs, auth_params, token, object_id, &ref, error), out);
1645 if (ref != NULL) {
1646 if ((ref_attrs = SecItemCopyAttributeDictionary(ref, false)) != NULL) {
1647 CFDictionaryForEach(ref_attrs, ^(const void *key, const void *value) {
1648 if (!CFEqual(key, kSecValueData)) {
1649 CFDictionaryAddValue(attrs, key, value);
1650 }
1651 });
1652 }
1653 }
1654 }
1655
1656 // Make sure that both attributes and data are returned.
1657 CFDictionarySetValue(attrs, kSecReturnAttributes, kCFBooleanTrue);
1658 CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue);
1659
1660 if (!CFEqualSafe(CFDictionaryGetValue(attrs, kSecAttrIsPermanent), kCFBooleanFalse)) {
1661 // IsPermanent is not present or is true, so add item to the db.
1662 require_quiet(SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attrs,
1663 SecSecurityClientGet(), &db_result, error), out);
1664 } else {
1665 // Process directly result of token call.
1666 db_result = CFRetain(attrs);
1667 }
1668 require_quiet(SecItemResultProcess(attributes, auth_params, token, db_result, result, error), out);
1669 ok = true;
1670
1671 out:
1672 CFReleaseSafe(db_result);
1673 CFReleaseSafe(db_value);
1674 CFReleaseSafe(attrs);
1675 CFReleaseSafe(ref_attrs);
1676 CFReleaseSafe(object_id);
1677 CFReleaseSafe(ref);
1678 return ok;
1679 }
1680
1681 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
1682 __block SecCFDictionaryCOW attrs = { attributes };
1683 OSStatus status;
1684
1685 os_activity_t activity = os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1686 os_activity_scope(activity);
1687 os_release(activity);
1688
1689 require_quiet(!explode_identity(attrs.dictionary, (secitem_operation)SecItemAdd, &status, result), errOut);
1690 infer_cert_label(&attrs);
1691
1692 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1693 return SecItemAuthDoQuery(&attrs, NULL, SecItemAdd, error, ^bool(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef unused, CFDictionaryRef auth_params, CFErrorRef *error) {
1694 if (token == NULL) {
1695 CFTypeRef raw_result = NULL;
1696 logUnreasonableDataLength(attributes);
1697 if (!SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attributes, SecSecurityClientGet(), &raw_result, error))
1698 return false;
1699
1700 bool ok = SecItemResultProcess(attributes, auth_params, token, raw_result, result, error);
1701 CFReleaseSafe(raw_result);
1702 return ok;
1703 } else {
1704 // Send request to an appropriate token instead of secd.
1705 return SecTokenItemAdd(token, attributes, auth_params, result, error);
1706 }
1707 });
1708 });
1709
1710 errOut:
1711 CFReleaseSafe(attrs.mutable_dictionary);
1712 secdebug("secitem", "SecItemAdd returned: %d", (int)status);
1713
1714 return status;
1715 }
1716
1717
1718 OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) {
1719 OSStatus status;
1720 __block SecCFDictionaryCOW query = { inQuery };
1721
1722 os_activity_t activity = os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1723 os_activity_scope(activity);
1724 os_release(activity);
1725
1726 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemCopyMatching, &status, result), errOut);
1727
1728 bool wants_data = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnData));
1729 bool wants_attributes = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnAttributes));
1730 if ((wants_data && !wants_attributes)) {
1731 // When either attributes or data are requested, we need to query both, because for token based items,
1732 // both are needed in order to generate proper data and/or attributes results.
1733 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query), kSecReturnAttributes, kCFBooleanTrue);
1734 }
1735
1736 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1737 return SecItemAuthDoQuery(&query, NULL, SecItemCopyMatching, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1738 CFTypeRef raw_result = NULL;
1739 if (!SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, query, SecSecurityClientGet(), &raw_result, error))
1740 return false;
1741
1742 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1743 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1744 // to currently processed item.
1745 bool ok = SecItemResultProcess(inQuery, auth_params, NULL, raw_result, result, error);
1746 CFReleaseSafe(raw_result);
1747 return ok;
1748 });
1749 });
1750
1751 errOut:
1752 secdebug("secitem", "SecItemCopyMatching_ios returned: %d", (int)status);
1753 CFReleaseSafe(query.mutable_dictionary);
1754 return status;
1755 }
1756
1757 // Invokes token-object handler for each item matching specified query.
1758 static bool SecTokenItemForEachMatching(CFDictionaryRef query, CFErrorRef *error,
1759 bool (^perform)(CFDictionaryRef item_value, CFDictionaryRef item_query,
1760 CFErrorRef *error)) {
1761 bool ok = false;
1762 CFMutableDictionaryRef list_query = NULL;
1763 CFTypeRef items = NULL;
1764 CFArrayRef ref_array = NULL;
1765 CFDictionaryRef item_query = NULL, item_data = NULL;
1766
1767 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1768 // items in the keychain.
1769 list_query = CFDictionaryCreateMutableCopy(NULL, 0, query);
1770 if (CFDictionaryGetValue(list_query, kSecMatchLimit) == NULL) {
1771 CFDictionarySetValue(list_query, kSecMatchLimit, kSecMatchLimitAll);
1772 }
1773 CFDictionarySetValue(list_query, kSecReturnData, kCFBooleanTrue);
1774 CFDictionarySetValue(list_query, kSecReturnPersistentRef, kCFBooleanTrue);
1775 require_quiet(SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, list_query,
1776 SecSecurityClientGet(), &items, error), out);
1777 if (CFGetTypeID(items) != CFArrayGetTypeID()) {
1778 // Wrap single returned item into the array.
1779 CFArrayRef item_array = CFArrayCreateForCFTypes(NULL, items, NULL);
1780 CFAssignRetained(items, item_array);
1781 }
1782
1783 CFTypeRef item;
1784 CFArrayForEachC(items, item) {
1785 CFDataRef data = CFDictionaryGetValue(item, kSecValueData);
1786 require_action_quiet(data != NULL, out, SecError(errSecInternal, error, CFSTR("value not present for token item")));
1787
1788 CFAssignRetained(item_data, SecTokenItemValueCopy(data, error));
1789 require_quiet(item_data, out);
1790
1791 CFAssignRetained(item_query,
1792 CFDictionaryCreateForCFTypes(NULL,
1793 kSecValuePersistentRef, CFDictionaryGetValue(item, kSecValuePersistentRef),
1794 NULL));
1795 require_quiet(perform(item_data, item_query, error), out);
1796 }
1797
1798 ok = true;
1799
1800 out:
1801 CFReleaseSafe(list_query);
1802 CFReleaseSafe(items);
1803 CFReleaseSafe(item_data);
1804 CFReleaseSafe(ref_array);
1805 CFReleaseSafe(item_query);
1806 return ok;
1807 }
1808
1809 static bool SecItemRawUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1810 bool ok = false;
1811 if (gSecurityd) {
1812 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1813 CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
1814 CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); });
1815 ok = gSecurityd->sec_item_update(query, tmp, SecSecurityClientGet(), error);
1816 CFRelease(tmp);
1817 } else {
1818 xpc_object_t message = securityd_create_message(sec_item_update_id, error);
1819 if (message) {
1820 if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) &&
1821 SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) {
1822 logUnreasonableDataLength(attributesToUpdate);
1823 xpc_object_t reply = securityd_message_with_reply_sync(message, error);
1824 if (reply) {
1825 ok = securityd_message_no_error(reply, error);
1826 xpc_release(reply);
1827 }
1828 }
1829 xpc_release(message);
1830 }
1831 }
1832 return ok;
1833 }
1834
1835 static bool SecTokenItemUpdate(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1836 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1837 bool ok = false;
1838 CFDataRef object_id = NULL;
1839 CFMutableDictionaryRef db_value = NULL;
1840
1841 // Update attributes on the token.
1842 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(NULL, 0, attributesToUpdate);
1843 require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey),
1844 attributes, error), out);
1845
1846 // Update attributes in the database.
1847 require_quiet(SecItemRawUpdate(item_query, attributes, error), out);
1848
1849 ok = true;
1850
1851 out:
1852 CFReleaseSafe(object_id);
1853 CFReleaseSafe(attributes);
1854 CFReleaseSafe(db_value);
1855 return ok;
1856 });
1857 }
1858
1859 OSStatus SecItemUpdate(CFDictionaryRef inQuery, CFDictionaryRef inAttributesToUpdate) {
1860 os_activity_t activity = os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1861 os_activity_scope(activity);
1862 os_release(activity);
1863
1864 return SecOSStatusWith(^bool(CFErrorRef *error) {
1865 return SecItemUpdateWithError(inQuery, inAttributesToUpdate, error);
1866 });
1867 }
1868
1869 bool
1870 SecItemUpdateWithError(CFDictionaryRef inQuery,
1871 CFDictionaryRef inAttributesToUpdate,
1872 CFErrorRef *error)
1873 {
1874 __block SecCFDictionaryCOW query = { inQuery };
1875 __block SecCFDictionaryCOW attributesToUpdate = { inAttributesToUpdate };
1876 bool result = false;
1877
1878 if (handleUpdateIdentity(inQuery, inAttributesToUpdate, &result, error))
1879 goto errOut;
1880
1881 result = SecItemAuthDoQuery(&query, &attributesToUpdate, SecItemUpdate, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1882 if (token == NULL) {
1883 return SecItemRawUpdate(query, attributes, error);
1884 } else {
1885 return SecTokenItemUpdate(token, query, attributes, error);
1886 }
1887 });
1888
1889 errOut:
1890 CFReleaseSafe(query.mutable_dictionary);
1891 CFReleaseSafe(attributesToUpdate.mutable_dictionary);
1892 secdebug("secitem", "SecItemUpdateWithError returned: %d", (int)result);
1893 return result;
1894 }
1895
1896 static OSStatus explode_persistent_identity_ref(SecCFDictionaryCOW *query)
1897 {
1898 OSStatus status = errSecSuccess;
1899 CFTypeRef persist = CFDictionaryGetValue(query->dictionary, kSecValuePersistentRef);
1900 CFStringRef class;
1901 if (persist && _SecItemParsePersistentRef(persist, &class, NULL, NULL)
1902 && CFEqual(class, kSecClassIdentity)) {
1903 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef };
1904 const void *vals[] = { kCFBooleanTrue, persist };
1905 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys,
1906 vals, (array_size(keys)), NULL, NULL);
1907 CFTypeRef item_query = NULL;
1908 status = SecItemCopyMatching(persistent_query, &item_query);
1909 CFReleaseNull(persistent_query);
1910 if (status)
1911 return status;
1912 if (item_query == NULL)
1913 return errSecItemNotFound;
1914
1915 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecValuePersistentRef);
1916 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecValueRef, item_query);
1917 CFRelease(item_query);
1918 }
1919
1920 return status;
1921 }
1922
1923 OSStatus SecItemDelete(CFDictionaryRef inQuery) {
1924 OSStatus status;
1925 __block SecCFDictionaryCOW query = { inQuery };
1926
1927 os_activity_t activity = os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1928 os_activity_scope(activity);
1929 os_release(activity);
1930
1931 require_noerr_quiet(status = explode_persistent_identity_ref(&query), errOut);
1932 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemDelete, &status, NULL), errOut);
1933
1934 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1935 return SecItemAuthDoQuery(&query, NULL, SecItemDelete, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1936 if (token == NULL) {
1937 return SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, query, SecSecurityClientGet(), error);
1938 } else {
1939 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1940 bool ok = false;
1941
1942 // Delete item from the token.
1943 CFDataRef object_id = CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey);
1944 require_action_quiet(TKTokenDeleteObject(token, object_id, error), out,
1945 SecTokenProcessError(kAKSKeyOpDelete, token, object_id, error));
1946
1947 // Delete the item from the keychain.
1948 require_quiet(SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, item_query,
1949 SecSecurityClientGet(), error), out);
1950 ok = true;
1951
1952 out:
1953 return ok;
1954 });
1955 }
1956 });
1957 });
1958
1959 errOut:
1960 CFReleaseSafe(query.mutable_dictionary);
1961 secdebug("secitem", "SecItemDelete returned: %d", (int)status);
1962
1963 return status;
1964 }
1965
1966 OSStatus
1967 SecItemDeleteAll(void)
1968 {
1969 return SecOSStatusWith(^bool (CFErrorRef *error) {
1970 bool ok = true;
1971 if (gSecurityd) {
1972 if (!gSecurityd->sec_item_delete_all(error))
1973 ok &= SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL"));
1974 } else {
1975 ok &= securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL);
1976 }
1977 return ok;
1978 });
1979 }
1980
1981 #if 0
1982 static bool
1983 agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unused SecurityClient *client, CFErrorRef *error)
1984 {
1985 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1986 return SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, agrps, error);
1987 }, NULL);
1988 }
1989 #endif
1990
1991 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error) {
1992 #if 0
1993 os_activity_t activity = os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1994 os_activity_scope(activity);
1995 os_release(activity);
1996
1997 return SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups,
1998 SecSecurityClientGet(), error);
1999 #else
2000 return true;
2001 #endif
2002 }
2003
2004 OSStatus
2005 #if SECITEM_SHIM_OSX
2006 SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
2007 #else
2008 SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
2009 #endif
2010 {
2011 OSStatus status;
2012
2013 os_activity_t activity = os_activity_create("SecItemUpdateTokenItems_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2014 os_activity_scope(activity);
2015 os_release(activity);
2016
2017 status = SecOSStatusWith(^bool(CFErrorRef *error) {
2018 CFArrayRef tmpArrayRef = tokenItemsAttributes;
2019 if (tokenItemsAttributes) {
2020 CFMutableArrayRef tokenItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2021 for (CFIndex i = 0; i < CFArrayGetCount(tokenItemsAttributes); ++i) {
2022 CFDictionaryRef itemAttributes = CFArrayGetValueAtIndex(tokenItemsAttributes, i);
2023 CFTypeRef accessControl = CFDictionaryGetValue(itemAttributes, kSecAttrAccessControl);
2024 CFTypeRef tokenOID = CFDictionaryGetValue(itemAttributes, kSecAttrTokenOID);
2025 CFTypeRef valueData = CFDictionaryGetValue(itemAttributes, kSecValueData);
2026 if (tokenOID != NULL && accessControl != NULL && CFDataGetTypeID() == CFGetTypeID(accessControl)) {
2027 CFDataRef data = SecTokenItemValueCreate(tokenOID, accessControl, valueData, error);
2028 if (!data) {
2029 CFRelease(tokenItems);
2030 return false;
2031 }
2032
2033 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, itemAttributes);
2034 CFDictionarySetValue(attributes, kSecValueData, data);
2035 CFDictionarySetValue(attributes, kSecAttrTokenID, tokenID);
2036 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
2037 CFDictionaryRemoveValue(attributes, kSecAttrTokenOID);
2038 CFArrayAppendValue(tokenItems, attributes);
2039 CFRelease(attributes);
2040 CFRelease(data);
2041 }
2042 else
2043 CFArrayAppendValue(tokenItems, itemAttributes);
2044 }
2045
2046 tmpArrayRef = tokenItems;
2047 }
2048
2049 return SECURITYD_XPC(sec_item_update_token_items, cfstring_array_to_error_request, tokenID, tmpArrayRef, SecSecurityClientGet(), error);
2050 });
2051
2052 return status;
2053 }
2054
2055 CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) {
2056 __block CFArrayRef result;
2057 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT, ^{
2058 result = SECURITYD_XPC(sec_keychain_sync_update_message, dict_to_array_error_request, updates, error);
2059 });
2060 return result;
2061 }
2062
2063 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
2064
2065 bool _SecKeychainRollKeys(bool force, CFErrorRef *error)
2066 {
2067 do_if_registered(sec_roll_keys, force, error);
2068
2069 __block bool result = false;
2070
2071 secdebug("secitem","enter - %s", __FUNCTION__);
2072 securityd_send_sync_and_do(kSecXPCOpRollKeys, error,
2073 ^bool(xpc_object_t message, CFErrorRef *error) {
2074 xpc_dictionary_set_bool(message, "force", force);
2075 return true;
2076 },
2077 ^bool(xpc_object_t response, __unused CFErrorRef *error) {
2078 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
2079 return result;
2080 });
2081 return result;
2082 }
2083
2084 static CFArrayRef data_array_to_array_error_request(enum SecXPCOperation op, CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) {
2085 __block CFArrayRef results = NULL;
2086 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
2087 SecXPCDictionarySetData(message, kSecXPCKeyNormalizedIssuer, normalizedIssuer, error);
2088 SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, accessGroups, error);
2089 return true;
2090 }, ^bool(xpc_object_t response, CFErrorRef *error) {
2091 return SecXPCDictionaryCopyArrayOptional(response, kSecXPCKeyResult, &results, error);
2092 });
2093 return results;
2094 }
2095
2096 static bool data_data_array_to_bool_error_request(enum SecXPCOperation op, CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) {
2097 __block bool result = false;
2098 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
2099 SecXPCDictionarySetData(message, kSecXPCKeyNormalizedIssuer, normalizedIssuer, error);
2100 SecXPCDictionarySetData(message, kSecXPCKeySerialNumber, serialNumber, error);
2101 SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, accessGroups, error);
2102 return true;
2103 }, ^bool(xpc_object_t response, CFErrorRef *error) {
2104 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
2105 return result;
2106 });
2107 return result;
2108 }
2109
2110 CFArrayRef SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) {
2111 CFArrayRef results = NULL;
2112
2113 os_activity_t activity = os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2114 os_activity_scope(activity);
2115 os_release(activity);
2116
2117 results = SECURITYD_XPC(sec_item_copy_parent_certificates, data_array_to_array_error_request, normalizedIssuer, accessGroups, error);
2118
2119 return results;
2120 }
2121
2122 bool SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) {
2123 bool results = false;
2124
2125 os_activity_t activity = os_activity_create("SecItemCertificateExists", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2126 os_activity_scope(activity);
2127 os_release(activity);
2128
2129 results = SECURITYD_XPC(sec_item_certificate_exists, data_data_array_to_bool_error_request, normalizedIssuer, serialNumber, accessGroups, error);
2130
2131 return results;
2132 }