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