]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/Security/SecTrust.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrust.c
index 73ee03c6328d8e32470ca9bb38e5dd321a9715eb..6768a0636c4872d5d561481f12333717c6997ec7 100644 (file)
@@ -56,6 +56,7 @@
 #include <utilities/SecCertificateTrace.h>
 #include <utilities/debugging.h>
 #include <utilities/der_plist.h>
+#include <utilities/SecDispatchRelease.h>
 
 #include "SecRSAKey.h"
 #include <libDER/oids.h>
@@ -132,6 +133,9 @@ struct __SecTrust {
      */
     SecTrustResultType      _trustResultBeforeExceptions;
 
+    /* Dispatch queue for thread-safety */
+    dispatch_queue_t        _trustQueue;
+
     /* === IMPORTANT! ===
      * Any change to this structure definition
      * must also be made in the TSecTrust structure,
@@ -154,18 +158,19 @@ static CFStringRef SecTrustCopyFormatDescription(CFTypeRef cf, CFDictionaryRef f
 static void SecTrustDestroy(CFTypeRef cf) {
     SecTrustRef trust = (SecTrustRef)cf;
 
-    CFReleaseSafe(trust->_certificates);
-    CFReleaseSafe(trust->_policies);
-    CFReleaseSafe(trust->_responses);
-    CFReleaseSafe(trust->_SCTs);
-    CFReleaseSafe(trust->_trustedLogs);
-    CFReleaseSafe(trust->_verifyDate);
-    CFReleaseSafe(trust->_anchors);
-    CFReleaseSafe(trust->_chain);
-    CFReleaseSafe(trust->_publicKey);
-    CFReleaseSafe(trust->_details);
-    CFReleaseSafe(trust->_info);
-    CFReleaseSafe(trust->_exceptions);
+    dispatch_release_null(trust->_trustQueue);
+    CFReleaseNull(trust->_certificates);
+    CFReleaseNull(trust->_policies);
+    CFReleaseNull(trust->_responses);
+    CFReleaseNull(trust->_SCTs);
+    CFReleaseNull(trust->_trustedLogs);
+    CFReleaseNull(trust->_verifyDate);
+    CFReleaseNull(trust->_anchors);
+    CFReleaseNull(trust->_chain);
+    CFReleaseNull(trust->_publicKey);
+    CFReleaseNull(trust->_details);
+    CFReleaseNull(trust->_info);
+    CFReleaseNull(trust->_exceptions);
 
     if (trust->_legacy_info_array) {
         free(trust->_legacy_info_array);
@@ -239,6 +244,7 @@ errOut:
         result->_certificates = l_certs;
         result->_policies = l_policies;
         result->_keychainsAllowed = true;
+        result->_trustQueue = dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL);
         if (trust)
             *trust = result;
         else
@@ -247,11 +253,55 @@ errOut:
     return status;
 }
 
+OSStatus SecTrustCopyInputCertificates(SecTrustRef trust, CFArrayRef *certificates) {
+    if (!trust || !certificates) {
+        return errSecParam;
+    }
+    __block CFArrayRef certArray = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        certArray = CFArrayCreateCopy(NULL, trust->_certificates);
+    });
+    if (!certArray) {
+        return errSecAllocate;
+    }
+    *certificates = certArray;
+    return errSecSuccess;
+}
+
+OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef certificates) {
+    if (!trust || !certificates) {
+        return errSecParam;
+    }
+    __block CFMutableArrayRef newCertificates = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        newCertificates = CFArrayCreateMutableCopy(NULL, 0, trust->_certificates);
+    });
+
+    if (isArray(certificates)) {
+        CFArrayAppendArray(newCertificates, certificates,
+                            CFRangeMake(0, CFArrayGetCount(certificates)));
+    } else if (CFGetTypeID(certificates) == SecCertificateGetTypeID()) {
+        CFArrayAppendValue(newCertificates, certificates);
+    } else {
+        CFReleaseNull(newCertificates);
+        return errSecParam;
+    }
+
+    dispatch_sync(trust->_trustQueue, ^{
+        CFReleaseNull(trust->_certificates);
+        trust->_certificates = (CFArrayRef)newCertificates;
+    });
+
+    return errSecSuccess;
+}
+
 static void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
     check(trust);
     if (trust) {
-        trust->_trustResult = kSecTrustResultInvalid;
-        trust->_trustResultBeforeExceptions = kSecTrustResultInvalid;
+        dispatch_sync(trust->_trustQueue, ^{
+            trust->_trustResult = kSecTrustResultInvalid;
+            trust->_trustResultBeforeExceptions = kSecTrustResultInvalid;
+        });
     }
 }
 
@@ -274,9 +324,11 @@ OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust,
     SecTrustSetNeedsEvaluation(trust);
     if (anchorCertificates)
         CFRetain(anchorCertificates);
-    if (trust->_anchors)
-        CFRelease(trust->_anchors);
-    trust->_anchors = anchorCertificates;
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_anchors)
+            CFRelease(trust->_anchors);
+        trust->_anchors = anchorCertificates;
+    });
     trust->_anchorsOnly = (anchorCertificates != NULL);
 
     return errSecSuccess;
@@ -287,13 +339,13 @@ OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust,
        if (!trust|| !anchors) {
                return errSecParam;
        }
-       CFArrayRef anchorsArray = NULL;
-       if (trust->_anchors) {
-               anchorsArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_anchors);
-               if (!anchorsArray) {
-                       return errSecAllocate;
-               }
-       }
+       __block CFArrayRef anchorsArray = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_anchors) {
+            anchorsArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_anchors);
+        }
+    });
+
        *anchors = anchorsArray;
        return errSecSuccess;
 }
@@ -314,10 +366,11 @@ OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) {
             return errSecParam;
         }
     }
-       if (trust->_responses)
-               CFRelease(trust->_responses);
-       trust->_responses = responseArray;
-
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_responses)
+            CFRelease(trust->_responses);
+        trust->_responses = responseArray;
+    });
        return errSecSuccess;
 }
 
@@ -326,8 +379,9 @@ OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef sc
         return errSecParam;
     }
     SecTrustSetNeedsEvaluation(trust);
-    CFRetainAssign(trust->_SCTs, sctArray);
-
+    dispatch_sync(trust->_trustQueue, ^{
+        CFRetainAssign(trust->_SCTs, sctArray);
+    });
     return errSecSuccess;
 }
 
@@ -336,8 +390,9 @@ OSStatus SecTrustSetTrustedLogs(SecTrustRef trust, CFArrayRef trustedLogs) {
         return errSecParam;
     }
     SecTrustSetNeedsEvaluation(trust);
-    CFRetainAssign(trust->_trustedLogs, trustedLogs);
-
+    dispatch_sync(trust->_trustQueue, ^{
+        CFRetainAssign(trust->_trustedLogs, trustedLogs);
+    });
     return errSecSuccess;
 }
 
@@ -347,8 +402,9 @@ OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) {
     }
     SecTrustSetNeedsEvaluation(trust);
     check(verifyDate);
-    CFRetainAssign(trust->_verifyDate, verifyDate);
-
+    dispatch_sync(trust->_trustQueue, ^{
+        CFRetainAssign(trust->_verifyDate, verifyDate);
+    });
     return errSecSuccess;
 }
 
@@ -359,7 +415,7 @@ OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) {
     SecTrustSetNeedsEvaluation(trust);
     check(newPolicies);
 
-    CFArrayRef policyArray = NULL;
+    __block CFArrayRef policyArray = NULL;
     if (CFGetTypeID(newPolicies) == CFArrayGetTypeID()) {
                policyArray = CFArrayCreateCopy(kCFAllocatorDefault, newPolicies);
        } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) {
@@ -369,9 +425,10 @@ OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) {
         return errSecParam;
     }
 
-    if (trust->_policies)
-        CFRelease(trust->_policies);
-    trust->_policies = policyArray;
+    dispatch_sync(trust->_trustQueue, ^{
+        CFReleaseSafe(trust->_policies);
+        trust->_policies = policyArray;
+    });
 
     return errSecSuccess;
 }
@@ -399,10 +456,10 @@ OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) {
        if (!trust|| !policies) {
                return errSecParam;
        }
-       if (!trust->_policies) {
-               return errSecInternal;
-       }
-       CFArrayRef policyArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_policies);
+    __block CFArrayRef policyArray = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        policyArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_policies);
+    });
        if (!policyArray) {
                return errSecAllocate;
        }
@@ -473,30 +530,28 @@ OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch) {
        if (!trust) {
                return errSecParam;
        }
-    if (!trust->_policies) {
-        return errSecInternal;
-    }
-    if (!allowFetch) {
-        return SecTrustSetOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess, kCFBooleanTrue);
-    }
-    else {
-        return SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
-    }
-       return errSecSuccess;
+    __block OSStatus status = errSecSuccess;
+    dispatch_sync(trust->_trustQueue, ^{
+        if (!allowFetch) {
+            status = SecTrustSetOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess, kCFBooleanTrue);
+        } else {
+            status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
+        }
+    });
+       return status;
 }
 
 OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) {
        if (!trust || !allowFetch) {
                return errSecParam;
        }
-    if (!trust->_policies) {
-        return errSecInternal;
-    }
-    CFArrayRef foundValues = NULL;
-    if ((foundValues = SecTrustCopyOptionsFromPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess))) {
+    __block CFArrayRef foundValues = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        foundValues = SecTrustCopyOptionsFromPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
+    });
+    if (foundValues) {
         *allowFetch = false;
-    }
-    else {
+    } else {
         *allowFetch = true;
     }
     CFReleaseNull(foundValues);
@@ -504,16 +559,18 @@ OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch)
 }
 
 CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) {
-    CFAbsoluteTime verifyTime;
-    if (trust && trust->_verifyDate) {
-        verifyTime = CFDateGetAbsoluteTime(trust->_verifyDate);
-    } else {
-        verifyTime = CFAbsoluteTimeGetCurrent();
-               /* Record the verifyDate we ended up using. */
-        if (trust) {
+    __block CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
+    if (!trust) {
+        return verifyTime;
+    }
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_verifyDate) {
+            verifyTime = CFDateGetAbsoluteTime(trust->_verifyDate);
+        } else {
             trust->_verifyDate = CFDateCreate(CFGetAllocator(trust), verifyTime);
         }
-    }
+    });
+
     return verifyTime;
 }
 
@@ -530,22 +587,34 @@ OSStatus SecTrustGetTrustResult(SecTrustRef trust,
        if (!trust || !result) {
                return errSecParam;
        }
-       *result = trust->_trustResult;
+    dispatch_sync(trust->_trustQueue, ^{
+        *result = trust->_trustResult;
+    });
        return errSecSuccess;
 }
 
 static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest");
 
 static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) {
-    if (!trust->_exceptions || ix >= CFArrayGetCount(trust->_exceptions))
-        return NULL;
-    CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_exceptions, ix);
-    if (CFGetTypeID(exception) != CFDictionaryGetTypeID())
-        return NULL;
+    CFDictionaryRef exception = NULL;
+    __block CFArrayRef exceptions = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        exceptions = CFRetainSafe(trust->_exceptions);
+    });
+    if (!exceptions || ix >= CFArrayGetCount(exceptions)) {
+        goto out;
+    }
 
-       SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
-    if (!certificate)
-        return NULL;
+    SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
+    if (!certificate) {
+        goto out;
+    }
+
+    exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
+    if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) {
+        exception = NULL;
+        goto out;
+    }
 
     /* If the exception contains the current certificates sha1Digest in the
        kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
@@ -554,9 +623,66 @@ static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef tru
     if (!digestValue || !CFEqual(sha1Digest, digestValue))
         exception = NULL;
 
+out:
+    CFReleaseSafe(exceptions);
     return exception;
 }
 
+struct SecTrustFilteredDetailContext {
+    CFDictionaryRef exception;
+    CFMutableDictionaryRef filteredDetail;
+};
+
+static void SecTrustFilterDetail(const void *key, const void *value, void *context) {
+    struct SecTrustFilteredDetailContext *ctx = (struct SecTrustFilteredDetailContext *)context;
+    if (!key || !value || !ctx->exception || !ctx->filteredDetail) {
+        return;
+    }
+    if (CFEqual(kSecCertificateDetailSHA1Digest, key)) {
+        return; /* ignore SHA1 hash entry */
+    }
+    CFTypeRef exceptionValue = CFDictionaryGetValue(ctx->exception, key);
+    if (exceptionValue && CFEqual(exceptionValue, value)) {
+        /* both key and value match the exception */
+        CFDictionaryRemoveValue(ctx->filteredDetail, key);
+    }
+}
+
+CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust) {
+    if (!trust) {
+        return NULL;
+    }
+    SecTrustEvaluateIfNecessary(trust);
+    __block CFArrayRef details = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        details = CFRetainSafe(trust->_details);
+    });
+    CFIndex ix, pathLength = details ? CFArrayGetCount(details) : 0;
+    CFMutableArrayRef filteredDetails = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
+    if (!filteredDetails) {
+        CFReleaseNull(details);
+        return NULL;
+    }
+    for (ix = 0; ix < pathLength; ++ix) {
+        CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
+        CFIndex count = (detail) ? CFDictionaryGetCount(detail) : 0;
+        CFMutableDictionaryRef filteredDetail = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, count, detail);
+        CFDictionaryRef exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix);
+        if (exception) {
+            /* for each entry in the detail dictionary, remove from filteredDetail
+               if it also appears in the corresponding exception dictionary. */
+            struct SecTrustFilteredDetailContext context = { exception, filteredDetail };
+            CFDictionaryApplyFunction(detail, SecTrustFilterDetail, &context);
+        }
+        if (filteredDetail) {
+            CFArrayAppendValue(filteredDetails, filteredDetail);
+            CFReleaseSafe(filteredDetail);
+        }
+    }
+    CFReleaseNull(details);
+    return filteredDetails;
+}
+
 struct SecTrustCheckExceptionContext {
     CFDictionaryRef exception;
     bool exceptionNotFound;
@@ -595,24 +721,29 @@ static void SecTrustAddPolicyAnchors(SecTrustRef trust)
        This is used to evaluate test policies where the anchor is not provided
        in the root store and may not be able to be supplied by the caller.
      */
-    CFArrayRef policies = (trust) ? trust->_policies : NULL;
-    if (!policies) {
-        return;
-    }
+    if (!trust) { return; }
+    __block CFArrayRef policies = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        policies = CFRetain(trust->_policies);
+    });
     CFIndex ix, count = CFArrayGetCount(policies);
     for (ix = 0; ix < count; ++ix) {
         SecPolicyRef policy = (SecPolicyRef) CFArrayGetValueAtIndex(policies, ix);
         if (policy) {
                        #if TARGET_OS_IPHONE
             if (CFEqual(policy->_oid, kSecPolicyAppleTestSMPEncryption)) {
-                CFReleaseSafe(trust->_anchors);
-                trust->_anchors = SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC, sizeof(_SEC_TestAppleRootCAECC));
+                __block CFArrayRef policyAnchors = SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC, sizeof(_SEC_TestAppleRootCAECC));
+                dispatch_sync(trust->_trustQueue, ^{
+                    CFReleaseSafe(trust->_anchors);
+                    trust->_anchors = policyAnchors;
+                });
                 trust->_anchorsOnly = true;
                 break;
             }
                        #endif
         }
     }
+    CFReleaseSafe(policies);
 }
 
 
@@ -657,7 +788,7 @@ static void sectrustshow(CFTypeRef obj, const char *context)
 }
 
 static void cert_trust_dump(SecTrustRef trust) {
-       SecCertificateRef leaf = (SecCertificateRef) CFArrayGetValueAtIndex(trust->_certificates, 0);
+       SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
        CFStringRef name = (leaf) ? SecCertificateCopySubjectSummary(leaf) : NULL;
        secerror("leaf \"%@\"", name);
        secerror(": result = %d", (int) trust->_trustResult);
@@ -702,32 +833,48 @@ OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) {
         return status;
     }
     /* post-process trust result based on exceptions */
-    SecTrustResultType trustResult = trust->_trustResult;
+    __block SecTrustResultType trustResult = kSecTrustResultInvalid;
+    dispatch_sync(trust->_trustQueue, ^{
+        trustResult = trust->_trustResult;
+    });
     if (trustResult == kSecTrustResultUnspecified) {
         /* If leaf is in exceptions -> proceed, otherwise unspecified. */
         if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
             trustResult = kSecTrustResultProceed;
     } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
         /* If we have exceptions get details and match to exceptions. */
-        CFIndex pathLength = (trust->_details) ? CFArrayGetCount(trust->_details) : 0;
+        __block CFArrayRef details = NULL;
+        dispatch_sync(trust->_trustQueue, ^{
+            details = CFRetainSafe(trust->_details);
+        });
+        CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
         struct SecTrustCheckExceptionContext context = {};
         CFIndex ix;
         for (ix = 0; ix < pathLength; ++ix) {
-            CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_details, ix);
+            CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
             context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix);
             CFDictionaryApplyFunction(detail, SecTrustCheckException, &context);
             if (context.exceptionNotFound) {
                 break;
             }
         }
-        if (!trust->_exceptions || !CFArrayGetCount(trust->_exceptions)) {
+        CFReleaseSafe(details);
+        __block bool done = false;
+        dispatch_sync(trust->_trustQueue, ^{
+            if (!trust->_exceptions || !CFArrayGetCount(trust->_exceptions)) {
+                done = true;
+            }
+        });
+        if (done) {
             goto DoneCheckingTrust;
         }
         if (!context.exceptionNotFound)
             trustResult = kSecTrustResultProceed;
     }
 DoneCheckingTrust:
-       trust->_trustResult = trustResult;
+    dispatch_sync(trust->_trustQueue, ^{
+        trust->_trustResult = trustResult;
+    });
 
     /* log to syslog when there is a trust failure */
     if (trustResult != kSecTrustResultProceed &&
@@ -749,12 +896,14 @@ DoneCheckingTrust:
 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
        dispatch_queue_t queue, SecTrustCallback result)
 {
+    CFRetainSafe(trust);
        dispatch_async(queue, ^{
                SecTrustResultType trustResult;
                if (errSecSuccess != SecTrustEvaluate(trust, &trustResult)) {
                        trustResult = kSecTrustResultInvalid;
                }
                result(trust, trustResult);
+        CFReleaseSafe(trust);
        });
        return errSecSuccess;
 }
@@ -983,21 +1132,21 @@ static OSStatus SecTrustValidateInput(SecTrustRef trust) {
 
 
 static void SecTrustPostEvaluate(SecTrustRef trust) {
-       if (!trust) { return; }
-
-       CFIndex pathLength = (trust->_details) ? CFArrayGetCount(trust->_details) : 0;
-       CFIndex ix;
-       for (ix = 0; ix < pathLength; ++ix) {
-               CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_details, ix);
-               if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf)) {
-                       trust->_trustResult = kSecTrustResultFatalTrustFailure;
-                       return;
-               }
-               if (CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedKey)) {
-                       trust->_trustResult = kSecTrustResultFatalTrustFailure;
-                       return;
-               }
-       }
+    if (!trust) { return; }
+
+    CFIndex pathLength = (trust->_details) ? CFArrayGetCount(trust->_details) : 0;
+    CFIndex ix;
+    for (ix = 0; ix < pathLength; ++ix) {
+        CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_details, ix);
+        if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf)) {
+            trust->_trustResult = kSecTrustResultFatalTrustFailure;
+            return;
+        }
+        if (CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedKey)) {
+            trust->_trustResult = kSecTrustResultFatalTrustFailure;
+            return;
+        }
+    }
 }
 
 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
@@ -1006,56 +1155,60 @@ static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
     if (!trust)
         return errSecParam;
 
-    if (trust->_trustResult != kSecTrustResultInvalid)
-        return errSecSuccess;
+    __block CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
+    SecTrustAddPolicyAnchors(trust);
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_trustResult != kSecTrustResultInvalid) {
+            result = errSecSuccess;
+            return;
+        }
 
-    trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
+        trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
 
-    CFReleaseNull(trust->_chain);
-    CFReleaseNull(trust->_details);
-    CFReleaseNull(trust->_info);
-    if (trust->_legacy_info_array) {
-        free(trust->_legacy_info_array);
-        trust->_legacy_info_array = NULL;
-    }
-    if (trust->_legacy_status_array) {
-        free(trust->_legacy_status_array);
-        trust->_legacy_status_array = NULL;
-    }
-
-    os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT, ^{
-        SecTrustAddPolicyAnchors(trust);
-        SecTrustValidateInput(trust);
-
-        /* @@@ Consider an optimization where we keep a side dictionary with the SHA1 hash of ever SecCertificateRef we send, so we only send potential duplicates once, and have the server respond with either just the SHA1 hash of a certificate, or the complete certificate in the response depending on whether the client already sent it, so we don't send back certificates to the client it already has. */
-        result = SecOSStatusWith(^bool (CFErrorRef *error) {
-            trust->_trustResult = SECURITYD_XPC(sec_trust_evaluate,
-                                                certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request,
-                                                trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
-                                                trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
-                                                SecTrustGetVerifyTime(trust), SecAccessGroupsGetCurrent(),
-                                                &trust->_details, &trust->_info, &trust->_chain, error);
-            if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
-                SecErrorGetOSStatus(*error) == errSecNotAvailable &&
-                CFArrayGetCount(trust->_certificates)) {
-            /* We failed to talk to securityd.  The only time this should
-               happen is when we are running prior to launchd enabling
-               registration of services.  This currently happens when we
-               are running from the ramdisk.   To make ASR happy we initialize
-               _chain and return success with a failure as the trustResult, to
-               make it seem like we did a cert evaluation, so ASR can extract
-               the public key from the leaf. */
-                trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL);
-                if (error)
-                    CFReleaseNull(*error);
-                return true;
-            }
-            SecTrustPostEvaluate(trust);
-            trust->_trustResultBeforeExceptions = trust->_trustResult;
-            return trust->_trustResult != kSecTrustResultInvalid;
+        CFReleaseNull(trust->_chain);
+        CFReleaseNull(trust->_details);
+        CFReleaseNull(trust->_info);
+        if (trust->_legacy_info_array) {
+            free(trust->_legacy_info_array);
+            trust->_legacy_info_array = NULL;
+        }
+        if (trust->_legacy_status_array) {
+            free(trust->_legacy_status_array);
+            trust->_legacy_status_array = NULL;
+        }
+
+        os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT, ^{
+            SecTrustValidateInput(trust);
+
+            /* @@@ Consider an optimization where we keep a side dictionary with the SHA1 hash of ever SecCertificateRef we send, so we only send potential duplicates once, and have the server respond with either just the SHA1 hash of a certificate, or the complete certificate in the response depending on whether the client already sent it, so we don't send back certificates to the client it already has. */
+            result = SecOSStatusWith(^bool (CFErrorRef *error) {
+                trust->_trustResult = SECURITYD_XPC(sec_trust_evaluate,
+                                                    certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request,
+                                                    trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
+                                                    trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
+                                                    verifyTime, SecAccessGroupsGetCurrent(),
+                                                    &trust->_details, &trust->_info, &trust->_chain, error);
+                if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
+                    SecErrorGetOSStatus(*error) == errSecNotAvailable &&
+                    CFArrayGetCount(trust->_certificates)) {
+                    /* We failed to talk to securityd.  The only time this should
+                     happen is when we are running prior to launchd enabling
+                     registration of services.  This currently happens when we
+                     are running from the ramdisk.   To make ASR happy we initialize
+                     _chain and return success with a failure as the trustResult, to
+                     make it seem like we did a cert evaluation, so ASR can extract
+                     the public key from the leaf. */
+                    trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL);
+                    if (error)
+                        CFReleaseNull(*error);
+                    return true;
+                }
+                SecTrustPostEvaluate(trust);
+                trust->_trustResultBeforeExceptions = trust->_trustResult;
+                return trust->_trustResult != kSecTrustResultInvalid;
+            });
         });
     });
-
     return result;
 }
 
@@ -1067,8 +1220,15 @@ static int compare_strings(const void *a1, const void *a2) {
 }
 
 CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
+    if (!trust) {
+        return NULL;
+    }
     CFMutableStringRef reason = CFStringCreateMutable(NULL, 0);
-    CFArrayRef details = SecTrustGetDetails(trust);
+    SecTrustEvaluateIfNecessary(trust);
+    __block CFArrayRef details = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        details = CFRetainSafe(trust->_details);
+    });
     CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
     for (CFIndex ix = 0; ix < pathLength; ++ix) {
         CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
@@ -1094,10 +1254,11 @@ CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
             CFStringAppend(reason, CFSTR("]"));
         }
     }
+    CFReleaseSafe(details);
     return reason;
 }
 
-#if SECTRUST_OSX
+#if TARGET_OS_OSX
 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
    so we will refer to this one internally as SecTrustCopyPublicKey_ios,
    and call it from SecTrustCopyPublicKey.
@@ -1110,40 +1271,33 @@ SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
     if (!trust) {
         return NULL;
     }
-       if (!trust->_publicKey) {
-        if (!trust->_chain) {
-            /* Trust hasn't been evaluated yet, first attempt to retrieve public key from leaf cert as is. */
-        #if SECTRUST_OSX
-            trust->_publicKey = SecCertificateCopyPublicKey_ios(SecTrustGetCertificateAtIndex(trust, 0));
-        #else
-            trust->_publicKey = SecCertificateCopyPublicKey(SecTrustGetCertificateAtIndex(trust, 0));
-        #endif
-#if 0
-            if (!trust->_publicKey) {
-                /* If this fails, use the passed-in certs in order as if they are a valid cert path,
-                   and attempt to extract the key. */
-                SecCertificatePathRef path;
-                // SecCertificatePathCreateWithArray would have crashed if this code was ever called,
-                // since it expected an array of CFDataRefs, not an array of certificates.
-                path = SecCertificatePathCreateWithArray(trust->_certificates);
-                trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(path, 0);
-                CFRelease(path);
-            }
-#endif
-            if (!trust->_publicKey) {
-                /* Last resort, we evaluate the trust to get a _chain. */
-                SecTrustEvaluateIfNecessary(trust);
-            }
+    __block SecKeyRef publicKey = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_publicKey) {
+            publicKey = CFRetainSafe(trust->_publicKey);
+            return;
         }
-        if (trust->_chain) {
-            trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(trust->_chain, 0);
+        SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
+#if TARGET_OS_OSX
+        trust->_publicKey = SecCertificateCopyPublicKey_ios(leaf);
+#else
+        trust->_publicKey = SecCertificateCopyPublicKey(leaf);
+#endif
+        if (trust->_publicKey) {
+            publicKey = CFRetainSafe(trust->_publicKey);
         }
-       }
-
-       if (trust->_publicKey)
-               CFRetain(trust->_publicKey);
-
-       return trust->_publicKey;
+    });
+    /* If we couldn't get a public key from the leaf cert alone. */
+    if (!publicKey) {
+        SecTrustEvaluateIfNecessary(trust);
+        dispatch_sync(trust->_trustQueue, ^{
+            if (trust->_chain) {
+                trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(trust->_chain, 0);
+                publicKey = CFRetainSafe(trust->_publicKey);
+            }
+        });
+    }
+       return publicKey;
 }
 
 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
@@ -1151,7 +1305,13 @@ CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
         return 0;
     }
     SecTrustEvaluateIfNecessary(trust);
-       return (trust->_chain) ? SecCertificatePathGetCount(trust->_chain) : 1;
+    __block CFIndex certCount = 1;
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_chain) {
+            certCount = SecCertificatePathGetCount(trust->_chain);
+        }
+    });
+       return certCount;
 }
 
 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
@@ -1159,11 +1319,20 @@ SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
     if (!trust) {
         return NULL;
     }
+    __block SecCertificateRef cert = NULL;
     if (ix == 0) {
-        return (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
+        dispatch_sync(trust->_trustQueue, ^{
+            cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
+        });
+        return cert;
     }
     SecTrustEvaluateIfNecessary(trust);
-    return (trust->_chain) ? SecCertificatePathGetCertificateAtIndex(trust->_chain, ix) : NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_chain) {
+            cert = SecCertificatePathGetCertificateAtIndex(trust->_chain, ix);
+        }
+    });
+    return cert;
 }
 
 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
@@ -1171,9 +1340,10 @@ CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
         return NULL;
     }
     SecTrustEvaluateIfNecessary(trust);
-    CFDictionaryRef info = trust->_info;
-    if (info)
-        CFRetain(info);
+    __block CFDictionaryRef info = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        info = CFRetainSafe(trust->_info);
+    });
     return info;
 }
 
@@ -1182,7 +1352,11 @@ CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) {
 }
 
 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
-    CFArrayRef details = SecTrustGetDetails(trust);
+    __block CFArrayRef details = NULL;
+    SecTrustEvaluateIfNecessary(trust);
+    dispatch_sync(trust->_trustQueue, ^{
+        details = CFRetainSafe(trust->_details);
+    });
     CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
     CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
     CFIndex ix;
@@ -1218,7 +1392,7 @@ CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
     CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
         exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
     CFRelease(exceptions);
-
+    CFReleaseSafe(details);
     return encodedExceptions;
 }
 
@@ -1238,20 +1412,24 @@ bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
                exceptions = NULL;
        }
 
-       if (trust->_exceptions && !exceptions) {
-               /* Exceptions are currently set and now we are clearing them. */
-               trust->_trustResult = trust->_trustResultBeforeExceptions;
-       }
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_exceptions && !exceptions) {
+            /* Exceptions are currently set and now we are clearing them. */
+            trust->_trustResult = trust->_trustResultBeforeExceptions;
+        }
 
-       CFReleaseSafe(trust->_exceptions);
-       trust->_exceptions = exceptions;
+        CFReleaseSafe(trust->_exceptions);
+        trust->_exceptions = exceptions;
+    });
 
        /* If there is a valid exception entry for our current leaf we're golden. */
        if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
                return true;
 
        /* The passed in exceptions didn't match our current leaf, so we discard it. */
-       CFReleaseNull(trust->_exceptions);
+    dispatch_sync(trust->_trustQueue, ^{
+        CFReleaseNull(trust->_exceptions);
+    });
        return false;
 }
 
@@ -1449,14 +1627,21 @@ static void appendError(CFMutableArrayRef properties, CFStringRef error) {
     CFReleaseNull(localizedError);
 }
 
-#if SECTRUST_OSX || !TARGET_OS_IPHONE
+#if TARGET_OS_OSX
 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
 CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust)
 #else
 CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
 #endif
 {
-    CFArrayRef details = SecTrustGetDetails(trust);
+    if (!trust) {
+        return NULL;
+    }
+    SecTrustEvaluateIfNecessary(trust);
+    __block CFArrayRef details = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        details = CFRetainSafe(trust->_details);
+    });
     if (!details)
         return NULL;
 
@@ -1506,6 +1691,7 @@ CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
         CFReleaseNull(properties);
     }
 
+    CFReleaseNull(details);
     return properties;
 }
 
@@ -1514,73 +1700,76 @@ CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
        if (!trust) {
                return NULL;
        }
-       CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
+       __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
                        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 
-       // kSecTrustResultDetails (per-cert results)
-       CFArrayRef details = SecTrustGetDetails(trust);
-       if (details) {
-               CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
-       }
+    SecTrustEvaluateIfNecessary(trust);
+    dispatch_sync(trust->_trustQueue, ^{
+        // kSecTrustResultDetails (per-cert results)
+        CFArrayRef details = trust->_details;
+        if (details) {
+            CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
+        }
 
-       // kSecTrustResultValue (overall trust result)
-       CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
-       if (numValue) {
-               CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
-               CFRelease(numValue);
-       }
-       CFDictionaryRef info = trust->_info;
-       if (trust->_trustResult == kSecTrustResultInvalid || !info) {
-               return results; // we have nothing more to add
-       }
+        // kSecTrustResultValue (overall trust result)
+        CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
+        if (numValue) {
+            CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
+            CFRelease(numValue);
+        }
+        CFDictionaryRef info = trust->_info;
+        if (trust->_trustResult == kSecTrustResultInvalid || !info) {
+            return; // we have nothing more to add
+        }
 
-       // kSecTrustEvaluationDate
-       CFDateRef evaluationDate = trust->_verifyDate;
-       if (evaluationDate) {
-               CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
-       }
+        // kSecTrustEvaluationDate
+        CFDateRef evaluationDate = trust->_verifyDate;
+        if (evaluationDate) {
+            CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
+        }
 
-       // kSecTrustCertificateTransparency
-       CFBooleanRef ctValue;
-       if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
-               CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
-       }
+        // kSecTrustCertificateTransparency
+        CFBooleanRef ctValue;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
+        }
 
-    // kSecTrustCertificateTransparencyWhiteList
-    CFBooleanRef ctWhiteListValue;
-    if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyWhiteListKey, (const void **)&ctWhiteListValue)) {
-        CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparencyWhiteList, (const void *)ctWhiteListValue);
-    }
+        // kSecTrustCertificateTransparencyWhiteList
+        CFBooleanRef ctWhiteListValue;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyWhiteListKey, (const void **)&ctWhiteListValue)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparencyWhiteList, (const void *)ctWhiteListValue);
+        }
 
-       // kSecTrustExtendedValidation
-       CFBooleanRef evValue;
-       if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
-               CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
-       }
+        // kSecTrustExtendedValidation
+        CFBooleanRef evValue;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
+        }
 
-       // kSecTrustOrganizationName
-       CFStringRef organizationName;
-       if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
-               CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
-       }
+        // kSecTrustOrganizationName
+        CFStringRef organizationName;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
+        }
 
-       // kSecTrustRevocationChecked
-       CFBooleanRef revocationChecked;
-       if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
-               CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
-       }
+        // kSecTrustRevocationChecked
+        CFBooleanRef revocationChecked;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
+        }
 
-       // kSecTrustRevocationReason
-       CFNumberRef revocationReason;
-       if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
-               CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
-       }
+        // kSecTrustRevocationReason
+        CFNumberRef revocationReason;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
+        }
 
-       // kSecTrustRevocationValidUntilDate
-       CFDateRef validUntilDate;
-       if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
-               CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
-       }
+        // kSecTrustRevocationValidUntilDate
+        CFDateRef validUntilDate;
+        if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
+            CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
+        }
+    });
 
        return results;
 }
@@ -1659,41 +1848,49 @@ OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result)
         return errSecParam;
     }
     OSStatus status = errSecSuccess;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
     if((status = SecTrustValidateInput(trust))) {
         return status;
     }
 
     struct OpaqueSecLeafPVC pvc;
-    SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
-
-    SecLeafPVCInit(&pvc, leaf, trust->_policies, SecTrustGetVerifyTime(trust));
+    SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
+    __block CFArrayRef policies = NULL;
+    dispatch_sync(trust->_trustQueue, ^{
+        policies = CFRetainSafe(trust->_policies);
+    });
+    SecLeafPVCInit(&pvc, leaf, policies, SecTrustGetVerifyTime(trust));
 
     if(!SecLeafPVCLeafChecks(&pvc)) {
-        trust->_trustResult = kSecTrustResultRecoverableTrustFailure;
+        trustResult = kSecTrustResultRecoverableTrustFailure;
     } else {
-        trust->_trustResult = kSecTrustResultUnspecified;
+        trustResult = kSecTrustResultUnspecified;
     }
 
     /* Set other result context information */
-    trust->_details = CFRetainSafe(pvc.details);
-    trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                             &kCFTypeDictionaryKeyCallBacks,
-                                             &kCFTypeDictionaryValueCallBacks);
-    trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL);
+    dispatch_sync(trust->_trustQueue, ^{
+        trust->_trustResult = trustResult;
+        trust->_details = CFRetainSafe(pvc.details);
+        trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                 &kCFTypeDictionaryKeyCallBacks,
+                                                 &kCFTypeDictionaryValueCallBacks);
+        trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL);
+    });
 
     SecLeafPVCDelete(&pvc);
 
     /* log to syslog when there is a trust failure */
-    if (trust->_trustResult != kSecTrustResultUnspecified) {
+    if (trustResult != kSecTrustResultUnspecified) {
         CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
         secerror("%@", failureDesc);
         CFRelease(failureDesc);
     }
 
     if (result) {
-        *result = trust->_trustResult;
+        *result = trustResult;
     }
 
+    CFReleaseSafe(policies);
     return status;
 }
 
@@ -1708,7 +1905,7 @@ static void deserializeCert(const void *value, void *context) {
     }
 }
 
-static CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
+static CF_RETURNS_RETAINED CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
     CFMutableArrayRef result = NULL;
     require_quiet(isArray(serializedCertificates), errOut);
     CFIndex count = CFArrayGetCount(serializedCertificates);
@@ -1742,76 +1939,77 @@ errOut:
 }
 
 static CFPropertyListRef SecTrustCopyPlist(SecTrustRef trust) {
-    CFMutableDictionaryRef output = NULL;
-    CFNumberRef trustResult = NULL;
-
+    __block CFMutableDictionaryRef output = NULL;
     output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks);
-    if (trust->_certificates) {
-        CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
-        if (serializedCerts) {
-            CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
-            CFRelease(serializedCerts);
+
+    dispatch_sync(trust->_trustQueue, ^{
+        if (trust->_certificates) {
+            CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
+            if (serializedCerts) {
+                CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
+                CFRelease(serializedCerts);
+            }
         }
-    }
-    if (trust->_anchors) {
-        CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
-        if (serializedAnchors) {
-            CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
-            CFRelease(serializedAnchors);
+        if (trust->_anchors) {
+            CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
+            if (serializedAnchors) {
+                CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
+                CFRelease(serializedAnchors);
+            }
         }
-    }
-    if (trust->_policies) {
-        CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
-        if (serializedPolicies) {
-            CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
-            CFRelease(serializedPolicies);
+        if (trust->_policies) {
+            CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
+            if (serializedPolicies) {
+                CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
+                CFRelease(serializedPolicies);
+            }
         }
-    }
-    if (trust->_responses) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
-    }
-    if (trust->_SCTs) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
-    }
-    if (trust->_trustedLogs) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
-    }
-    if (trust->_verifyDate) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
-    }
-    if (trust->_chain) {
-        CFArrayRef serializedChain = SecCertificatePathCreateSerialized(trust->_chain, NULL);
-        if (serializedChain) {
-            CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedChain);
-            CFRelease(serializedChain);
+        if (trust->_responses) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
         }
-    }
-    if (trust->_details) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
-    }
-    if (trust->_info) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
-    }
-    if (trust->_exceptions) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
-    }
-    trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
-    if (trustResult) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
-    }
-    if (trust->_anchorsOnly) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
-    } else {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
-    }
-    if (trust->_keychainsAllowed) {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
-    } else {
-        CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
-    }
+        if (trust->_SCTs) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
+        }
+        if (trust->_trustedLogs) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
+        }
+        if (trust->_verifyDate) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
+        }
+        if (trust->_chain) {
+            CFArrayRef serializedChain = SecCertificatePathCreateSerialized(trust->_chain, NULL);
+            if (serializedChain) {
+                CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedChain);
+                CFRelease(serializedChain);
+            }
+        }
+        if (trust->_details) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
+        }
+        if (trust->_info) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
+        }
+        if (trust->_exceptions) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
+        }
+        CFNumberRef trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
+        if (trustResult) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
+        }
+        CFReleaseNull(trustResult);
+        if (trust->_anchorsOnly) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
+        } else {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
+        }
+        if (trust->_keychainsAllowed) {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
+        } else {
+            CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
+        }
+    });
 
-    CFReleaseNull(trustResult);
     return output;
 }
 
@@ -1871,7 +2069,7 @@ static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_
     }
     serializedChain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
     if (isArray(serializedChain)) {
-        chain = SecCertificatPathCreateDeserialized(serializedChain, NULL);
+        chain = SecCertificatePathCreateDeserialized(serializedChain, NULL);
         output->_chain = chain;
     }
     details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
@@ -1925,416 +2123,3 @@ out:
     CFReleaseNull(plist);
     return trust;
 }
-
-#if 0
-// MARK: -
-// MARK: SecTrustNode
-/********************************************************
- **************** SecTrustNode object *******************
- ********************************************************/
-typedef uint8_t SecFetchingState;
-enum {
-    kSecFetchingStatePassedIn = 0,
-    kSecFetchingStateLocal,
-    kSecFetchingStateFromURL,
-    kSecFetchingStateDone,
-};
-
-typedef uint8_t SecTrustState;
-enum {
-    kSecTrustStateUnknown = 0,
-    kSecTrustStateNotSigner,
-    kSecTrustStateValidSigner,
-};
-
-typedef struct __SecTrustNode *SecTrustNodeRef;
-struct __SecTrustNode {
-       SecTrustNodeRef         _child;
-       SecCertificateRef       _certificate;
-
-    /* Cached information about _certificate */
-    bool                _isAnchor;
-    bool                _isSelfSigned;
-
-    /* Set of all certificates we have ever considered as a parent.  We use
-       this to avoid having to recheck certs when we go to the next phase. */
-    CFMutableSet        _certificates;
-
-    /* Parents that are still partial chains we haven't yet considered. */
-    CFMutableSet        _partials;
-    /* Parents that are still partial chains we have rejected.  We reconsider
-      these if we get to the final phase and we still haven't found a valid
-      candidate. */
-    CFMutableSet        _rejected_partials;
-
-    /* Parents that are complete chains we haven't yet considered. */
-    CFMutableSet        _candidates;
-    /* Parents that are complete chains we have rejected. */
-    CFMutableSet        _rejected_candidates;
-
-    /* State of candidate fetching. */
-    SecFetchingState    _fetchingState;
-
-    /* Trust state of _candidates[_candidateIndex] */
-    SecTrustState       _trustState;
-};
-typedef struct __SecTrustNode SecTrustNode;
-
-/* Forward declarations of static functions. */
-static CFStringRef SecTrustNodeDescribe(CFTypeRef cf);
-static void SecTrustNodeDestroy(CFTypeRef cf);
-
-/* Static functions. */
-static CFStringRef SecTrustNodeCopyDescription(CFTypeRef cf) {
-    SecTrustNodeRef node = (SecTrustNodeRef)cf;
-    return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
-        CFSTR("<SecTrustNodeRef: %p>"), node);
-}
-
-static void SecTrustNodeDestroy(CFTypeRef cf) {
-    SecTrustNodeRef trust = (SecTrustNodeRef)cf;
-    if (trust->_child) {
-        free(trust->_child);
-    }
-    if (trust->_certificate) {
-        free(trust->_certificate);
-    }
-       if (trust->_candidates) {
-               CFRelease(trust->_candidates);
-       }
-}
-
-/* SecTrustNode API functions. */
-CFGiblisFor(SecTrustNode)
-
-SecTrustNodeRef SecTrustNodeCreate(SecTrustRef trust,
-    SecCertificateRef certificate, SecTrustNodeRef child) {
-    CFAllocatorRef allocator = kCFAllocatorDefault;
-       check(trust);
-       check(certificate);
-
-    CFIndex size = sizeof(struct __SecTrustNode);
-    SecTrustNodeRef result = (SecTrustNodeRef)_CFRuntimeCreateInstance(
-               allocator, SecTrustNodeGetTypeID(), size - sizeof(CFRuntimeBase), 0);
-       if (!result)
-        return NULL;
-
-    memset((char*)result + sizeof(result->_base), 0,
-        sizeof(*result) - sizeof(result->_base));
-    if (child) {
-        CFRetain(child);
-        result->_child = child;
-    }
-    CFRetain(certificate);
-    result->_certificate = certificate;
-    result->_isAnchor = SecTrustCertificateIsAnchor(certificate);
-
-    return result;
-}
-
-SecCertificateRef SecTrustGetCertificate(SecTrustNodeRef node) {
-       check(node);
-    return node->_certificate;
-}
-
-CFArrayRef SecTrustNodeCopyProperties(SecTrustNodeRef node,
-    SecTrustRef trust) {
-       check(node);
-    check(trust);
-    CFMutableArrayRef summary = SecCertificateCopySummaryProperties(
-        node->_certificate, SecTrustGetVerifyTime(trust));
-    /* FIXME Add more details in the failure case. */
-    return summary;
-}
-
-/* Attempt to verify this node's signature chain down to the child. */
-SecTrustState SecTrustNodeVerifySignatureChain(SecTrustNodeRef node) {
-    /* FIXME */
-    return kSecTrustStateUnknown;
-}
-
-
-/* See if the next candidate works. */
-SecTrustNodeRef SecTrustNodeCopyNextCandidate(SecTrustNodeRef node,
-    SecTrustRef trust, SecFetchingState fetchingState) {
-    check(node);
-    check(trust);
-
-    CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
-
-    for (;;) {
-        /* If we have any unconsidered candidates left check those first. */
-        while (node->_candidateIndex < CFArrayGetCount(node->_candidates)) {
-            SecCertificateRef candidate = (SecCertificateRef)
-                CFArrayGetValueAtIndex(node->_candidates, node->_candidateIndex);
-            if (node->_fetchingState != kSecFetchingStateDone) {
-                /* If we still have potential sources to fetch other candidates
-                   from we ignore expired candidates. */
-                if (!SecCertificateIsValidOn(candidate, verifyTime)) {
-                    node->_candidateIndex++;
-                    continue;
-                }
-            }
-
-            SecTrustNodeRef parent = SecTrustNodeCreate(candidate, node);
-            CFArrayRemoveValueAtIndex(node->_candidates, node->_candidateIndex);
-            if (SecTrustNodeVerifySignatureChain(parent) ==
-                kSecTrustStateNotSigner) {
-                /* This candidate parent is not a valid signer of its
-                   child. */
-                CFRelease(parent);
-                /* If another signature failed further down the chain we need
-                   to backtrack down to whatever child is still a valid
-                   candidate and has additional candidates to consider.
-                   @@@ We really want to make the fetchingState a global of
-                   SecTrust itself as well and not have any node go beyond the
-                   current state of SecTrust if there are other (read cheap)
-                   options to consider. */
-                continue;
-            }
-            return parent;
-        }
-
-        /* We've run out of candidates in our current state so let's try to
-           find some more. Note we fetch candidates in increasing order of
-           cost in the hope we won't ever get to the more expensive fetching
-           methods.  */
-        SecCertificateRef certificate = node->_certificate;
-        switch (node->_fetchingState) {
-        case kSecFetchingStatePassedIn:
-            /* Get the list of candidates from SecTrust. */
-            CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
-            if (akid) {
-                SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
-            } else {
-                CFDataRef issuer =
-                    SecCertificateGetNormalizedIssuerContent(certificate);
-                SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
-            }
-            node->_fetchingState = kSecFetchingStateLocal;
-            break;
-        case kSecFetchingStateLocal:
-            /* Lookup candidates in the local database. */
-            node->_fetchingState = kSecFetchingStateFromURL;
-            break;
-        case kSecFetchingStateFromURL:
-            node->_fetchingState = kSecFetchingStateCheckExpired;
-            break;
-        case kSecFetchingStateCheckExpired:
-            /* Time to start considering expired candidates as well. */
-            node->_candidateIndex = 0;
-            node->_fetchingState = kSecFetchingStateDone;
-            break;
-        case kSecFetchingStateDone;
-            return NULL;
-        }
-    }
-
-    CFAllocatorRef allocator = CFGetAllocator(node);
-
-    /* A trust node has a number of states.
-       1) Look for issuing certificates by asking SecTrust about known
-          parent certificates.
-       2) Look for issuing certificates in certificate databases (keychains)
-       3) Look for issuing certificates by going out to the web if the nodes
-          certificate has a issuer location URL.
-       4) Look through expired or not yet valid candidates we have put aside.
-
-       We go though the stages 1 though 3 looking for candidate issuer
-       certificates.  If a candidate certificate is not valid at verifyTime
-       we put it in a to be examined later queue.  If a candidate certificate
-       is valid we verify if it actually signed our certificate (if possible).
-       If not we discard it and continue on to the next candidate certificate.
-       If it is we return a new SecTrustNodeRef for that certificate.  */
-
-    CFMutableArrayRef issuers = CFArrayCreateMutable(allocator, 0,
-        &kCFTypeArrayCallBacks);
-
-    /* Find a node's parent. */
-    certificate = node->_certificate;
-    CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
-    CFTypeRef candidates = NULL;
-    if (akid) {
-        candidates = (CFTypeRef)CFDictionaryGetValueForKey(skidDict, akid);
-        if (candidates) {
-            addValidIssuersFrom(issuers, certificate, candidates, true);
-        }
-    }
-    if (!candidates) {
-        CFDataRef issuer =
-            SecCertificateGetNormalizedIssuerContent(certificate);
-        candidates = (CFTypeRef)
-            CFDictionaryGetValueForKey(subjectDict, issuer);
-        addValidIssuersFrom(issuers, certificate, candidates, false);
-    }
-
-    if (CFArrayGetCount(issuers) == 0) {
-        /* O no! we can't find an issuer for this certificate.  Let's see
-           if we can find one in the local database. */
-    }
-
-    return errSecSuccess;
-}
-
-CFArrayRef SecTrustNodeCopyNextChain(SecTrustNodeRef node,
-    SecTrustRef trust) {
-    /* Return the next full chain that isn't a reject unless we are in
-       a state where we consider returning rejects. */
-
-    switch (node->_fetchingState) {
-    case kSecFetchingStatePassedIn:
-        /* Get the list of candidates from SecTrust. */
-        CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
-        if (akid) {
-            SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
-        } else {
-            CFDataRef issuer =
-                SecCertificateGetNormalizedIssuerContent(certificate);
-            SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
-        }
-        node->_fetchingState = kSecFetchingStateLocal;
-        break;
-    case kSecFetchingStateLocal:
-        /* Lookup candidates in the local database. */
-        node->_fetchingState = kSecFetchingStateFromURL;
-        break;
-    case kSecFetchingStateFromURL:
-        node->_fetchingState = kSecFetchingStateCheckExpired;
-        break;
-    case kSecFetchingStateCheckExpired:
-        /* Time to start considering expired candidates as well. */
-        node->_candidateIndex = 0;
-        node->_fetchingState = kSecFetchingStateDone;
-        break;
-    case kSecFetchingStateDone;
-        return NULL;
-    }
-}
-
-class Source {
-       Iterator parentIterator(Cert);
-};
-
-class NodeCache {
-       Set nodes;
-
-       static bool unique(Node node) {
-               if (nodes.contains(node))
-                       return false;
-               nodes.add(node);
-               return true;
-       }
-
-       static bool isAnchor(Cert cert);
-};
-
-class Node {
-       Cert cert;
-       Node child;
-       int nextSource;
-       Iterator parentIterator; /* For current source of parents. */
-
-       Node(Cert inCert) : child(nil), cert(inCert), nextSource(0) {}
-       Node(Node inChild, Cert inCert) : child(inChild), cert(inCert),
-               nextSource(0) {}
-
-       CertPath certPath() {
-               CertPath path;
-               Node node = this;
-               while (node) {
-                       path.add(node.cert);
-                       node = node.child;
-               }
-               return path;
-       }
-
-       void contains(Cert cert) {
-               Node node = this;
-               while (node) {
-                       if (cert == node.cert)
-                               return true;
-                       node = node.child;
-               }
-               return false;
-       }
-
-       Node nextParent(Array currentSources) {
-               for (;;) {
-                       if (!nextSource ||
-                               parentIterator == currentSources[nextSource - 1].end()) {
-                               if (nextSource == currentSources.count) {
-                                       /* We ran out of parent sources. */
-                                       return nil;
-                               }
-                               parentIterator = currentSources[nextSource++].begin();
-                       }
-                       Certificate cert = *parentIterator++;
-                       /* Check for cycles and self signed chains. */
-                       if (!contains(cert)) {
-                               Node node = Node(this, parent);
-                               if (!NodeCache.unique(node))
-                                       return node;
-                       }
-               }
-       }
-};
-
-
-class PathBuilder {
-       List nodes;
-       List rejects;
-       Array currentSources;
-       Iterator nit;
-       Array allSources;
-       Iterator sourceIT;
-       CertPath chain;
-
-       PathBuilder(Cert cert) {
-               nodes.append(Node(cert));
-               nit = nodes.begin();
-               sourceIT = allSources.begin();
-       }
-
-       nextAnchoredPath() {
-               if (nit == nodes.end()) {
-                       /* We should add another source to the list of sources to
-                          search. */
-                       if (sourceIT == allSources.end()) {
-                               /* No more sources to add. */
-                       }
-                       currentSources += *sourceIT++;
-                       /* Resort nodes by size. */
-                       Nodes.sortBySize();
-                       nit = nodes.begin();
-                       /* Set the source list for all nodes. */
-
-               }
-               while (Node node = *nit) {
-                       Node candidate = node.nextParent(currentSources);
-                       if (!candidate) {
-                               /* The current node has no more candidate parents so move
-                                  along. */
-                               nit++;
-                               continue;
-                       }
-
-                       if (candidate.isAnchored) {
-                               candidates.append(candidate);
-                       } else
-                               nodes.insert(candidate, nit);
-               }
-       }
-
-       findValidPath() {
-               while (Node node = nextAnchoredPath()) {
-                       if (node.isValid()) {
-                               chain = node.certPath;
-                               break;
-                       }
-                       rejects.append(node);
-               }
-       }
-}
-
-
-#endif