]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecItem.c
Security-55471.14.4.tar.gz
[apple/security.git] / sec / Security / SecItem.c
1 /*
2 * Copyright (c) 2006-2013 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 #ifndef SECITEM_SHIM_OSX
35 #include <Security/SecKey.h>
36 #include <Security/SecKeyPriv.h>
37 #include <Security/SecCertificateInternal.h>
38 #include <Security/SecIdentity.h>
39 #include <Security/SecIdentityPriv.h>
40 #include <Security/SecRandom.h>
41 #include <Security/SecBasePriv.h>
42 #endif // *** END SECITEM_SHIM_OSX ***
43 #include <Security/SecTask.h>
44 #include <errno.h>
45 #include <limits.h>
46 #include <sqlite3.h>
47 #include <stdint.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <Security/SecBase.h>
53 #include <CoreFoundation/CFData.h>
54 #include <CoreFoundation/CFDate.h>
55 #include <CoreFoundation/CFDictionary.h>
56 #include <CoreFoundation/CFNumber.h>
57 #include <CoreFoundation/CFString.h>
58 #include <CoreFoundation/CFURL.h>
59 #include <CommonCrypto/CommonDigest.h>
60 #include <libkern/OSByteOrder.h>
61 #include <utilities/array_size.h>
62 #include <utilities/debugging.h>
63 #include <utilities/SecCFError.h>
64 #include <utilities/SecCFWrappers.h>
65 #include <utilities/SecIOFormat.h>
66 #include <utilities/SecXPCError.h>
67 #include <utilities/der_plist.h>
68 #include <assert.h>
69
70 #include <Security/SecInternal.h>
71 #include <TargetConditionals.h>
72 #include "securityd_client.h"
73 #include "SecuritydXPC.h"
74 #include <AssertMacros.h>
75 #include <asl.h>
76 #include <sys/types.h>
77 #include <pwd.h>
78 #include <grp.h>
79 #include <unistd.h>
80 #ifndef SECITEM_SHIM_OSX
81 #include <libDER/asn1Types.h>
82 #endif // *** END SECITEM_SHIM_OSX ***
83
84 /* label when certificate data is joined with key data */
85 #define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
86
87 #include <utilities/SecDb.h>
88 #include <IOKit/IOReturn.h>
89
90 /* Return an OSStatus for a sqlite3 error code. */
91 static OSStatus osstatus_for_s3e(int s3e)
92 {
93 if (s3e > 0 && s3e <= SQLITE_DONE) switch (s3e)
94 {
95 case SQLITE_OK:
96 return 0;
97 case SQLITE_ERROR:
98 return errSecNotAvailable; /* errSecDuplicateItem; */
99 case SQLITE_FULL: /* Happens if we run out of uniqueids */
100 return errSecNotAvailable; /* TODO: Replace with a better error code. */
101 case SQLITE_PERM:
102 case SQLITE_READONLY:
103 return errSecNotAvailable;
104 case SQLITE_CANTOPEN:
105 return errSecNotAvailable;
106 case SQLITE_EMPTY:
107 return errSecNotAvailable;
108 case SQLITE_CONSTRAINT:
109 return errSecDuplicateItem;
110 case SQLITE_ABORT:
111 return -1;
112 case SQLITE_MISMATCH:
113 return errSecNoSuchAttr;
114 case SQLITE_AUTH:
115 return errSecNotAvailable;
116 case SQLITE_NOMEM:
117 return -2; /* TODO: Replace with a real error code. */
118 case SQLITE_INTERNAL:
119 default:
120 return errSecNotAvailable; /* TODO: Replace with a real error code. */
121 }
122 return s3e;
123 }
124
125 static OSStatus osstatus_for_kern_return(CFIndex kernResult)
126 {
127 switch (kernResult)
128 {
129 case KERN_SUCCESS:
130 return errSecSuccess;
131 case kIOReturnNotReadable:
132 case kIOReturnNotWritable:
133 return errSecAuthFailed;
134 case kIOReturnNotPermitted:
135 case kIOReturnNotPrivileged:
136 case kIOReturnLockedRead:
137 case kIOReturnLockedWrite:
138 return errSecInteractionNotAllowed;
139 case kIOReturnError:
140 return errSecDecode;
141 case kIOReturnBadArgument:
142 return errSecParam;
143 default:
144 return errSecNotAvailable; /* TODO: Replace with a real error code. */
145 }
146 }
147
148 static OSStatus osstatus_for_xpc_error(CFIndex xpcError) {
149 switch (xpcError)
150 {
151 case kSecXPCErrorSuccess:
152 return errSecSuccess;
153 case kSecXPCErrorUnexpectedType:
154 case kSecXPCErrorUnexpectedNull:
155 return errSecParam;
156 case kSecXPCErrorConnectionFailed:
157 return errSecNotAvailable;
158 case kSecXPCErrorUnknown:
159 default:
160 return errSecInternal;
161 }
162 }
163
164 static OSStatus osstatus_for_der_error(CFIndex derError) {
165 switch (derError)
166 {
167 case kSecDERErrorUnknownEncoding:
168 //case kSecDERErrorUnsupportedDERType:
169 return errSecDecode;
170 case kSecDERErrorUnsupportedCFObject:
171 case kSecDERErrorUnsupportedNumberType:
172 return errSecParam;
173 case kSecDERErrorAllocationFailure:
174 case kSecDERErrorUnderlyingError:
175 return errSecAllocate;
176 default:
177 return errSecInternal;
178 }
179 }
180
181 // Convert from securityd error codes to OSStatus for legacy API.
182 OSStatus SecErrorGetOSStatus(CFErrorRef error) {
183 OSStatus status;
184 if (error == NULL) {
185 status = errSecSuccess;
186 } else {
187 CFStringRef domain = CFErrorGetDomain(error);
188 if (domain == NULL) {
189 secerror("No error domain for error: %@", error);
190 status = errSecInternal;
191 } else if (CFEqual(kSecErrorDomain, domain)) {
192 status = (OSStatus)CFErrorGetCode(error);
193 } else if (CFEqual(kSecDbErrorDomain, domain)) {
194 status = osstatus_for_s3e((int)CFErrorGetCode(error));
195 } else if (CFEqual(kSecErrnoDomain, domain)) {
196 status = (OSStatus)CFErrorGetCode(error);
197 } else if (CFEqual(kSecKernDomain, domain)) {
198 status = osstatus_for_kern_return(CFErrorGetCode(error));
199 } else if (CFEqual(sSecXPCErrorDomain, domain)) {
200 status = osstatus_for_xpc_error(CFErrorGetCode(error));
201 } else if (CFEqual(sSecDERErrorDomain, domain)) {
202 status = osstatus_for_der_error(CFErrorGetCode(error));
203 } else {
204 secerror("unknown error domain: %@ for error: %@", domain, error);
205 status = errSecInternal;
206 }
207 }
208 return status;
209 }
210
211 // Wrapper to provide a CFErrorRef for legacy API.
212 OSStatus SecOSStatusWith(bool (^perform)(CFErrorRef *error)) {
213 CFErrorRef error = NULL;
214 OSStatus status;
215 if (perform(&error)) {
216 assert(error == NULL);
217 status = errSecSuccess;
218 } else {
219 assert(error);
220 status = SecErrorGetOSStatus(error);
221 if (status != errSecItemNotFound) // Occurs in normal operation, so exclude
222 secerror("error:[%" PRIdOSStatus "] %@", status, error);
223 CFReleaseNull(error);
224 }
225 return status;
226 }
227
228
229 /* IPC uses CFPropertyList to un/marshall input/output data and can handle:
230 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber
231
232 Currently in need of conversion below:
233 @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef
234 @@@ kSecMatchPolicy allows a query with a SecPolicyRef
235 @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't
236 currently implemented at all, but when it is needs to short circuit to
237 local evaluation, different from the sql query abilities
238 */
239
240 #ifndef SECITEM_SHIM_OSX
241 static CFDictionaryRef
242 SecItemCopyAttributeDictionary(CFTypeRef ref) {
243 CFDictionaryRef refDictionary = NULL;
244 CFTypeID typeID = CFGetTypeID(ref);
245 if (typeID == SecKeyGetTypeID()) {
246 refDictionary = SecKeyCopyAttributeDictionary((SecKeyRef)ref);
247 } else if (typeID == SecCertificateGetTypeID()) {
248 refDictionary =
249 SecCertificateCopyAttributeDictionary((SecCertificateRef)ref);
250 } else if (typeID == SecIdentityGetTypeID()) {
251 assert(false);
252 SecIdentityRef identity = (SecIdentityRef)ref;
253 SecCertificateRef cert = NULL;
254 SecKeyRef key = NULL;
255 if (!SecIdentityCopyCertificate(identity, &cert) &&
256 !SecIdentityCopyPrivateKey(identity, &key))
257 {
258 CFDataRef data = SecCertificateCopyData(cert);
259 CFDictionaryRef key_dict = SecKeyCopyAttributeDictionary(key);
260
261 if (key_dict && data) {
262 refDictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, key_dict);
263 CFDictionarySetValue((CFMutableDictionaryRef)refDictionary,
264 CFSTR(CERTIFICATE_DATA_COLUMN_LABEL), data);
265 }
266 CFReleaseNull(key_dict);
267 CFReleaseNull(data);
268 }
269 CFReleaseNull(cert);
270 CFReleaseNull(key);
271 } else {
272 refDictionary = NULL;
273 }
274 return refDictionary;
275 }
276
277 static CFTypeRef
278 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
279 CFTypeRef ref = NULL;
280 CFStringRef class = CFDictionaryGetValue(refAttributes, kSecClass);
281 if (CFEqual(class, kSecClassCertificate)) {
282 ref = SecCertificateCreateFromAttributeDictionary(refAttributes);
283 } else if (CFEqual(class, kSecClassKey)) {
284 ref = SecKeyCreateFromAttributeDictionary(refAttributes);
285 } else if (CFEqual(class, kSecClassIdentity)) {
286 CFAllocatorRef allocator = NULL;
287 CFDataRef data = CFDictionaryGetValue(refAttributes, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL));
288 SecCertificateRef cert = SecCertificateCreateWithData(allocator, data);
289 SecKeyRef key = SecKeyCreateFromAttributeDictionary(refAttributes);
290 if (key && cert)
291 ref = SecIdentityCreate(allocator, cert, key);
292 CFReleaseSafe(cert);
293 CFReleaseSafe(key);
294 #if 0
295 /* We don't support SecKeychainItemRefs yet. */
296 } else if (CFEqual(class, kSecClassGenericPassword)) {
297 } else if (CFEqual(class, kSecClassInternetPassword)) {
298 } else if (CFEqual(class, kSecClassAppleSharePassword)) {
299 #endif
300 } else {
301 ref = NULL;
302 }
303 return ref;
304 }
305 #else
306
307 extern CFTypeRef SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes);
308
309 #endif
310
311 /* Turn the returned dictionary that contains all the attributes to create a
312 ref into the exact result the client asked for */
313 static CFTypeRef makeRef(CFTypeRef ref, bool return_data, bool return_attributes)
314 {
315 CFTypeRef result = NULL;
316 if (!ref || (CFGetTypeID(ref) != CFDictionaryGetTypeID()))
317 return NULL;
318
319 CFTypeRef return_ref = SecItemCreateFromAttributeDictionary(ref);
320
321 if (return_data || return_attributes) {
322 if (return_attributes)
323 result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, ref);
324 else
325 result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
326
327 if (return_ref) {
328 CFDictionarySetValue((CFMutableDictionaryRef)result, kSecValueRef, return_ref);
329 CFRelease(return_ref);
330 }
331
332 if (!return_data)
333 CFDictionaryRemoveValue((CFMutableDictionaryRef)result, kSecValueData);
334 } else
335 result = return_ref;
336
337 return result;
338 }
339
340 OSStatus
341 SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames)
342 {
343 // @@@ TBI
344 return -1 /* errSecUnimplemented */;
345 }
346
347 #ifndef SECITEM_SHIM_OSX
348 static void merge_dictionary_by_overwrite(const void *key, const void *value, void *context)
349 {
350 if (!CFEqual(key, kSecValueRef))
351 CFDictionarySetValue((CFMutableDictionaryRef)context, key, value);
352 }
353
354 static void copy_applier(const void *key, const void *value, void *context)
355 {
356 CFDictionarySetValue(context, key, value);
357 }
358
359 static OSStatus cook_query(CFDictionaryRef query, CFMutableDictionaryRef *explode)
360 {
361 /* If a ref was specified we get it's attribute dictionary and parse it. */
362 CFMutableDictionaryRef args = NULL;
363 CFTypeRef value = CFDictionaryGetValue(query, kSecValueRef);
364 if (value) {
365 CFDictionaryRef refAttributes = SecItemCopyAttributeDictionary(value);
366 if (!refAttributes)
367 return errSecValueRefUnsupported;
368
369 /* Replace any attributes we already got from the ref with the ones
370 from the attributes dictionary the caller passed us. This allows
371 a caller to add an item using attributes from the ref and still
372 override some of them in the dictionary directly. */
373 args = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, refAttributes);
374 CFRelease(refAttributes);
375 CFDictionaryApplyFunction(query, merge_dictionary_by_overwrite, args);
376 }
377 value = CFDictionaryGetValue(query, kSecAttrIssuer);
378 if (value) {
379 /* convert DN to canonical issuer, if value is DN (top level sequence) */
380 const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) };
381 DERDecodedInfo content;
382 if (!DERDecodeItem(&name, &content) &&
383 (content.tag == ASN1_CONSTR_SEQUENCE))
384 {
385 CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content);
386 if (canonical_issuer) {
387 if (!args) {
388 args = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
389 /* This is necessary because we rely on non NULL callbacks */
390 CFDictionaryApplyFunction(query, copy_applier, args);
391 }
392 /* Overwrite with new issuer */
393 CFDictionarySetValue(args, kSecAttrIssuer, canonical_issuer);
394 CFRelease(canonical_issuer);
395 }
396 }
397 }
398 *explode = args;
399 return errSecSuccess;
400 }
401
402 typedef OSStatus (*secitem_operation)(CFDictionaryRef attributes, CFTypeRef *result);
403
404 static bool explode_identity(CFDictionaryRef attributes, secitem_operation operation,
405 OSStatus *return_status, CFTypeRef *return_result)
406 {
407 bool handled = false;
408 CFTypeRef value = CFDictionaryGetValue(attributes, kSecValueRef);
409 if (value) {
410 CFTypeID typeID = CFGetTypeID(value);
411 if (typeID == SecIdentityGetTypeID()) {
412 handled = true;
413 OSStatus status = errSecSuccess;
414 SecIdentityRef identity = (SecIdentityRef)value;
415 SecCertificateRef cert = NULL;
416 SecKeyRef key = NULL;
417 if (!SecIdentityCopyCertificate(identity, &cert) &&
418 !SecIdentityCopyPrivateKey(identity, &key))
419 {
420 CFMutableDictionaryRef partial_query =
421 CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
422 CFDictionarySetValue(partial_query, kSecValueRef, cert);
423 CFTypeRef result = NULL;
424 bool duplicate_cert = false;
425 /* an identity is first and foremost a key, but it can have multiple
426 certs associated with it: so we identify it by the cert */
427 status = operation(partial_query, return_result ? &result : NULL);
428 if ((operation == (secitem_operation)SecItemAdd) &&
429 (status == errSecDuplicateItem)) {
430 duplicate_cert = true;
431 status = errSecSuccess;
432 }
433
434 if (!status || status == errSecItemNotFound) {
435 bool skip_key_operation = false;
436
437 /* if the key is still in use, skip deleting it */
438 if (operation == (secitem_operation)SecItemDelete) {
439 // find certs with cert.pkhh == keys.klbl
440 CFDictionaryRef key_dict = NULL, query_dict = NULL;
441 CFDataRef pkhh = NULL;
442
443 key_dict = SecKeyCopyAttributeDictionary(key);
444 if (key_dict)
445 pkhh = (CFDataRef)CFDictionaryGetValue(key_dict, kSecAttrApplicationLabel);
446 const void *keys[] = { kSecClass, kSecAttrPublicKeyHash };
447 const void *vals[] = { kSecClassCertificate, pkhh };
448 if (pkhh)
449 query_dict = CFDictionaryCreate(NULL, keys,
450 vals, (array_size(keys)),
451 NULL, NULL);
452 if (query_dict)
453 if (errSecSuccess == SecItemCopyMatching(query_dict, NULL))
454 skip_key_operation = true;
455 CFReleaseSafe(query_dict);
456 CFReleaseSafe(key_dict);
457 }
458
459 if (!skip_key_operation) {
460 /* now perform the operation for the key */
461 CFDictionarySetValue(partial_query, kSecValueRef, key);
462 CFDictionarySetValue(partial_query, kSecReturnPersistentRef, kCFBooleanFalse);
463 status = operation(partial_query, NULL);
464 if ((operation == (secitem_operation)SecItemAdd) &&
465 (status == errSecDuplicateItem) &&
466 !duplicate_cert)
467 status = errSecSuccess;
468 }
469
470 /* add and copy matching for an identityref have a persistent ref result */
471 if (result) {
472 if (!status) {
473 /* result is a persistent ref to a cert */
474 sqlite_int64 rowid;
475 if (_SecItemParsePersistentRef(result, NULL, &rowid)) {
476 *return_result = _SecItemMakePersistentRef(kSecClassIdentity, rowid);
477 }
478 }
479 CFRelease(result);
480 }
481 }
482 CFReleaseNull(partial_query);
483 }
484 else
485 status = errSecInvalidItemRef;
486
487 CFReleaseNull(cert);
488 CFReleaseNull(key);
489 *return_status = status;
490 }
491 } else {
492 value = CFDictionaryGetValue(attributes, kSecClass);
493 if (value && CFEqual(kSecClassIdentity, value) &&
494 (operation == (secitem_operation)SecItemDelete)) {
495 CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
496 CFDictionaryRemoveValue(dict, kSecClass);
497 CFDictionarySetValue(dict, kSecClass, kSecClassCertificate);
498 OSStatus status = SecItemDelete(dict);
499 if (!status) {
500 CFDictionarySetValue(dict, kSecClass, kSecClassKey);
501 status = SecItemDelete(dict);
502 }
503 CFRelease(dict);
504 *return_status = status;
505 handled = true;
506 }
507 }
508 return handled;
509 }
510
511 static void infer_cert_label(CFDictionaryRef attributes, CFMutableDictionaryRef args)
512 {
513 if (!args || !attributes)
514 return;
515
516 if (CFDictionaryContainsKey(attributes, kSecAttrLabel))
517 return;
518
519 CFTypeRef value_ref = CFDictionaryGetValue(attributes, kSecValueRef);
520 if (!value_ref || (CFGetTypeID(value_ref) != SecCertificateGetTypeID()))
521 return;
522
523 SecCertificateRef certificate = (SecCertificateRef)value_ref;
524 CFStringRef label = SecCertificateCopySubjectSummary(certificate);
525 if (label) {
526 CFDictionarySetValue(args, kSecAttrLabel, label);
527 CFReleaseNull(label);
528 }
529 }
530
531 /* A persistent ref is just the class and the rowid of the record. */
532 CF_RETURNS_RETAINED CFDataRef _SecItemMakePersistentRef(CFTypeRef class, sqlite_int64 rowid)
533 {
534 uint8_t bytes[sizeof(sqlite_int64) + 4];
535 if (rowid < 0)
536 return NULL;
537 if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/,
538 kCFStringEncodingUTF8))
539 {
540 OSWriteBigInt64(bytes + 4, 0, rowid);
541 return CFDataCreate(NULL, bytes, sizeof(bytes));
542 }
543 return NULL;
544 }
545
546 /* AUDIT[securityd](done):
547 persistent_ref (ok) is a caller provided, non NULL CFTypeRef.
548 */
549 bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid)
550 {
551 bool valid_ref = false;
552 if (CFGetTypeID(persistent_ref) == CFDataGetTypeID() &&
553 CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) {
554 const uint8_t *bytes = CFDataGetBytePtr(persistent_ref);
555 sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0);
556
557 CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault,
558 bytes, CFStringGetLength(kSecClassGenericPassword),
559 kCFStringEncodingUTF8, true);
560 const void *valid_classes[] = { kSecClassGenericPassword,
561 kSecClassInternetPassword,
562 kSecClassAppleSharePassword,
563 kSecClassCertificate,
564 kSecClassKey,
565 kSecClassIdentity };
566
567 unsigned i;
568 for (i=0; i< array_size(valid_classes); i++) {
569 if (CFEqual(valid_classes[i], class)) {
570 if (return_class)
571 *return_class = valid_classes[i];
572 if (return_rowid)
573 *return_rowid = rowid;
574 valid_ref = true;
575 break;
576 }
577 }
578 CFRelease(class);
579 }
580 return valid_ref;
581 }
582
583 #endif // *** END SECITEM_SHIM_OSX ***
584
585 static bool cf_bool_value(CFTypeRef cf_bool)
586 {
587 return (cf_bool && CFEqual(kCFBooleanTrue, cf_bool));
588 }
589
590
591 static void
592 result_post(CFDictionaryRef query, CFTypeRef raw_result, CFTypeRef *result) {
593 if (!raw_result)
594 return;
595
596 if (!result) {
597 CFRelease(raw_result);
598 return;
599 }
600
601 bool return_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef));
602 bool return_data = cf_bool_value(CFDictionaryGetValue(query, kSecReturnData));
603 bool return_attributes = cf_bool_value(CFDictionaryGetValue(query, kSecReturnAttributes));
604
605 if (return_ref) {
606 if (CFGetTypeID(raw_result) == CFArrayGetTypeID()) {
607 CFIndex i, count = CFArrayGetCount(raw_result);
608 CFMutableArrayRef tmp_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
609 for (i = 0; i < count; i++) {
610 CFTypeRef ref = makeRef(CFArrayGetValueAtIndex(raw_result, i), return_data, return_attributes);
611 if (ref) {
612 CFArrayAppendValue(tmp_array, ref);
613 CFRelease(ref);
614 }
615 }
616 *result = tmp_array;
617 } else
618 *result = makeRef(raw_result, return_data, return_attributes);
619
620 CFRelease(raw_result);
621 } else
622 *result = raw_result;
623 }
624
625 #if SECITEM_SHIM_OSX
626 /* TODO: Should be in some header */
627 OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result);
628 OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result);
629 OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
630 OSStatus SecItemDelete_ios(CFDictionaryRef query);
631 #endif
632
633 static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error)
634 {
635 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
636 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error);
637 }, ^bool(xpc_object_t response, CFErrorRef *error) {
638 if (result) {
639 return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error);
640 }
641 return true;
642 });
643 }
644
645 static bool cftype_ag_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error) {
646 return cftype_to_bool_cftype_error_request(op, attributes, result, error);
647 }
648
649 static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error)
650 {
651 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
652 return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error);
653 }, NULL);
654 }
655
656 static bool dict_ag_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused CFArrayRef accessGroups, CFErrorRef *error)
657 {
658 return dict_to_error_request(op, query, error);
659 }
660
661 static CFDataRef data_data_to_data_error_request(enum SecXPCOperation op, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
662 __block CFDataRef result = NULL;
663 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
664 return SecXPCDictionarySetDataOptional(message, kSecXPCKeyKeybag, keybag, error)
665 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error);
666 }, ^bool(xpc_object_t response, CFErrorRef *error) {
667 return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error));
668 });
669 return result;
670 }
671
672 static bool data_data_data_to_error_request(enum SecXPCOperation op, CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
673 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
674 return SecXPCDictionarySetData(message, kSecXPCKeyBackup, backup, error)
675 && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error)
676 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error);
677 } , NULL);
678 }
679
680 static bool dict_data_data_to_error_request(enum SecXPCOperation op, CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
681 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
682 return SecXPCDictionarySetPList(message, kSecXPCKeyBackup, backup, error)
683 && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error)
684 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error);
685 } , NULL);
686 }
687
688 static CFDictionaryRef data_data_dict_to_dict_error_request(enum SecXPCOperation op, CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
689 __block CFDictionaryRef dict = NULL;
690 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
691 return SecXPCDictionarySetPListOptional(message, kSecXPCKeyBackup, backup, error)
692 && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error)
693 && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error);
694 }, ^bool(xpc_object_t response, CFErrorRef *error) {
695 return (dict = SecXPCDictionaryCopyDictionary(response, kSecXPCKeyResult, error));
696 });
697 return dict;
698 }
699
700 OSStatus
701 #if SECITEM_SHIM_OSX
702 SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result)
703 #else
704 SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)
705 #endif // *** END SECITEM_SHIM_OSX ***
706 {
707 CFMutableDictionaryRef args = NULL;
708 OSStatus status;
709
710 #ifndef SECITEM_SHIM_OSX
711 require_quiet(!explode_identity(attributes, (secitem_operation)SecItemAdd, &status, result), errOut);
712 require_noerr_quiet(status = cook_query(attributes, &args), errOut);
713 infer_cert_label(attributes, args);
714 #endif // *** END SECITEM_SHIM_OSX ***
715 if (args)
716 attributes = args;
717
718 status = SecOSStatusWith(^bool (CFErrorRef *error) {
719 CFTypeRef raw_result = NULL;
720 if (!SECURITYD_XPC(sec_item_add, cftype_ag_to_bool_cftype_error_request, attributes, SecAccessGroupsGetCurrent(), &raw_result, error))
721 return false;
722
723 result_post(attributes, raw_result, result);
724 return true;
725 });
726
727 #ifndef SECITEM_SHIM_OSX
728 errOut:
729 #endif // *** END SECITEM_SHIM_OSX ***
730 CFReleaseSafe(args);
731 return status;
732 }
733
734
735 OSStatus
736 #if SECITEM_SHIM_OSX
737 SecItemCopyMatching_ios(CFDictionaryRef inQuery, CFTypeRef *result)
738 #else
739 SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result)
740 #endif // *** END SECITEM_SHIM_OSX ***
741 {
742 __block CFDictionaryRef query = inQuery;
743 __block CFMutableDictionaryRef args = NULL;
744 OSStatus status;
745
746 #ifndef SECITEM_SHIM_OSX
747 require_quiet(!explode_identity(query, (secitem_operation)SecItemCopyMatching, &status, result), errOut);
748 require_noerr_quiet(status = cook_query(query, &args), errOut);
749 #endif // *** END SECITEM_SHIM_OSX ***
750 if (args)
751 query = args;
752
753 status = SecOSStatusWith(^bool (CFErrorRef *error) {
754 CFTypeRef raw_result = NULL;
755 if (!SECURITYD_XPC(sec_item_copy_matching, cftype_ag_to_bool_cftype_error_request, query, SecAccessGroupsGetCurrent(), &raw_result, error))
756 return false;
757
758 #ifdef SECITEM_SHIM_OSX
759 if ((!cf_bool_value(CFDictionaryGetValue(query, kSecReturnPersistentRef))) && cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef))) {
760 CFReleaseSafe(args);
761 args = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
762 CFDictionaryAddValue(args, kSecReturnPersistentRef, kCFBooleanTrue);
763 query = args;
764 }
765 #endif
766 result_post(query, raw_result, result);
767 return true;
768 });
769
770 #ifndef SECITEM_SHIM_OSX
771 errOut:
772 #endif // *** END SECITEM_SHIM_OSX ***
773 CFReleaseSafe(args);
774 return status;
775 }
776
777 OSStatus
778 #if SECITEM_SHIM_OSX
779 SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
780 #else
781 SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
782 #endif // *** END SECITEM_SHIM_OSX ***
783 {
784 CFMutableDictionaryRef args = NULL;
785 __block OSStatus status; // TODO loose block once gSecurityd functions return CFErrorRefs
786 #ifndef SECITEM_SHIM_OSX
787 require_noerr_quiet(status = cook_query(query, &args), errOut);
788 #endif
789 if (args)
790 query = args;
791
792 status = SecOSStatusWith(^bool (CFErrorRef *error) {
793 bool ok = false;
794 if (gSecurityd) {
795 // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks.
796 CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
797 CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); });
798 ok = gSecurityd->sec_item_update(query, tmp, SecAccessGroupsGetCurrent(), error);
799 CFRelease(tmp);
800 } else {
801 xpc_object_t message = securityd_create_message(sec_item_update_id, error);
802 if (message) {
803 if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) &&
804 SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) {
805 xpc_object_t reply = securityd_message_with_reply_sync(message, error);
806 if (reply) {
807 ok = securityd_message_no_error(reply, error);
808 xpc_release(reply);
809 }
810 }
811 xpc_release(message);
812 }
813 }
814 return ok;
815 });
816
817 #ifndef SECITEM_SHIM_OSX
818 errOut:
819 #endif
820 CFReleaseSafe(args);
821 return status;
822 }
823
824 #ifndef SECITEM_SHIM_OSX
825 static void copy_all_keys_and_values(const void *key, const void *value, void *context)
826 {
827 CFDictionaryAddValue((CFMutableDictionaryRef)context, key, value);
828 }
829 #endif
830
831 #ifndef SECITEM_SHIM_OSX
832 static OSStatus explode_persistent_identity_ref(CFDictionaryRef query, CFMutableDictionaryRef *delete_query)
833 {
834 OSStatus status = errSecSuccess;
835 CFTypeRef persist = CFDictionaryGetValue(query, kSecValuePersistentRef);
836 CFStringRef class;
837 if (persist && _SecItemParsePersistentRef(persist, &class, NULL)
838 && CFEqual(class, kSecClassIdentity)) {
839 const void *keys[] = { kSecReturnRef, kSecValuePersistentRef };
840 const void *vals[] = { kCFBooleanTrue, persist };
841 CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys,
842 vals, (array_size(keys)), NULL, NULL);
843 CFTypeRef item_query = NULL;
844 status = SecItemCopyMatching(persistent_query, &item_query);
845 CFReleaseNull(persistent_query);
846 if (status)
847 return status;
848 CFMutableDictionaryRef new_query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
849 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
850 if (new_query) {
851 CFDictionaryApplyFunction(query, copy_all_keys_and_values, new_query);
852 CFDictionaryRemoveValue(new_query, kSecValuePersistentRef);
853 CFDictionarySetValue(new_query, kSecValueRef, item_query);
854 *delete_query = new_query;
855 } else
856 status = errSecAllocate;
857 CFRelease(item_query);
858 }
859
860 return status;
861 }
862 #endif
863
864 OSStatus
865 #if SECITEM_SHIM_OSX
866 SecItemDelete_ios(CFDictionaryRef query)
867 #else
868 SecItemDelete(CFDictionaryRef query)
869 #endif // *** END SECITEM_SHIM_OSX ***
870 {
871 CFMutableDictionaryRef args1 = NULL, args2 = NULL;
872 OSStatus status;
873
874 #ifndef SECITEM_SHIM_OSX
875 require_noerr_quiet(status = explode_persistent_identity_ref(query, &args1), errOut);
876 if (args1)
877 query = args1;
878 require_quiet(!explode_identity(query, (secitem_operation)SecItemDelete, &status, NULL), errOut);
879 require_noerr_quiet(status = cook_query(query, &args2), errOut);
880 #endif // *** END SECITEM_SHIM_OSX ***
881 if (args2)
882 query = args2;
883
884 status = SecOSStatusWith(^bool (CFErrorRef *error) {
885 return SECURITYD_XPC(sec_item_delete, dict_ag_to_error_request, query, SecAccessGroupsGetCurrent(), error);
886 });
887
888 #ifndef SECITEM_SHIM_OSX
889 errOut:
890 #endif // *** END SECITEM_SHIM_OSX ***
891 CFReleaseSafe(args1);
892 CFReleaseSafe(args2);
893 return status;
894 }
895
896 OSStatus
897 SecItemDeleteAll(void)
898 {
899 return SecOSStatusWith(^bool (CFErrorRef *error) {
900 bool ok;
901 if (gSecurityd) {
902 #ifndef SECITEM_SHIM_OSX
903 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
904 if (!gSecurityd->sec_truststore_remove_all(ts, error))
905 ok = SecError(errSecInternal, error, CFSTR("sec_truststore_remove_all is NULL"));
906 #endif // *** END SECITEM_SHIM_OSX ***
907 if (!gSecurityd->sec_item_delete_all(error))
908 ok = SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL"));
909 ok = true;
910 } else {
911 ok = securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL);
912 }
913 return ok;
914 });
915 }
916
917 CFDataRef _SecKeychainCopyOTABackup(void) {
918 return SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, NULL, NULL, NULL);
919 }
920
921 CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password) {
922 return SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, backupKeybag, password, NULL);
923 }
924
925 OSStatus _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag,
926 CFDataRef password) {
927 return SecOSStatusWith(^bool (CFErrorRef *error) {
928 return SECURITYD_XPC(sec_keychain_restore, data_data_data_to_error_request, backup, backupKeybag, password, error);
929 });
930 }
931
932 bool _SecKeychainSyncUpdate(CFDictionaryRef updates, CFErrorRef *error) {
933 return SECURITYD_XPC(sec_keychain_sync_update, dict_to_error_request, updates, error);
934 }
935
936 OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out)
937 {
938 return SecOSStatusWith(^bool (CFErrorRef *error) {
939 *backup_out = SECURITYD_XPC(sec_keychain_backup_syncable, data_data_dict_to_dict_error_request, backup_in, keybag, password, error);
940 return *backup_out != NULL;
941 });
942 }
943
944 OSStatus _SecKeychainRestoreSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in)
945 {
946 return SecOSStatusWith(^bool (CFErrorRef *error) {
947 return SECURITYD_XPC(sec_keychain_restore_syncable, dict_data_data_to_error_request, backup_in, keybag, password, error);
948 });
949 }
950
951
952 #ifndef SECITEM_SHIM_OSX
953 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
954
955 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement)
956 {
957 return -1; /* this is only on OS X currently */
958 }
959
960 #else
961
962 extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
963
964 #endif