]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecItem.c
dfed22891a913cafef697990526ff69a2574d23a
[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 static CFTypeRef sharedLAContext = NULL;
1164 static CFDataRef sharedACMContext = NULL;
1165 static dispatch_once_t onceToken;
1166 dispatch_once(&onceToken, ^{
1167 CFBundleRef bundle = CFBundleGetMainBundle();
1168 CFStringRef bundleName = (bundle != NULL)?CFBundleGetIdentifier(bundle):NULL;
1169 if (bundleName && CFEqual(bundleName, CFSTR("com.apple.mail"))) {
1170 sharedLAContext = LACreateNewContextWithACMContext(NULL, error);
1171 sharedACMContext = (sharedLAContext != NULL)?LACopyACMContext(sharedLAContext, error):NULL;
1172 }
1173 });
1174 if (sharedLAContext && sharedACMContext &&
1175 (auth_params->dictionary == NULL || (CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationContext) == NULL &&
1176 CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference) == NULL))) {
1177 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, sharedLAContext);
1178 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, sharedACMContext);
1179 }
1180
1181 for (uint32_t i = 0;; ++i) {
1182 // If the operation succeeded or failed with other than auth-needed error, just leave.
1183 SecItemAuthResult auth_result = perform(auth_params->dictionary, &ac_pairs, error);
1184 require_quiet(auth_result != kSecItemAuthResultError, out);
1185 require_action_quiet(auth_result == kSecItemAuthResultNeedAuth, out, ok = true);
1186
1187 // If auth_params were not created up to now, do create them because we will definitely need them.
1188 SecCFDictionaryCOWGetMutable(auth_params);
1189
1190 // Retrieve or create authentication handle and/or ACM context.
1191 CFTypeRef auth_handle = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationContext);
1192 if (auth_handle == NULL) {
1193 CFDataRef acm_context = CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference);
1194 require_quiet(auth_handle = LACreateNewContextWithACMContext(acm_context, error), out);
1195 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, auth_handle);
1196 CFRelease(auth_handle);
1197 if (acm_context == NULL) {
1198 require_quiet(acm_context = LACopyACMContext(auth_handle, error), out);
1199 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1200 CFRelease(acm_context);
1201 }
1202 }
1203
1204 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1205 // user retry limit.
1206 require_action(i < 20, out, SecItemAuthMaxAttemptsReached(ac_pairs, error));
1207
1208 // Prepare auth options dictionary.
1209 if (auth_options.dictionary == NULL) {
1210 CFStringRef operation_prompt = CFDictionaryGetValue(auth_params->dictionary, kSecUseOperationPrompt);
1211 if (operation_prompt != NULL) {
1212 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionAuthenticationReason);
1213 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, operation_prompt);
1214 CFRelease(key);
1215 }
1216
1217 CFStringRef caller_name = CFDictionaryGetValue(auth_params->dictionary, kSecUseCallerName);
1218 if (caller_name != NULL) {
1219 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionCallerName);
1220 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, caller_name);
1221 CFRelease(key);
1222 }
1223
1224 CFTypeRef auth_ui = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationUI);
1225 if (CFEqualSafe(auth_ui, kSecUseAuthenticationUIFail)) {
1226 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionNotInteractive);
1227 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, kCFBooleanTrue);
1228 CFRelease(key);
1229 }
1230 }
1231
1232 // Go through all access_control-operation pairs and evaluate them.
1233 CFArrayRef ac_pair;
1234 CFArrayForEachC(ac_pairs, ac_pair) {
1235 CFDataRef updated_acl = NULL;
1236 require_quiet(LAEvaluateAndUpdateACL(auth_handle,
1237 CFArrayGetValueAtIndex(ac_pair, 0), CFArrayGetValueAtIndex(ac_pair, 1),
1238 auth_options.dictionary, &updated_acl, error), out);
1239
1240 if (updated_acl || CFEqual(CFArrayGetValueAtIndex(ac_pair, 1), CFSTR(""))) {
1241 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1242 SecAccessControlRef ac = NULL;
1243 require(ac = SecAccessControlCreateFromData(kCFAllocatorDefault,
1244 updated_acl ? updated_acl : CFArrayGetValueAtIndex(ac_pair, 0), error), out);
1245 SecAccessControlSetBound(ac, true);
1246 CFAssignRetained(updated_acl, SecAccessControlCopyData(ac));
1247 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecAttrAccessControl, updated_acl);
1248 CFRelease(updated_acl);
1249 CFRelease(ac);
1250 }
1251 }
1252 }
1253
1254 ok = true;
1255
1256 out:
1257 CFReleaseSafe(auth_options.mutable_dictionary);
1258 CFReleaseSafe(ac_pairs);
1259 return ok;
1260 }
1261
1262 void SecItemAuthCopyParams(SecCFDictionaryCOW *auth_params, SecCFDictionaryCOW *query) {
1263 // Store operation prompt.
1264 CFStringRef operation_prompt = CFDictionaryGetValue(query->dictionary, kSecUseOperationPrompt);
1265 if (operation_prompt != NULL) {
1266 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseOperationPrompt, operation_prompt);
1267 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseOperationPrompt);
1268 }
1269
1270 // Store caller name.
1271 CFStringRef caller_name = CFDictionaryGetValue(query->dictionary, kSecUseCallerName);
1272 if (caller_name != NULL) {
1273 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCallerName, caller_name);
1274 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseCallerName);
1275 }
1276
1277 // Find out whether we are allowed to pop up a UI.
1278 CFTypeRef auth_ui = CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI) ?:
1279 (CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI), kCFBooleanTrue) ?
1280 kSecUseAuthenticationUIFail : kSecUseAuthenticationUIAllow);
1281 if (!CFEqual(auth_ui, kSecUseAuthenticationUISkip) || CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI)) {
1282 if (CFDictionaryContainsKey(query->dictionary, kSecUseNoAuthenticationUI))
1283 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseNoAuthenticationUI);
1284 if (!CFEqualSafe(auth_ui, kSecUseAuthenticationUISkip) && CFDictionaryContainsKey(query->dictionary, kSecUseAuthenticationUI))
1285 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseAuthenticationUI);
1286 }
1287
1288 if (!CFEqual(auth_ui, kSecUseAuthenticationUIAllow)) {
1289 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationUI, auth_ui);
1290 }
1291
1292 CFDataRef acm_context = CFDictionaryGetValue(query->dictionary, kSecUseCredentialReference);
1293 if (acm_context != NULL) {
1294 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1295 }
1296 }
1297
1298 static SecItemAuthResult SecItemCreatePairsFromError(CFErrorRef *error, CFArrayRef *ac_pairs)
1299 {
1300 if (error && *error && CFErrorGetCode(*error) == errSecAuthNeeded && CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain)) {
1301 // Extract ACLs to be verified from the error.
1302 CFDictionaryRef user_info = CFErrorCopyUserInfo(*error);
1303 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
1304 CFRetainAssign(*ac_pairs, CFDictionaryGetValue(user_info, key));
1305 if (*ac_pairs == NULL)
1306 CFAssignRetained(*ac_pairs, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
1307
1308 CFRelease(key);
1309 CFRelease(user_info);
1310 CFReleaseNull(*error);
1311 return kSecItemAuthResultNeedAuth;
1312 }
1313 return kSecItemAuthResultError;
1314 }
1315
1316 // Wrapper to handle automatic authentication and token/secd case switching.
1317 static bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error,
1318 bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) {
1319 bool ok = false;
1320 SecCFDictionaryCOW auth_params = { NULL };
1321 SecAccessControlRef access_control = NULL;
1322 __block TKTokenRef token = NULL;
1323
1324 if (secItemOperation == SecItemAdd || secItemOperation == SecItemUpdate) {
1325 CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary;
1326 access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl);
1327 if (access_control && SecAccessControlGetConstraints(access_control) &&
1328 CFEqualSafe(CFDictionaryGetValue(dict, kSecAttrSynchronizable), kCFBooleanTrue))
1329 require_quiet(SecError(errSecParam, error, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out);
1330 }
1331
1332 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1333 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1334 bool forQuery =
1335 secItemOperation == SecItemCopyMatching ||
1336 secItemOperation == SecItemUpdate ||
1337 secItemOperation == SecItemDelete;
1338
1339 require_quiet(SecItemAttributesPrepare(query, forQuery, error), out);
1340 if (attributes != NULL)
1341 require_quiet(SecItemAttributesPrepare(attributes, false, error), out);
1342
1343 // Populate auth_params dictionary according to initial query contents.
1344 SecItemAuthCopyParams(&auth_params, query);
1345
1346 if (secItemOperation != SecItemCopyMatching) {
1347 // UISkip is allowed only for CopyMatching.
1348 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI), kSecUseAuthenticationUISkip), out,
1349 SecError(errSecParam, error,
1350 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1351 }
1352
1353 ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error) {
1354 SecItemAuthResult result = kSecItemAuthResultError;
1355
1356 // Propagate actual credential reference to the query.
1357 if (auth_params != NULL) {
1358 CFDataRef acm_context = CFDictionaryGetValue(auth_params, kSecUseCredentialReference);
1359 if (acm_context != NULL) {
1360 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecUseCredentialReference, acm_context);
1361 }
1362
1363 CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params, kSecAttrAccessControl);
1364 if (acl_data_ref != NULL) {
1365 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes ?: query), kSecAttrAccessControl, acl_data_ref);
1366 }
1367 }
1368
1369 // Prepare connection to target token if it is present.
1370 CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID);
1371 if (secItemOperation != SecItemCopyMatching && token_id != NULL) {
1372 require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, auth_params, error)), out);
1373 }
1374
1375 CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL;
1376 if(!perform(token, query->dictionary, attrs, auth_params, error)) {
1377 require_quiet((result = SecItemCreatePairsFromError(error, ac_pairs)) == kSecItemAuthResultOK, out);
1378 }
1379
1380 result = kSecItemAuthResultOK;
1381
1382 out:
1383 return result;
1384 });
1385 require_quiet(ok, out);
1386
1387 ok = true;
1388
1389 out:
1390 CFReleaseSafe(token);
1391 CFReleaseSafe(auth_params.mutable_dictionary);
1392 return ok;
1393 }
1394
1395 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error)
1396 {
1397 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1398 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error);
1399 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1400 if (result) {
1401 return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error);
1402 }
1403 return true;
1404 });
1405 }
1406
1407 static CFArrayRef dict_to_array_error_request(enum SecXPCOperation op, CFDictionaryRef attributes, CFErrorRef *error)
1408 {
1409 CFArrayRef result = NULL;
1410 bool success = cftype_to_bool_cftype_error_request(op, attributes, (CFTypeRef*)&result, error);
1411 if(success && !isArray(result)){
1412 SecError(errSecUnimplemented, error, CFSTR("Unexpected nonarray returned: %@"), result);
1413 CFReleaseNull(result);
1414 }
1415 return result;
1416 }
1417
1418 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused SecurityClient *client, CFTypeRef *result, CFErrorRef *error) {
1419 return cftype_to_bool_cftype_error_request(op, attributes, result, error);
1420 }
1421
1422 static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error)
1423 {
1424 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1425 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error);
1426 }, NULL);
1427 }
1428
1429 static bool cfstring_array_to_error_request(enum SecXPCOperation op, CFStringRef string, CFArrayRef attributes, __unused SecurityClient *client, CFErrorRef *error)
1430 {
1431 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1432 if (string) {
1433 if (!SecXPCDictionarySetString(message, kSecXPCKeyString, string, error))
1434 return false;
1435 }
1436
1437 if (attributes) {
1438 if (!SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error))
1439 return false;
1440 }
1441
1442 return true;
1443 }, NULL);
1444 }
1445
1446 static bool dict_client_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused SecurityClient *client, CFErrorRef *error)
1447 {
1448 return dict_to_error_request(op, query, error);
1449 }
1450
1451 static bool SecTokenCreateAccessControlError(CFStringRef operation, CFDataRef access_control, CFErrorRef *error) {
1452 CFArrayRef ac_pair = CFArrayCreateForCFTypes(NULL, access_control, operation, NULL);
1453 const void *ac_pairs[] = { CFArrayCreateForCFTypes(NULL, ac_pair, NULL) };
1454 const void *keys[] = { CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded) };
1455 CFAssignRetained(*error, CFErrorCreateWithUserInfoKeysAndValues(NULL, kSecErrorDomain, errSecAuthNeeded,
1456 keys, ac_pairs, 1));
1457 CFRelease(keys[0]);
1458 CFRelease(ac_pairs[0]);
1459 CFRelease(ac_pair);
1460 return false;
1461 }
1462
1463 static bool SecTokenProcessError(CFStringRef operation, TKTokenRef token, CFTypeRef object_or_attrs, CFErrorRef *error) {
1464 if (CFEqualSafe(CFErrorGetDomain(*error), CFSTR(kTKErrorDomain)) &&
1465 CFErrorGetCode(*error) == kTKErrorCodeAuthenticationFailed) {
1466 // Replace error with the one which is augmented with access control and operation which failed,
1467 // which will cause SecItemDoWithAuth to throw UI.
1468 // Create array containing tuple (array) with error and requested operation.
1469 CFDataRef access_control = (CFGetTypeID(object_or_attrs) == CFDataGetTypeID()) ?
1470 TKTokenCopyObjectAccessControl(token, object_or_attrs, error) :
1471 TKTokenCopyObjectCreationAccessControl(token, object_or_attrs, error);
1472 if (access_control != NULL) {
1473 SecTokenCreateAccessControlError(operation, access_control, error);
1474 CFRelease(access_control);
1475 }
1476 }
1477 return false;
1478 }
1479
1480 static CFTypeRef SecTokenCopyUpdatedObjectID(TKTokenRef token, CFDataRef object_id, CFMutableDictionaryRef attributes, CFErrorRef *error) {
1481 CFDataRef access_control = NULL, db_value = NULL, new_object_id = NULL;
1482 SecAccessControlRef ac = NULL;
1483
1484 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1485 CFDataRef ac_data = CFDictionaryGetValue(attributes, kSecAttrAccessControl);
1486 if (ac_data != NULL) {
1487 require_quiet(ac = SecAccessControlCreateFromData(NULL, ac_data, error), out);
1488 require_action_quiet(SecAccessControlIsBound(ac), out,
1489 SecTokenCreateAccessControlError(CFSTR(""), ac_data, error));
1490 }
1491
1492 // Create or update the object on the token.
1493 require_action_quiet(new_object_id = TKTokenCreateOrUpdateObject(token, object_id, attributes, error), out,
1494 SecTokenProcessError(kAKSKeyOpEncrypt, token, object_id ?: (CFTypeRef)attributes, error));
1495
1496 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1497 require_quiet(access_control = TKTokenCopyObjectAccessControl(token, new_object_id, error), out);
1498 require_quiet(db_value = SecTokenItemValueCreate(new_object_id, access_control,
1499 CFDictionaryGetValue(attributes, kSecValueData), error), out);
1500 CFDictionarySetValue(attributes, kSecValueData, db_value);
1501
1502 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1503 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
1504
1505 out:
1506 CFReleaseSafe(ac);
1507 CFReleaseSafe(access_control);
1508 CFReleaseSafe(db_value);
1509 return new_object_id;
1510 }
1511
1512 static bool SecTokenItemAdd(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef auth_params,
1513 CFTypeRef *result, CFErrorRef *error) {
1514 bool ok = false;
1515 CFTypeRef object_id = NULL, ref = NULL;
1516 CFDictionaryRef ref_attrs = NULL;
1517 CFTypeRef db_result = NULL;
1518
1519 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
1520 require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, NULL, attrs, error), out);
1521
1522 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1523 // by creating ref and getting back its attributes.
1524 require_quiet(SecTokenItemCreateFromAttributes(attrs, auth_params, token, object_id, &ref, error), out);
1525 if (ref != NULL) {
1526 if ((ref_attrs = SecItemCopyAttributeDictionary(ref, false)) != NULL) {
1527 CFDictionaryForEach(ref_attrs, ^(const void *key, const void *value) {
1528 if (!CFEqual(key, kSecValueData)) {
1529 CFDictionaryAddValue(attrs, key, value);
1530 }
1531 });
1532 }
1533 }
1534
1535 // Make sure that both attributes and data are returned.
1536 CFDictionarySetValue(attrs, kSecReturnAttributes, kCFBooleanTrue);
1537 CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue);
1538
1539 if (!CFEqualSafe(CFDictionaryGetValue(attrs, kSecAttrIsPermanent), kCFBooleanFalse)) {
1540 // IsPermanent is not present or is true, so add item to the db.
1541 require_quiet(SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attrs,
1542 SecSecurityClientGet(), &db_result, error), out);
1543 } else {
1544 // Process directly result of token call.
1545 db_result = CFRetain(attrs);
1546 }
1547 require_quiet(SecItemResultProcess(attributes, auth_params, token, db_result, result, error), out);
1548
1549 ok = true;
1550
1551 out:
1552 CFReleaseSafe(db_result);
1553 CFReleaseSafe(attrs);
1554 CFReleaseSafe(ref_attrs);
1555 CFReleaseSafe(object_id);
1556 CFReleaseSafe(ref);
1557 return ok;
1558 }
1559
1560 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
1561 __block SecCFDictionaryCOW attrs = { attributes };
1562 OSStatus status;
1563
1564 os_activity_t trace_activity = os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT);
1565
1566 require_quiet(!explode_identity(attrs.dictionary, (secitem_operation)SecItemAdd, &status, result), errOut);
1567 infer_cert_label(&attrs);
1568
1569 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1570 return SecItemAuthDoQuery(&attrs, NULL, SecItemAdd, error, ^bool(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef unused, CFDictionaryRef auth_params, CFErrorRef *error) {
1571 if (token == NULL) {
1572 CFTypeRef raw_result = NULL;
1573 if (!SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attributes, SecSecurityClientGet(), &raw_result, error))
1574 return false;
1575
1576 bool ok = SecItemResultProcess(attributes, auth_params, token, raw_result, result, error);
1577 CFReleaseSafe(raw_result);
1578 return ok;
1579 } else {
1580 // Send request to an appropriate token instead of secd.
1581 return SecTokenItemAdd(token, attributes, auth_params, result, error);
1582 }
1583 });
1584 });
1585
1586 errOut:
1587 CFReleaseSafe(attrs.mutable_dictionary);
1588
1589 os_activity_end(trace_activity);
1590 return status;
1591 }
1592
1593
1594 OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) {
1595 OSStatus status;
1596 __block SecCFDictionaryCOW query = { inQuery };
1597
1598 os_activity_t trace_activity = os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT);
1599
1600 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemCopyMatching, &status, result), errOut);
1601
1602 bool wants_data = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnData));
1603 bool wants_attributes = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnAttributes));
1604 if ((wants_data && !wants_attributes) || (!wants_data && wants_attributes)) {
1605 // When either attributes or data are requested, we need to query both, because for token based items,
1606 // both are needed in order to generate proper data and/or attributes results.
1607 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query), kSecReturnAttributes, kCFBooleanTrue);
1608 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query), kSecReturnData, kCFBooleanTrue);
1609 }
1610
1611 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1612 return SecItemAuthDoQuery(&query, NULL, SecItemCopyMatching, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1613 CFTypeRef raw_result = NULL;
1614 if (!SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, query, SecSecurityClientGet(), &raw_result, error))
1615 return false;
1616
1617 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1618 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1619 // to currently processed item.
1620 bool ok = SecItemResultProcess(inQuery, auth_params, NULL, raw_result, result, error);
1621 CFReleaseSafe(raw_result);
1622 return ok;
1623 });
1624 });
1625
1626 errOut:
1627
1628 CFReleaseSafe(query.mutable_dictionary);
1629 os_activity_end(trace_activity);
1630 return status;
1631 }
1632
1633 // Invokes token-object handler for each item matching specified query.
1634 static bool SecTokenItemForEachMatching(CFDictionaryRef query, CFErrorRef *error,
1635 bool (^perform)(CFDictionaryRef item_value, CFDictionaryRef item_query,
1636 CFErrorRef *error)) {
1637 bool ok = false;
1638 CFMutableDictionaryRef list_query = NULL;
1639 CFTypeRef items = NULL;
1640 CFArrayRef ref_array = NULL;
1641 CFDictionaryRef item_query = NULL, item_data = NULL;
1642
1643 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1644 // items in the keychain.
1645 list_query = CFDictionaryCreateMutableCopy(NULL, 0, query);
1646 if (CFDictionaryGetValue(list_query, kSecMatchLimit) == NULL) {
1647 CFDictionarySetValue(list_query, kSecMatchLimit, kSecMatchLimitAll);
1648 }
1649 CFDictionarySetValue(list_query, kSecReturnData, kCFBooleanTrue);
1650 CFDictionarySetValue(list_query, kSecReturnPersistentRef, kCFBooleanTrue);
1651 require_quiet(SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, list_query,
1652 SecSecurityClientGet(), &items, error), out);
1653 if (CFGetTypeID(items) != CFArrayGetTypeID()) {
1654 // Wrap single returned item into the array.
1655 CFArrayRef item_array = CFArrayCreateForCFTypes(NULL, items, NULL);
1656 CFAssignRetained(items, item_array);
1657 }
1658
1659 CFTypeRef item;
1660 CFArrayForEachC(items, item) {
1661 CFDataRef data = CFDictionaryGetValue(item, kSecValueData);
1662 require_action_quiet(data != NULL, out, SecError(errSecInternal, error, CFSTR("value not present for token item")));
1663
1664 CFAssignRetained(item_data, SecTokenItemValueCopy(data, error));
1665 require_quiet(item_data, out);
1666
1667 CFAssignRetained(item_query,
1668 CFDictionaryCreateForCFTypes(NULL,
1669 kSecValuePersistentRef, CFDictionaryGetValue(item, kSecValuePersistentRef),
1670 NULL));
1671 require_quiet(perform(item_data, item_query, error), out);
1672 }
1673
1674 ok = true;
1675
1676 out:
1677 CFReleaseSafe(list_query);
1678 CFReleaseSafe(items);
1679 CFReleaseSafe(item_data);
1680 CFReleaseSafe(ref_array);
1681 CFReleaseSafe(item_query);
1682 return ok;
1683 }
1684
1685 static bool SecItemRawUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1686 bool ok = false;
1687 if (gSecurityd) {
1688 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1689 CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
1690 CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); });
1691 ok = gSecurityd->sec_item_update(query, tmp, SecSecurityClientGet(), error);
1692 CFRelease(tmp);
1693 } else {
1694 xpc_object_t message = securityd_create_message(sec_item_update_id, error);
1695 if (message) {
1696 if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) &&
1697 SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) {
1698 xpc_object_t reply = securityd_message_with_reply_sync(message, error);
1699 if (reply) {
1700 ok = securityd_message_no_error(reply, error);
1701 xpc_release(reply);
1702 }
1703 }
1704 xpc_release(message);
1705 }
1706 }
1707 return ok;
1708 }
1709
1710 static bool SecTokenItemUpdate(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1711 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1712 bool ok = false;
1713 CFDataRef object_id = NULL;
1714 CFMutableDictionaryRef db_value = NULL;
1715
1716 // Update attributes on the token.
1717 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(NULL, 0, attributesToUpdate);
1718 require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey),
1719 attributes, error), out);
1720
1721 // Update attributes in the database.
1722 require_quiet(SecItemRawUpdate(item_query, attributes, error), out);
1723
1724 ok = true;
1725
1726 out:
1727 CFReleaseSafe(object_id);
1728 CFReleaseSafe(attributes);
1729 CFReleaseSafe(db_value);
1730 return ok;
1731 });
1732 }
1733
1734 OSStatus SecItemUpdate(CFDictionaryRef inQuery, CFDictionaryRef inAttributesToUpdate) {
1735 return SecOSStatusWith(^bool(CFErrorRef *error) {
1736 return SecItemUpdateWithError(inQuery, inAttributesToUpdate, error);
1737 });
1738 }
1739
1740 bool
1741 SecItemUpdateWithError(CFDictionaryRef inQuery,
1742 CFDictionaryRef inAttributesToUpdate,
1743 CFErrorRef *error)
1744 {
1745 __block SecCFDictionaryCOW query = { inQuery };
1746 __block SecCFDictionaryCOW attributesToUpdate = { inAttributesToUpdate };
1747 bool result = false;
1748
1749 if (handleUpdateIdentity(inQuery, inAttributesToUpdate, &result, error))
1750 goto errOut;
1751
1752 result = SecItemAuthDoQuery(&query, &attributesToUpdate, SecItemUpdate, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1753 if (token == NULL) {
1754 return SecItemRawUpdate(query, attributes, error);
1755 } else {
1756 return SecTokenItemUpdate(token, query, attributes, error);
1757 }
1758 });
1759
1760 errOut:
1761 CFReleaseSafe(query.mutable_dictionary);
1762 CFReleaseSafe(attributesToUpdate.mutable_dictionary);
1763 return result;
1764 }
1765
1766 static OSStatus explode_persistent_identity_ref(SecCFDictionaryCOW *query)
1767 {
1768 OSStatus status = errSecSuccess;
1769 CFTypeRef persist = CFDictionaryGetValue(query->dictionary, kSecValuePersistentRef);
1770 CFStringRef class;
1771 if (persist && _SecItemParsePersistentRef(persist, &class, NULL)
1772 && CFEqual(class, kSecClassIdentity)) {
1773 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef };
1774 const void *vals[] = { kCFBooleanTrue, persist };
1775 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys,
1776 vals, (array_size(keys)), NULL, NULL);
1777 CFTypeRef item_query = NULL;
1778 status = SecItemCopyMatching(persistent_query, &item_query);
1779 CFReleaseNull(persistent_query);
1780 if (status)
1781 return status;
1782
1783 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecValuePersistentRef);
1784 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecValueRef, item_query);
1785 CFRelease(item_query);
1786 }
1787
1788 return status;
1789 }
1790
1791 OSStatus SecItemDelete(CFDictionaryRef inQuery) {
1792 OSStatus status;
1793 __block SecCFDictionaryCOW query = { inQuery };
1794
1795 os_activity_t trace_activity = os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT);
1796
1797 require_noerr_quiet(status = explode_persistent_identity_ref(&query), errOut);
1798 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemDelete, &status, NULL), errOut);
1799
1800 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1801 return SecItemAuthDoQuery(&query, NULL, SecItemDelete, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1802 if (token == NULL) {
1803 return SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, query, SecSecurityClientGet(), error);
1804 } else {
1805 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1806 bool ok = false;
1807
1808 // Delete item from the token.
1809 CFDataRef object_id = CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey);
1810 require_action_quiet(TKTokenDeleteObject(token, object_id, error), out,
1811 SecTokenProcessError(kAKSKeyOpDelete, token, object_id, error));
1812
1813 // Delete the item from the keychain.
1814 require_quiet(SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, item_query,
1815 SecSecurityClientGet(), error), out);
1816 ok = true;
1817
1818 out:
1819 return ok;
1820 });
1821 }
1822 });
1823 });
1824
1825 errOut:
1826 CFReleaseSafe(query.mutable_dictionary);
1827
1828 os_activity_end(trace_activity);
1829
1830 return status;
1831 }
1832
1833 OSStatus
1834 SecItemDeleteAll(void)
1835 {
1836 return SecOSStatusWith(^bool (CFErrorRef *error) {
1837 bool ok;
1838 if (gSecurityd) {
1839 ok = true;
1840 #ifndef SECITEM_SHIM_OSX
1841 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
1842 if (!gSecurityd->sec_truststore_remove_all(ts, error))
1843 ok = SecError(errSecInternal, error, CFSTR("sec_truststore_remove_all is NULL"));
1844 #endif // *** END SECITEM_SHIM_OSX ***
1845 if (!gSecurityd->sec_item_delete_all(error))
1846 ok = SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL"));
1847 } else {
1848 ok = securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL);
1849 }
1850 return ok;
1851 });
1852 }
1853
1854 static bool
1855 agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unused SecurityClient *client, CFErrorRef *error)
1856 {
1857 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1858 return SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, agrps, error);
1859 }, NULL);
1860 }
1861
1862 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error) {
1863 os_activity_t trace_activity = os_activity_start("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_FLAG_DEFAULT);
1864
1865 bool ok = SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups,
1866 SecSecurityClientGet(), error);
1867
1868 os_activity_end(trace_activity);
1869 return ok;
1870 }
1871
1872 OSStatus
1873 #if SECITEM_SHIM_OSX
1874 SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
1875 #else
1876 SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
1877 #endif
1878 {
1879 OSStatus status;
1880
1881 os_activity_t trace_activity = os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT);
1882
1883 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1884 CFArrayRef tmpArrayRef = tokenItemsAttributes;
1885 if (tokenItemsAttributes) {
1886 CFMutableArrayRef tokenItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1887 for (CFIndex i = 0; i < CFArrayGetCount(tokenItemsAttributes); ++i) {
1888 CFDictionaryRef itemAttributes = CFArrayGetValueAtIndex(tokenItemsAttributes, i);
1889 CFTypeRef accessControl = CFDictionaryGetValue(itemAttributes, kSecAttrAccessControl);
1890 CFTypeRef tokenOID = CFDictionaryGetValue(itemAttributes, kSecAttrTokenOID);
1891 CFTypeRef valueData = CFDictionaryGetValue(itemAttributes, kSecValueData);
1892 if (tokenOID != NULL && accessControl != NULL && CFDataGetTypeID() == CFGetTypeID(accessControl)) {
1893 CFDataRef data = SecTokenItemValueCreate(tokenOID, accessControl, valueData, error);
1894 if (!data) {
1895 CFRelease(tokenItems);
1896 return false;
1897 }
1898
1899 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, itemAttributes);
1900 CFDictionarySetValue(attributes, kSecValueData, data);
1901 CFDictionarySetValue(attributes, kSecAttrTokenID, tokenID);
1902 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
1903 CFDictionaryRemoveValue(attributes, kSecAttrTokenOID);
1904 CFArrayAppendValue(tokenItems, attributes);
1905 CFRelease(attributes);
1906 CFRelease(data);
1907 }
1908 else
1909 CFArrayAppendValue(tokenItems, itemAttributes);
1910 }
1911
1912 tmpArrayRef = tokenItems;
1913 }
1914
1915 return SECURITYD_XPC(sec_item_update_token_items, cfstring_array_to_error_request, tokenID, tmpArrayRef, SecSecurityClientGet(), error);
1916 });
1917
1918 os_activity_end(trace_activity);
1919
1920 return status;
1921 }
1922
1923 CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) {
1924 __block CFArrayRef result;
1925 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT, ^{
1926 result = SECURITYD_XPC(sec_keychain_sync_update_message, dict_to_array_error_request, updates, error);
1927 });
1928 return result;
1929 }
1930
1931 #ifndef SECITEM_SHIM_OSX
1932 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
1933
1934 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement)
1935 {
1936 return -1; /* this is only on OS X currently */
1937 }
1938
1939 #else
1940
1941 extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
1942
1943 #endif
1944
1945 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1946
1947 bool _SecKeychainRollKeys(bool force, CFErrorRef *error)
1948 {
1949 do_if_registered(sec_roll_keys, force, error);
1950
1951 __block bool result = false;
1952
1953 secdebug("secitem","enter - %s", __FUNCTION__);
1954 securityd_send_sync_and_do(kSecXPCOpRollKeys, error,
1955 ^bool(xpc_object_t message, CFErrorRef *error) {
1956 xpc_dictionary_set_bool(message, "force", force);
1957 return true;
1958 },
1959 ^bool(xpc_object_t response, __unused CFErrorRef *error) {
1960 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
1961 return result;
1962 });
1963 return result;
1964 }
1965
1966