/*
- * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2019 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
#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 <AssertMacros.h>
#include <syslog.h>
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,
// 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<CFTypeRef> keys(itemsInDictionary);
+ std::vector<CFTypeRef> 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;
// 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<SecKeychainAttrType> tags(itemsInDictionary);
+ std::vector<ItemRepresentation> types(itemsInDictionary);
for (i = 0; i < itemsInDictionary; ++i)
{
- CFTypeRef key = keysPtr[i];
+ CFTypeRef key = keys[i];
int j;
for (j = 0; j < infoNumItems; ++j)
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;
}
// [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);
// 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;
SecTrustResultType trustResult;
Boolean needChain = false;
+ Boolean needCSEKU = false;
OSStatus status;
if (!policy || !cert) return errSecParam;
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;
}
}
//
// 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;
}
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);
}
}
/* 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);
/* 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);
}
/* 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;
}
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;
}
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;
}
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);
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;
}