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