X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/79b9da22a1f4b26279940d285c1bc28ce4e99252..0d4552ce43ff8bf2e8666a9c5c44c3590eb117a8:/OSX/libsecurity_keychain/lib/SecItem.cpp?ds=inline diff --git a/OSX/libsecurity_keychain/lib/SecItem.cpp b/OSX/libsecurity_keychain/lib/SecItem.cpp index ab0419a2..2cdb17f9 100644 --- a/OSX/libsecurity_keychain/lib/SecItem.cpp +++ b/OSX/libsecurity_keychain/lib/SecItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2019 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ #include "SecBridge.h" -#include "SecInternal.h" +#include #include #include #include @@ -31,15 +31,17 @@ #include #include #include "cssmdatetime.h" -#include "SecItem.h" -#include "SecItemPriv.h" -#include "SecIdentitySearchPriv.h" -#include "SecKeychainPriv.h" -#include "SecCertificatePriv.h" +#include +#include +#include +#include +#include +#include #include "TrustAdditions.h" #include "TrustSettingsSchema.h" #include #include "utilities/array_size.h" +#include "utilities/SecCFWrappers.h" #include #include @@ -538,6 +540,12 @@ _ConvertNewFormatToOldFormat( SecKeychainAttributeList* &attrList ) { + // make storage to extract the dictionary items + CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); + if (itemsInDictionary > 10000) { + return errSecParam; + } + // get the keychain attributes array from the data item // here's the problem. On the one hand, we have a dictionary that is purported to contain // attributes for our type. On the other hand, the dictionary may contain items we don't support, @@ -546,15 +554,10 @@ _ConvertNewFormatToOldFormat( // setup the return attrList = (SecKeychainAttributeList*) calloc(1, sizeof(SecKeychainAttributeList)); - // make storage to extract the dictionary items - CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); - CFTypeRef keys[itemsInDictionary]; - CFTypeRef values[itemsInDictionary]; + std::vector keys(itemsInDictionary); + std::vector values(itemsInDictionary); - CFTypeRef *keysPtr = keys; - CFTypeRef *valuesPtr = values; - - CFDictionaryGetKeysAndValues(dictionaryRef, keys, values); + CFDictionaryGetKeysAndValues(dictionaryRef, keys.data(), values.data()); // count the number of items we are interested in CFIndex count = 0; @@ -562,12 +565,12 @@ _ConvertNewFormatToOldFormat( // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that // we don't pay the price for this twice - SecKeychainAttrType tags[itemsInDictionary]; - ItemRepresentation types[itemsInDictionary]; + std::vector tags(itemsInDictionary); + std::vector types(itemsInDictionary); for (i = 0; i < itemsInDictionary; ++i) { - CFTypeRef key = keysPtr[i]; + CFTypeRef key = keys[i]; int j; for (j = 0; j < infoNumItems; ++j) @@ -584,28 +587,33 @@ _ConvertNewFormatToOldFormat( if (j >= infoNumItems) { // if we got here, we aren't interested in this item. - valuesPtr[i] = NULL; + values[i] = NULL; } } // now we can make the result array attrList->count = (UInt32)count; - attrList->attr = (count > 0) ? (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count) : NULL; - // fill out the array - int resultPointer = 0; - for (i = 0; i < itemsInDictionary; ++i) - { - if (values[i] != NULL) - { - attrList->attr[resultPointer].tag = tags[i]; + if(count == 0) { + attrList->attr = NULL; + } else { + attrList->attr = (SecKeychainAttribute*) calloc(count, sizeof(SecKeychainAttribute)); - // we have to clone the data pointer. The caller will need to make sure to throw these away - // with _FreeAttrList when it is done... - attrList->attr[resultPointer].data = CloneDataByType(types[i], valuesPtr[i], attrList->attr[resultPointer].length); - resultPointer += 1; - } - } + // fill out the array + int resultPointer = 0; + for (i = 0; i < itemsInDictionary; ++i) + { + if (values[i] != NULL) + { + attrList->attr[resultPointer].tag = tags[i]; + + // we have to clone the data pointer. The caller will need to make sure to throw these away + // with _FreeAttrList when it is done... + attrList->attr[resultPointer].data = CloneDataByType(types[i], values[i], attrList->attr[resultPointer].length); + resultPointer += 1; + } + } + } return errSecSuccess; } @@ -1579,7 +1587,7 @@ _CreateSecKeychainKeyAttributeListFromDictionary( // [5] get the kSecKeyKeyType number if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeyType, (const void **)&value) && value) { - UInt32 keyAlgValue = _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType); + UInt32 keyAlgValue = _SecAlgorithmTypeFromSecAttrKeyType(value); if (keyAlgValue != 0) { attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32)); require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall); @@ -2359,24 +2367,11 @@ _ReplaceKeychainItem( // make attribute list for new item (the data is still owned by attrList) newAttrList.count = attrList->count; - newAttrList.attr = (SecKeychainAttribute *) malloc(sizeof(SecKeychainAttribute) * attrList->count); + newAttrList.attr = (SecKeychainAttribute *) calloc(attrList->count, sizeof(SecKeychainAttribute)); int i, newCount; for (i=0, newCount=0; i < attrList->count; i++) { if (attrList->attr[i].length > 0) { newAttrList.attr[newCount++] = attrList->attr[i]; - #if 0 - // debugging code to log item attributes - SecKeychainAttrType tag = attrList->attr[i].tag; - SecKeychainAttrType htag=(SecKeychainAttrType)OSSwapConstInt32(tag); - char tmp[sizeof(SecKeychainAttrType) + 1]; - char tmpdata[attrList->attr[i].length + 1]; - memcpy(tmp, &htag, sizeof(SecKeychainAttrType)); - tmp[sizeof(SecKeychainAttrType)]=0; - memcpy(tmpdata, attrList->attr[i].data, attrList->attr[i].length); - tmpdata[attrList->attr[i].length]=0; - secitemlog(priority, "item attr '%s' = %d bytes: \"%s\"", - tmp, (int)attrList->attr[i].length, tmpdata); - #endif } } newAttrList.count = newCount; @@ -3290,6 +3285,7 @@ _FilterWithPolicy(SecPolicyRef policy, CFDateRef date, SecCertificateRef cert) SecTrustResultType trustResult; Boolean needChain = false; + Boolean needCSEKU = false; OSStatus status; if (!policy || !cert) return errSecParam; @@ -3303,13 +3299,33 @@ _FilterWithPolicy(SecPolicyRef policy, CFDateRef date, SecCertificateRef cert) if(status) goto cleanup; } - /* Check whether this is the X509 Basic policy, which means chain building */ + /* Check whether we can avoid full chain evaluation, based on policy */ props = SecPolicyCopyProperties(policy); if (props) { CFTypeRef oid = (CFTypeRef) CFDictionaryGetValue(props, kSecPolicyOid); if (oid && (CFEqual(oid, kSecPolicyAppleX509Basic) || - CFEqual(oid, kSecPolicyAppleRevocation))) { + CFEqual(oid, kSecPolicyAppleRevocation))) { needChain = true; + } else if (oid && (CFEqual(oid, kSecPolicyAppleCodeSigning))) { + needCSEKU = true; + } + } + + /* If a code signing EKU purpose is needed, filter out certs without it here + to reduce log noise associated with evaluation failures. */ + if (needCSEKU) { + CFDataRef eku = CFDataCreate(kCFAllocatorDefault, + oidExtendedKeyUsageCodeSigning.data, + oidExtendedKeyUsageCodeSigning.length); + if (eku) { + if (!SecPolicyCheckCertExtendedKeyUsage(cert, eku)) { + needCSEKU = false; + } + CFRelease(eku); + } + if (!needCSEKU) { + status = errSecCertificateCannotOperate; + goto cleanup; } } @@ -4027,23 +4043,32 @@ extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref); // // Function to find out which keychains are targetted by the query. // -static OSStatus SecItemCategorizeQuery(CFDictionaryRef query, bool &can_target_ios, bool &can_target_osx) +static OSStatus SecItemCategorizeQuery(CFDictionaryRef query, bool &can_target_ios, bool &can_target_osx, bool &useDataProtectionKeychainFlag) { // By default, target both keychain. can_target_osx = can_target_ios = true; + useDataProtectionKeychainFlag = false; // Check no-legacy flag. // it's iOS or bust if we're on MZ! - CFTypeRef noLegacy = NULL; + CFTypeRef useDataProtection = NULL; if (_CFMZEnabled()) { - noLegacy = kCFBooleanTrue; + useDataProtection = kCFBooleanTrue; } else { - noLegacy = CFDictionaryGetValue(query, kSecAttrNoLegacy); + // In case your CFDict is dumb and compares by pointer equality we check both versions of the symbol + if (!CFDictionaryGetValueIfPresent(query, kSecUseDataProtectionKeychain, &useDataProtection)) { + // Ah the irony of ignoring deprecation while checking for a legacy-avoiding attribute +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + useDataProtection = CFDictionaryGetValue(query, kSecAttrNoLegacy); +#pragma clang diagnostic pop + } } - if (noLegacy != NULL) { - can_target_ios = readNumber(noLegacy) != 0; + if (useDataProtection != NULL) { + useDataProtectionKeychainFlag = readNumber(useDataProtection); + can_target_ios = useDataProtectionKeychainFlag; can_target_osx = !can_target_ios; return errSecSuccess; } @@ -4285,7 +4310,7 @@ SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes) { CFTypeRef v; Item item = Item(item_class, &attrs, 0, ""); - v = CFDictionaryGetValue(refAttributes, kSecValuePersistentRef); + v = CFCast(CFData, CFDictionaryGetValue(refAttributes, kSecValuePersistentRef)); if (v) { item->setPersistentRef((CFDataRef)v); } @@ -4415,7 +4440,7 @@ SecItemCopyParentCertificates_osx(SecCertificateRef certificate, void *context) } /* Cache miss. Query for parents. */ -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) +#if TARGET_OS_OSX CFDataRef normalizedIssuer = SecCertificateCopyNormalizedIssuerContent(certificate, NULL); #else CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); @@ -4506,7 +4531,7 @@ SecCertificateRef SecItemCopyStoredCertificate(SecCertificateRef certificate, vo /* Certificates are unique by issuer and serial number. */ CFDataRef serialNumber = SecCertificateCopySerialNumberData(certificate, NULL); -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) +#if TARGET_OS_OSX CFDataRef normalizedIssuer = SecCertificateCopyNormalizedIssuerContent(certificate, NULL); #else CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); @@ -4707,7 +4732,12 @@ SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass, } /* This attribute is consumed by the bridge itself. */ + CFDictionaryRemoveValue(result, kSecUseDataProtectionKeychain); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // Also remove deprecated symbol in case your CFDict is derpy CFDictionaryRemoveValue(result, kSecAttrNoLegacy); +#pragma clang diagnostic pop return result; } @@ -4836,8 +4866,8 @@ SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) OSStatus status_osx = errSecItemNotFound, status_ios = errSecItemNotFound; CFTypeRef result_osx = NULL, result_ios = NULL; - bool can_target_ios, can_target_osx; - OSStatus status = SecItemCategorizeQuery(query, can_target_ios, can_target_osx); + bool can_target_ios, can_target_osx, useDataProtectionKeychainFlag; + OSStatus status = SecItemCategorizeQuery(query, can_target_ios, can_target_osx, useDataProtectionKeychainFlag); if (status != errSecSuccess) { return status; } @@ -4890,8 +4920,8 @@ SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) secitemshow(attributes, "SecItemAdd attrs:"); CFTypeRef result_osx = NULL, result_ios = NULL; - bool can_target_ios, can_target_osx; - OSStatus status = SecItemCategorizeQuery(attributes, can_target_ios, can_target_osx); + bool can_target_ios, can_target_osx, useDataProtectionKeychainFlag; + OSStatus status = SecItemCategorizeQuery(attributes, can_target_ios, can_target_osx, useDataProtectionKeychainFlag); if (status != errSecSuccess) { return status; } @@ -4940,12 +4970,29 @@ SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) secitemshow(attributesToUpdate, "SecItemUpdate attrs:"); OSStatus status_osx = errSecItemNotFound, status_ios = errSecItemNotFound; - bool can_target_ios, can_target_osx; - OSStatus status = SecItemCategorizeQuery(query, can_target_ios, can_target_osx); + bool can_target_ios, can_target_osx, useDataProtectionKeychainFlag; + OSStatus status = SecItemCategorizeQuery(query, can_target_ios, can_target_osx, useDataProtectionKeychainFlag); if (status != errSecSuccess) { return status; } + /* + * If the user have explicity opted in to UseDataProtectionKeychain, then don't touch the legacy keychain at all + * ie don't move the item back to legacy keychain if you remove sync=1 or the inverse. + */ + if (useDataProtectionKeychainFlag) { + CFDictionaryRef attrs_ios = SecItemCopyTranslatedAttributes(query, + CFDictionaryGetValue(query, kSecClass), true, true, false, true, true, true); + if (!attrs_ios) { + status_ios = errSecParam; + } else { + status_ios = SecItemUpdate_ios(attrs_ios, attributesToUpdate); + CFRelease(attrs_ios); + } + secitemlog(LOG_NOTICE, "SecItemUpdate(ios only) result: %d", status_ios); + return status_ios; + } + if (can_target_ios) { CFDictionaryRef attrs_ios = SecItemCopyTranslatedAttributes(query, CFDictionaryGetValue(query, kSecClass), true, true, false, true, true, true); @@ -4999,8 +5046,8 @@ SecItemDelete(CFDictionaryRef query) secitemshow(query, "SecItemDelete query:"); OSStatus status_osx = errSecItemNotFound, status_ios = errSecItemNotFound; - bool can_target_ios, can_target_osx; - OSStatus status = SecItemCategorizeQuery(query, can_target_ios, can_target_osx); + bool can_target_ios, can_target_osx, useDataProtectionKeychainFlag; + OSStatus status = SecItemCategorizeQuery(query, can_target_ios, can_target_osx, useDataProtectionKeychainFlag); if (status != errSecSuccess) { return status; }