]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/SecItem.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecItem.cpp
index ad88d453afc834ecf5df225ce809a9e14d666af6..e5b078ad01aa9b189fd1ccc28b3dba9e469d732f 100644 (file)
@@ -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 <Security/SecInternal.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <security_utilities/cfutilities.h>
 #include <Security/SecBase.h>
 #include <Security/SecCertificatePriv.h>
 #include <sys/param.h>
 #include "cssmdatetime.h"
-#include "SecItem.h"
-#include "SecItemPriv.h"
-#include "SecIdentitySearchPriv.h"
-#include "SecKeychainPriv.h"
-#include "SecCertificatePriv.h"
+#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
+#include <Security/SecIdentitySearchPriv.h>
+#include <Security/SecKeychainPriv.h>
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecPolicyPriv.h>
 #include "TrustAdditions.h"
 #include "TrustSettingsSchema.h"
 #include <Security/SecTrustPriv.h>
 #include "utilities/array_size.h"
+#include "utilities/SecCFWrappers.h"
+#include "LegacyAPICounts.h"
 
 #include <AssertMacros.h>
 #include <syslog.h>
@@ -69,8 +72,6 @@ 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);
-OSStatus SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes);
-
 
 OSStatus SecItemValidateAppleApplicationGroupAccess(CFStringRef group);
 CFDictionaryRef SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass,
@@ -538,6 +539,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,8 +553,6 @@ _ConvertNewFormatToOldFormat(
        // setup the return
        attrList = (SecKeychainAttributeList*) calloc(1, sizeof(SecKeychainAttributeList));
 
-       // make storage to extract the dictionary items
-       CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef);
        std::vector<CFTypeRef> keys(itemsInDictionary);
        std::vector<CFTypeRef> values(itemsInDictionary);
 
@@ -587,22 +592,27 @@ _ConvertNewFormatToOldFormat(
 
        // 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], values[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;
 }
@@ -1576,7 +1586,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);
@@ -2356,7 +2366,7 @@ _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) {
@@ -3274,6 +3284,7 @@ _FilterWithPolicy(SecPolicyRef policy, CFDateRef date, SecCertificateRef cert)
 
        SecTrustResultType      trustResult;
        Boolean needChain = false;
+       Boolean needCSEKU = false;
        OSStatus status;
        if (!policy || !cert) return errSecParam;
 
@@ -3287,13 +3298,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;
                }
        }
 
@@ -3795,6 +3826,8 @@ AddItemResults(SecKeychainItemRef item,
        //
        // Note that we allocate *items if needed.
 
+       CFTypeRef localResult = NULL;
+
        if (!item || !itemParams || !result)
                return errSecParam;
 
@@ -3823,7 +3856,8 @@ AddItemResults(SecKeychainItemRef item,
                        CFArrayAppendValue(itemArray, itemRef);
                }
                else {
-                       *result = CFRetain((CFTypeRef)itemRef);
+                       CFReleaseNull(localResult);
+                       localResult = CFRetain((CFTypeRef)itemRef);
                }
        }
 
@@ -3842,7 +3876,8 @@ AddItemResults(SecKeychainItemRef item,
                                CFArrayAppendValue(itemArray, persistentRef);
                        }
                        else {
-                               *result = CFRetain(persistentRef);
+                               CFReleaseNull(localResult);
+                               localResult = CFRetain(persistentRef);
                        }
                        CFRelease(persistentRef);
                }
@@ -3866,7 +3901,8 @@ AddItemResults(SecKeychainItemRef item,
                                        CFArrayAppendValue(itemArray, dataRef);
                                }
                                else {
-                                       *result = CFRetain(dataRef);
+                                       CFReleaseNull(localResult);
+                                       localResult = CFRetain(dataRef);
                                }
                                CFRelease(dataRef);
                                status = errSecSuccess;
@@ -3888,7 +3924,8 @@ AddItemResults(SecKeychainItemRef item,
                                        CFArrayAppendValue(itemArray, dataRef);
                                }
                                else {
-                                       *result = CFRetain(dataRef);
+                                       CFReleaseNull(localResult);
+                                       localResult = CFRetain(dataRef);
                                }
                                CFRelease(dataRef);
                                (void) SecKeychainItemFreeContent(NULL, data);
@@ -3917,7 +3954,8 @@ AddItemResults(SecKeychainItemRef item,
                                CFArrayAppendValue(itemArray, attrsDict);
                        }
                        else {
-                               *result = CFRetain(attrsDict);
+                               CFReleaseNull(localResult);
+                               localResult = CFRetain(attrsDict);
                        }
                        CFRelease(attrsDict);
                }
@@ -3930,14 +3968,22 @@ AddItemResults(SecKeychainItemRef item,
                if (itemArray) {
                        CFArrayAppendValue(itemArray, itemDict);
                        CFRelease(itemDict);
-                       *result = itemArray;
+                       CFReleaseNull(localResult);
+                       localResult = itemArray;
                }
                else {
-                       *result = itemDict;
+                       CFReleaseNull(localResult);
+                       localResult = itemDict;
                }
        }
        else if (itemArray) {
-               *result = itemArray;
+               CFReleaseNull(localResult);
+               localResult = itemArray;
+       }
+
+       if (localResult) {
+               *result = localResult;
+               localResult = NULL;
        }
 
        return status;
@@ -4011,23 +4057,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;
        }
@@ -4269,7 +4324,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);
                }
@@ -4399,7 +4454,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);
@@ -4490,7 +4545,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);
@@ -4691,7 +4746,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;
 }
@@ -4820,8 +4880,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;
        }
@@ -4874,8 +4934,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;
        }
@@ -4924,12 +4984,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);
@@ -4983,8 +5060,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;
        }
@@ -5019,14 +5096,6 @@ SecItemDelete(CFDictionaryRef query)
        return status;
 }
 
-OSStatus
-SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
-{
-       OSStatus status = SecItemUpdateTokenItems_ios(tokenID, tokenItemsAttributes);
-       secitemlog(LOG_NOTICE, "SecItemUpdateTokenItems_ios result: %d", status);
-       return status;
-}
-
 OSStatus
 SecItemCopyMatching_osx(
        CFDictionaryRef query,
@@ -5037,6 +5106,8 @@ SecItemCopyMatching_osx(
        else
                *result = NULL;
 
+    setCountLegacyAPIEnabledForThread(false);
+
        CFAllocatorRef allocator = CFGetAllocator(query);
        CFIndex matchCount = 0;
        CFMutableArrayRef itemArray = NULL;
@@ -5081,20 +5152,9 @@ error_exit:
        }
        _FreeSecItemParams(itemParams);
 
-       return status;
-}
+    setCountLegacyAPIEnabledForThread(true);
 
-OSStatus
-SecItemCopyDisplayNames(
-       CFArrayRef items,
-       CFArrayRef *displayNames)
-{
-    BEGIN_SECAPI
-       Required(items);
-       Required(displayNames);
-    //%%%TBI
-    return errSecUnimplemented;
-    END_SECAPI
+       return status;
 }
 
 OSStatus
@@ -5107,6 +5167,8 @@ SecItemAdd_osx(
        else if (result)
                *result = NULL;
 
+    setCountLegacyAPIEnabledForThread(false);
+
        CFAllocatorRef allocator = CFGetAllocator(attributes);
        CFMutableArrayRef itemArray = NULL;
        SecKeychainItemRef item = NULL;
@@ -5240,6 +5302,7 @@ error_exit:
                *result = NULL;
        }
        _FreeSecItemParams(itemParams);
+    setCountLegacyAPIEnabledForThread(true);
 
        return status;
 }
@@ -5267,6 +5330,8 @@ SecItemUpdate_osx(
                CFRelease(results);
        }
 
+    setCountLegacyAPIEnabledForThread(false);
+
        OSStatus result = errSecSuccess;
        CFIndex ix, count = CFArrayGetCount(items);
        for (ix=0; ix < count; ix++) {
@@ -5277,6 +5342,8 @@ SecItemUpdate_osx(
                }
        }
 
+    setCountLegacyAPIEnabledForThread(true);
+
        if (items) {
                CFRelease(items);
        }
@@ -5305,6 +5372,8 @@ SecItemDelete_osx(
                CFRelease(results);
        }
 
+    setCountLegacyAPIEnabledForThread(false);
+
        OSStatus result = errSecSuccess;
        CFIndex ix, count = CFArrayGetCount(items);
        for (ix=0; ix < count; ix++) {
@@ -5320,6 +5389,8 @@ SecItemDelete_osx(
                }
        }
 
+    setCountLegacyAPIEnabledForThread(true);
+
        if (items)
                CFRelease(items);