]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecItem.c
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / sec / Security / SecItem.c
1 /*
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
27 passwords.)
28 */
29
30 #include <Security/SecBasePriv.h>
31 #include <Security/SecItem.h>
32 #include <Security/SecItemPriv.h>
33 #include <Security/SecItemInternal.h>
34 #include <Security/SecItemShim.h>
35 #include <Security/SecAccessControl.h>
36 #include <Security/SecAccessControlPriv.h>
37 #include <Security/SecKey.h>
38 #include <Security/SecKeyPriv.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecIdentity.h>
41 #include <Security/SecIdentityPriv.h>
42 #include <Security/SecRandom.h>
43 #include <Security/SecBasePriv.h>
44 #include <Security/SecCTKKeyPriv.h>
45 #include <Security/SecTask.h>
46 #include <Security/SecPolicyInternal.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <sqlite3.h>
50 #include <stdint.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <sys/param.h>
54 #include <sys/stat.h>
55 #include <Security/SecBase.h>
56 #include <CoreFoundation/CFData.h>
57 #include <CoreFoundation/CFDate.h>
58 #include <CoreFoundation/CFDictionary.h>
59 #include <CoreFoundation/CFNumber.h>
60 #include <CoreFoundation/CFString.h>
61 #include <CoreFoundation/CFURL.h>
62 #include <CommonCrypto/CommonDigest.h>
63 #include <libkern/OSByteOrder.h>
64 #include <corecrypto/ccder.h>
65 #include <utilities/array_size.h>
66 #include <utilities/debugging.h>
67 #include <utilities/SecCFError.h>
68 #include <utilities/SecCFWrappers.h>
69 #include <utilities/SecIOFormat.h>
70 #include <utilities/SecXPCError.h>
71 #include <utilities/der_plist.h>
72 #include <utilities/der_plist_internal.h>
73 #include <assert.h>
74 #include <dlfcn.h>
75 #include <libaks_acl_cf_keys.h>
76 #include <os/activity.h>
77 #include <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 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 static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, CFErrorRef *error) {
1032 bool ok = false;
1033 CFDataRef ac_data = NULL, acm_context = NULL;
1034 void *la_lib = NULL;
1035
1036 SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(attrs->dictionary, kSecAttrAccessControl);
1037 if (access_control != NULL) {
1038 require_quiet(ac_data = SecAccessControlCopyData(access_control), out);
1039 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrAccessControl, ac_data);
1040 }
1041
1042 const CFTypeRef la_context = CFDictionaryGetValue(attrs->dictionary, kSecUseAuthenticationContext);
1043 if (la_context) {
1044 require_action_quiet(!CFDictionaryContainsKey(attrs->dictionary, kSecUseCredentialReference), out,
1045 SecError(errSecParam, error, CFSTR("kSecUseAuthenticationContext cannot be used together with kSecUseCredentialReference")));
1046 require_action_quiet(la_lib = dlopen("/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication", RTLD_LAZY), out,
1047 SecError(errSecInternal, error, CFSTR("failed to open LocalAuthentication.framework")));
1048 LAFunctionCopyExternalizedContext fnCopyExternalizedContext = NULL;
1049 require_action_quiet(fnCopyExternalizedContext = dlsym(la_lib, "LACopyExternalizedContext"), out,
1050 SecError(errSecInternal, error, CFSTR("failed to obtain LACopyExternalizedContext")));
1051 require_action_quiet(acm_context = fnCopyExternalizedContext(la_context), out,
1052 SecError(errSecInternal, error, CFSTR("failed to get ACM handle from LAContext")));
1053 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseAuthenticationContext);
1054 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseCredentialReference, acm_context);
1055 }
1056
1057 // If a ref was specified we get its attribute dictionary and parse it.
1058 CFTypeRef value = CFDictionaryGetValue(attrs->dictionary, kSecValueRef);
1059 if (value) {
1060 CFDictionaryRef ref_attributes;
1061 require_action_quiet(ref_attributes = SecItemCopyAttributeDictionary(value, forQuery), out,
1062 SecError(errSecValueRefUnsupported, error, CFSTR("unsupported kSecValueRef in query")));
1063
1064 /* Replace any attributes we already got from the ref with the ones
1065 from the attributes dictionary the caller passed us. This allows
1066 a caller to add an item using attributes from the ref and still
1067 override some of them in the dictionary directly. */
1068 CFMutableDictionaryRef new_query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, ref_attributes);
1069 CFRelease(ref_attributes);
1070 CFDictionaryForEach(attrs->dictionary, ^(const void *key, const void *value) {
1071 if (!CFEqual(key, kSecValueRef))
1072 CFDictionarySetValue(new_query, key, value);
1073 });
1074 CFAssignRetained(attrs->mutable_dictionary, new_query);
1075 attrs->dictionary = attrs->mutable_dictionary;
1076 }
1077
1078 CFTypeRef policy = CFDictionaryGetValue(attrs->dictionary, kSecMatchPolicy);
1079 if (policy) {
1080 require_action_quiet(CFGetTypeID(policy) == SecPolicyGetTypeID(), out,
1081 SecError(errSecParam, error, CFSTR("unsupported kSecMatchPolicy in query")));
1082
1083 CFTypeRef values[] = { policy };
1084 CFArrayRef policiesArray = CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks);
1085 xpc_object_t policiesArrayXPC = SecPolicyArrayCopyXPCArray(policiesArray, error);
1086 CFReleaseSafe(policiesArray);
1087 require_action_quiet(policiesArrayXPC, out,
1088 SecError(errSecInternal, error, CFSTR("Failed to copy XPC policy")));
1089
1090 CFTypeRef objectReadyForXPC = _CFXPCCreateCFObjectFromXPCObject(policiesArrayXPC);
1091 xpc_release(policiesArrayXPC);
1092 require_action_quiet(objectReadyForXPC, out,
1093 SecError(errSecInternal, error, CFSTR("Failed to create CFObject from XPC policy")));
1094
1095 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecMatchPolicy, objectReadyForXPC);
1096 CFRelease(objectReadyForXPC);
1097 }
1098 #ifndef SECITEM_SHIM_OSX
1099 value = CFDictionaryGetValue(attrs->dictionary, kSecAttrIssuer);
1100 if (value) {
1101 /* convert DN to canonical issuer, if value is DN (top level sequence) */
1102 const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) };
1103 DERDecodedInfo content;
1104 if (!DERDecodeItem(&name, &content) &&
1105 (content.tag == ASN1_CONSTR_SEQUENCE))
1106 {
1107 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content);
1108 if (canonical_issuer) {
1109 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrIssuer, canonical_issuer);
1110 CFRelease(canonical_issuer);
1111 }
1112 }
1113 }
1114 #endif
1115
1116 ok = true;
1117
1118 out:
1119 if (la_lib != NULL) {
1120 dlclose(la_lib);
1121 }
1122 CFReleaseSafe(ac_data);
1123 CFReleaseSafe(acm_context);
1124 return ok;
1125 }
1126
1127 static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs, CFErrorRef *error)
1128 {
1129 CFMutableStringRef log_string = CFStringCreateMutable(kCFAllocatorDefault, 0);
1130 CFArrayRef ac_pair;
1131 CFArrayForEachC(ac_pairs, ac_pair) {
1132 CFStringRef acl_hex_string = CFDataCopyHexString(CFArrayGetValueAtIndex(ac_pair, 0));
1133 CFStringRef str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("operation: %@ acl:%@\n"), CFArrayGetValueAtIndex(ac_pair, 1), acl_hex_string);
1134 CFStringAppend(log_string, str);
1135 CFRelease(acl_hex_string);
1136 CFRelease(str);
1137 }
1138
1139 CFStringRef reason = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string);
1140 SecError(errSecAuthFailed, error, reason);
1141 __security_simulatecrash(reason, __sec_exception_code_AuthLoop);
1142
1143 CFRelease(reason);
1144 CFRelease(log_string);
1145 return false;
1146 }
1147
1148 bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error)) {
1149 bool ok = false;
1150 CFArrayRef ac_pairs = NULL;
1151 SecCFDictionaryCOW auth_options = { NULL };
1152
1153 for (uint32_t i = 0;; ++i) {
1154 // If the operation succeeded or failed with other than auth-needed error, just leave.
1155 SecItemAuthResult auth_result = perform(auth_params->dictionary, &ac_pairs, error);
1156 require_quiet(auth_result != kSecItemAuthResultError, out);
1157 require_action_quiet(auth_result == kSecItemAuthResultNeedAuth, out, ok = true);
1158
1159 // If auth_params were not created up to now, do create them because we will definitely need them.
1160 SecCFDictionaryCOWGetMutable(auth_params);
1161
1162 // Retrieve or create authentication handle and/or ACM context.
1163 CFTypeRef auth_handle = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationContext);
1164 if (auth_handle == NULL) {
1165 CFDataRef acm_context = CFDictionaryGetValue(auth_params->dictionary, kSecUseCredentialReference);
1166 require_quiet(auth_handle = LACreateNewContextWithACMContext(acm_context, error), out);
1167 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationContext, auth_handle);
1168 CFRelease(auth_handle);
1169 if (acm_context == NULL) {
1170 require_quiet(acm_context = LACopyACMContext(auth_handle, error), out);
1171 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1172 CFRelease(acm_context);
1173 }
1174 }
1175
1176 // Throttle max authentication attempts. This is mainly protection against exceptional states, not ordinary
1177 // user retry limit.
1178 require_action(i < 20, out, SecItemAuthMaxAttemptsReached(ac_pairs, error));
1179
1180 // Prepare auth options dictionary.
1181 if (auth_options.dictionary == NULL) {
1182 CFStringRef operation_prompt = CFDictionaryGetValue(auth_params->dictionary, kSecUseOperationPrompt);
1183 if (operation_prompt != NULL) {
1184 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionAuthenticationReason);
1185 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, operation_prompt);
1186 CFRelease(key);
1187 }
1188
1189 CFStringRef caller_name = CFDictionaryGetValue(auth_params->dictionary, kSecUseCallerName);
1190 if (caller_name != NULL) {
1191 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionCallerName);
1192 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, caller_name);
1193 CFRelease(key);
1194 }
1195
1196 CFTypeRef auth_ui = CFDictionaryGetValue(auth_params->dictionary, kSecUseAuthenticationUI);
1197 if (CFEqualSafe(auth_ui, kSecUseAuthenticationUIFail)) {
1198 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, kLAOptionNotInteractive);
1199 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&auth_options), key, kCFBooleanTrue);
1200 CFRelease(key);
1201 }
1202 }
1203
1204 // Go through all access_control-operation pairs and evaluate them.
1205 CFArrayRef ac_pair;
1206 CFArrayForEachC(ac_pairs, ac_pair) {
1207 CFDataRef updated_acl = NULL;
1208 require_quiet(LAEvaluateAndUpdateACL(auth_handle,
1209 CFArrayGetValueAtIndex(ac_pair, 0), CFArrayGetValueAtIndex(ac_pair, 1),
1210 auth_options.dictionary, &updated_acl, error), out);
1211
1212 if (updated_acl || CFEqual(CFArrayGetValueAtIndex(ac_pair, 1), CFSTR(""))) {
1213 // we assume that only one ACL can be modified during ItemAdd or ItemUpdate
1214 SecAccessControlRef ac = NULL;
1215 require(ac = SecAccessControlCreateFromData(kCFAllocatorDefault,
1216 updated_acl ? updated_acl : CFArrayGetValueAtIndex(ac_pair, 0), error), out);
1217 SecAccessControlSetBound(ac, true);
1218 CFAssignRetained(updated_acl, SecAccessControlCopyData(ac));
1219 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecAttrAccessControl, updated_acl);
1220 CFRelease(updated_acl);
1221 CFRelease(ac);
1222 }
1223 }
1224 }
1225
1226 ok = true;
1227
1228 out:
1229 CFReleaseSafe(auth_options.mutable_dictionary);
1230 CFReleaseSafe(ac_pairs);
1231 return ok;
1232 }
1233
1234 void SecItemAuthCopyParams(SecCFDictionaryCOW *auth_params, SecCFDictionaryCOW *query) {
1235 // Store operation prompt.
1236 CFStringRef operation_prompt = CFDictionaryGetValue(query->dictionary, kSecUseOperationPrompt);
1237 if (operation_prompt != NULL) {
1238 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseOperationPrompt, operation_prompt);
1239 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseOperationPrompt);
1240 }
1241
1242 // Store caller name.
1243 CFStringRef caller_name = CFDictionaryGetValue(query->dictionary, kSecUseCallerName);
1244 if (caller_name != NULL) {
1245 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCallerName, caller_name);
1246 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseCallerName);
1247 }
1248
1249 // Find out whether we are allowed to pop up a UI.
1250 CFTypeRef auth_ui = CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI) ?:
1251 (CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI), kCFBooleanTrue) ?
1252 kSecUseAuthenticationUIFail : kSecUseAuthenticationUIAllow);
1253 if (!CFEqual(auth_ui, kSecUseAuthenticationUISkip) || CFDictionaryGetValue(query->dictionary, kSecUseNoAuthenticationUI)) {
1254 if (CFDictionaryContainsKey(query->dictionary, kSecUseNoAuthenticationUI))
1255 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseNoAuthenticationUI);
1256 if (!CFEqualSafe(auth_ui, kSecUseAuthenticationUISkip) && CFDictionaryContainsKey(query->dictionary, kSecUseAuthenticationUI))
1257 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecUseAuthenticationUI);
1258 }
1259
1260 if (!CFEqual(auth_ui, kSecUseAuthenticationUIAllow)) {
1261 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseAuthenticationUI, auth_ui);
1262 }
1263
1264 CFDataRef acm_context = CFDictionaryGetValue(query->dictionary, kSecUseCredentialReference);
1265 if (acm_context != NULL) {
1266 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context);
1267 }
1268 }
1269
1270 static SecItemAuthResult SecItemCreatePairsFromError(CFErrorRef *error, CFArrayRef *ac_pairs)
1271 {
1272 if (error && *error && CFErrorGetCode(*error) == errSecAuthNeeded && CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain)) {
1273 // Extract ACLs to be verified from the error.
1274 CFDictionaryRef user_info = CFErrorCopyUserInfo(*error);
1275 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
1276 CFRetainAssign(*ac_pairs, CFDictionaryGetValue(user_info, key));
1277 if (*ac_pairs == NULL)
1278 CFAssignRetained(*ac_pairs, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
1279
1280 CFRelease(key);
1281 CFRelease(user_info);
1282 CFReleaseNull(*error);
1283 return kSecItemAuthResultNeedAuth;
1284 }
1285 return kSecItemAuthResultError;
1286 }
1287
1288 // Wrapper to handle automatic authentication and token/secd case switching.
1289 static bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error,
1290 bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) {
1291 bool ok = false;
1292 SecCFDictionaryCOW auth_params = { NULL };
1293 SecAccessControlRef access_control = NULL;
1294 __block TKTokenRef token = NULL;
1295
1296 if (secItemOperation == SecItemAdd || secItemOperation == SecItemUpdate) {
1297 CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary;
1298 access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl);
1299 if (access_control && SecAccessControlGetConstraints(access_control) &&
1300 CFEqualSafe(CFDictionaryGetValue(dict, kSecAttrSynchronizable), kCFBooleanTrue))
1301 require_quiet(SecError(errSecParam, error, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out);
1302 }
1303
1304 // Perform initial surgery on query/attributes (resolve LAContext to serialized ACM handle, resolve
1305 // SecAccessControlRef to serialized forms, expand kSecValueRef etc.)
1306 bool forQuery =
1307 secItemOperation == SecItemCopyMatching ||
1308 secItemOperation == SecItemUpdate ||
1309 secItemOperation == SecItemDelete;
1310
1311 require_quiet(SecItemAttributesPrepare(query, forQuery, error), out);
1312 if (attributes != NULL)
1313 require_quiet(SecItemAttributesPrepare(attributes, false, error), out);
1314
1315 // Populate auth_params dictionary according to initial query contents.
1316 SecItemAuthCopyParams(&auth_params, query);
1317
1318 if (secItemOperation != SecItemCopyMatching) {
1319 // UISkip is allowed only for CopyMatching.
1320 require_action_quiet(!CFEqualSafe(CFDictionaryGetValue(query->dictionary, kSecUseAuthenticationUI), kSecUseAuthenticationUISkip), out,
1321 SecError(errSecParam, error,
1322 CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching")));
1323 }
1324
1325 ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error) {
1326 SecItemAuthResult result = kSecItemAuthResultError;
1327
1328 // Propagate actual credential reference to the query.
1329 if (auth_params != NULL) {
1330 CFDataRef acm_context = CFDictionaryGetValue(auth_params, kSecUseCredentialReference);
1331 if (acm_context != NULL) {
1332 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecUseCredentialReference, acm_context);
1333 }
1334
1335 CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params, kSecAttrAccessControl);
1336 if (acl_data_ref != NULL) {
1337 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes ?: query), kSecAttrAccessControl, acl_data_ref);
1338 }
1339 }
1340
1341 // Prepare connection to target token if it is present.
1342 CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID);
1343 if (secItemOperation != SecItemCopyMatching && token_id != NULL) {
1344 require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, auth_params, error)), out);
1345 }
1346
1347 CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL;
1348 if(!perform(token, query->dictionary, attrs, auth_params, error)) {
1349 require_quiet((result = SecItemCreatePairsFromError(error, ac_pairs)) == kSecItemAuthResultOK, out);
1350 }
1351
1352 result = kSecItemAuthResultOK;
1353
1354 out:
1355 return result;
1356 });
1357 require_quiet(ok, out);
1358
1359 ok = true;
1360
1361 out:
1362 CFReleaseSafe(token);
1363 CFReleaseSafe(auth_params.mutable_dictionary);
1364 return ok;
1365 }
1366
1367 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error)
1368 {
1369 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1370 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error);
1371 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1372 if (result) {
1373 return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error);
1374 }
1375 return true;
1376 });
1377 }
1378
1379 static CFArrayRef dict_to_array_error_request(enum SecXPCOperation op, CFDictionaryRef attributes, CFErrorRef *error)
1380 {
1381 CFArrayRef result = NULL;
1382 bool success = cftype_to_bool_cftype_error_request(op, attributes, (CFTypeRef*)&result, error);
1383 if(success && !isArray(result)){
1384 SecError(errSecUnimplemented, error, CFSTR("Unexpected nonarray returned: %@"), result);
1385 CFReleaseNull(result);
1386 }
1387 return result;
1388 }
1389
1390 bool cftype_client_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused SecurityClient *client, CFTypeRef *result, CFErrorRef *error) {
1391 return cftype_to_bool_cftype_error_request(op, attributes, result, error);
1392 }
1393
1394 static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error)
1395 {
1396 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1397 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error);
1398 }, NULL);
1399 }
1400
1401 static bool cfstring_array_to_error_request(enum SecXPCOperation op, CFStringRef string, CFArrayRef attributes, __unused SecurityClient *client, CFErrorRef *error)
1402 {
1403 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1404 if (string) {
1405 if (!SecXPCDictionarySetString(message, kSecXPCKeyString, string, error))
1406 return false;
1407 }
1408
1409 if (attributes) {
1410 if (!SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error))
1411 return false;
1412 }
1413
1414 return true;
1415 }, NULL);
1416 }
1417
1418 static bool dict_client_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused SecurityClient *client, CFErrorRef *error)
1419 {
1420 return dict_to_error_request(op, query, error);
1421 }
1422
1423 static bool SecTokenCreateAccessControlError(CFStringRef operation, CFDataRef access_control, CFErrorRef *error) {
1424 CFArrayRef ac_pair = CFArrayCreateForCFTypes(NULL, access_control, operation, NULL);
1425 const void *ac_pairs[] = { CFArrayCreateForCFTypes(NULL, ac_pair, NULL) };
1426 const void *keys[] = { CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded) };
1427 CFAssignRetained(*error, CFErrorCreateWithUserInfoKeysAndValues(NULL, kSecErrorDomain, errSecAuthNeeded,
1428 keys, ac_pairs, 1));
1429 CFRelease(keys[0]);
1430 CFRelease(ac_pairs[0]);
1431 CFRelease(ac_pair);
1432 return false;
1433 }
1434
1435 static bool SecTokenProcessError(CFStringRef operation, TKTokenRef token, CFTypeRef object_or_attrs, CFErrorRef *error) {
1436 if (CFEqualSafe(CFErrorGetDomain(*error), CFSTR(kTKErrorDomain)) &&
1437 CFErrorGetCode(*error) == kTKErrorCodeAuthenticationFailed) {
1438 // Replace error with the one which is augmented with access control and operation which failed,
1439 // which will cause SecItemDoWithAuth to throw UI.
1440 // Create array containing tuple (array) with error and requested operation.
1441 CFDataRef access_control = (CFGetTypeID(object_or_attrs) == CFDataGetTypeID()) ?
1442 TKTokenCopyObjectAccessControl(token, object_or_attrs, error) :
1443 TKTokenCopyObjectCreationAccessControl(token, object_or_attrs, error);
1444 if (access_control != NULL) {
1445 SecTokenCreateAccessControlError(operation, access_control, error);
1446 CFRelease(access_control);
1447 }
1448 }
1449 return false;
1450 }
1451
1452 static CFTypeRef SecTokenCopyUpdatedObjectID(TKTokenRef token, CFDataRef object_id, CFMutableDictionaryRef attributes, CFErrorRef *error) {
1453 CFDataRef access_control = NULL, db_value = NULL, new_object_id = NULL;
1454 SecAccessControlRef ac = NULL;
1455
1456 // Make sure that ACL is bound - if not, generate an error which will trigger binding.
1457 CFDataRef ac_data = CFDictionaryGetValue(attributes, kSecAttrAccessControl);
1458 if (ac_data != NULL) {
1459 require_quiet(ac = SecAccessControlCreateFromData(NULL, ac_data, error), out);
1460 require_action_quiet(SecAccessControlIsBound(ac), out,
1461 SecTokenCreateAccessControlError(CFSTR(""), ac_data, error));
1462 }
1463
1464 // Create or update the object on the token.
1465 require_action_quiet(new_object_id = TKTokenCreateOrUpdateObject(token, object_id, attributes, error), out,
1466 SecTokenProcessError(kAKSKeyOpEncrypt, token, object_id ?: (CFTypeRef)attributes, error));
1467
1468 // Prepare kSecValueData field for the item to be stored into the keychain DB.
1469 require_quiet(access_control = TKTokenCopyObjectAccessControl(token, new_object_id, error), out);
1470 require_quiet(db_value = SecTokenItemValueCreate(new_object_id, access_control,
1471 CFDictionaryGetValue(attributes, kSecValueData), error), out);
1472 CFDictionarySetValue(attributes, kSecValueData, db_value);
1473
1474 // kSecAttrAccessControl is handled directly by the token and stored inside data field.
1475 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
1476
1477 out:
1478 CFReleaseSafe(ac);
1479 CFReleaseSafe(access_control);
1480 CFReleaseSafe(db_value);
1481 return new_object_id;
1482 }
1483
1484 static bool SecTokenItemAdd(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef auth_params,
1485 CFTypeRef *result, CFErrorRef *error) {
1486 bool ok = false;
1487 CFTypeRef object_id = NULL, ref = NULL;
1488 CFDictionaryRef ref_attrs = NULL;
1489 CFTypeRef db_result = NULL;
1490
1491 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
1492 require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, NULL, attrs, error), out);
1493
1494 // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done
1495 // by creating ref and getting back its attributes.
1496 require_quiet(SecTokenItemCreateFromAttributes(attrs, auth_params, token, object_id, &ref, error), out);
1497 if (ref != NULL) {
1498 if ((ref_attrs = SecItemCopyAttributeDictionary(ref, false)) != NULL) {
1499 CFDictionaryForEach(ref_attrs, ^(const void *key, const void *value) {
1500 if (!CFEqual(key, kSecValueData)) {
1501 CFDictionaryAddValue(attrs, key, value);
1502 }
1503 });
1504 }
1505 }
1506
1507 // Make sure that both attributes and data are returned.
1508 CFDictionarySetValue(attrs, kSecReturnAttributes, kCFBooleanTrue);
1509 CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue);
1510
1511 if (!CFEqualSafe(CFDictionaryGetValue(attrs, kSecAttrIsPermanent), kCFBooleanFalse)) {
1512 // IsPermanent is not present or is true, so add item to the db.
1513 require_quiet(SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attrs,
1514 SecSecurityClientGet(), &db_result, error), out);
1515 } else {
1516 // Process directly result of token call.
1517 db_result = CFRetain(attrs);
1518 }
1519 require_quiet(SecItemResultProcess(attributes, auth_params, token, db_result, result, error), out);
1520
1521 ok = true;
1522
1523 out:
1524 CFReleaseSafe(db_result);
1525 CFReleaseSafe(attrs);
1526 CFReleaseSafe(ref_attrs);
1527 CFReleaseSafe(object_id);
1528 CFReleaseSafe(ref);
1529 return ok;
1530 }
1531
1532 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
1533 __block SecCFDictionaryCOW attrs = { attributes };
1534 OSStatus status;
1535
1536 os_activity_t trace_activity = os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT);
1537
1538 require_quiet(!explode_identity(attrs.dictionary, (secitem_operation)SecItemAdd, &status, result), errOut);
1539 infer_cert_label(&attrs);
1540
1541 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1542 return SecItemAuthDoQuery(&attrs, NULL, SecItemAdd, error, ^bool(TKTokenRef token, CFDictionaryRef attributes, CFDictionaryRef unused, CFDictionaryRef auth_params, CFErrorRef *error) {
1543 if (token == NULL) {
1544 CFTypeRef raw_result = NULL;
1545 if (!SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attributes, SecSecurityClientGet(), &raw_result, error))
1546 return false;
1547
1548 bool ok = SecItemResultProcess(attributes, auth_params, token, raw_result, result, error);
1549 CFReleaseSafe(raw_result);
1550 return ok;
1551 } else {
1552 // Send request to an appropriate token instead of secd.
1553 return SecTokenItemAdd(token, attributes, auth_params, result, error);
1554 }
1555 });
1556 });
1557
1558 errOut:
1559 CFReleaseSafe(attrs.mutable_dictionary);
1560
1561 os_activity_end(trace_activity);
1562 return status;
1563 }
1564
1565
1566 OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) {
1567 OSStatus status;
1568 __block SecCFDictionaryCOW query = { inQuery };
1569
1570 os_activity_t trace_activity = os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT);
1571
1572 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemCopyMatching, &status, result), errOut);
1573
1574 bool wants_data = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnData));
1575 bool wants_attributes = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnAttributes));
1576 if ((wants_data && !wants_attributes) || (!wants_data && wants_attributes)) {
1577 // When either attributes or data are requested, we need to query both, because for token based items,
1578 // both are needed in order to generate proper data and/or attributes results.
1579 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query), kSecReturnAttributes, kCFBooleanTrue);
1580 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&query), kSecReturnData, kCFBooleanTrue);
1581 }
1582
1583 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1584 return SecItemAuthDoQuery(&query, NULL, SecItemCopyMatching, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1585 CFTypeRef raw_result = NULL;
1586 if (!SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, query, SecSecurityClientGet(), &raw_result, error))
1587 return false;
1588
1589 // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
1590 // on per-record basis, not wholesale. Logic inside SecItemResultCopyPrepared will open proper token according
1591 // to currently processed item.
1592 bool ok = SecItemResultProcess(inQuery, auth_params, NULL, raw_result, result, error);
1593 CFReleaseSafe(raw_result);
1594 return ok;
1595 });
1596 });
1597
1598 errOut:
1599
1600 CFReleaseSafe(query.mutable_dictionary);
1601 os_activity_end(trace_activity);
1602 return status;
1603 }
1604
1605 // Invokes token-object handler for each item matching specified query.
1606 static bool SecTokenItemForEachMatching(CFDictionaryRef query, CFErrorRef *error,
1607 bool (^perform)(CFDictionaryRef item_value, CFDictionaryRef item_query,
1608 CFErrorRef *error)) {
1609 bool ok = false;
1610 CFMutableDictionaryRef list_query = NULL;
1611 CFTypeRef items = NULL;
1612 CFArrayRef ref_array = NULL;
1613 CFDictionaryRef item_query = NULL, item_data = NULL;
1614
1615 // Query all items with data and persistent_ref, so that we can extract objectIDs and also identify originating
1616 // items in the keychain.
1617 list_query = CFDictionaryCreateMutableCopy(NULL, 0, query);
1618 if (CFDictionaryGetValue(list_query, kSecMatchLimit) == NULL) {
1619 CFDictionarySetValue(list_query, kSecMatchLimit, kSecMatchLimitAll);
1620 }
1621 CFDictionarySetValue(list_query, kSecReturnData, kCFBooleanTrue);
1622 CFDictionarySetValue(list_query, kSecReturnPersistentRef, kCFBooleanTrue);
1623 require_quiet(SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, list_query,
1624 SecSecurityClientGet(), &items, error), out);
1625 if (CFGetTypeID(items) != CFArrayGetTypeID()) {
1626 // Wrap single returned item into the array.
1627 CFArrayRef item_array = CFArrayCreateForCFTypes(NULL, items, NULL);
1628 CFAssignRetained(items, item_array);
1629 }
1630
1631 CFTypeRef item;
1632 CFArrayForEachC(items, item) {
1633 CFDataRef data = CFDictionaryGetValue(item, kSecValueData);
1634 require_action_quiet(data != NULL, out, SecError(errSecInternal, error, CFSTR("value not present for token item")));
1635
1636 CFAssignRetained(item_data, SecTokenItemValueCopy(data, error));
1637 require_quiet(item_data, out);
1638
1639 CFAssignRetained(item_query,
1640 CFDictionaryCreateForCFTypes(NULL,
1641 kSecValuePersistentRef, CFDictionaryGetValue(item, kSecValuePersistentRef),
1642 NULL));
1643 require_quiet(perform(item_data, item_query, error), out);
1644 }
1645
1646 ok = true;
1647
1648 out:
1649 CFReleaseSafe(list_query);
1650 CFReleaseSafe(items);
1651 CFReleaseSafe(item_data);
1652 CFReleaseSafe(ref_array);
1653 CFReleaseSafe(item_query);
1654 return ok;
1655 }
1656
1657 static bool SecItemRawUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1658 bool ok = false;
1659 if (gSecurityd) {
1660 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
1661 CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
1662 CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); });
1663 ok = gSecurityd->sec_item_update(query, tmp, SecSecurityClientGet(), error);
1664 CFRelease(tmp);
1665 } else {
1666 xpc_object_t message = securityd_create_message(sec_item_update_id, error);
1667 if (message) {
1668 if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) &&
1669 SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) {
1670 xpc_object_t reply = securityd_message_with_reply_sync(message, error);
1671 if (reply) {
1672 ok = securityd_message_no_error(reply, error);
1673 xpc_release(reply);
1674 }
1675 }
1676 xpc_release(message);
1677 }
1678 }
1679 return ok;
1680 }
1681
1682 static bool SecTokenItemUpdate(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFErrorRef *error) {
1683 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1684 bool ok = false;
1685 CFDataRef object_id = NULL;
1686 CFMutableDictionaryRef db_value = NULL;
1687
1688 // Update attributes on the token.
1689 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(NULL, 0, attributesToUpdate);
1690 require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey),
1691 attributes, error), out);
1692
1693 // Update attributes in the database.
1694 require_quiet(SecItemRawUpdate(item_query, attributes, error), out);
1695
1696 ok = true;
1697
1698 out:
1699 CFReleaseSafe(object_id);
1700 CFReleaseSafe(attributes);
1701 CFReleaseSafe(db_value);
1702 return ok;
1703 });
1704 }
1705
1706 OSStatus SecItemUpdate(CFDictionaryRef inQuery, CFDictionaryRef inAttributesToUpdate) {
1707 return SecOSStatusWith(^bool(CFErrorRef *error) {
1708 return SecItemUpdateWithError(inQuery, inAttributesToUpdate, error);
1709 });
1710 }
1711
1712 bool
1713 SecItemUpdateWithError(CFDictionaryRef inQuery,
1714 CFDictionaryRef inAttributesToUpdate,
1715 CFErrorRef *error)
1716 {
1717 __block SecCFDictionaryCOW query = { inQuery };
1718 __block SecCFDictionaryCOW attributesToUpdate = { inAttributesToUpdate };
1719 bool result = false;
1720
1721 if (handleUpdateIdentity(inQuery, inAttributesToUpdate, &result, error))
1722 goto errOut;
1723
1724 result = SecItemAuthDoQuery(&query, &attributesToUpdate, SecItemUpdate, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1725 if (token == NULL) {
1726 return SecItemRawUpdate(query, attributes, error);
1727 } else {
1728 return SecTokenItemUpdate(token, query, attributes, error);
1729 }
1730 });
1731
1732 errOut:
1733 CFReleaseSafe(query.mutable_dictionary);
1734 CFReleaseSafe(attributesToUpdate.mutable_dictionary);
1735 return result;
1736 }
1737
1738 static OSStatus explode_persistent_identity_ref(SecCFDictionaryCOW *query)
1739 {
1740 OSStatus status = errSecSuccess;
1741 CFTypeRef persist = CFDictionaryGetValue(query->dictionary, kSecValuePersistentRef);
1742 CFStringRef class;
1743 if (persist && _SecItemParsePersistentRef(persist, &class, NULL)
1744 && CFEqual(class, kSecClassIdentity)) {
1745 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef };
1746 const void *vals[] = { kCFBooleanTrue, persist };
1747 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys,
1748 vals, (array_size(keys)), NULL, NULL);
1749 CFTypeRef item_query = NULL;
1750 status = SecItemCopyMatching(persistent_query, &item_query);
1751 CFReleaseNull(persistent_query);
1752 if (status)
1753 return status;
1754
1755 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecValuePersistentRef);
1756 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecValueRef, item_query);
1757 CFRelease(item_query);
1758 }
1759
1760 return status;
1761 }
1762
1763 OSStatus SecItemDelete(CFDictionaryRef inQuery) {
1764 OSStatus status;
1765 __block SecCFDictionaryCOW query = { inQuery };
1766
1767 os_activity_t trace_activity = os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT);
1768
1769 require_noerr_quiet(status = explode_persistent_identity_ref(&query), errOut);
1770 require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemDelete, &status, NULL), errOut);
1771
1772 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1773 return SecItemAuthDoQuery(&query, NULL, SecItemDelete, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
1774 if (token == NULL) {
1775 return SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, query, SecSecurityClientGet(), error);
1776 } else {
1777 return SecTokenItemForEachMatching(query, error, ^bool(CFDictionaryRef object_data, CFDictionaryRef item_query, CFErrorRef *error) {
1778 bool ok = false;
1779
1780 // Delete item from the token.
1781 CFDataRef object_id = CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey);
1782 require_action_quiet(TKTokenDeleteObject(token, object_id, error), out,
1783 SecTokenProcessError(kAKSKeyOpDelete, token, object_id, error));
1784
1785 // Delete the item from the keychain.
1786 require_quiet(SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, item_query,
1787 SecSecurityClientGet(), error), out);
1788 ok = true;
1789
1790 out:
1791 return ok;
1792 });
1793 }
1794 });
1795 });
1796
1797 errOut:
1798 CFReleaseSafe(query.mutable_dictionary);
1799
1800 os_activity_end(trace_activity);
1801
1802 return status;
1803 }
1804
1805 OSStatus
1806 SecItemDeleteAll(void)
1807 {
1808 return SecOSStatusWith(^bool (CFErrorRef *error) {
1809 bool ok;
1810 if (gSecurityd) {
1811 ok = true;
1812 #ifndef SECITEM_SHIM_OSX
1813 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
1814 if (!gSecurityd->sec_truststore_remove_all(ts, error))
1815 ok = SecError(errSecInternal, error, CFSTR("sec_truststore_remove_all is NULL"));
1816 #endif // *** END SECITEM_SHIM_OSX ***
1817 if (!gSecurityd->sec_item_delete_all(error))
1818 ok = SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL"));
1819 } else {
1820 ok = securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL);
1821 }
1822 return ok;
1823 });
1824 }
1825
1826 static bool
1827 agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unused SecurityClient *client, CFErrorRef *error)
1828 {
1829 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1830 return SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, agrps, error);
1831 }, NULL);
1832 }
1833
1834 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error) {
1835 os_activity_t trace_activity = os_activity_start("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_FLAG_DEFAULT);
1836
1837 bool ok = SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups,
1838 SecSecurityClientGet(), error);
1839
1840 os_activity_end(trace_activity);
1841 return ok;
1842 }
1843
1844 OSStatus
1845 #if SECITEM_SHIM_OSX
1846 SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
1847 #else
1848 SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
1849 #endif
1850 {
1851 OSStatus status;
1852
1853 os_activity_t trace_activity = os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT);
1854
1855 status = SecOSStatusWith(^bool(CFErrorRef *error) {
1856 CFArrayRef tmpArrayRef = tokenItemsAttributes;
1857 if (tokenItemsAttributes) {
1858 CFMutableArrayRef tokenItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1859 for (CFIndex i = 0; i < CFArrayGetCount(tokenItemsAttributes); ++i) {
1860 CFDictionaryRef itemAttributes = CFArrayGetValueAtIndex(tokenItemsAttributes, i);
1861 CFTypeRef accessControl = CFDictionaryGetValue(itemAttributes, kSecAttrAccessControl);
1862 CFTypeRef tokenOID = CFDictionaryGetValue(itemAttributes, kSecAttrTokenOID);
1863 CFTypeRef valueData = CFDictionaryGetValue(itemAttributes, kSecValueData);
1864 if (tokenOID != NULL && accessControl != NULL && CFDataGetTypeID() == CFGetTypeID(accessControl)) {
1865 CFDataRef data = SecTokenItemValueCreate(tokenOID, accessControl, valueData, error);
1866 if (!data) {
1867 CFRelease(tokenItems);
1868 return false;
1869 }
1870
1871 CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, itemAttributes);
1872 CFDictionarySetValue(attributes, kSecValueData, data);
1873 CFDictionarySetValue(attributes, kSecAttrTokenID, tokenID);
1874 CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
1875 CFDictionaryRemoveValue(attributes, kSecAttrTokenOID);
1876 CFArrayAppendValue(tokenItems, attributes);
1877 CFRelease(attributes);
1878 CFRelease(data);
1879 }
1880 else
1881 CFArrayAppendValue(tokenItems, itemAttributes);
1882 }
1883
1884 tmpArrayRef = tokenItems;
1885 }
1886
1887 return SECURITYD_XPC(sec_item_update_token_items, cfstring_array_to_error_request, tokenID, tmpArrayRef, SecSecurityClientGet(), error);
1888 });
1889
1890 os_activity_end(trace_activity);
1891
1892 return status;
1893 }
1894
1895 CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) {
1896 __block CFArrayRef result;
1897 os_activity_initiate("_SecKeychainSyncUpdateMessage", OS_ACTIVITY_FLAG_DEFAULT, ^{
1898 result = SECURITYD_XPC(sec_keychain_sync_update_message, dict_to_array_error_request, updates, error);
1899 });
1900 return result;
1901 }
1902
1903 #ifndef SECITEM_SHIM_OSX
1904 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
1905
1906 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement)
1907 {
1908 return -1; /* this is only on OS X currently */
1909 }
1910
1911 #else
1912
1913 extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
1914
1915 #endif
1916
1917 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1918
1919 bool _SecKeychainRollKeys(bool force, CFErrorRef *error)
1920 {
1921 do_if_registered(sec_roll_keys, force, error);
1922
1923 __block bool result = false;
1924
1925 secdebug("secitem","enter - %s", __FUNCTION__);
1926 securityd_send_sync_and_do(kSecXPCOpRollKeys, error,
1927 ^bool(xpc_object_t message, CFErrorRef *error) {
1928 xpc_dictionary_set_bool(message, "force", force);
1929 return true;
1930 },
1931 ^bool(xpc_object_t response, __unused CFErrorRef *error) {
1932 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
1933 return result;
1934 });
1935 return result;
1936 }
1937
1938