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