#include <utilities/SecCertificateTrace.h>
 #include <utilities/debugging.h>
 #include <utilities/der_plist.h>
+#include <utilities/SecDispatchRelease.h>
 
 #include "SecRSAKey.h"
 #include <libDER/oids.h>
      */
     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,
 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);
         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
     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;
+        });
     }
 }
 
     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;
        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;
 }
             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;
 }
 
         return errSecParam;
     }
     SecTrustSetNeedsEvaluation(trust);
-    CFRetainAssign(trust->_SCTs, sctArray);
-
+    dispatch_sync(trust->_trustQueue, ^{
+        CFRetainAssign(trust->_SCTs, sctArray);
+    });
     return errSecSuccess;
 }
 
         return errSecParam;
     }
     SecTrustSetNeedsEvaluation(trust);
-    CFRetainAssign(trust->_trustedLogs, trustedLogs);
-
+    dispatch_sync(trust->_trustQueue, ^{
+        CFRetainAssign(trust->_trustedLogs, trustedLogs);
+    });
     return errSecSuccess;
 }
 
     }
     SecTrustSetNeedsEvaluation(trust);
     check(verifyDate);
-    CFRetainAssign(trust->_verifyDate, verifyDate);
-
+    dispatch_sync(trust->_trustQueue, ^{
+        CFRetainAssign(trust->_verifyDate, verifyDate);
+    });
     return errSecSuccess;
 }
 
     SecTrustSetNeedsEvaluation(trust);
     check(newPolicies);
 
-    CFArrayRef policyArray = NULL;
+    __block CFArrayRef policyArray = NULL;
     if (CFGetTypeID(newPolicies) == CFArrayGetTypeID()) {
                policyArray = CFArrayCreateCopy(kCFAllocatorDefault, newPolicies);
        } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) {
         return errSecParam;
     }
 
-    if (trust->_policies)
-        CFRelease(trust->_policies);
-    trust->_policies = policyArray;
+    dispatch_sync(trust->_trustQueue, ^{
+        CFReleaseSafe(trust->_policies);
+        trust->_policies = policyArray;
+    });
 
     return errSecSuccess;
 }
        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;
        }
        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);
 }
 
 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;
 }
 
        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. */
     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;
        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);
 }
 
 
 }
 
 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);
         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 &&
 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;
 }
 
 
 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) {
     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;
 }
 
 }
 
 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);
             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.
     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) {
         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,
     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) {
         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;
 }
 
 }
 
 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;
     CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
         exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
     CFRelease(exceptions);
-
+    CFReleaseSafe(details);
     return 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;
 }
 
     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;
 
         CFReleaseNull(properties);
     }
 
+    CFReleaseNull(details);
     return properties;
 }
 
        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;
 }
         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;
 }
 
     }
 }
 
-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);
 }
 
 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;
 }
 
     }
     serializedChain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
     if (isArray(serializedChain)) {
-        chain = SecCertificatPathCreateDeserialized(serializedChain, NULL);
+        chain = SecCertificatePathCreateDeserialized(serializedChain, NULL);
         output->_chain = chain;
     }
     details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
     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