]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/securityd/SecCertificateSource.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / sec / securityd / SecCertificateSource.c
diff --git a/OSX/sec/securityd/SecCertificateSource.c b/OSX/sec/securityd/SecCertificateSource.c
new file mode 100644 (file)
index 0000000..76811f4
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) 2016 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@
+ *
+ * SecCertificateSource.c - certificate sources for trust evaluation engine
+ *
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <AssertMacros.h>
+
+#include <CommonCrypto/CommonDigest.h>
+
+#include <Security/SecCertificate.h>
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecItem.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecPolicyInternal.h>
+
+#include <utilities/debugging.h>
+#include <utilities/SecCFWrappers.h>
+
+#include <securityd/SecTrustServer.h>
+#include <securityd/SecItemServer.h>
+#include <securityd/SecTrustStoreServer.h>
+#include <securityd/SecCAIssuerRequest.h>
+
+#include "OTATrustUtilities.h"
+#include "SecCertificateSource.h"
+
+/********************************************************
+ ***************** OTA Trust support ********************
+ ********************************************************/
+
+
+//#ifndef SECITEM_SHIM_OSX
+
+static CFArrayRef subject_to_anchors(CFDataRef nic);
+static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets);
+
+static CFArrayRef subject_to_anchors(CFDataRef nic)
+{
+    CFArrayRef result = NULL;
+
+    if (NULL == nic)
+    {
+        return result;
+    }
+
+    SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
+    if (NULL == otapkiref)
+    {
+        return result;
+    }
+
+    CFDictionaryRef lookupTable = SecOTAPKICopyAnchorLookupTable(otapkiref);
+    CFRelease(otapkiref);
+
+    if (NULL == lookupTable)
+    {
+        return result;
+    }
+
+    unsigned char subject_digest[CC_SHA1_DIGEST_LENGTH];
+    memset(subject_digest, 0, CC_SHA1_DIGEST_LENGTH);
+
+    (void)CC_SHA1(CFDataGetBytePtr(nic), (CC_LONG)CFDataGetLength(nic), subject_digest);
+    CFDataRef sha1Digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subject_digest, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
+
+
+    result = (CFArrayRef)CFDictionaryGetValue(lookupTable, sha1Digest);
+    CFReleaseSafe(lookupTable);
+    CFReleaseSafe(sha1Digest);
+
+    return result;
+}
+
+static CFArrayRef CopyCertDataFromIndices(CFArrayRef offsets)
+{
+    CFMutableArrayRef result = NULL;
+
+    SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
+    if (NULL == otapkiref)
+    {
+        return result;
+    }
+
+    const char* anchorTable = SecOTAPKIGetAnchorTable(otapkiref);
+    if (NULL == anchorTable)
+    {
+        CFReleaseSafe(otapkiref);
+        return result;
+    }
+
+    CFIndex num_offsets = CFArrayGetCount(offsets);
+
+    result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+    for (CFIndex idx = 0; idx < num_offsets; idx++)
+    {
+        CFNumberRef offset = (CFNumberRef)CFArrayGetValueAtIndex(offsets, idx);
+        uint32_t offset_value = 0;
+        if (CFNumberGetValue(offset, kCFNumberSInt32Type, &offset_value))
+        {
+            char* pDataPtr = (char *)(anchorTable + offset_value);
+            //int32_t record_length = *((int32_t * )pDataPtr);
+            //record_length = record_length;
+            pDataPtr += sizeof(uint32_t);
+
+            int32_t cert_data_length = *((int32_t * )pDataPtr);
+            pDataPtr += sizeof(uint32_t);
+
+            CFDataRef cert_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)pDataPtr,
+                                                              cert_data_length, kCFAllocatorNull);
+            if (NULL != cert_data)
+            {
+                CFArrayAppendValue(result, cert_data);
+                CFReleaseSafe(cert_data);
+            }
+        }
+    }
+    CFReleaseSafe(otapkiref);
+    return result;
+}
+
+static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets)
+{
+    CFMutableArrayRef result = NULL;
+
+    CFArrayRef cert_data_array = CopyCertDataFromIndices(offsets);
+
+    if (NULL != cert_data_array)
+    {
+        result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+        CFIndex num_cert_datas = CFArrayGetCount(cert_data_array);
+        for (CFIndex idx = 0; idx < num_cert_datas; idx++)
+        {
+            CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_data_array, idx);
+            if (NULL != cert_data)
+            {
+                SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_data);
+                if (NULL != cert)
+                {
+                    CFArrayAppendValue(result, cert);
+                    CFRelease(cert);
+                }
+            }
+        }
+        CFRelease(cert_data_array);
+    }
+    return result;
+
+}
+//#endif // SECITEM_SHIM_OSX
+
+/********************************************************
+ *************** END OTA Trust support ******************
+ ********************************************************/
+
+/********************************************************
+ ************ SecCertificateSource object ***************
+ ********************************************************/
+
+bool SecCertificateSourceCopyParents(SecCertificateSourceRef source,
+                                     SecCertificateRef certificate,
+                                     void *context, SecCertificateSourceParents callback) {
+    return source->copyParents(source, certificate, context, callback);
+}
+
+CFArrayRef SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source,
+                                                    SecCertificateRef certificate) {
+    if (source->copyUsageConstraints) {
+        return source->copyUsageConstraints(source, certificate);
+    } else {
+        return NULL;
+    }
+}
+
+bool SecCertificateSourceContains(SecCertificateSourceRef source,
+                                  SecCertificateRef certificate) {
+    return source->contains(source, certificate);
+}
+
+// MARK: -
+// MARK: SecItemCertificateSource
+/********************************************************
+ *********** SecItemCertificateSource object ************
+ ********************************************************/
+struct SecItemCertificateSource {
+    struct SecCertificateSource base;
+    CFArrayRef accessGroups;
+};
+typedef struct SecItemCertificateSource *SecItemCertificateSourceRef;
+
+static CF_RETURNS_RETAINED CFTypeRef SecItemCertificateSourceResultsPost(CFTypeRef raw_results) {
+    if (isArray(raw_results)) {
+        CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks);
+        CFArrayForEach(raw_results, ^(const void *value) {
+            SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value);
+            if (cert) {
+                CFArrayAppendValue(result, cert);
+                CFRelease(cert);
+            }
+        });
+        return result;
+    } else if (isData(raw_results)) {
+        return SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results);
+    }
+    return NULL;
+}
+
+static bool SecItemCertificateSourceCopyParents(
+                                                SecCertificateSourceRef source, SecCertificateRef certificate,
+                                                void *context, SecCertificateSourceParents callback) {
+    SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
+    /* FIXME: Search for things other than just subject of our issuer if we
+     have a subjectID or authorityKeyIdentifier. */
+    CFDataRef normalizedIssuer =
+    SecCertificateGetNormalizedIssuerContent(certificate);
+    const void *keys[] = {
+        kSecClass,
+        kSecReturnData,
+        kSecMatchLimit,
+        kSecAttrSubject
+    },
+    *values[] = {
+        kSecClassCertificate,
+        kCFBooleanTrue,
+        kSecMatchLimitAll,
+        normalizedIssuer
+    };
+    CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4,
+                                               NULL, NULL);
+    CFTypeRef results = NULL;
+    SecurityClient client = {
+        .task = NULL,
+        .accessGroups = msource->accessGroups,
+        .allowSystemKeychain = true,
+        .allowSyncBubbleKeychain = false,
+        .isNetworkExtension = false,
+    };
+
+    /* We can make this async or run this on a queue now easily. */
+    CFErrorRef localError = NULL;
+    if (!_SecItemCopyMatching(query, &client, &results, &localError)) {
+        if (localError && (CFErrorGetCode(localError) != errSecItemNotFound)) {
+            secdebug("trust", "_SecItemCopyMatching: %@", localError);
+        }
+        CFReleaseSafe(localError);
+    }
+    CFRelease(query);
+    CFTypeRef certs = SecItemCertificateSourceResultsPost(results);
+    CFReleaseSafe(results);
+    callback(context, certs);
+    CFReleaseSafe(certs);
+    return true;
+}
+
+static bool SecItemCertificateSourceContains(SecCertificateSourceRef source,
+                                             SecCertificateRef certificate) {
+    SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
+    /* Look up a certificate by issuer and serial number. */
+    CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate);
+    CFRetainSafe(normalizedIssuer);
+    CFDataRef serialNumber =
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+    SecCertificateCopySerialNumber(certificate, NULL);
+#else
+    SecCertificateCopySerialNumber(certificate);
+#endif
+    const void *keys[] = {
+        kSecClass,
+        kSecMatchLimit,
+        kSecAttrIssuer,
+        kSecAttrSerialNumber
+    },
+    *values[] = {
+        kSecClassCertificate,
+        kSecMatchLimitOne,
+        normalizedIssuer,
+        serialNumber
+    };
+    SecurityClient client = {
+        .task = NULL,
+        .accessGroups = msource->accessGroups,
+        .allowSystemKeychain = true,
+        .allowSyncBubbleKeychain = false,
+        .isNetworkExtension = false,
+    };
+    CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL);
+    CFErrorRef localError = NULL;
+    CFTypeRef results = NULL;
+    bool ok = _SecItemCopyMatching(query, &client, &results, &localError);
+    CFReleaseSafe(query);
+    CFReleaseSafe(serialNumber);
+    CFReleaseSafe(normalizedIssuer);
+    CFReleaseSafe(results);
+    if (!ok) {
+        if (CFErrorGetCode(localError) != errSecItemNotFound) {
+            secdebug("trust", "_SecItemCopyMatching: %@", localError);
+        }
+        CFReleaseSafe(localError);
+        return false;
+    }
+    return true;
+}
+
+SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) {
+    SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result));
+    result->base.copyParents = SecItemCertificateSourceCopyParents;
+    result->base.copyUsageConstraints = NULL;
+    result->base.contains = SecItemCertificateSourceContains;
+    result->accessGroups = accessGroups;
+    CFRetainSafe(accessGroups);
+    return (SecCertificateSourceRef)result;
+}
+
+void SecItemCertificateSourceDestroy(SecCertificateSourceRef source) {
+    SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
+    CFReleaseSafe(msource->accessGroups);
+    free(msource);
+}
+
+// MARK: -
+// MARK: SecSystemAnchorSource
+/********************************************************
+ *********** SecSystemAnchorSource object ************
+ ********************************************************/
+
+static bool SecSystemAnchorSourceCopyParents(
+                                             SecCertificateSourceRef source, SecCertificateRef certificate,
+                                             void *context, SecCertificateSourceParents callback) {
+    //#ifndef SECITEM_SHIM_OSX
+    CFArrayRef parents = NULL;
+    CFArrayRef anchors = NULL;
+    SecOTAPKIRef otapkiref = NULL;
+
+    CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate);
+    /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
+     It does not matter since we would be returning the wrong anchors */
+    assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */
+
+    otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
+    require_quiet(otapkiref, errOut);
+    anchors = subject_to_anchors(nic);
+    require_quiet(anchors, errOut);
+    parents = CopyCertsFromIndices(anchors);
+
+errOut:
+    callback(context, parents);
+    CFReleaseSafe(parents);
+    CFReleaseSafe(otapkiref);
+    //#endif // SECITEM_SHIM_OSX
+    return true;
+}
+
+static CFArrayRef SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSourceRef __unused source,
+                                                            SecCertificateRef __unused certificate)
+{
+    CFMutableArrayRef result = NULL;
+    CFMutableDictionaryRef options = NULL, hashConstraint = NULL, trustRoot = NULL;
+    CFNumberRef trustResult = NULL;
+
+    require_quiet(options = CFDictionaryCreateMutable(NULL, 1,
+                                                      &kCFTypeDictionaryKeyCallBacks,
+                                                      &kCFTypeDictionaryValueCallBacks),
+                  out);
+    require_quiet(hashConstraint = CFDictionaryCreateMutable(NULL, 1,
+                                                             &kCFTypeDictionaryKeyCallBacks,
+                                                             &kCFTypeDictionaryValueCallBacks),
+                  out);
+    require_quiet(trustRoot = CFDictionaryCreateMutable(NULL, 1,
+                                                        &kCFTypeDictionaryKeyCallBacks,
+                                                        &kCFTypeDictionaryValueCallBacks),
+                  out);
+
+    uint32_t temp = kSecTrustSettingsResultTrustRoot;
+    require_quiet(trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &temp), out);
+    CFDictionaryAddValue(trustRoot, kSecTrustSettingsResult, trustResult);
+
+    CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue);
+    CFDictionaryAddValue(hashConstraint, kSecTrustSettingsPolicyOptions, options);
+
+    require_quiet(result = CFArrayCreateMutable(NULL, 2, &kCFTypeArrayCallBacks), out);
+    CFArrayAppendValue(result, hashConstraint);
+    CFArrayAppendValue(result, trustRoot);
+
+out:
+    CFReleaseNull(options);
+    CFReleaseNull(trustResult);
+    CFReleaseNull(trustRoot);
+    CFReleaseNull(hashConstraint);
+    return result;
+}
+
+static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source,
+                                          SecCertificateRef certificate) {
+    bool result = false;
+    CFArrayRef anchors = NULL;
+    SecOTAPKIRef otapkiref = NULL;
+    CFArrayRef cert_datas = NULL;
+
+    CFDataRef nic = SecCertificateGetNormalizedSubjectContent(certificate);
+    /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
+     It does not matter since we would be returning the wrong anchors */
+    assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */
+
+    otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
+    require_quiet(otapkiref, errOut);
+    anchors = subject_to_anchors(nic);
+    require_quiet(anchors, errOut);
+    cert_datas = CopyCertDataFromIndices(anchors);
+    require_quiet(cert_datas, errOut);
+
+    CFIndex cert_length = SecCertificateGetLength(certificate);
+    const UInt8 *cert_data_ptr = SecCertificateGetBytePtr(certificate);
+
+    CFIndex num_cert_datas = CFArrayGetCount(cert_datas);
+    for (CFIndex idx = 0; idx < num_cert_datas; idx++)
+    {
+        CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, idx);
+
+        if (NULL != cert_data)
+        {
+            if (CFGetTypeID(cert_data) == CFDataGetTypeID())
+            {
+                CFIndex  aCert_Length = CFDataGetLength(cert_data);
+                const UInt8*  aCert_Data_Ptr = CFDataGetBytePtr(cert_data);
+
+                if (aCert_Length == cert_length)
+                {
+                    if (!memcmp(cert_data_ptr, aCert_Data_Ptr, cert_length))
+                    {
+                        result = true;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+errOut:
+    CFReleaseSafe(cert_datas);
+    CFReleaseSafe(otapkiref);
+    return result;
+}
+
+struct SecCertificateSource _kSecSystemAnchorSource = {
+    SecSystemAnchorSourceCopyParents,
+    SecSystemAnchorSourceCopyUsageConstraints,
+    SecSystemAnchorSourceContains
+};
+
+const SecCertificateSourceRef kSecSystemAnchorSource = &_kSecSystemAnchorSource;
+
+
+#if TARGET_OS_IPHONE
+// MARK: -
+// MARK: SecUserAnchorSource
+/********************************************************
+ ************* SecUserAnchorSource object ***************
+ ********************************************************/
+static bool SecUserAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate,
+                                           void *context, SecCertificateSourceParents callback) {
+    CFArrayRef parents = SecTrustStoreCopyParents(SecTrustStoreForDomain(kSecTrustStoreDomainUser),
+                                                  certificate, NULL);
+    callback(context, parents);
+    CFReleaseSafe(parents);
+    return true;
+}
+
+static CFArrayRef SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source,
+                                                          SecCertificateRef certificate) {
+    CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
+    if (!digest)
+        return NULL;
+    CFArrayRef usageConstraints = NULL;
+    bool ok = _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser),
+                                                 digest, &usageConstraints, NULL);
+    return (ok) ? usageConstraints : NULL;
+}
+
+static bool SecUserAnchorSourceContains(SecCertificateSourceRef source,
+                                        SecCertificateRef certificate) {
+    return SecTrustStoreContains(SecTrustStoreForDomain(kSecTrustStoreDomainUser),
+                                 certificate);
+}
+
+struct SecCertificateSource _kSecUserAnchorSource = {
+    SecUserAnchorSourceCopyParents,
+    SecUserAnchorSourceCopyUsageConstraints,
+    SecUserAnchorSourceContains
+};
+
+const SecCertificateSourceRef kSecUserAnchorSource = &_kSecUserAnchorSource;
+#endif
+
+// MARK: -
+// MARK: SecMemoryCertificateSource
+/********************************************************
+ ********** SecMemoryCertificateSource object ***********
+ ********************************************************/
+struct SecMemoryCertificateSource {
+    struct SecCertificateSource base;
+    CFMutableSetRef certificates;
+    CFMutableDictionaryRef subjects;
+};
+typedef struct SecMemoryCertificateSource *SecMemoryCertificateSourceRef;
+
+static bool SecMemoryCertificateSourceCopyParents(
+                                                  SecCertificateSourceRef source, SecCertificateRef certificate,
+                                                  void *context, SecCertificateSourceParents callback) {
+    SecMemoryCertificateSourceRef msource =
+    (SecMemoryCertificateSourceRef)source;
+    CFDataRef normalizedIssuer =
+    SecCertificateGetNormalizedIssuerContent(certificate);
+    CFArrayRef parents = (normalizedIssuer) ? CFDictionaryGetValue(msource->subjects,
+                                                                   normalizedIssuer) : NULL;
+    /* FIXME filter parents by subjectID if certificate has an
+     authorityKeyIdentifier. */
+    secdebug("trust", "%@ parents -> %@", certificate, parents);
+    callback(context, parents);
+    return true;
+}
+
+static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source,
+                                               SecCertificateRef certificate) {
+    SecMemoryCertificateSourceRef msource =
+    (SecMemoryCertificateSourceRef)source;
+    return CFSetContainsValue(msource->certificates, certificate);
+}
+
+static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict,
+                                      const void *key, const void *value) {
+    if (!key)
+        return;
+
+    CFMutableArrayRef values =
+    (CFMutableArrayRef)CFDictionaryGetValue(dict, key);
+    if (!values) {
+        values = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+                                      &kCFTypeArrayCallBacks);
+        CFDictionaryAddValue(dict, key, values);
+        CFRelease(values);
+    }
+
+    if (values)
+        CFArrayAppendValue(values, value);
+}
+
+static void SecMemoryCertificateSourceApplierFunction(const void *value,
+                                                      void *context) {
+    SecMemoryCertificateSourceRef msource =
+    (SecMemoryCertificateSourceRef)context;
+    SecCertificateRef certificate = (SecCertificateRef)value;
+
+    /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
+    if (CFSetContainsValue(msource->certificates, certificate))
+        return;
+    CFSetAddValue(msource->certificates, certificate);
+
+    CFDataRef key = SecCertificateGetNormalizedSubjectContent(certificate);
+    dictAddValueToArrayForKey(msource->subjects, key, value);
+}
+
+SecCertificateSourceRef SecMemoryCertificateSourceCreate(CFArrayRef certificates) {
+    SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef)
+    malloc(sizeof(*result));
+    result->base.copyParents = SecMemoryCertificateSourceCopyParents;
+    result->base.copyUsageConstraints = NULL;
+    result->base.contains = SecMemoryCertificateSourceContains;
+    CFIndex count = CFArrayGetCount(certificates);
+    result->certificates = CFSetCreateMutable(kCFAllocatorDefault, count,
+                                              &kCFTypeSetCallBacks);
+    result->subjects = CFDictionaryCreateMutable(kCFAllocatorDefault,
+                                                 count, &kCFTypeDictionaryKeyCallBacks,
+                                                 &kCFTypeDictionaryValueCallBacks);
+    CFRange range = { 0, count };
+    CFArrayApplyFunction(certificates, range,
+                         SecMemoryCertificateSourceApplierFunction, result);
+
+    return (SecCertificateSourceRef)result;
+}
+
+void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source) {
+    SecMemoryCertificateSourceRef msource =
+    (SecMemoryCertificateSourceRef)source;
+    CFRelease(msource->certificates);
+    CFRelease(msource->subjects);
+    free(msource);
+}
+
+// MARK: -
+// MARK: SecCAIssuerCertificateSource
+/********************************************************
+ ********* SecCAIssuerCertificateSource object **********
+ ********************************************************/
+static bool SecCAIssuerCertificateSourceCopyParents(
+                                                    SecCertificateSourceRef source, SecCertificateRef certificate,
+                                                    void *context, SecCertificateSourceParents callback) {
+    return SecCAIssuerCopyParents(certificate, SecPathBuilderGetQueue((SecPathBuilderRef)context), context, callback);
+}
+
+static bool SecCAIssuerCertificateSourceContains(
+                                                 SecCertificateSourceRef source, SecCertificateRef certificate) {
+    return false;
+}
+
+struct SecCertificateSource _kSecCAIssuerSource = {
+    SecCAIssuerCertificateSourceCopyParents,
+    NULL,
+    SecCAIssuerCertificateSourceContains
+};
+
+const SecCertificateSourceRef kSecCAIssuerSource = &_kSecCAIssuerSource;
+
+#if TARGET_OS_OSX
+#include <Security/SecItemPriv.h>
+// MARK: -
+// MARK: SecLegacyCertificateSource
+/********************************************************
+ ********** SecLegacyCertificateSource object ***********
+ ********************************************************/
+
+static bool SecLegacyCertificateSourceCopyParents(
+                                                  SecCertificateSourceRef source, SecCertificateRef certificate,
+                                                  void *context, SecCertificateSourceParents callback) {
+    CFArrayRef parents = SecItemCopyParentCertificates(certificate, NULL);
+    callback(context, parents);
+    CFReleaseSafe(parents);
+    return true;
+}
+
+static bool SecLegacyCertificateSourceContains(
+                                               SecCertificateSourceRef source, SecCertificateRef certificate) {
+    SecCertificateRef cert = SecItemCopyStoredCertificate(certificate, NULL);
+    bool result = (cert) ? true : false;
+    CFReleaseSafe(cert);
+    return result;
+}
+
+struct SecCertificateSource _kSecLegacyCertificateSource = {
+    SecLegacyCertificateSourceCopyParents,
+    NULL,
+    SecLegacyCertificateSourceContains
+};
+
+const SecCertificateSourceRef kSecLegacyCertificateSource = &_kSecLegacyCertificateSource;
+
+#endif /* SecLegacyCertificateSource */
+
+#if TARGET_OS_OSX
+// MARK: -
+// MARK: SecLegacyAnchorSource
+/********************************************************
+ ************ SecLegacyAnchorSource object **************
+ ********************************************************/
+
+static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate,
+                                             void *context, SecCertificateSourceParents callback) {
+    CFMutableArrayRef anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+    CFArrayRef parents = SecItemCopyParentCertificates(certificate, NULL);
+    CFArrayRef trusted = NULL;
+    if (parents == NULL) {
+        goto finish;
+    }
+    /* Get the custom anchors which have been trusted in the user and admin domains.
+     * We don't need system domain roots here, since SecSystemAnchorSource provides those.
+     */
+    OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
+    if (status == errSecSuccess && trusted) {
+        CFIndex index, count = CFArrayGetCount(parents);
+        for (index = 0; index < count; index++) {
+            SecCertificateRef parent = (SecCertificateRef)CFArrayGetValueAtIndex(parents, index);
+            if (parent && CFArrayContainsValue(trusted, CFRangeMake(0, CFArrayGetCount(trusted)), parent)) {
+                CFArrayAppendValue(anchors, parent);
+            }
+        }
+    }
+
+finish:
+    callback(context, anchors);
+    CFReleaseSafe(anchors);
+    CFReleaseSafe(parents);
+    CFReleaseSafe(trusted);
+    return true;
+}
+
+static CFArrayRef SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source,
+                                                            SecCertificateRef certificate) {
+    CFArrayRef result = NULL;
+    CFArrayRef userTrustSettings = NULL, adminTrustSettings = NULL;
+
+    OSStatus status = SecTrustSettingsCopyTrustSettings(certificate,
+                                                        kSecTrustSettingsDomainUser,
+                                                        &userTrustSettings);
+    if ((status == errSecSuccess) && (userTrustSettings != NULL)) {
+        result = CFRetain(userTrustSettings);
+    }
+
+    status = SecTrustSettingsCopyTrustSettings(certificate,
+                                               kSecTrustSettingsDomainAdmin,
+                                               &adminTrustSettings);
+    /* user trust settings overrule admin trust settings */
+    if ((status == errSecSuccess) && (adminTrustSettings != NULL) && (result == NULL)) {
+        result = CFRetain(adminTrustSettings);
+    }
+
+    CFReleaseNull(userTrustSettings);
+    CFReleaseNull(adminTrustSettings);
+    return result;
+}
+
+static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source,
+                                          SecCertificateRef certificate) {
+    if (certificate == NULL) {
+        return false;
+    }
+    CFArrayRef trusted = NULL;
+    bool result = false;
+    OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
+    if ((status == errSecSuccess) && (trusted != NULL)) {
+        CFIndex index, count = CFArrayGetCount(trusted);
+        for (index = 0; index < count; index++) {
+            SecCertificateRef anchor = (SecCertificateRef)CFArrayGetValueAtIndex(trusted, index);
+            if (anchor && CFEqual(anchor, certificate)) {
+                result = true;
+                break;
+            }
+        }
+    }
+    CFReleaseSafe(trusted);
+    return result;
+}
+
+struct SecCertificateSource _kSecLegacyAnchorSource = {
+    SecLegacyAnchorSourceCopyParents,
+    SecLegacyAnchorSourceCopyUsageConstraints,
+    SecLegacyAnchorSourceContains
+};
+
+const SecCertificateSourceRef kSecLegacyAnchorSource = &_kSecLegacyAnchorSource;
+
+#endif /* SecLegacyAnchorSource */