]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecItem.c
Security-59306.101.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;
678 CFDictionaryRef itemValue = NULL;
679 require_quiet(tokenId = CFCast(CFString, CFDictionaryGetValue(attributes, kSecAttrTokenID)), out);
680 if (CFEqual(class, kSecClassIdentity)) {
681 itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecAttrIdentityCertificateData), NULL);
682 } else {
683 itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecValueData), NULL);
684 }
685 require_quiet(itemValue, out);
686 CFDataRef oid = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey);
687 require_quiet(oid, out);
688 CFArrayRef array = CFArrayCreateForCFTypes(kCFAllocatorDefault, class, tokenId, oid, NULL);
689 tokenPersistentRef = CFPropertyListCreateDERData(kCFAllocatorDefault, array, NULL);
690 CFRelease(array);
691 out:
692 CFReleaseNull(itemValue);
693 return tokenPersistentRef;
694 }
695
696 static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'};
697 /* A persistent ref is just the class and the rowid of the record.
698 Persistent ref for token items is a der blob with class, tokenID and objectId. */
699 CFDataRef _SecItemCreatePersistentRef(CFTypeRef class, sqlite_int64 rowid, CFDictionaryRef attributes)
700 {
701 CFDataRef result = NULL;
702 if (attributes && CFDictionaryContainsKey(attributes, CFEqual(class, kSecClassIdentity) ? kSecAttrIdentityCertificateTokenID : kSecAttrTokenID)) {
703 CFDataRef tokenPersistentRef = CreateTokenPersistentRefData(class, attributes);
704 require(tokenPersistentRef, out);
705 CFMutableDataRef tmpData = CFDataCreateMutable(kCFAllocatorDefault, sizeof(tk_persistent_ref_id) + CFDataGetLength(tokenPersistentRef));
706 CFDataAppendBytes(tmpData, tk_persistent_ref_id, sizeof(tk_persistent_ref_id));
707 CFDataAppend(tmpData, tokenPersistentRef);
708 CFReleaseNull(tokenPersistentRef);
709 result = tmpData;
710 } else {
711 require(rowid >= 0, out);
712 uint8_t bytes[sizeof(sqlite_int64) + 4];
713 if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/,
714 kCFStringEncodingUTF8))
715 {
716 OSWriteBigInt64(bytes + 4, 0, rowid);
717 result = CFDataCreate(NULL, bytes, sizeof(bytes));
718 }
719 }
720 out:
721 return result;
722 }
723
724 static Boolean isValidClass(CFStringRef class, CFStringRef *return_class) {
725 const void *valid_classes[] = { kSecClassGenericPassword,
726 kSecClassInternetPassword,
727 kSecClassAppleSharePassword,
728 kSecClassCertificate,
729 kSecClassKey,
730 kSecClassIdentity };
731
732 for (size_t i = 0; i < array_size(valid_classes); i++) {
733 if (CFEqual(valid_classes[i], class)) {
734 if (return_class)
735 *return_class = valid_classes[i];
736 return true;
737 }
738 }
739
740 return false;
741 }
742
743 static bool ParseTokenPersistentRefData(CFDataRef persistent_ref, CFStringRef *return_class, CFDictionaryRef *return_token_attrs) {
744 bool valid_ref = false;
745 CFPropertyListRef pl = NULL;
746 const uint8_t *der = CFDataGetBytePtr(persistent_ref) + sizeof(tk_persistent_ref_id);
747 const uint8_t *der_end = der + (CFDataGetLength(persistent_ref) - sizeof(tk_persistent_ref_id));
748 require_quiet(der = der_decode_plist(0, kCFPropertyListImmutable, &pl, NULL, der, der_end), out);
749 require_quiet(der == der_end, out);
750 require_quiet(CFGetTypeID(pl) == CFArrayGetTypeID(), out);
751 require_quiet(CFArrayGetCount(pl) == 3, out);
752 require_quiet(valid_ref = isValidClass(CFArrayGetValueAtIndex(pl, 0), return_class), out);
753 if (return_token_attrs) {
754 *return_token_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
755 kSecAttrTokenID, CFArrayGetValueAtIndex(pl, 1),
756 kSecAttrTokenOID, CFArrayGetValueAtIndex(pl, 2), NULL);
757 }
758 out:
759 CFReleaseNull(pl);
760 return valid_ref;
761 }
762
763 /* AUDIT[securityd](done):
764 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
765 */
766 bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid, CFDictionaryRef *return_token_attrs)
767 {
768 bool valid_ref = false;
769 require(CFGetTypeID(persistent_ref) == CFDataGetTypeID(), out);
770
771 if (CFDataGetLength(persistent_ref) > (CFIndex)sizeof(tk_persistent_ref_id) &&
772 memcmp(tk_persistent_ref_id, CFDataGetBytePtr(persistent_ref), sizeof(tk_persistent_ref_id)) == 0) {
773 valid_ref = ParseTokenPersistentRefData(persistent_ref, return_class, return_token_attrs);
774 } else if (CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) {
775 const uint8_t *bytes = CFDataGetBytePtr(persistent_ref);
776 sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0);
777
778 CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault,
779 bytes, CFStringGetLength(kSecClassGenericPassword),
780 kCFStringEncodingUTF8, true);
781
782 if ((valid_ref = isValidClass(class, return_class))) {
783 if (return_rowid)
784 *return_rowid = rowid;
785 }
786 CFRelease(class);
787 }
788 out:
789 return valid_ref;
790 }
791
792 static bool cf_bool_value(CFTypeRef cf_bool) {
793 return cf_bool && CFBooleanGetValue(cf_bool);
794 }
795
796 CFMutableDictionaryRef SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW *cow_dictionary) {
797 if (cow_dictionary->mutable_dictionary == NULL) {
798 cow_dictionary->mutable_dictionary = CFDictionaryCreateMutableForCFTypes(NULL);
799 if (cow_dictionary->dictionary != NULL) {
800 CFDictionaryForEach(cow_dictionary->dictionary, ^(const void *key, const void *value) {
801 CFDictionarySetValue(cow_dictionary->mutable_dictionary, key, value);
802 });
803 }
804 cow_dictionary->dictionary = cow_dictionary->mutable_dictionary;
805 }
806
807 return cow_dictionary->mutable_dictionary;
808 }
809
810 // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real
811 // access_control and optionally of the data value.
812 static CFDataRef SecTokenItemValueCreate(CFDataRef oid, CFDataRef access_control, CFDataRef object_value, CFErrorRef *error) {
813 CFMutableDictionaryRef value = NULL;
814 value = CFDictionaryCreateMutableForCFTypesWith(NULL,
815 kSecTokenValueObjectIDKey, oid,
816 kSecTokenValueAccessControlKey, access_control,
817 NULL);
818 if (object_value != NULL) {
819 CFDictionarySetValue(value, kSecTokenValueDataKey, object_value);
820 }
821
822 CFDataRef value_data = CFPropertyListCreateDERData(NULL, value, error);
823 CFRelease(value);
824 return value_data;
825 }
826
827 CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error) {
828 CFPropertyListRef plist = NULL;
829 require_quiet(CFCastWithError(CFData, db_value, error), out);
830 const uint8_t *der = CFDataGetBytePtr(db_value);
831 const uint8_t *der_end = der + CFDataGetLength(db_value);
832 require_quiet(der = der_decode_plist(0, kCFPropertyListImmutable, &plist, error, der, der_end), out);
833 require_action_quiet(der == der_end, out, SecError(errSecDecode, error, CFSTR("trailing garbage at end of token data field")));
834 CFTypeRef value = CFDictionaryGetValue(plist, kSecTokenValueObjectIDKey);
835 require_action_quiet(CFCast(CFData, value) != NULL, out,
836 SecError(errSecInternal, error, CFSTR("token based item data does not have OID")));
837 value = CFDictionaryGetValue(plist, kSecTokenValueAccessControlKey);
838 require_quiet(value == NULL || CFCastWithError(CFData, value, error), out);
839 value = CFDictionaryGetValue(plist, kSecTokenValueDataKey);
840 require_quiet(value == NULL || CFCastWithError(CFData, value, error), out);
841
842 out:
843 return plist;
844 }
845
846 TKTokenRef SecTokenCreate(CFStringRef token_id, SecCFDictionaryCOW *auth_params, CFErrorRef *error) {
847 CFMutableDictionaryRef token_attrs = NULL;
848 TKTokenRef token = NULL;
849
850 static CFMutableDictionaryRef sharedLAContexts = NULL;
851 static dispatch_once_t onceToken;
852 static os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
853 if ((auth_params->dictionary == NULL || CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference) == NULL) && !CFStringHasPrefix(token_id, kSecAttrTokenIDSecureEnclave)) {
854 dispatch_once(&onceToken, ^{
855 sharedLAContexts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
856 });
857
858 os_unfair_lock_lock(&lock);
859 CFTypeRef ctx = CFDictionaryGetValue(sharedLAContexts, token_id);
860 if (ctx == nil) {
861 ctx = LACreateNewContextWithACMContext(NULL, error);
862 if (!ctx) {
863 os_unfair_lock_unlock(&lock);
864 secerror("Failed to create authentication context %@", *error);
865 return token;
866 }
867 CFDictionarySetValue(sharedLAContexts, token_id, ctx);
868 CFRelease(ctx);
869 ctx = CFDictionaryGetValue(sharedLAContexts, token_id);
870 }
871
872 CFDataRef credRef = NULL;
873 if (ctx != nil) {
874 credRef = LACopyACMContext(ctx, NULL);
875 }
876
877 if (credRef) {
878 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, ctx);
879 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, credRef);
880 CFRelease(credRef);
881 }
882 os_unfair_lock_unlock(&lock);
883 }
884
885 token_attrs = (auth_params->dictionary != NULL) ?
886 CFDictionaryCreateMutableCopy(NULL, 0, auth_params->dictionary) :
887 CFDictionaryCreateMutableForCFTypes(NULL);
888 CFDictionarySetValue(token_attrs, kSecAttrTokenID, token_id);
889
890 CFDictionaryRemoveValue(token_attrs, kSecUseAuthenticationContext);
891 token = TKTokenCreate(token_attrs, error);
892
893 CFReleaseSafe(token_attrs);
894 return token;
895 }
896
897 static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes, CFDictionaryRef auth_params_dict,
898 TKTokenRef token, CFDataRef object_id, CFTypeRef *ref, CFErrorRef *error) {
899 bool ok = false;
900 SecCFDictionaryCOW auth_params = { auth_params_dict };
901 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
902 CFTypeRef token_id = CFDictionaryGetValue(attributes, kSecAttrTokenID);
903 if (token_id != NULL && object_id != NULL) {
904 require_quiet(CFCastWithError(CFString, token_id, error), out);
905 if (CFRetainSafe(token) == NULL) {
906 require_quiet(token = SecTokenCreate(token_id, &auth_params, error), out);
907 }
908
909 if (auth_params.dictionary != NULL) {
910 CFDictionaryForEach(auth_params.dictionary, ^(const void *key, const void *value) {
911 CFDictionaryAddValue(attrs, key, value);
912 });
913 }
914 CFDictionarySetValue(attrs, kSecUseToken, token);
915 CFDictionarySetValue(attrs, kSecAttrTokenOID, object_id);
916 CFRelease(token);
917 }
918 *ref = SecItemCreateFromAttributeDictionary(attrs);
919 ok = true;
920
921 out:
922 CFReleaseSafe(attrs);
923 CFReleaseSafe(auth_params.mutable_dictionary);
924 return ok;
925 }
926
927
928 /* Turn the returned single value or dictionary that contains all the attributes to create a
929 ref into the exact result the client asked for */
930 static bool SecItemResultCopyPrepared(CFTypeRef raw_result, TKTokenRef token,
931 CFDictionaryRef query, CFDictionaryRef auth_params_dict,
932 CFTypeRef *result, CFErrorRef *error) {
933 bool ok = false;
934 CFDataRef ac_data = NULL;
935 CFDataRef value = NULL;
936 CFTypeRef persistent_ref = NULL;
937 CFStringRef token_id = NULL;
938 CFStringRef cert_token_id = NULL;
939 CFDataRef object_id = NULL;
940 CFMutableDictionaryRef attrs = NULL;
941 CFDataRef cert_data = NULL;
942 CFDataRef cert_object_id = NULL;
943 TKTokenRef cert_token = NULL;
944 SecCFDictionaryCOW auth_params = { auth_params_dict };
945
946 bool wants_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef));
947 bool wants_data = cf_bool_value(CFDictionaryGetValue(query, kSecReturnData));
948 bool wants_attributes = cf_bool_value(CFDictionaryGetValue(query, kSecReturnAttributes));
949 bool wants_persistent_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnPersistentRef));
950
951 // Get token value if not provided by the caller.
952 bool token_item = false;
953 bool cert_token_item = false;
954 if (token == NULL) {
955 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID()) {
956 token_id = CFDictionaryGetValue(raw_result, kSecAttrTokenID);
957 require_quiet(token_id == NULL || CFCastWithError(CFString, token_id, error) != NULL, out);
958 token_item = (token_id != NULL);
959
960 cert_token_id = CFDictionaryGetValue(raw_result, kSecAttrIdentityCertificateTokenID);
961 require_quiet(cert_token_id == NULL || CFCastWithError(CFString, cert_token_id, error) != NULL, out);
962 cert_token_item = (cert_token_id != NULL);
963 }
964 } else {
965 token_item = true;
966 cert_token_item = true;
967 CFRetain(token);
968 CFRetainAssign(cert_token, token);
969 }
970
971 if ((token_item || cert_token_item) && cf_bool_value(CFDictionaryGetValue(query, kSecUseTokenRawItems))) {
972 token_item = false;
973 cert_token_item = false;
974 }
975
976 // Decode and prepare data value, if it is requested at the output, or if we want attributes from token.
977 if (wants_data || wants_ref || (token_item && wants_attributes)) {
978 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID())
979 value = CFRetainSafe(CFDictionaryGetValue(raw_result, kSecValueData));
980 else
981 value = CFRetainSafe(raw_result);
982 if (token_item && value != NULL) {
983 // Parse token-based item's data field.
984 CFDataRef object_value = NULL;
985 CFDictionaryRef parsed_value = NULL;
986 require_quiet(parsed_value = SecTokenItemValueCopy(value, error), out);
987 object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey));
988 ac_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueAccessControlKey));
989 object_value = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey));
990 CFRelease(parsed_value);
991 if ((wants_data || wants_ref) && object_value == NULL) {
992 // Retrieve value directly from the token.
993 if (token == NULL) {
994 require_quiet(token = SecTokenCreate(token_id, &auth_params, error), out);
995 }
996 require_quiet(object_value = TKTokenCopyObjectData(token, object_id, error), out);
997 if (CFEqual(object_value, kCFNull))
998 CFReleaseNull(object_value);
999 }
1000 CFAssignRetained(value, object_value);
1001 }
1002
1003 // If only thing requested is data, return them directly.
1004 if (!(wants_attributes || wants_persistent_ref || wants_ref)) {
1005 *result = CFRetainSafe(value);
1006 ok = true;
1007 goto out;
1008 }
1009 }
1010
1011 // Extract persistent_ref, if caller wants it.
1012 if (wants_persistent_ref) {
1013 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID())
1014 persistent_ref = CFRetainSafe(CFDictionaryGetValue(raw_result, kSecValuePersistentRef));
1015 else
1016 persistent_ref = CFRetainSafe(raw_result);
1017
1018 // If only thing requested is persistentref, extract it from dictionary if needed and return it.
1019 if (!(wants_attributes || wants_data || wants_ref)) {
1020 *result = CFRetainSafe(persistent_ref);
1021 ok = true;
1022 goto out;
1023 }
1024 }
1025
1026 if (!wants_ref && !wants_attributes && (!wants_data || !wants_persistent_ref)) {
1027 *result = NULL;
1028 ok = true;
1029 goto out;
1030 }
1031
1032 // For other cases we need an output dictionary.
1033 if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID())
1034 *result = CFDictionaryCreateMutableCopy(NULL, 0, raw_result);
1035 else
1036 *result = CFDictionaryCreateForCFTypes(NULL, NULL);
1037 CFMutableDictionaryRef output = (CFMutableDictionaryRef)*result;
1038
1039 if ((wants_data || wants_ref) && value != NULL)
1040 CFDictionarySetValue(output, kSecValueData, value);
1041 else
1042 CFDictionaryRemoveValue(output, kSecValueData);
1043
1044 if (wants_persistent_ref && persistent_ref != NULL)
1045 CFDictionarySetValue(output, kSecValuePersistentRef, persistent_ref);
1046 else
1047 CFDictionaryRemoveValue(output, kSecValuePersistentRef);
1048
1049 if ((wants_ref || wants_attributes) && cert_token_item &&
1050 CFEqualSafe(CFDictionaryGetValue(output, kSecClass), kSecClassIdentity)) {
1051 // Decode also certdata field of the identity.
1052 CFDataRef data = CFDictionaryGetValue(output, kSecAttrIdentityCertificateData);
1053 if (data != NULL) {
1054 CFDictionaryRef parsed_value;
1055 require_quiet(parsed_value = SecTokenItemValueCopy(data, error), out);
1056 cert_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey));
1057 cert_object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey));
1058 CFRelease(parsed_value);
1059 if (cert_data == NULL) {
1060 // Retrieve value directly from the token.
1061 if (cert_token == NULL) {
1062 require_quiet(cert_token = SecTokenCreate(cert_token_id, &auth_params, error), out);
1063 }
1064 require_quiet(cert_data = TKTokenCopyObjectData(cert_token, cert_object_id, error), out);
1065 if (CFEqual(cert_data, kCFNull))
1066 CFReleaseNull(cert_data);
1067 }
1068 if (cert_data != NULL) {
1069 CFDictionarySetValue(output, kSecAttrIdentityCertificateData, cert_data);
1070 } else {
1071 CFDictionaryRemoveValue(output, kSecAttrIdentityCertificateData);
1072 }
1073 }
1074 }
1075
1076 if (wants_ref || wants_attributes) {
1077 // Convert serialized form of access control to object form.
1078 if (!token_item) {
1079 CFRetainAssign(ac_data, CFDictionaryGetValue(output, kSecAttrAccessControl));
1080 }
1081
1082 if (ac_data != NULL) {
1083 SecAccessControlRef ac;
1084 require_quiet(ac = SecAccessControlCreateFromData(kCFAllocatorDefault, ac_data, error), out);
1085 CFDictionarySetValue(output, kSecAttrAccessControl, ac);
1086 CFRelease(ac);
1087 }
1088 }
1089
1090 if (wants_ref) {
1091 CFTypeRef ref;
1092 require_quiet(SecTokenItemCreateFromAttributes(output, auth_params.dictionary, token, object_id, &ref, error), out);
1093 if (!(wants_attributes || wants_data || wants_persistent_ref)) {
1094 CFAssignRetained(*result, ref);
1095 } else if (ref != NULL) {
1096 CFDictionarySetValue(output, kSecValueRef, ref);
1097 CFRelease(ref);
1098 if (!wants_data) {
1099 // We could have stored data value previously to make ref creation succeed.
1100 // They are not needed any more and in case that caller did not want the data, avoid returning them.
1101 CFDictionaryRemoveValue(output, kSecValueData);
1102 }
1103 }
1104 }
1105
1106 ok = true;
1107
1108 out:
1109 CFReleaseSafe(cert_object_id);
1110 CFReleaseSafe(cert_data);
1111 CFReleaseSafe(ac_data);
1112 CFReleaseSafe(value);
1113 CFReleaseSafe(persistent_ref);
1114 CFReleaseSafe(object_id);
1115 CFReleaseSafe(attrs);
1116 CFReleaseSafe(token);
1117 CFReleaseSafe(cert_token);
1118 CFReleaseSafe(auth_params.mutable_dictionary);
1119 return ok;
1120 }
1121
1122 bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TKTokenRef token,
1123 CFTypeRef raw_result, CFTypeRef *result, CFErrorRef *error) {
1124 bool ok = false;
1125 require_action_quiet(raw_result != NULL, out, ok = true);
1126 require_action_quiet(result != NULL, out, ok = true);
1127
1128 if (CFGetTypeID(raw_result) == CFArrayGetTypeID()) {
1129 CFIndex i, count = CFArrayGetCount(raw_result);
1130 *result = CFArrayCreateMutableForCFTypes(NULL);
1131 for (i = 0; i < count; i++) {
1132 CFTypeRef ref;
1133 require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result, i),
1134 token, query, auth_params, &ref, error), out);
1135 if (ref != NULL) {
1136 CFArrayAppendValue((CFMutableArrayRef)*result, ref);
1137 CFRelease(ref);
1138 }
1139 }
1140 } else {
1141 require_quiet(SecItemResultCopyPrepared(raw_result, token, query, auth_params, result, error), out);
1142 }
1143
1144 ok = true;
1145
1146 out:
1147 return ok;
1148 }
1149
1150 static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, CFErrorRef *error) {
1151 bool ok = false;
1152 CFDataRef ac_data = NULL, acm_context = NULL;
1153 void *la_lib = NULL;
1154
1155 // If a ref was specified we get its attribute dictionary and parse it.
1156 CFTypeRef value = CFDictionaryGetValue(attrs->dictionary, kSecValueRef);
1157 if (value) {
1158 CFDictionaryRef ref_attributes;
1159 require_action_quiet(ref_attributes = SecItemCopyAttributeDictionary(value, forQuery), out,
1160 SecError(errSecValueRefUnsupported, error, CFSTR("unsupported kSecValueRef in query")));
1161
1162 // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us.
1163 // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly.
1164 CFDictionaryForEach(ref_attributes, ^(const void *key, const void *value) {
1165 // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref,
1166 // so add only those attributes from 'ref' which are missing in attrs.
1167 CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs), key, value);
1168 });
1169 CFRelease(ref_attributes);
1170
1171 if (forQuery) {
1172 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrTokenOID);
1173 }
1174
1175 // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid
1176 // another roundtrip to token driver.
1177 if (forQuery || !CFDictionaryContainsKey(attrs->dictionary, kSecAttrTokenID)) {
1178 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecValueRef);
1179 }
1180 }
1181
1182 SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(attrs->dictionary, kSecAttrAccessControl);
1183 if (access_control != NULL) {
1184 require_action_quiet(CFGetTypeID(access_control) == SecAccessControlGetTypeID(), out,
1185 SecError(errSecParam, error, CFSTR("Unexpected type of kSecAttrAccessControl attribute")));
1186 require_action_quiet(ac_data = SecAccessControlCopyData(access_control), out,
1187 SecError(errSecParam, error, CFSTR("unsupported kSecAttrAccessControl in query")));
1188 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrAccessControl, ac_data);
1189 }
1190
1191 const CFTypeRef la_context = CFDictionaryGetValue(attrs->dictionary, kSecUseAuthenticationContext);
1192 if (la_context) {
1193 require_action_quiet(!CFDictionaryContainsKey(attrs->dictionary, kSecUseCredentialReference), out,
1194 SecError(errSecParam, error, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1195 require_quiet(acm_context = LACopyACMContext(la_context, error), out);
1196 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseAuthenticationContext);
1197 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseCredentialReference, acm_context);
1198 }
1199
1200 CFTypeRef policy = CFDictionaryGetValue(attrs->dictionary, kSecMatchPolicy);
1201 if (policy) {
1202 require_action_quiet(CFGetTypeID(policy) == SecPolicyGetTypeID(), out,
1203 SecError(errSecParam, error, CFSTR("unsupported kSecMatchPolicy in query")));
1204
1205 CFTypeRef values[] = { policy };
1206 CFArrayRef policiesArray = CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks);
1207 xpc_object_t policiesArrayXPC = SecPolicyArrayCopyXPCArray(policiesArray, error);
1208 CFReleaseSafe(policiesArray);
1209 require_action_quiet(policiesArrayXPC, out,
1210 SecError(errSecInternal, error, CFSTR("Failed to copy XPC policy")));
1211
1212 CFTypeRef objectReadyForXPC = _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC);
1213 xpc_release(policiesArrayXPC);
1214 require_action_quiet(objectReadyForXPC, out,
1215 SecError(errSecInternal, error, CFSTR("Failed to create CFObject from XPC policy")));
1216
1217 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecMatchPolicy, objectReadyForXPC);
1218 CFRelease(objectReadyForXPC);
1219 }
1220 value = CFDictionaryGetValue(attrs->dictionary, kSecAttrIssuer);
1221 if (value) {
1222 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1223 CFDataRef issuer;
1224 require_quiet(issuer = CFCastWithError(CFData, value, error), out);
1225 const DERItem name = { (unsigned char *)CFDataGetBytePtr(issuer), CFDataGetLength(issuer) };
1226 DERDecodedInfo content;
1227 if (DERDecodeItem(&name, &content) == DR_Success && content.tag == ASN1_CONSTR_SEQUENCE) {
1228 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content);
1229 if (canonical_issuer) {
1230 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrIssuer, canonical_issuer);
1231 CFRelease(canonical_issuer);
1232 }
1233 }
1234 }
1235
1236 if (CFDictionaryContainsKey(attrs->dictionary, kSecUseTokenRawItems)) {
1237 // This use flag is client-only, securityd does not understand it.
1238 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseTokenRawItems);
1239 }
1240
1241 ok = true;
1242
1243 out:
1244 if (la_lib != NULL) {
1245 dlclose(la_lib);
1246 }
1247 CFReleaseSafe(ac_data);
1248 CFReleaseSafe(acm_context);
1249 return ok;
1250 }
1251
1252 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs, CFErrorRef *error)
1253 {
1254 CFMutableStringRef log_string = CFStringCreateMutable(kCFAllocatorDefault, 0);
1255 CFArrayRef ac_pair;
1256 CFArrayForEachC(ac_pairs, ac_pair) {
1257 CFStringRef acl_hex_string = CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair, 0));
1258 CFStringRef str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair, 1), acl_hex_string);
1259 CFStringAppend(log_string, str);
1260 CFRelease(acl_hex_string);
1261 CFRelease(str);
1262 }
1263
1264 CFStringRef reason = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string);
1265 SecError(errSecAuthFailed, error, CFSTR("%@"), reason);
1266 __security_simulatecrash(reason, __sec_exception_code_AuthLoop);
1267 CFRelease(reason);
1268 CFRelease(log_string);
1269 return false;
1270 }
1271
1272 bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFArrayRef *ac_pairs, CFErrorRef *error),
1273 void (^newCredentialRefAdded)(void)) {
1274 bool ok = false;
1275 CFArrayRef ac_pairs = NULL;
1276 SecCFDictionaryCOW auth_options = { NULL };
1277
1278 for (uint32_t i = 0;; ++i) {
1279 // If the operation succeeded or failed with other than auth-needed error, just leave.
1280 SecItemAuthResult auth_result = perform(&ac_pairs, error);
1281 require_quiet(auth_result != kSecItemAuthResultError, out);
1282 require_action_quiet(auth_result == kSecItemAuthResultNeedAuth, out, ok = true);
1283
1284 // If auth_params were not created up to now, do create them because we will definitely need them.
1285 SecCFDictionaryCOWGetMutable(auth_params);
1286
1287 // Retrieve or create authentication handle and/or ACM context.
1288 CFTypeRef auth_handle = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationContext);
1289 if (auth_handle == NULL) {
1290 CFDataRef acm_context = CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference);
1291 require_quiet(auth_handle = LACreateNewContextWithACMContext(acm_context, error), out);
1292 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, auth_handle);
1293 CFRelease(auth_handle);
1294 if (acm_context == NULL) {
1295 require_quiet(acm_context = LACopyACMContext(auth_handle, error), out);
1296 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1297 CFRelease(acm_context);
1298 if (newCredentialRefAdded) {
1299 newCredentialRefAdded();
1300 }
1301 }
1302 }
1303
1304 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1305 // user retry limit.
1306 require_action(i < 20, out, SecItemAuthMaxAttemptsReached(ac_pairs, error));
1307
1308 // Prepare auth options dictionary.
1309 if (auth_options.dictionary == NULL) {
1310 CFStringRef operation_prompt = CFDictionaryGetValue(auth_params->dictionary, kSecUseOperationPrompt);
1311 if (operation_prompt != NULL) {
1312 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionAuthenticationReason);
1313 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, operation_prompt);
1314 CFRelease(key);
1315 }
1316
1317 CFStringRef caller_name = CFDictionaryGetValue(auth_params->dictionary, kSecUseCallerName);
1318 if (caller_name != NULL) {
1319 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionCallerName);
1320 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, caller_name);
1321 CFRelease(key);
1322 }
1323
1324 CFTypeRef auth_ui = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationUI);
1325 if (CFEqualSafe(auth_ui, kSecUseAuthenticationUIFail)) {
1326 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionNotInteractive);
1327 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, kCFBooleanTrue);
1328 CFRelease(key);
1329 }
1330 }
1331
1332 // Go through all access_control-operation pairs and evaluate them.
1333 CFArrayRef ac_pair;
1334 CFArrayForEachC(ac_pairs, ac_pair) {
1335 CFDataRef updated_acl = NULL;
1336 require_quiet(LAEvaluateAndUpdateACL(auth_handle,
1337 CFArrayGetValueAtIndex(ac_pair, 0), CFArrayGetValueAtIndex(ac_pair, 1),
1338 auth_options.dictionary, &updated_acl, error), out);
1339
1340 if (updated_acl || CFEqual(CFArrayGetValueAtIndex(ac_pair, 1), CFSTR(""))) {
1341 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1342 SecAccessControlRef ac = NULL;
1343 require(ac = SecAccessControlCreateFromData(kCFAllocatorDefault,
1344 updated_acl ? updated_acl : CFArrayGetValueAtIndex(ac_pair, 0), error), out);
1345 SecAccessControlSetBound(ac, true);
1346 CFAssignRetained(updated_acl, SecAccessControlCopyData(ac));
1347 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecAttrAccessControl, updated_acl);
1348 CFRelease(updated_acl);
1349 CFRelease(ac);
1350 }
1351 }
1352 }
1353
1354 ok = true;
1355
1356 out:
1357 CFReleaseSafe(auth_options.mutable_dictionary);
1358 CFReleaseSafe(ac_pairs);
1359 return ok;
1360 }
1361
1362 void SecItemAuthCopyParams(SecCFDictionaryCOW *auth_params, SecCFDictionaryCOW *query) {
1363 // Store operation prompt.
1364 CFStringRef operation_prompt = CFDictionaryGetValue(query->dictionary, kSecUseOperationPrompt);
1365 if (operation_prompt != NULL) {
1366 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseOperationPrompt, operation_prompt);
1367 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseOperationPrompt);
1368 }
1369
1370 // Store caller name.
1371 CFStringRef caller_name = CFDictionaryGetValue(query->dictionary, kSecUseCallerName);
1372 if (caller_name != NULL) {
1373 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCallerName, caller_name);
1374 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseCallerName);
1375 }
1376
1377 // Find out whether we are allowed to pop up a UI.
1378 CFTypeRef auth_ui = CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI) ?:
1379 (CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI), kCFBooleanTrue) ?
1380 kSecUseAuthenticationUIFail : kSecUseAuthenticationUIAllow);
1381 if (!CFEqual(auth_ui, kSecUseAuthenticationUISkip) || CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI)) {
1382 if (CFDictionaryContainsKey(query->dictionary, kSecUseNoAuthenticationUI))
1383 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseNoAuthenticationUI);
1384 if (!CFEqualSafe(auth_ui, kSecUseAuthenticationUISkip) && CFDictionaryContainsKey(query->dictionary, kSecUseAuthenticationUI))
1385 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseAuthenticationUI);
1386 }
1387
1388 if (!CFEqual(auth_ui, kSecUseAuthenticationUIAllow)) {
1389 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationUI, auth_ui);
1390 }
1391
1392 CFDataRef acm_context = CFDictionaryGetValue(query->dictionary, kSecUseCredentialReference);
1393 if (acm_context != NULL) {
1394 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1395 }
1396 }
1397
1398 static SecItemAuthResult SecItemCreatePairsFromError(CFErrorRef *error, CFArrayRef *ac_pairs)
1399 {
1400 if (error && *error && CFErrorGetCode(*error) == errSecAuthNeeded && CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain)) {
1401 // Extract ACLs to be verified from the error.
1402 CFDictionaryRef user_info = CFErrorCopyUserInfo(*error);
1403 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
1404 CFRetainAssign(*ac_pairs, CFDictionaryGetValue(user_info, key));
1405 if (*ac_pairs == NULL)
1406 CFAssignRetained(*ac_pairs, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
1407
1408 CFRelease(key);
1409 CFRelease(user_info);
1410 CFReleaseNull(*error);
1411 return kSecItemAuthResultNeedAuth;
1412 }
1413 return kSecItemAuthResultError;
1414 }
1415
1416 // Wrapper to handle automatic authentication and token/secd case switching.
1417 bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error,
1418 bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) {
1419 bool ok = false;
1420 __block SecCFDictionaryCOW auth_params = { NULL };
1421 __block TKTokenRef token = NULL;
1422
1423 CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary;
1424 SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl);
1425 require_action_quiet(access_control == NULL || CFGetTypeID(access_control) == SecAccessControlGetTypeID(), out,
1426 SecError(errSecParam, error, CFSTR("Unexpected type of kSecAttrAccessControl attribute")));
1427
1428 if (secItemOperation == SecItemAdd || secItemOperation == SecItemUpdate) {
1429 if (access_control && SecAccessControlGetConstraints(access_control) &&
1430 CFEqualSafe(CFDictionaryGetValue(dict, kSecAttrSynchronizable), kCFBooleanTrue))
1431 require_quiet(SecError(errSecParam, error, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out);
1432 }
1433
1434 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1435 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1436 bool forQuery =
1437 secItemOperation == SecItemCopyMatching ||
1438 secItemOperation == SecItemUpdate ||
1439 secItemOperation == SecItemDelete;
1440
1441 require_quiet(SecItemAttributesPrepare(query, forQuery, error), out);
1442 if (attributes != NULL)
1443 require_quiet(SecItemAttributesPrepare(attributes, false, error), out);
1444
1445 // Populate auth_params dictionary according to initial query contents.
1446 SecItemAuthCopyParams(&auth_params, query);
1447
1448 if (secItemOperation != SecItemCopyMatching) {
1449 // UISkip is allowed only for CopyMatching.
1450 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI), kSecUseAuthenticationUISkip), out,
1451 SecError(errSecParam, error,
1452 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1453 }
1454
1455 ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFArrayRef *ac_pairs, CFErrorRef *error) {
1456 SecItemAuthResult result = kSecItemAuthResultError;
1457
1458 // Propagate actual credential reference to the query.
1459 if (auth_params.dictionary != NULL) {
1460 CFDataRef acm_context = CFDictionaryGetValue(auth_params.dictionary, kSecUseCredentialReference);
1461 if (acm_context != NULL) {
1462 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecUseCredentialReference, acm_context);
1463 }
1464
1465 CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params.dictionary, kSecAttrAccessControl);
1466 if (acl_data_ref != NULL) {
1467 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes ?: query), kSecAttrAccessControl, acl_data_ref);
1468 }
1469 }
1470
1471 // Prepare connection to target token if it is present.
1472 CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID);
1473 require_quiet(token_id == NULL || CFCastWithError(CFString, token_id, error) != NULL, out);
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 }