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