+++ /dev/null
-/*
- * Copyright (c) 2006-2010 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@
- *
- * SecTrustServer.c - certificate trust evaluation engine
- *
- * Created by Michael Brouwer on 12/12/08.
- *
- */
-
-#include <securityd/SecTrustServer.h>
-#include <securityd/SecPolicyServer.h>
-#include <securityd/SecTrustStoreServer.h>
-#include <securityd/SecCAIssuerRequest.h>
-#include <securityd/SecItemServer.h>
-
-#include <utilities/SecIOFormat.h>
-#include <utilities/SecDispatchRelease.h>
-
-#include <Security/SecTrustPriv.h>
-#include <Security/SecItem.h>
-#include <Security/SecCertificateInternal.h>
-#include <Security/SecCertificatePath.h>
-#include <Security/SecFramework.h>
-#include <Security/SecPolicyInternal.h>
-#include <CoreFoundation/CFRuntime.h>
-#include <CoreFoundation/CFSet.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFNumber.h>
-#include <CoreFoundation/CFArray.h>
-#include <CoreFoundation/CFPropertyList.h>
-#include <AssertMacros.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <Security/SecBase.h>
-#include "SecRSAKey.h"
-#include <libDER/oids.h>
-#include <utilities/debugging.h>
-#include <utilities/SecCFWrappers.h>
-#include <Security/SecInternal.h>
-#include "securityd_client.h"
-#include <CommonCrypto/CommonDigest.h>
-#include "OTATrustUtilities.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
-
-/********************************************************
- *************** END OTA Trust support ******************
- ********************************************************/
-
-#define MAX_CHAIN_LENGTH 15
-
-/* Forward declaration for use in SecCertificateSource. */
-static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents);
-
-
-// MARK: -
-// MARK: SecCertificateSource
-/********************************************************
- ************ SecCertificateSource object ***************
- ********************************************************/
-
-typedef struct SecCertificateSource *SecCertificateSourceRef;
-typedef void(*SecCertificateSourceParents)(void *, CFArrayRef);
-typedef bool(*CopyParents)(SecCertificateSourceRef source,
- SecCertificateRef certificate, void *context, SecCertificateSourceParents);
-typedef bool(*Contains)(SecCertificateSourceRef source,
- SecCertificateRef certificate);
-
-struct SecCertificateSource {
- CopyParents copyParents;
- Contains contains;
-};
-
-static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source,
- SecCertificateRef certificate,
- void *context, SecCertificateSourceParents callback) {
- return source->copyParents(source, certificate, context, callback);
-}
-
-static 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 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;
- /* We can make this async or run this on a queue now easily. */
- CFErrorRef localError = NULL;
- if (!_SecItemCopyMatching(query, msource->accessGroups, &results, &localError)) {
- if (CFErrorGetCode(localError) != errSecItemNotFound) {
- secdebug("trust", "_SecItemCopyMatching: %@", localError);
- }
- CFRelease(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;
- /* Lookup a certificate by issuer and serial number. */
- CFDataRef normalizedSubject =
- SecCertificateGetNormalizedSubjectContent(certificate);
- CFDataRef serialNumber =
- SecCertificateCopySerialNumber(certificate);
- const void *keys[] = {
- kSecClass,
- kSecMatchLimit,
- kSecAttrIssuer,
- kSecAttrSerialNumber
- },
- *values[] = {
- kSecClassCertificate,
- kSecMatchLimitOne,
- normalizedSubject,
- serialNumber
- };
- CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 5,
- NULL, NULL);
- CFErrorRef localError = NULL;
- CFTypeRef results = NULL;
- bool ok = _SecItemCopyMatching(query, msource->accessGroups, &results, &localError);
- CFRelease(query);
- CFRelease(serialNumber);
- CFReleaseSafe(results);
- if (!ok) {
- if (CFErrorGetCode(localError) != errSecItemNotFound) {
- secdebug("trust", "_SecItemCopyMatching: %@", localError);
- }
- CFRelease(localError);
- return false;
- }
- return true;
-}
-
-static SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) {
- SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result));
- result->base.copyParents = SecItemCertificateSourceCopyParents;
- result->base.contains = SecItemCertificateSourceContains;
- result->accessGroups = accessGroups;
- CFRetainSafe(accessGroups);
- return (SecCertificateSourceRef)result;
-}
-
-static 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
- return true;
-}
-
-/* Quick thought: we can eliminate this method if we search anchor sources
- before all others and we remember if we got a cert from an anchorsource. */
-static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source,
- SecCertificateRef certificate) {
- bool result = false;
-#ifndef SECITEM_SHIM_OSX
- 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);
-#endif
- return result;
-}
-
-
-
-struct SecCertificateSource kSecSystemAnchorSource = {
- SecSystemAnchorSourceCopyParents,
- SecSystemAnchorSourceContains
-};
-
-// 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 bool SecUserAnchorSourceContains(SecCertificateSourceRef source,
- SecCertificateRef certificate) {
- return SecTrustStoreContains(
- SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate);
-}
-
-struct SecCertificateSource kSecUserAnchorSource = {
- SecUserAnchorSourceCopyParents,
- SecUserAnchorSourceContains
-};
-
-// 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 = CFDictionaryGetValue(msource->subjects,
- normalizedIssuer);
- /* 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);
-}
-
-static SecCertificateSourceRef SecMemoryCertificateSourceCreate(
- CFArrayRef certificates) {
- SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef)
- malloc(sizeof(*result));
- result->base.copyParents = SecMemoryCertificateSourceCopyParents;
- 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;
-}
-
-static 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,
- SecCAIssuerCertificateSourceContains
-};
-
-// MARK: -
-// MARK: SecPathBuilder
-/********************************************************
- *************** SecPathBuilder object ******************
- ********************************************************/
-struct SecPathBuilder {
- dispatch_queue_t queue;
- SecCertificateSourceRef certificateSource;
- SecCertificateSourceRef itemCertificateSource;
- SecCertificateSourceRef anchorSource;
- CFMutableArrayRef anchorSources;
- CFIndex nextParentSource;
- CFMutableArrayRef parentSources;
-
- /* Hashed set of all paths we've constructed so far, used to prevent
- re-considering a path that was already constructed once before.
- Note that this is the only container in which certificatePath
- objects are retained.
- Every certificatePath being considered is always in allPaths and in at
- most one of partialPaths, rejectedPaths, candidatePath or extendedPaths
- all of which don't retain their values. */
- CFMutableSetRef allPaths;
-
- /* No trusted anchor, satisfies the linking to intermediates for all
- policies (unless considerRejected is true). */
- CFMutableArrayRef partialPaths;
- /* No trusted anchor, does not satisfy linking to intermediates for all
- policies. */
- CFMutableArrayRef rejectedPaths;
- /* Trusted anchor, satisfies the policies so far. */
- CFMutableArrayRef candidatePaths;
-
- CFIndex partialIX;
-
- CFArrayRef leafDetails;
-
- CFIndex rejectScore;
-
- bool considerRejected;
- bool considerPartials;
- bool canAccessNetwork;
-
- struct OpaqueSecPVC path;
- SecCertificatePathRef bestPath;
- bool bestPathIsEV;
-
- CFIndex activations;
- bool (*state)(SecPathBuilderRef);
- SecPathBuilderCompleted completed;
- const void *context;
-};
-
-/* State functions. Return false if a async job was scheduled, return
- true to execute the next state. */
-static bool SecPathBuilderGetNext(SecPathBuilderRef builder);
-static bool SecPathBuilderValidatePath(SecPathBuilderRef builder);
-static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder);
-static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder);
-static bool SecPathBuilderReportResult(SecPathBuilderRef builder);
-
-/* Forward declarations. */
-static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder,
- SecCertificateRef certificate);
-
-/* IDEA: policies could be made cabable of replacing incoming anchors and
- anchorsOnly argument values. For example some policies require the
- Apple Inc. CA and not any other anchor. This can be done in
- SecPathBuilderLeafCertificateChecks since this only runs once. */
-static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder,
- SecCertificatePathRef path) {
- CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(
- kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- builder->leafDetails = CFArrayCreate(kCFAllocatorDefault,
- (const void **)&certDetail, 1, &kCFTypeArrayCallBacks);
- CFRelease(certDetail);
- SecPVCRef pvc = &builder->path;
- SecPVCSetPath(pvc, path, builder->leafDetails);
- builder->considerRejected = !SecPVCLeafChecks(pvc);
-}
-
-static void SecPathBuilderInit(SecPathBuilderRef builder,
- CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly,
- CFArrayRef policies, CFAbsoluteTime verifyTime, CFArrayRef accessGroups,
- SecPathBuilderCompleted completed, const void *context) {
- secdebug("alloc", "%p", builder);
- CFAllocatorRef allocator = kCFAllocatorDefault;
-
- builder->queue = dispatch_queue_create("builder", DISPATCH_QUEUE_SERIAL);
-
- builder->nextParentSource = 1;
- builder->considerPartials = false;
- builder->canAccessNetwork = true;
-
- builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL);
- builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL);
- builder->allPaths = CFSetCreateMutable(allocator, 0,
- &kCFTypeSetCallBacks);
-
- builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL);
- builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL);
- builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL);
- builder->partialIX = 0;
-
- /* Init the policy verification context. */
- SecPVCInit(&builder->path, builder, policies, verifyTime);
- builder->bestPath = NULL;
- builder->bestPathIsEV = false;
- builder->rejectScore = 0;
-
- /* Let's create all the certificate sources we might want to use. */
- builder->certificateSource =
- SecMemoryCertificateSourceCreate(certificates);
- if (anchors)
- builder->anchorSource = SecMemoryCertificateSourceCreate(anchors);
- else
- builder->anchorSource = NULL;
-
- /* We always search certificateSource for parents since it includes the
- leaf itself and it might be self signed. */
- CFArrayAppendValue(builder->parentSources, builder->certificateSource);
- if (builder->anchorSource) {
- CFArrayAppendValue(builder->anchorSources, builder->anchorSource);
- }
- builder->itemCertificateSource = SecItemCertificateSourceCreate(accessGroups);
- CFArrayAppendValue(builder->parentSources, builder->itemCertificateSource);
- if (anchorsOnly) {
- /* Add the system and user anchor certificate db to the search list
- if we don't explicitly trust them. */
- CFArrayAppendValue(builder->parentSources, &kSecSystemAnchorSource);
- CFArrayAppendValue(builder->parentSources, &kSecUserAnchorSource);
- } else {
- /* Only add the system and user anchor certificate db to the
- anchorSources if we are supposed to trust them. */
- CFArrayAppendValue(builder->anchorSources, &kSecSystemAnchorSource);
- CFArrayAppendValue(builder->anchorSources, &kSecUserAnchorSource);
- }
- CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);
-
- /* Now let's get the leaf cert and turn it into a path. */
- SecCertificateRef leaf =
- (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0);
- SecCertificatePathRef path = SecCertificatePathCreate(NULL, leaf);
- CFSetAddValue(builder->allPaths, path);
- CFArrayAppendValue(builder->partialPaths, path);
- if (SecPathBuilderIsAnchor(builder, leaf)) {
- SecCertificatePathSetIsAnchored(path);
- CFArrayAppendValue(builder->candidatePaths, path);
- }
- SecPathBuilderLeafCertificateChecks(builder, path);
- CFRelease(path);
-
- builder->activations = 0;
- builder->state = SecPathBuilderGetNext;
- builder->completed = completed;
- builder->context = context;
-}
-
-SecPathBuilderRef SecPathBuilderCreate(CFArrayRef certificates,
- CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies,
- CFAbsoluteTime verifyTime, CFArrayRef accessGroups,
- SecPathBuilderCompleted completed, const void *context) {
- SecPathBuilderRef builder = malloc(sizeof(*builder));
- SecPathBuilderInit(builder, certificates, anchors, anchorsOnly,
- policies, verifyTime, accessGroups, completed, context);
- return builder;
-}
-
-static void SecPathBuilderDestroy(SecPathBuilderRef builder) {
- secdebug("alloc", "%p", builder);
- dispatch_release_null(builder->queue);
- if (builder->anchorSource)
- SecMemoryCertificateSourceDestroy(builder->anchorSource);
- if (builder->certificateSource)
- SecMemoryCertificateSourceDestroy(builder->certificateSource);
- if (builder->itemCertificateSource)
- SecItemCertificateSourceDestroy(builder->itemCertificateSource);
- CFReleaseSafe(builder->anchorSources);
- CFReleaseSafe(builder->parentSources);
- CFReleaseSafe(builder->allPaths);
- CFReleaseSafe(builder->partialPaths);
- CFReleaseSafe(builder->rejectedPaths);
- CFReleaseSafe(builder->candidatePaths);
- CFReleaseSafe(builder->leafDetails);
-
- SecPVCDelete(&builder->path);
-}
-
-bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) {
- return builder->canAccessNetwork;
-}
-
-void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow) {
- if (builder->canAccessNetwork != allow) {
- builder->canAccessNetwork = allow;
- if (allow) {
- secdebug("http", "network access re-enabled by policy");
- /* re-enabling network_access re-adds kSecCAIssuerSource as
- a parent source. */
- CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);
- } else {
- secdebug("http", "network access disabled by policy");
- /* disabling network_access removes kSecCAIssuerSource from
- the list of parent sources. */
- CFIndex ix = CFArrayGetFirstIndexOfValue(builder->parentSources,
- CFRangeMake(0, CFArrayGetCount(builder->parentSources)),
- &kSecCAIssuerSource);
- if (ix >= 0)
- CFArrayRemoveValueAtIndex(builder->parentSources, ix);
- }
- }
-}
-
-static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder,
- SecCertificateRef certificate) {
- /* We always look through all anchor sources. */
- CFIndex count = CFArrayGetCount(builder->anchorSources);
- CFIndex ix;
- for (ix = 0; ix < count; ++ix) {
- SecCertificateSourceRef source = (SecCertificateSourceRef)
- CFArrayGetValueAtIndex(builder->anchorSources, ix);
- if (SecCertificateSourceContains(source, certificate)) {
- return true;
- }
- }
- return false;
-}
-
-/* Return false if path is not a partial, if path was a valid candidate it
- will have been added to builder->candidatePaths, if path was rejected
- by the parent certificate checks (because it's expired or some other
- static chaining check failed) it will have been added to rejectedPaths.
- Return true path if path is a partial. */
-static bool SecPathBuilderIsPartial(SecPathBuilderRef builder,
- SecCertificatePathRef path) {
- SecPVCRef pvc = &builder->path;
- SecPVCSetPath(pvc, path, NULL);
-
- if (!builder->considerRejected && !SecPVCParentCertificateChecks(pvc,
- SecPVCGetCertificateCount(pvc) - 1)) {
- secdebug("trust", "Found rejected path %@", path);
- CFArrayAppendValue(builder->rejectedPaths, path);
- return false;
- }
-
- SecPathVerifyStatus vstatus = SecCertificatePathVerify(path);
- /* Candidate paths with failed signatures are discarded. */
- if (vstatus == kSecPathVerifyFailed) {
- secdebug("trust", "Verify failed for path %@", path);
- return false;
- }
-
- if (vstatus == kSecPathVerifySuccess) {
- /* The signature chain verified sucessfully, now let's find
- out if we have an anchor for path. */
- if (SecCertificatePathIsAnchored(path)) {
- secdebug("trust", "Adding candidate %@", path);
- CFArrayAppendValue(builder->candidatePaths, path);
- return false;
- }
- }
-
- return true;
-}
-
-/* Given the builder, a partial chain partial and the parents array, construct
- a SecCertificatePath for each parent. After discarding previously
- considered paths and paths with cycles, sort out which array each path
- should go in, if any. */
-static void SecPathBuilderProccessParents(SecPathBuilderRef builder,
- SecCertificatePathRef partial, CFArrayRef parents) {
- CFIndex rootIX = SecCertificatePathGetCount(partial) - 1;
- CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0;
- CFIndex parentIX;
- bool is_anchor = SecCertificatePathGetNextSourceIndex(partial) <=
- CFArrayGetCount(builder->anchorSources);
- secdebug("trust", "found %" PRIdCFIndex " candidate %s", num_parents,
- (is_anchor ? "anchors" : "parents"));
- for (parentIX = 0; parentIX < num_parents; ++parentIX) {
- SecCertificateRef parent = (SecCertificateRef)
- CFArrayGetValueAtIndex(parents, parentIX);
- CFIndex ixOfParent = SecCertificatePathGetIndexOfCertificate(partial,
- parent);
- if (ixOfParent != kCFNotFound) {
- /* partial already contains parent. Let's not add the same
- certificate again. */
- if (ixOfParent == rootIX) {
- /* parent is equal to the root of the partial, so partial
- looks to be self issued. */
- SecCertificatePathSetSelfIssued(partial);
- }
- continue;
- }
-
- /* FIXME Add more sanity checks to see that parent really can be
- a parent of partial_root. subjectKeyID == authorityKeyID,
- signature algorithm matches public key algorithm, etc. */
- SecCertificatePathRef path = SecCertificatePathCreate(partial, parent);
- if (!path)
- continue;
- if (!CFSetContainsValue(builder->allPaths, path)) {
- CFSetAddValue(builder->allPaths, path);
- if (is_anchor)
- SecCertificatePathSetIsAnchored(path);
- if (SecPathBuilderIsPartial(builder, path)) {
- /* Insert path right at the current position since it's a new
- candiate partial. */
- CFArrayInsertValueAtIndex(builder->partialPaths,
- ++builder->partialIX, path);
- secdebug("trust", "Adding partial for parent %" PRIdCFIndex "/%" PRIdCFIndex " %@",
- parentIX + 1, num_parents, path);
- }
- secdebug("trust", "found new path %@", path);
- }
- CFRelease(path);
- }
-}
-
-/* Callback for the SecPathBuilderGetNext() functions call to
- SecCertificateSourceCopyParents(). */
-static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) {
- SecPathBuilderRef builder = (SecPathBuilderRef)context;
- SecCertificatePathRef partial = (SecCertificatePathRef)
- CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
- secdebug("async", "%@ parents %@", partial, parents);
- SecPathBuilderProccessParents(builder, partial, parents);
-
- builder->state = SecPathBuilderGetNext;
- SecPathBuilderStep(builder);
-}
-
-static bool SecPathBuilderGetNext(SecPathBuilderRef builder) {
- /* If we have any candidates left to go return those first. */
- if (CFArrayGetCount(builder->candidatePaths)) {
- SecCertificatePathRef path = (SecCertificatePathRef)
- CFArrayGetValueAtIndex(builder->candidatePaths, 0);
- CFArrayRemoveValueAtIndex(builder->candidatePaths, 0);
- secdebug("trust", "SecPathBuilderGetNext returning candidate %@",
- path);
- SecPVCSetPath(&builder->path, path, NULL);
- builder->state = SecPathBuilderValidatePath;
- return true;
- }
-
- /* If we are considering rejected chains we check each rejected path
- with SecPathBuilderIsPartial() which checks the signature chain and
- either drops the path if it's not properly signed, add it as a
- candidate if it has a trusted anchor, or adds it as a partial
- to be considered once we finish considering all the rejects. */
- if (builder->considerRejected) {
- CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths);
- if (rejectedIX) {
- rejectedIX--;
- SecCertificatePathRef path = (SecCertificatePathRef)
- CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX);
- if (SecPathBuilderIsPartial(builder, path)) {
- CFArrayInsertValueAtIndex(builder->partialPaths,
- ++builder->partialIX, path);
- }
- CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX);
-
- /* Keep going until we have moved all rejected partials into
- the regular partials or candidates array. */
- return true;
- }
- }
-
- /* If builder->partialIX is < 0 we have considered all partial chains
- this block must ensure partialIX >= 0 if execution continues past
- it's end. */
- if (builder->partialIX < 0) {
- CFIndex num_sources = CFArrayGetCount(builder->parentSources);
- if (builder->nextParentSource < num_sources) {
- builder->nextParentSource++;
- secdebug("trust", "broading search to %" PRIdCFIndex "/%" PRIdCFIndex " sources",
- builder->nextParentSource, num_sources);
- } else {
- /* We've run out of new sources to consider so let's look at
- rejected chains and after that even consider partials
- directly.
- FIXME we might not want to consider partial paths that
- are subsets of other partial paths, or not consider them
- at all if we already have an anchored reject. */
- if (!builder->considerRejected) {
- builder->considerRejected = true;
- secdebug("trust", "considering rejected paths");
- } else if (!builder->considerPartials) {
- builder->considerPartials = true;
- secdebug("trust", "considering partials");
- } else {
- /* We're all out of options, so we can't produce any more
- candidates. Let's calculate details and return the best
- path we found. */
- builder->state = SecPathBuilderComputeDetails;
- return true;
- }
- }
- builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1;
- secdebug("trust", "re-checking %" PRIdCFIndex " partials", builder->partialIX + 1);
- return true;
- }
-
- /* We know builder->partialIX >= 0 if we get here. */
- SecCertificatePathRef partial = (SecCertificatePathRef)
- CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
- /* Don't try to extend partials anymore once we are in the considerPartials
- state, since at this point every partial has been extended with every
- possible parentSource already. */
- if (builder->considerPartials) {
- --builder->partialIX;
- SecPVCSetPath(&builder->path, partial, NULL);
- builder->state = SecPathBuilderValidatePath;
- return true;
- }
-
- /* Attempt to extend this partial path with another certificate. This
- should give us a list of potential parents to consider. */
- secdebug("trust", "looking for parents of partial %" PRIdCFIndex "/%" PRIdCFIndex ": %@",
- builder->partialIX + 1, CFArrayGetCount(builder->partialPaths),
- partial);
-
- /* Attempt to extend partial, leaving all possible extended versions
- of partial in builder->extendedPaths. */
- CFIndex sourceIX = SecCertificatePathGetNextSourceIndex(partial);
- CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources);
- if (sourceIX < num_anchor_sources + builder->nextParentSource) {
- SecCertificateSourceRef source;
- if (sourceIX < num_anchor_sources) {
- source = (SecCertificateSourceRef)
- CFArrayGetValueAtIndex(builder->anchorSources, sourceIX);
- secdebug("trust", "searching anchor source %" PRIdCFIndex "/%" PRIdCFIndex, sourceIX + 1,
- num_anchor_sources);
- } else {
- CFIndex parentIX = sourceIX - num_anchor_sources;
- source = (SecCertificateSourceRef)
- CFArrayGetValueAtIndex(builder->parentSources, parentIX);
- secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1,
- builder->nextParentSource);
- }
- SecCertificatePathSetNextSourceIndex(partial, sourceIX + 1);
- SecCertificateRef root = SecCertificatePathGetRoot(partial);
- return SecCertificateSourceCopyParents(source, root,
- builder, SecPathBuilderExtendPaths);
- } else {
- --builder->partialIX;
- }
-
- return true;
-}
-
-/* One or more of the policies did not accept the candidate path. */
-static void SecPathBuilderReject(SecPathBuilderRef builder) {
- check(builder);
- SecPVCRef pvc = &builder->path;
-
- builder->state = SecPathBuilderGetNext;
-
- if (builder->bestPathIsEV && !pvc->is_ev) {
- /* We never replace an ev reject with a non ev reject. */
- return;
- }
-
- CFIndex rejectScore = builder->rejectScore;
- CFIndex score = SecCertificatePathScore(builder->path.path,
- SecPVCGetVerifyTime(&builder->path));
-
- /* The current chain is valid for EV, but revocation checking failed. We
- replace any previously accepted or rejected non EV chains with the
- current one. */
- if (pvc->is_ev && !builder->bestPathIsEV) {
- rejectScore = 0;
- }
-
-#if 0
- if (pvc->is_ev) {
- /* Since this means we found a valid ev chain that was revoked,
- we might want to switch directly to the
- SecPathBuilderComputeDetails state here if we think further
- searching for new chains is pointless. For now we'll keep
- going, since we could accept an alternate EV certification
- path that isn't revoked. */
- builder->state = SecPathBuilderComputeDetails;
- }
-#endif
-
- /* Do this last so that changes to rejectScore above will take affect. */
- if (!builder->bestPath || score > rejectScore) {
- if (builder->bestPath) {
- secdebug("reject",
- "replacing %sev %s score: %ld with %sev reject score: %" PRIdCFIndex " %@",
- (builder->bestPathIsEV ? "" : "non "),
- (builder->rejectScore == INTPTR_MAX ? "accept" : "reject"),
- builder->rejectScore,
- (pvc->is_ev ? "" : "non "), (long)score, builder->path.path);
- } else {
- secdebug("reject", "%sev reject score: %" PRIdCFIndex " %@",
- (pvc->is_ev ? "" : "non "), score, builder->path.path);
- }
-
- builder->rejectScore = score;
- builder->bestPath = pvc->path;
- builder->bestPathIsEV = pvc->is_ev;
- } else {
- secdebug("reject", "%sev reject score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@",
- (pvc->is_ev ? "" : "non "), score, rejectScore, builder->path.path);
- }
-}
-
-/* All policies accepted the candidate path. */
-static void SecPathBuilderAccept(SecPathBuilderRef builder) {
- check(builder);
- SecPVCRef pvc = &builder->path;
- if (pvc->is_ev || !builder->bestPathIsEV) {
- secdebug("accept", "replacing %sev accept with %sev %@",
- (builder->bestPathIsEV ? "" : "non "),
- (pvc->is_ev ? "" : "non "), builder->path.path);
- builder->rejectScore = INTPTR_MAX; /* CFIndex is signed long which is INTPTR_T */
- builder->bestPathIsEV = pvc->is_ev;
- builder->bestPath = pvc->path;
- }
-
- /* If we found the best accept we can we want to switch directly to the
- SecPathBuilderComputeDetails state here, since we're done. */
- if (pvc->is_ev || !pvc->optionally_ev)
- builder->state = SecPathBuilderComputeDetails;
- else
- builder->state = SecPathBuilderGetNext;
-}
-
-/* Return true iff a given path satisfies all the specified policies at
- verifyTime. */
-static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) {
- SecPVCRef pvc = &builder->path;
-
- if (builder->considerRejected) {
- SecPathBuilderReject(builder);
- return true;
- }
-
- builder->state = SecPathBuilderDidValidatePath;
- return SecPVCPathChecks(pvc);
-}
-
-static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) {
- SecPVCRef pvc = &builder->path;
- if (pvc->result) {
- SecPathBuilderAccept(builder);
- } else {
- SecPathBuilderReject(builder);
- }
- assert(builder->state != SecPathBuilderDidValidatePath);
- return true;
-}
-
-static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) {
- // foobar
- SecPVCRef pvc = &builder->path;
-#if 0
- if (!builder->caller_wants_details) {
- SecPVCSetPath(pvc, builder->bestPath, NULL);
- pvc->result = builder->rejectScore == INTPTR_MAX;
- builder->state = SecPathBuilderReportResult;
- return true;
- }
-#endif
- CFIndex ix, pathLength = SecCertificatePathGetCount(builder->bestPath);
- CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
- pathLength, builder->leafDetails);
- SecPVCSetPath(pvc, builder->bestPath, details);
- /* Only report on EV stuff if the bestPath actually was valid for EV. */
- pvc->optionally_ev = builder->bestPathIsEV;
- pvc->info = CFDictionaryCreateMutable(kCFAllocatorDefault,
- 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- for (ix = 1; ix < pathLength; ++ix) {
- CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(
- kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CFArrayAppendValue(details, certDetail);
- CFRelease(certDetail);
- SecPVCParentCertificateChecks(pvc, ix);
- SecPVCGrayListedKeyChecks(pvc, ix);
- SecPVCBlackListedKeyChecks(pvc, ix);
- }
- builder->state = SecPathBuilderReportResult;
- bool completed = SecPVCPathChecks(pvc);
-
- /* Reject the certificate if it was accepted before but we failed it now. */
- if (builder->rejectScore == INTPTR_MAX && !pvc->result) {
- builder->rejectScore = 0;
- }
-
- return completed;
-}
-
-static bool SecPathBuilderReportResult(SecPathBuilderRef builder) {
- SecPVCRef pvc = &builder->path;
- if (pvc->info && pvc->is_ev && pvc->result) {
- CFDictionarySetValue(pvc->info, kSecTrustInfoExtendedValidationKey,
- kCFBooleanTrue);
- SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
- CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf);
- if (leafCompanyName) {
- CFDictionarySetValue(pvc->info, kSecTrustInfoCompanyNameKey,
- leafCompanyName);
- CFRelease(leafCompanyName);
- }
- if (pvc->rvcs) {
- CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc);
- if (nextUpdate == 0) {
- CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey,
- kCFBooleanFalse);
- } else {
- CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate);
- CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationValidUntilKey,
- validUntil);
- CFRelease(validUntil);
- CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey,
- kCFBooleanTrue);
- }
- }
- }
-
- /* This will trigger the outer step function to call the completion
- function. */
- builder->state = NULL;
- return false;
-}
-
-/* @function SecPathBuilderStep
- @summary This is the core of the async engine.
- @description Return false iff job is complete, true if a network request
- is pending.
- builder->state is a function pointer which is to be invoked.
- If you call this function from within a builder->state invocation it
- immediately returns true.
- Otherwise the following steps are repeated endlessly (unless a step returns)
- builder->state is invoked. If it returns true and builder->state is still
- non NULL this proccess is repeated.
- If a state returns false, SecPathBuilder will return true
- if builder->state is non NULL.
- If builder->state is NULL then regardless of what the state function returns
- the completion callback will be invoked and the builder will be deallocated.
- */
-bool SecPathBuilderStep(SecPathBuilderRef builder) {
- if (builder->activations) {
- secdebug("async", "activations: %lu returning true",
- builder->activations);
- return true;
- }
-
- secdebug("async", "activations: %lu", builder->activations);
- builder->activations++;
- while (builder->state && builder->state(builder));
- --builder->activations;
-
- if (builder->state) {
- secdebug("async", "waiting for async reply, exiting");
- /* A state returned false, it's waiting for network traffic. Let's
- return. */
- return true;
- }
-
- if (builder->activations) {
- /* There is still at least one other running instance of this builder
- somewhere on the stack, we let that instance take care of sending
- the client a response. */
- return false;
- }
-
- SecTrustResultType result = (builder->rejectScore == INTPTR_MAX
- ? kSecTrustResultUnspecified : kSecTrustResultRecoverableTrustFailure);
-
- secdebug("trust", "completed: %@ details: %@ result: %d",
- builder->bestPath, builder->path.details, result);
-
- if (builder->completed) {
- builder->completed(builder->context, builder->bestPath,
- builder->path.details, builder->path.info, result);
- }
-
- /* Finally, destroy the builder and free it. */
- SecPathBuilderDestroy(builder);
- free(builder);
-
- return false;
-}
-
-dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) {
- return builder->queue;
-}
-
-// MARK: -
-// MARK: SecTrustServer
-/********************************************************
- ****************** SecTrustServer **********************
- ********************************************************/
-
-typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error);
-
-static void
-SecTrustServerEvaluateCompleted(const void *userData,
- SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info,
- SecTrustResultType result) {
- SecTrustServerEvaluationCompleted evaluated = (SecTrustServerEvaluationCompleted)userData;
- evaluated(result, details, info, chain, NULL);
- Block_release(evaluated);
-}
-
-void
-SecTrustServerEvaluateBlock(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)) {
- SecTrustServerEvaluationCompleted userData = Block_copy(evaluated);
- /* Call the actual evaluator function. */
- SecPathBuilderRef builder = SecPathBuilderCreate(certificates, anchors,
- anchorsOnly, policies,
- verifyTime, accessGroups,
- SecTrustServerEvaluateCompleted, userData);
- dispatch_async(builder->queue, ^{ SecPathBuilderStep(builder); });
-}
-
-
-// NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly
-SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *pdetails, CFDictionaryRef *pinfo, SecCertificatePathRef *pchain, CFErrorRef *perror) {
- dispatch_semaphore_t done = dispatch_semaphore_create(0);
- __block SecTrustResultType result = kSecTrustResultInvalid;
- SecTrustServerEvaluateBlock(certificates, anchors, anchorsOnly, policies, verifyTime, accessGroups, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error) {
- result = tr;
- if (tr == kSecTrustResultInvalid) {
- if (perror) {
- *perror = error;
- CFRetainSafe(error);
- }
- } else {
- if (pdetails) {
- *pdetails = details;
- CFRetainSafe(details);
- }
- if (pinfo) {
- *pinfo = info;
- CFRetainSafe(info);
- }
- if (pchain) {
- *pchain = chain;
- CFRetainSafe(chain);
- }
- }
- dispatch_semaphore_signal(done);
- });
- dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
-
- return result;
-}