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