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