X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/sec/Security/SecItem.c diff --git a/sec/Security/SecItem.c b/sec/Security/SecItem.c deleted file mode 100644 index 63906855..00000000 --- a/sec/Security/SecItem.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecItem.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#include -#include -#include -#include -#ifndef SECITEM_SHIM_OSX -#include -#include -#include -#include -#include -#include -#include -#endif // *** END SECITEM_SHIM_OSX *** -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "securityd_client.h" -#include "SecuritydXPC.h" -#include -#include -#include -#include -#include -#include -#ifndef SECITEM_SHIM_OSX -#include -#endif // *** END SECITEM_SHIM_OSX *** - -/* label when certificate data is joined with key data */ -#define CERTIFICATE_DATA_COLUMN_LABEL "certdata" - -#include -#include - -/* Return an OSStatus for a sqlite3 error code. */ -static OSStatus osstatus_for_s3e(int s3e) -{ - if (s3e > 0 && s3e <= SQLITE_DONE) switch (s3e) - { - case SQLITE_OK: - return 0; - case SQLITE_ERROR: - return errSecNotAvailable; /* errSecDuplicateItem; */ - case SQLITE_FULL: /* Happens if we run out of uniqueids */ - return errSecNotAvailable; /* TODO: Replace with a better error code. */ - case SQLITE_PERM: - case SQLITE_READONLY: - return errSecNotAvailable; - case SQLITE_CANTOPEN: - return errSecNotAvailable; - case SQLITE_EMPTY: - return errSecNotAvailable; - case SQLITE_CONSTRAINT: - return errSecDuplicateItem; - case SQLITE_ABORT: - return -1; - case SQLITE_MISMATCH: - return errSecNoSuchAttr; - case SQLITE_AUTH: - return errSecNotAvailable; - case SQLITE_NOMEM: - return -2; /* TODO: Replace with a real error code. */ - case SQLITE_INTERNAL: - default: - return errSecNotAvailable; /* TODO: Replace with a real error code. */ - } - return s3e; -} - -static OSStatus osstatus_for_kern_return(CFIndex kernResult) -{ - switch (kernResult) - { - case KERN_SUCCESS: - return errSecSuccess; - case kIOReturnNotReadable: - case kIOReturnNotWritable: - return errSecAuthFailed; - case kIOReturnNotPermitted: - case kIOReturnNotPrivileged: - case kIOReturnLockedRead: - case kIOReturnLockedWrite: - return errSecInteractionNotAllowed; - case kIOReturnError: - return errSecDecode; - case kIOReturnBadArgument: - return errSecParam; - default: - return errSecNotAvailable; /* TODO: Replace with a real error code. */ - } -} - -static OSStatus osstatus_for_xpc_error(CFIndex xpcError) { - switch (xpcError) - { - case kSecXPCErrorSuccess: - return errSecSuccess; - case kSecXPCErrorUnexpectedType: - case kSecXPCErrorUnexpectedNull: - return errSecParam; - case kSecXPCErrorConnectionFailed: - return errSecNotAvailable; - case kSecXPCErrorUnknown: - default: - return errSecInternal; - } -} - -static OSStatus osstatus_for_der_error(CFIndex derError) { - switch (derError) - { - case kSecDERErrorUnknownEncoding: - //case kSecDERErrorUnsupportedDERType: - return errSecDecode; - case kSecDERErrorUnsupportedCFObject: - case kSecDERErrorUnsupportedNumberType: - return errSecParam; - case kSecDERErrorAllocationFailure: - case kSecDERErrorUnderlyingError: - return errSecAllocate; - default: - return errSecInternal; - } -} - -// Convert from securityd error codes to OSStatus for legacy API. -OSStatus SecErrorGetOSStatus(CFErrorRef error) { - OSStatus status; - if (error == NULL) { - status = errSecSuccess; - } else { - CFStringRef domain = CFErrorGetDomain(error); - if (domain == NULL) { - secerror("No error domain for error: %@", error); - status = errSecInternal; - } else if (CFEqual(kSecErrorDomain, domain)) { - status = (OSStatus)CFErrorGetCode(error); - } else if (CFEqual(kSecDbErrorDomain, domain)) { - status = osstatus_for_s3e((int)CFErrorGetCode(error)); - } else if (CFEqual(kSecErrnoDomain, domain)) { - status = (OSStatus)CFErrorGetCode(error); - } else if (CFEqual(kSecKernDomain, domain)) { - status = osstatus_for_kern_return(CFErrorGetCode(error)); - } else if (CFEqual(sSecXPCErrorDomain, domain)) { - status = osstatus_for_xpc_error(CFErrorGetCode(error)); - } else if (CFEqual(sSecDERErrorDomain, domain)) { - status = osstatus_for_der_error(CFErrorGetCode(error)); - } else { - secerror("unknown error domain: %@ for error: %@", domain, error); - status = errSecInternal; - } - } - return status; -} - -// Wrapper to provide a CFErrorRef for legacy API. -OSStatus SecOSStatusWith(bool (^perform)(CFErrorRef *error)) { - CFErrorRef error = NULL; - OSStatus status; - if (perform(&error)) { - assert(error == NULL); - status = errSecSuccess; - } else { - assert(error); - status = SecErrorGetOSStatus(error); - if (status != errSecItemNotFound) // Occurs in normal operation, so exclude - secerror("error:[%" PRIdOSStatus "] %@", status, error); - CFReleaseNull(error); - } - return status; -} - - -/* IPC uses CFPropertyList to un/marshall input/output data and can handle: - CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, and CFNumber - - Currently in need of conversion below: - @@@ kSecValueRef allows SecKeychainItemRef and SecIdentityRef - @@@ kSecMatchPolicy allows a query with a SecPolicyRef - @@@ kSecUseItemList allows a query against a list of itemrefs, this isn't - currently implemented at all, but when it is needs to short circuit to - local evaluation, different from the sql query abilities -*/ - -#ifndef SECITEM_SHIM_OSX -static CFDictionaryRef -SecItemCopyAttributeDictionary(CFTypeRef ref) { - CFDictionaryRef refDictionary = NULL; - CFTypeID typeID = CFGetTypeID(ref); - if (typeID == SecKeyGetTypeID()) { - refDictionary = SecKeyCopyAttributeDictionary((SecKeyRef)ref); - } else if (typeID == SecCertificateGetTypeID()) { - refDictionary = - SecCertificateCopyAttributeDictionary((SecCertificateRef)ref); - } else if (typeID == SecIdentityGetTypeID()) { - assert(false); - SecIdentityRef identity = (SecIdentityRef)ref; - SecCertificateRef cert = NULL; - SecKeyRef key = NULL; - if (!SecIdentityCopyCertificate(identity, &cert) && - !SecIdentityCopyPrivateKey(identity, &key)) - { - CFDataRef data = SecCertificateCopyData(cert); - CFDictionaryRef key_dict = SecKeyCopyAttributeDictionary(key); - - if (key_dict && data) { - refDictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, key_dict); - CFDictionarySetValue((CFMutableDictionaryRef)refDictionary, - CFSTR(CERTIFICATE_DATA_COLUMN_LABEL), data); - } - CFReleaseNull(key_dict); - CFReleaseNull(data); - } - CFReleaseNull(cert); - CFReleaseNull(key); - } else { - refDictionary = NULL; - } - return refDictionary; -} - -static CFTypeRef -SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { - CFTypeRef ref = NULL; - CFStringRef class = CFDictionaryGetValue(refAttributes, kSecClass); - if (CFEqual(class, kSecClassCertificate)) { - ref = SecCertificateCreateFromAttributeDictionary(refAttributes); - } else if (CFEqual(class, kSecClassKey)) { - ref = SecKeyCreateFromAttributeDictionary(refAttributes); - } else if (CFEqual(class, kSecClassIdentity)) { - CFAllocatorRef allocator = NULL; - CFDataRef data = CFDictionaryGetValue(refAttributes, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL)); - SecCertificateRef cert = SecCertificateCreateWithData(allocator, data); - SecKeyRef key = SecKeyCreateFromAttributeDictionary(refAttributes); - if (key && cert) - ref = SecIdentityCreate(allocator, cert, key); - CFReleaseSafe(cert); - CFReleaseSafe(key); -#if 0 - /* We don't support SecKeychainItemRefs yet. */ - } else if (CFEqual(class, kSecClassGenericPassword)) { - } else if (CFEqual(class, kSecClassInternetPassword)) { - } else if (CFEqual(class, kSecClassAppleSharePassword)) { -#endif - } else { - ref = NULL; - } - return ref; -} -#else - -extern CFTypeRef SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes); - -#endif - -/* Turn the returned dictionary that contains all the attributes to create a - ref into the exact result the client asked for */ -static CFTypeRef makeRef(CFTypeRef ref, bool return_data, bool return_attributes) -{ - CFTypeRef result = NULL; - if (!ref || (CFGetTypeID(ref) != CFDictionaryGetTypeID())) - return NULL; - - CFTypeRef return_ref = SecItemCreateFromAttributeDictionary(ref); - - if (return_data || return_attributes) { - if (return_attributes) - result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, ref); - else - result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - if (return_ref) { - CFDictionarySetValue((CFMutableDictionaryRef)result, kSecValueRef, return_ref); - CFRelease(return_ref); - } - - if (!return_data) - CFDictionaryRemoveValue((CFMutableDictionaryRef)result, kSecValueData); - } else - result = return_ref; - - return result; -} - -OSStatus -SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames) -{ - // @@@ TBI - return -1 /* errSecUnimplemented */; -} - -#ifndef SECITEM_SHIM_OSX -static void merge_dictionary_by_overwrite(const void *key, const void *value, void *context) -{ - if (!CFEqual(key, kSecValueRef)) - CFDictionarySetValue((CFMutableDictionaryRef)context, key, value); -} - -static void copy_applier(const void *key, const void *value, void *context) -{ - CFDictionarySetValue(context, key, value); -} - -static OSStatus cook_query(CFDictionaryRef query, CFMutableDictionaryRef *explode) -{ - /* If a ref was specified we get it's attribute dictionary and parse it. */ - CFMutableDictionaryRef args = NULL; - CFTypeRef value = CFDictionaryGetValue(query, kSecValueRef); - if (value) { - CFDictionaryRef refAttributes = SecItemCopyAttributeDictionary(value); - if (!refAttributes) - return errSecValueRefUnsupported; - - /* Replace any attributes we already got from the ref with the ones - from the attributes dictionary the caller passed us. This allows - a caller to add an item using attributes from the ref and still - override some of them in the dictionary directly. */ - args = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, refAttributes); - CFRelease(refAttributes); - CFDictionaryApplyFunction(query, merge_dictionary_by_overwrite, args); - } - value = CFDictionaryGetValue(query, kSecAttrIssuer); - if (value) { - /* convert DN to canonical issuer, if value is DN (top level sequence) */ - const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) }; - DERDecodedInfo content; - if (!DERDecodeItem(&name, &content) && - (content.tag == ASN1_CONSTR_SEQUENCE)) - { - CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content); - if (canonical_issuer) { - if (!args) { - args = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - /* This is necessary because we rely on non NULL callbacks */ - CFDictionaryApplyFunction(query, copy_applier, args); - } - /* Overwrite with new issuer */ - CFDictionarySetValue(args, kSecAttrIssuer, canonical_issuer); - CFRelease(canonical_issuer); - } - } - } - *explode = args; - return errSecSuccess; -} - -typedef OSStatus (*secitem_operation)(CFDictionaryRef attributes, CFTypeRef *result); - -static bool explode_identity(CFDictionaryRef attributes, secitem_operation operation, - OSStatus *return_status, CFTypeRef *return_result) -{ - bool handled = false; - CFTypeRef value = CFDictionaryGetValue(attributes, kSecValueRef); - if (value) { - CFTypeID typeID = CFGetTypeID(value); - if (typeID == SecIdentityGetTypeID()) { - handled = true; - OSStatus status = errSecSuccess; - SecIdentityRef identity = (SecIdentityRef)value; - SecCertificateRef cert = NULL; - SecKeyRef key = NULL; - if (!SecIdentityCopyCertificate(identity, &cert) && - !SecIdentityCopyPrivateKey(identity, &key)) - { - CFMutableDictionaryRef partial_query = - CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes); - CFDictionarySetValue(partial_query, kSecValueRef, cert); - CFTypeRef result = NULL; - bool duplicate_cert = false; - /* an identity is first and foremost a key, but it can have multiple - certs associated with it: so we identify it by the cert */ - status = operation(partial_query, return_result ? &result : NULL); - if ((operation == (secitem_operation)SecItemAdd) && - (status == errSecDuplicateItem)) { - duplicate_cert = true; - status = errSecSuccess; - } - - if (!status || status == errSecItemNotFound) { - bool skip_key_operation = false; - - /* if the key is still in use, skip deleting it */ - if (operation == (secitem_operation)SecItemDelete) { - // find certs with cert.pkhh == keys.klbl - CFDictionaryRef key_dict = NULL, query_dict = NULL; - CFDataRef pkhh = NULL; - - key_dict = SecKeyCopyAttributeDictionary(key); - if (key_dict) - pkhh = (CFDataRef)CFDictionaryGetValue(key_dict, kSecAttrApplicationLabel); - const void *keys[] = { kSecClass, kSecAttrPublicKeyHash }; - const void *vals[] = { kSecClassCertificate, pkhh }; - if (pkhh) - query_dict = CFDictionaryCreate(NULL, keys, - vals, (array_size(keys)), - NULL, NULL); - if (query_dict) - if (errSecSuccess == SecItemCopyMatching(query_dict, NULL)) - skip_key_operation = true; - CFReleaseSafe(query_dict); - CFReleaseSafe(key_dict); - } - - if (!skip_key_operation) { - /* now perform the operation for the key */ - CFDictionarySetValue(partial_query, kSecValueRef, key); - CFDictionarySetValue(partial_query, kSecReturnPersistentRef, kCFBooleanFalse); - status = operation(partial_query, NULL); - if ((operation == (secitem_operation)SecItemAdd) && - (status == errSecDuplicateItem) && - !duplicate_cert) - status = errSecSuccess; - } - - /* add and copy matching for an identityref have a persistent ref result */ - if (result) { - if (!status) { - /* result is a persistent ref to a cert */ - sqlite_int64 rowid; - if (_SecItemParsePersistentRef(result, NULL, &rowid)) { - *return_result = _SecItemMakePersistentRef(kSecClassIdentity, rowid); - } - } - CFRelease(result); - } - } - CFReleaseNull(partial_query); - } - else - status = errSecInvalidItemRef; - - CFReleaseNull(cert); - CFReleaseNull(key); - *return_status = status; - } - } else { - value = CFDictionaryGetValue(attributes, kSecClass); - if (value && CFEqual(kSecClassIdentity, value) && - (operation == (secitem_operation)SecItemDelete)) { - CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes); - CFDictionaryRemoveValue(dict, kSecClass); - CFDictionarySetValue(dict, kSecClass, kSecClassCertificate); - OSStatus status = SecItemDelete(dict); - if (!status) { - CFDictionarySetValue(dict, kSecClass, kSecClassKey); - status = SecItemDelete(dict); - } - CFRelease(dict); - *return_status = status; - handled = true; - } - } - return handled; -} - -static void infer_cert_label(CFDictionaryRef attributes, CFMutableDictionaryRef args) -{ - if (!args || !attributes) - return; - - if (CFDictionaryContainsKey(attributes, kSecAttrLabel)) - return; - - CFTypeRef value_ref = CFDictionaryGetValue(attributes, kSecValueRef); - if (!value_ref || (CFGetTypeID(value_ref) != SecCertificateGetTypeID())) - return; - - SecCertificateRef certificate = (SecCertificateRef)value_ref; - CFStringRef label = SecCertificateCopySubjectSummary(certificate); - if (label) { - CFDictionarySetValue(args, kSecAttrLabel, label); - CFReleaseNull(label); - } -} - -/* A persistent ref is just the class and the rowid of the record. */ -CF_RETURNS_RETAINED CFDataRef _SecItemMakePersistentRef(CFTypeRef class, sqlite_int64 rowid) -{ - uint8_t bytes[sizeof(sqlite_int64) + 4]; - if (rowid < 0) - return NULL; - if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/, - kCFStringEncodingUTF8)) - { - OSWriteBigInt64(bytes + 4, 0, rowid); - return CFDataCreate(NULL, bytes, sizeof(bytes)); - } - return NULL; -} - -/* AUDIT[securityd](done): - persistent_ref (ok) is a caller provided, non NULL CFTypeRef. - */ -bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid) -{ - bool valid_ref = false; - if (CFGetTypeID(persistent_ref) == CFDataGetTypeID() && - CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) { - const uint8_t *bytes = CFDataGetBytePtr(persistent_ref); - sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0); - - CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault, - bytes, CFStringGetLength(kSecClassGenericPassword), - kCFStringEncodingUTF8, true); - const void *valid_classes[] = { kSecClassGenericPassword, - kSecClassInternetPassword, - kSecClassAppleSharePassword, - kSecClassCertificate, - kSecClassKey, - kSecClassIdentity }; - - unsigned i; - for (i=0; i< array_size(valid_classes); i++) { - if (CFEqual(valid_classes[i], class)) { - if (return_class) - *return_class = valid_classes[i]; - if (return_rowid) - *return_rowid = rowid; - valid_ref = true; - break; - } - } - CFRelease(class); - } - return valid_ref; -} - -#endif // *** END SECITEM_SHIM_OSX *** - -static bool cf_bool_value(CFTypeRef cf_bool) -{ - return (cf_bool && CFEqual(kCFBooleanTrue, cf_bool)); -} - - -static void -result_post(CFDictionaryRef query, CFTypeRef raw_result, CFTypeRef *result) { - if (!raw_result) - return; - - if (!result) { - CFRelease(raw_result); - return; - } - - bool return_ref = cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef)); - bool return_data = cf_bool_value(CFDictionaryGetValue(query, kSecReturnData)); - bool return_attributes = cf_bool_value(CFDictionaryGetValue(query, kSecReturnAttributes)); - - if (return_ref) { - if (CFGetTypeID(raw_result) == CFArrayGetTypeID()) { - CFIndex i, count = CFArrayGetCount(raw_result); - CFMutableArrayRef tmp_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); - for (i = 0; i < count; i++) { - CFTypeRef ref = makeRef(CFArrayGetValueAtIndex(raw_result, i), return_data, return_attributes); - if (ref) { - CFArrayAppendValue(tmp_array, ref); - CFRelease(ref); - } - } - *result = tmp_array; - } else - *result = makeRef(raw_result, return_data, return_attributes); - - CFRelease(raw_result); - } else - *result = raw_result; -} - -#if SECITEM_SHIM_OSX -/* TODO: Should be in some header */ -OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result); -OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result); -OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate); -OSStatus SecItemDelete_ios(CFDictionaryRef query); -#endif - -static bool cftype_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, CFTypeRef *result, CFErrorRef *error) -{ - return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { - return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error); - }, ^bool(xpc_object_t response, CFErrorRef *error) { - if (result) { - return SecXPCDictionaryCopyPListOptional(response, kSecXPCKeyResult, result, error); - } - return true; - }); -} - -static bool cftype_ag_to_bool_cftype_error_request(enum SecXPCOperation op, CFTypeRef attributes, __unused CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error) { - return cftype_to_bool_cftype_error_request(op, attributes, result, error); -} - -static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, CFErrorRef *error) -{ - return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { - return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error); - }, NULL); -} - -static bool dict_ag_to_error_request(enum SecXPCOperation op, CFDictionaryRef query, __unused CFArrayRef accessGroups, CFErrorRef *error) -{ - return dict_to_error_request(op, query, error); -} - -static CFDataRef data_data_to_data_error_request(enum SecXPCOperation op, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { - __block CFDataRef result = NULL; - securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { - return SecXPCDictionarySetDataOptional(message, kSecXPCKeyKeybag, keybag, error) - && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); - }, ^bool(xpc_object_t response, CFErrorRef *error) { - return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error)); - }); - return result; -} - -static bool data_data_data_to_error_request(enum SecXPCOperation op, CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { - return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { - return SecXPCDictionarySetData(message, kSecXPCKeyBackup, backup, error) - && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) - && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); - } , NULL); -} - -static bool dict_data_data_to_error_request(enum SecXPCOperation op, CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { - return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { - return SecXPCDictionarySetPList(message, kSecXPCKeyBackup, backup, error) - && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) - && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); - } , NULL); -} - -static CFDictionaryRef data_data_dict_to_dict_error_request(enum SecXPCOperation op, CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { - __block CFDictionaryRef dict = NULL; - securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { - return SecXPCDictionarySetPListOptional(message, kSecXPCKeyBackup, backup, error) - && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) - && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); - }, ^bool(xpc_object_t response, CFErrorRef *error) { - return (dict = SecXPCDictionaryCopyDictionary(response, kSecXPCKeyResult, error)); - }); - return dict; -} - -OSStatus -#if SECITEM_SHIM_OSX -SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result) -#else -SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) -#endif // *** END SECITEM_SHIM_OSX *** -{ - CFMutableDictionaryRef args = NULL; - OSStatus status; - -#ifndef SECITEM_SHIM_OSX - require_quiet(!explode_identity(attributes, (secitem_operation)SecItemAdd, &status, result), errOut); - require_noerr_quiet(status = cook_query(attributes, &args), errOut); - infer_cert_label(attributes, args); -#endif // *** END SECITEM_SHIM_OSX *** - if (args) - attributes = args; - - status = SecOSStatusWith(^bool (CFErrorRef *error) { - CFTypeRef raw_result = NULL; - if (!SECURITYD_XPC(sec_item_add, cftype_ag_to_bool_cftype_error_request, attributes, SecAccessGroupsGetCurrent(), &raw_result, error)) - return false; - - result_post(attributes, raw_result, result); - return true; - }); - -#ifndef SECITEM_SHIM_OSX -errOut: -#endif // *** END SECITEM_SHIM_OSX *** - CFReleaseSafe(args); - return status; -} - - -OSStatus -#if SECITEM_SHIM_OSX -SecItemCopyMatching_ios(CFDictionaryRef inQuery, CFTypeRef *result) -#else -SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) -#endif // *** END SECITEM_SHIM_OSX *** -{ - __block CFDictionaryRef query = inQuery; - __block CFMutableDictionaryRef args = NULL; - OSStatus status; - -#ifndef SECITEM_SHIM_OSX - require_quiet(!explode_identity(query, (secitem_operation)SecItemCopyMatching, &status, result), errOut); - require_noerr_quiet(status = cook_query(query, &args), errOut); -#endif // *** END SECITEM_SHIM_OSX *** - if (args) - query = args; - - status = SecOSStatusWith(^bool (CFErrorRef *error) { - CFTypeRef raw_result = NULL; - if (!SECURITYD_XPC(sec_item_copy_matching, cftype_ag_to_bool_cftype_error_request, query, SecAccessGroupsGetCurrent(), &raw_result, error)) - return false; - -#ifdef SECITEM_SHIM_OSX - if ((!cf_bool_value(CFDictionaryGetValue(query, kSecReturnPersistentRef))) && cf_bool_value(CFDictionaryGetValue(query, kSecReturnRef))) { - CFReleaseSafe(args); - args = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query); - CFDictionaryAddValue(args, kSecReturnPersistentRef, kCFBooleanTrue); - query = args; - } -#endif - result_post(query, raw_result, result); - return true; - }); - -#ifndef SECITEM_SHIM_OSX -errOut: -#endif // *** END SECITEM_SHIM_OSX *** - CFReleaseSafe(args); - return status; -} - -OSStatus -#if SECITEM_SHIM_OSX -SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) -#else -SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) -#endif // *** END SECITEM_SHIM_OSX *** -{ - CFMutableDictionaryRef args = NULL; - __block OSStatus status; // TODO loose block once gSecurityd functions return CFErrorRefs -#ifndef SECITEM_SHIM_OSX - require_noerr_quiet(status = cook_query(query, &args), errOut); -#endif - if (args) - query = args; - - status = SecOSStatusWith(^bool (CFErrorRef *error) { - bool ok = false; - if (gSecurityd) { - // Ensure the dictionary passed to securityd has proper kCFTypeDictionaryKeyCallBacks. - CFMutableDictionaryRef tmp = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); - CFDictionaryForEach(attributesToUpdate, ^(const void *key, const void *value) { CFDictionaryAddValue(tmp, key, value); }); - ok = gSecurityd->sec_item_update(query, tmp, SecAccessGroupsGetCurrent(), error); - CFRelease(tmp); - } else { - xpc_object_t message = securityd_create_message(sec_item_update_id, error); - if (message) { - if (SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error) && - SecXPCDictionarySetPList(message, kSecXPCKeyAttributesToUpdate, attributesToUpdate, error)) { - xpc_object_t reply = securityd_message_with_reply_sync(message, error); - if (reply) { - ok = securityd_message_no_error(reply, error); - xpc_release(reply); - } - } - xpc_release(message); - } - } - return ok; - }); - -#ifndef SECITEM_SHIM_OSX -errOut: -#endif - CFReleaseSafe(args); - return status; -} - -#ifndef SECITEM_SHIM_OSX -static void copy_all_keys_and_values(const void *key, const void *value, void *context) -{ - CFDictionaryAddValue((CFMutableDictionaryRef)context, key, value); -} -#endif - -#ifndef SECITEM_SHIM_OSX -static OSStatus explode_persistent_identity_ref(CFDictionaryRef query, CFMutableDictionaryRef *delete_query) -{ - OSStatus status = errSecSuccess; - CFTypeRef persist = CFDictionaryGetValue(query, kSecValuePersistentRef); - CFStringRef class; - if (persist && _SecItemParsePersistentRef(persist, &class, NULL) - && CFEqual(class, kSecClassIdentity)) { - const void *keys[] = { kSecReturnRef, kSecValuePersistentRef }; - const void *vals[] = { kCFBooleanTrue, persist }; - CFDictionaryRef persistent_query = CFDictionaryCreate(NULL, keys, - vals, (array_size(keys)), NULL, NULL); - CFTypeRef item_query = NULL; - status = SecItemCopyMatching(persistent_query, &item_query); - CFReleaseNull(persistent_query); - if (status) - return status; - CFMutableDictionaryRef new_query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (new_query) { - CFDictionaryApplyFunction(query, copy_all_keys_and_values, new_query); - CFDictionaryRemoveValue(new_query, kSecValuePersistentRef); - CFDictionarySetValue(new_query, kSecValueRef, item_query); - *delete_query = new_query; - } else - status = errSecAllocate; - CFRelease(item_query); - } - - return status; -} -#endif - -OSStatus -#if SECITEM_SHIM_OSX -SecItemDelete_ios(CFDictionaryRef query) -#else -SecItemDelete(CFDictionaryRef query) -#endif // *** END SECITEM_SHIM_OSX *** -{ - CFMutableDictionaryRef args1 = NULL, args2 = NULL; - OSStatus status; - -#ifndef SECITEM_SHIM_OSX - require_noerr_quiet(status = explode_persistent_identity_ref(query, &args1), errOut); - if (args1) - query = args1; - require_quiet(!explode_identity(query, (secitem_operation)SecItemDelete, &status, NULL), errOut); - require_noerr_quiet(status = cook_query(query, &args2), errOut); -#endif // *** END SECITEM_SHIM_OSX *** - if (args2) - query = args2; - - status = SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_item_delete, dict_ag_to_error_request, query, SecAccessGroupsGetCurrent(), error); - }); - -#ifndef SECITEM_SHIM_OSX -errOut: -#endif // *** END SECITEM_SHIM_OSX *** - CFReleaseSafe(args1); - CFReleaseSafe(args2); - return status; -} - -OSStatus -SecItemDeleteAll(void) -{ - return SecOSStatusWith(^bool (CFErrorRef *error) { - bool ok; - if (gSecurityd) { -#ifndef SECITEM_SHIM_OSX - SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser); - if (!gSecurityd->sec_truststore_remove_all(ts, error)) - ok = SecError(errSecInternal, error, CFSTR("sec_truststore_remove_all is NULL")); -#endif // *** END SECITEM_SHIM_OSX *** - if (!gSecurityd->sec_item_delete_all(error)) - ok = SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL")); - ok = true; - } else { - ok = securityd_send_sync_and_do(sec_delete_all_id, error, NULL, NULL); - } - return ok; - }); -} - -CFDataRef _SecKeychainCopyOTABackup(void) { - return SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, NULL, NULL, NULL); -} - -CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password) { - return SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, backupKeybag, password, NULL); -} - -OSStatus _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag, - CFDataRef password) { - return SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_keychain_restore, data_data_data_to_error_request, backup, backupKeybag, password, error); - }); -} - -bool _SecKeychainSyncUpdate(CFDictionaryRef updates, CFErrorRef *error) { - return SECURITYD_XPC(sec_keychain_sync_update, dict_to_error_request, updates, error); -} - -OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out) -{ - return SecOSStatusWith(^bool (CFErrorRef *error) { - *backup_out = SECURITYD_XPC(sec_keychain_backup_syncable, data_data_dict_to_dict_error_request, backup_in, keybag, password, error); - return *backup_out != NULL; - }); -} - -OSStatus _SecKeychainRestoreSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in) -{ - return SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_keychain_restore_syncable, dict_data_data_to_error_request, backup_in, keybag, password, error); - }); -} - - -#ifndef SECITEM_SHIM_OSX -OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); - -OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement) -{ - return -1; /* this is only on OS X currently */ -} - -#else - -extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); - -#endif