]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/securityd/SecPolicyServer.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / securityd / SecPolicyServer.c
index cfcc825d4f7946210403efd91a3ffe4af6962c0d..56d212ceaa8d03c8a741c568256987804dfb71d7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2015 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  */
 
 /*
- * SecPolicyServer.c - Trust policies dealing with certificate revocation.
+ * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies.
  */
 
 #include <securityd/SecPolicyServer.h>
 #include <Security/SecPolicyInternal.h>
 #include <Security/SecPolicyPriv.h>
-#include <utilities/SecIOFormat.h>
+#include <Security/SecTask.h>
 #include <securityd/asynchttp.h>
 #include <securityd/policytree.h>
 #include <securityd/nameconstraints.h>
@@ -39,6 +39,7 @@
 #include <Security/SecCertificateInternal.h>
 #include <AssertMacros.h>
 #include <utilities/debugging.h>
+#include <utilities/SecInternalReleasePriv.h>
 #include <security_asn1/SecAsn1Coder.h>
 #include <security_asn1/ocspTemplates.h>
 #include <security_asn1/oidsalg.h>
 #include <Security/SecFramework.h>
 #include <Security/SecPolicyInternal.h>
 #include <Security/SecTrustPriv.h>
+#include <Security/SecTrustInternal.h>
+#include <Security/SecTrustSettingsPriv.h>
 #include <Security/SecInternal.h>
 #include <Security/SecKeyPriv.h>
+#include <Security/SecTask.h>
 #include <CFNetwork/CFHTTPMessage.h>
 #include <CFNetwork/CFHTTPStream.h>
 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
 #include <asl.h>
-#include <securityd/SecOCSPRequest.h>
-#include <securityd/SecOCSPResponse.h>
-#include <securityd/asynchttp.h>
 #include <securityd/SecTrustServer.h>
-#include <securityd/SecOCSPCache.h>
+#include <securityd/SecTrustLoggingServer.h>
+#include <securityd/SecRevocationServer.h>
+#include <securityd/SecCertificateServer.h>
+#include <securityd/SecCertificateSource.h>
+#include <securityd/SecOCSPResponse.h>
 #include <utilities/array_size.h>
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecAppleAnchorPriv.h>
 #include "OTATrustUtilities.h"
+#include "personalization.h"
+#include <sys/codesign.h>
 
-#define ocspdErrorLog(args...)     asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
+#if !TARGET_OS_IPHONE
+#include <Security/SecTaskPriv.h>
+#endif
 
 /* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
 #ifndef DUMP_OCSPRESPONSES
@@ -88,6 +97,10 @@ static void secdumpdata(CFDataRef data, const char *name) {
  ****************** SecPolicy object ********************
  ********************************************************/
 
+static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix);
+static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc);
+static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc);
+
 static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL;
 static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL;
 
@@ -115,7 +128,7 @@ static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID)
         result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid);
                if (roots && CFGetTypeID(result) != CFArrayGetTypeID())
                {
-            ocspdErrorLog("EVRoot.plist has non array value");
+            secerror("EVRoot.plist has non array value");
             result = NULL;
         }
         CFRelease(oid);
@@ -125,12 +138,15 @@ static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID)
 }
 
 
-static bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
+bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
     return SecPolicyAnchorDigestsForEVPolicy(policyOID);
 }
 
 static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
     policy_set_t valid_policies) {
+    CFDictionaryRef keySizes = NULL;
+    CFNumberRef rsaSize = NULL, ecSize = NULL;
+    bool isEV = false;
     /* Ensure that this certificate is a valid anchor for one of the
        certificate policy oids specified in the leaf. */
     CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
@@ -145,124 +161,101 @@ static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
             break;
         }
     }
-    require_quiet(good_ev_anchor, notEV);
+    require_action_quiet(good_ev_anchor, notEV, secnotice("ev", "anchor not in plist"));
 
     CFAbsoluteTime october2006 = 178761600;
+    if (SecCertificateNotValidBefore(certificate) >= october2006) {
+        require_action_quiet(SecCertificateVersion(certificate) >= 3, notEV,
+                             secnotice("ev", "Anchor issued after October 2006 and is not v3"));
+    }
     if (SecCertificateVersion(certificate) >= 3
         && SecCertificateNotValidBefore(certificate) >= october2006) {
         const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
-        require_quiet(bc && bc->isCA == true, notEV);
+        require_action_quiet(bc && bc->isCA == true, notEV,
+                             secnotice("ev", "Anchor has invalid basic constraints"));
         SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
-        require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
-            == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
+        require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
+            == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV,
+                             secnotice("ev", "Anchor has invalid key usage %u", ku));
     }
 
-    CFAbsoluteTime jan2011 = 315532800;
-    if (SecCertificateNotValidBefore(certificate) < jan2011) {
-        /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
-    } else {
-        /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
-           ECC NIST P-256. */
-    }
+    /* At least RSA 2048 or ECC NIST P-256. */
+    require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
+    require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
+    const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC };
+    const void *values[] = { rsaSize, ecSize };
+    require_quiet(keySizes = CFDictionaryCreate(NULL, keys, values, 2,
+                                          &kCFTypeDictionaryKeyCallBacks,
+                                          &kCFTypeDictionaryValueCallBacks), notEV);
+    require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
+                         secnotice("ev", "Anchor's public key is too weak for EV"));
+
+    isEV = true;
 
-    return true;
 notEV:
-    return false;
+    CFReleaseNull(rsaSize);
+    CFReleaseNull(ecSize);
+    CFReleaseNull(keySizes);
+    return isEV;
 }
 
 static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) {
+    CFMutableDictionaryRef keySizes = NULL;
+    CFNumberRef rsaSize = NULL, ecSize = NULL;
+    bool isEV = false;
+
     const SecCECertificatePolicies *cp;
     cp = SecCertificateGetCertificatePolicies(certificate);
-    require_quiet(cp && cp->numPolicies > 0, notEV);
-    /* SecCertificateGetCRLDistributionPoints() is a noop right now */
-#if 0
+    require_action_quiet(cp && cp->numPolicies > 0, notEV,
+                         secnotice("ev", "SubCA missing certificate policies"));
     CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
-    require_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV);
-#endif
+    require_action_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV,
+                         secnotice("ev", "SubCA missing CRLDP"));
     const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
-    require_quiet(bc && bc->isCA == true, notEV);
+    require_action_quiet(bc && bc->isCA == true, notEV,
+                         secnotice("ev", "SubCA has invalid basic constraints"));
     SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
-    require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
-        == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
-    CFAbsoluteTime jan2011 = 315532800;
-    if (SecCertificateNotValidBefore(certificate) < jan2011) {
-        /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
-    } else {
-        /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
-           ECC NIST P-256. */
-    }
-
-    return true;
-notEV:
-    return false;
-}
-
-bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) {
-    /* 3. Subscriber Certificate. */
+    require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
+        == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV,
+                         secnotice("ev", "SubCA has invalid key usage %u", ku));
 
-    /* (a) certificate Policies */
-    const SecCECertificatePolicies *cp;
-    cp = SecCertificateGetCertificatePolicies(certificate);
-    require_quiet(cp && cp->numPolicies > 0, notEV);
-    /* Now find at least one policy in here that has a qualifierID of id-qt 2
-       and a policyQualifier that is a URI to the CPS and an EV policy OID. */
-    uint32_t ix = 0;
-    bool found_ev_anchor_for_leaf_policy = false;
-    for (ix = 0; ix < cp->numPolicies; ++ix) {
-        if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) {
-            found_ev_anchor_for_leaf_policy = true;
-        }
-    }
-    require_quiet(found_ev_anchor_for_leaf_policy, notEV);
-
-    /* SecCertificateGetCRLDistributionPoints() is a noop right now */
-#if 0
-    /* (b) cRLDistributionPoint
-       (c) authorityInformationAccess */
-    CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
-    if (cdp) {
-        require_quiet(CFArrayGetCount(cdp) > 0, notEV);
+    /* 6.1.5 Key Sizes */
+    CFAbsoluteTime jan2011 = 315532800;
+    CFAbsoluteTime jan2014 = 410227200;
+    require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
+    require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks,
+                                                 &kCFTypeDictionaryValueCallBacks), notEV);
+    CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize);
+    if (SecCertificateNotValidBefore(certificate) < jan2011 ||
+        SecCertificateNotValidAfter(certificate) < jan2014) {
+        /* At least RSA 1024 or ECC NIST P-256. */
+        require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV);
+        CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
+        require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
+                             secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014"));
     } else {
-        CFArrayRef or = SecCertificateGetOCSPResponders(certificate);
-        require_quiet(or && CFArrayGetCount(or) > 0, notEV);
-        //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
-    }
-#endif
-
-    /* (d) basicConstraints
-       If present, the cA field MUST be set false. */
-    const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
-    if (bc) {
-        require_quiet(bc->isCA == false, notEV);
+        /* At least RSA 2028 or ECC NIST P-256. */
+        require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
+        CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
+        require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
+                             secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013"));
     }
 
-    /* (e) keyUsage. */
-    SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
-    if (ku) {
-        require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV);
+    /* 7.1.3 Algorithm Object Identifiers */
+    CFAbsoluteTime jan2016 = 473299200;
+    if (SecCertificateNotValidBefore(certificate) > jan2016) {
+        /* SHA-2 only */
+        require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1,
+                             notEV, secnotice("ev", "SubCA was issued with SHA-1 after 2015"));
     }
 
-#if 0
-    /* The EV Cert Spec errata specifies this, though this is a check for SSL
-       not specifically EV. */
-
-    /* (e) extKeyUsage
-
-Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
-    SecCertificateCopyExtendedKeyUsage(certificate);
-#endif
-
-    CFAbsoluteTime jan2011 = 315532800;
-    if (SecCertificateNotValidAfter(certificate) < jan2011) {
-        /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
-    } else {
-        /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
-           ECC NIST P-256. */
-    }
+    isEV = true;
 
-    return true;
 notEV:
-    return false;
+    CFReleaseNull(rsaSize);
+    CFReleaseNull(ecSize);
+    CFReleaseNull(keySizes);
+    return isEV;
 }
 
 /********************************************************
@@ -298,78 +291,25 @@ static void SecPolicyCheckIdLinkage(SecPVCRef pvc,
        }
 }
 
-static bool keyusage_allows(SecKeyUsage keyUsage, CFTypeRef xku) {
-    if (!xku || CFGetTypeID(xku) != CFNumberGetTypeID())
-        return false;
-
-    SInt32 dku;
-    CFNumberGetValue((CFNumberRef)xku, kCFNumberSInt32Type, &dku);
-    SecKeyUsage ku = (SecKeyUsage)dku;
-    return (keyUsage & ku) == ku;
-}
-
 static void SecPolicyCheckKeyUsage(SecPVCRef pvc,
        CFStringRef key) {
     SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
-    SecKeyUsage keyUsage = SecCertificateGetKeyUsage(leaf);
-    bool match = false;
     SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef xku = CFDictionaryGetValue(policy->_options, key);
-    if (isArray(xku)) {
-        CFIndex ix, count = CFArrayGetCount(xku);
-        for (ix = 0; ix < count; ++ix) {
-            CFTypeRef ku = CFArrayGetValueAtIndex(xku, ix);
-            if (keyusage_allows(keyUsage, ku)) {
-                match = true;
-                break;
-            }
-        }
-    } else {
-        match = keyusage_allows(keyUsage, xku);
-    }
-    if (!match) {
+    if (!SecPolicyCheckCertKeyUsage(leaf, xku)) {
         SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
     }
 }
 
-static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage,
-                                    CFTypeRef xeku) {
-    if (!xeku || CFGetTypeID(xeku) != CFDataGetTypeID())
-        return false;
-    if (extendedKeyUsage) {
-        CFRange all = { 0, CFArrayGetCount(extendedKeyUsage) };
-        return CFArrayContainsValue(extendedKeyUsage, all, xeku);
-    } else {
-        /* Certificate has no extended key usage, only a match if the policy
-           contains a 0 length CFDataRef. */
-        return CFDataGetLength((CFDataRef)xeku) == 0;
-    }
-}
-
 /* AUDIT[securityd](done):
    policy->_options is a caller provided dictionary, only its cf type has
    been checked.
  */
 static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
     SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
-    CFArrayRef leafExtendedKeyUsage = SecCertificateCopyExtendedKeyUsage(leaf);
-    bool match = false;
     SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
-    if (isArray(xeku)) {
-        CFIndex ix, count = CFArrayGetCount(xeku);
-        for (ix = 0; ix < count; ix++) {
-            CFTypeRef eku = CFArrayGetValueAtIndex(xeku, ix);
-            if (extendedkeyusage_allows(leafExtendedKeyUsage, eku)) {
-                match = true;
-                break;
-            }
-        }
-    } else {
-        match = extendedkeyusage_allows(leafExtendedKeyUsage, xeku);
-    }
-    CFReleaseSafe(leafExtendedKeyUsage);
-    if (!match) {
+    if (!SecPolicyCheckCertExtendedKeyUsage(leaf, xeku)){
         SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
     }
 }
@@ -437,7 +377,7 @@ static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc,
 }
 #endif
 
-static void SecPolicyCheckBasicContraints(SecPVCRef pvc,
+static void SecPolicyCheckBasicConstraints(SecPVCRef pvc,
        CFStringRef key) {
        //SecPolicyCheckBasicContraintsCommon(pvc, key, false);
 }
@@ -445,25 +385,14 @@ static void SecPolicyCheckBasicContraints(SecPVCRef pvc,
 static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc,
        CFStringRef key) {
        CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key);
        for (ix = 0; ix < count; ++ix) {
                SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-               /* If the certificate has a subject, or
-                  if it doesn't, and it's the leaf and not self signed,
-                  and also has a critical subjectAltName extension it's valid. */
-               if (!SecCertificateHasSubject(cert)) {
-                       if (ix == 0 && count > 1) {
-                               if (!SecCertificateHasCriticalSubjectAltName(cert)) {
-                                       /* Leaf certificate with empty subject does not have
-                                          a critical subject alt name extension. */
-                                       if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
-                                               return;
-                               }
-                       } else {
-                               /* CA certificate has empty subject. */
-                               if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
-                                       return;
-                       }
-               }
+        if (!SecPolicyCheckCertNonEmptySubject(cert, pvcValue)) {
+            if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
+                return;
+        }
        }
 }
 
@@ -471,231 +400,6 @@ static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc,
        CFStringRef key) {
 }
 
-/* Compare hostname suffix to domain name.
-   This function does not process wildcards, and allows hostname to match
-   any subdomain level of the provided domain.
-
-   To match, the last domain length chars of hostname must equal domain,
-   and the character immediately preceding domain in hostname (if any)
-   must be a dot. This means that domain 'bar.com' will match hostname
-   values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'.
-
-   Characters in each string are converted to lowercase for the comparison.
-   Trailing '.' characters in both names will be ignored.
-
-   Returns true on match, else false.
- */
-static bool SecDomainSuffixMatch(CFStringRef hostname, CFStringRef domain) {
-       CFStringInlineBuffer hbuf, dbuf;
-       UniChar hch, dch;
-       CFIndex hix, dix,
-               hlength = CFStringGetLength(hostname),
-               dlength = CFStringGetLength(domain);
-       CFRange hrange = { 0, hlength }, drange = { 0, dlength };
-       CFStringInitInlineBuffer(hostname, &hbuf, hrange);
-       CFStringInitInlineBuffer(domain, &dbuf, drange);
-
-       if((hlength == 0) || (dlength == 0)) {
-               /* trivial case with at least one empty name */
-               return (hlength == dlength) ? true : false;
-       }
-
-       /* trim off trailing dots */
-       hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hlength-1);
-       dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dlength-1);
-       if(hch == '.') {
-               hrange.length = --hlength;
-       }
-       if(dch == '.') {
-               drange.length = --dlength;
-       }
-
-       /* trim off leading dot in suffix, if present */
-       dch = CFStringGetCharacterFromInlineBuffer(&dbuf, 0);
-       if((dlength > 0) && (dch == '.')) {
-               drange.location++;
-               drange.length = --dlength;
-       }
-
-       if(hlength < dlength) {
-               return false;
-       }
-
-       /* perform case-insensitive comparison of domain suffix */
-       for (hix = (hlength-dlength),
-                dix = drange.location; dix < drange.length; dix++) {
-               hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix);
-               dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dix);
-               if (towlower(hch) != towlower(dch)) {
-                       return false;
-               }
-       }
-
-       /* require a dot prior to domain suffix, unless hostname == domain */
-       if(hlength > dlength) {
-               hch = CFStringGetCharacterFromInlineBuffer(&hbuf, (hlength-(dlength+1)));
-               if(hch != '.') {
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-/* Compare hostname, to a server name obtained from the server's cert
-   Obtained from the SubjectAltName or the CommonName entry in the Subject.
-   Limited wildcard checking is performed here as outlined in
-
-   RFC 2818 Section 3.1.  Server Identity
-
-   [...] Names may contain the wildcard
-   character * which is considered to match any single domain name
-   component or component fragment. E.g., *.a.com matches foo.a.com but
-   not bar.foo.a.com. f*.com matches foo.com but not bar.com.
-   [...]
-
-   Trailing '.' characters in the hostname will be ignored.
-
-   Returns true on match, else false.
-
-   RFC6125:
- */
-bool SecDNSMatch(CFStringRef hostname, CFStringRef servername) {
-       CFStringInlineBuffer hbuf, sbuf;
-       CFIndex hix, six, tix,
-                       hlength = CFStringGetLength(hostname),
-                       slength = CFStringGetLength(servername);
-       CFRange hrange = { 0, hlength }, srange = { 0, slength };
-       CFStringInitInlineBuffer(hostname, &hbuf, hrange);
-       CFStringInitInlineBuffer(servername, &sbuf, srange);
-       bool prevLabel=false;
-
-       for (hix = six = 0; six < slength; ++six) {
-               UniChar tch, hch, sch = CFStringGetCharacterFromInlineBuffer(&sbuf, six);
-               if (sch == '*') {
-                       if (prevLabel) {
-                               /* RFC6125: No wildcard after a Previous Label */
-                               /* INVALID: Means we have something like foo.*.<public_suffix> */
-                               return false;
-                       }
-
-                       if (six + 1 >= slength) {
-                               /* Trailing '*' in servername, match until end of hostname or
-                                  trailing '.'.  */
-                               do {
-                                       if (hix >= hlength) {
-                                               /* If we reach the end of the hostname we have a
-                                                  match. */
-                                               return true;
-                                       }
-                                       hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
-                               } while (hch != '.');
-                               /* We reached the end of servername and found a '.' in
-                                  hostname.  Return true if hostname has a single
-                                  trailing '.' return false if there is anything after it. */
-                               return hix == hlength;
-                       }
-
-                       /* Grab the character after the '*'. */
-                       sch = CFStringGetCharacterFromInlineBuffer(&sbuf, ++six);
-                       if (sch != '.') {
-                               /* We have something of the form '*foo.com'.  Or '**.com'
-                                  We don't deal with that yet, since it might require
-                                  backtracking. Also RFC 2818 doesn't seem to require it. */
-                               return false;
-                       }
-
-                       /* We're looking at the '.' after the '*' in something of the
-                          form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
-                       if (prevLabel==false) {                 /* RFC6125: Check if *.<tld> */
-                               tix=six+1;
-                               do {                                    /* Loop to end of servername */
-                                       if (tix > slength)
-                                               return false;    /* Means we have something like *.com */
-                                       tch = CFStringGetCharacterFromInlineBuffer(&sbuf, tix++);
-                               } while (tch != '.');
-                               if (tix > slength)
-                                       return false;        /* In case we have *.com. */
-                       }
-
-                       do {
-                               /* Since we're not at the end of servername yet (that case
-                                  was handled above), running out of chars in hostname
-                                  means we don't have a match. */
-                               if (hix >= hlength)
-                                       return false;
-                               hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
-                       } while (hch != '.');
-               } else {
-                       /* We're looking at a non wildcard character in the servername.
-                          If we reached the end of hostname, it's not a match. */
-                       if (hix >= hlength)
-                               return false;
-
-                       /* Otherwise make sure the hostname matches the character in the
-                          servername, case insensitively. */
-                       hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
-                       if (towlower(hch) != towlower(sch))
-                               return false;
-                       if (sch == '.')
-                               prevLabel=true;   /* Set if a confirmed previous component */
-               }
-       }
-
-       if (hix < hlength) {
-               /* We reached the end of servername but we have one or more characters
-                  left to compare against in the hostname. */
-               if (hix + 1 == hlength &&
-                               CFStringGetCharacterFromInlineBuffer(&hbuf, hix) == '.') {
-                       /* Hostname has a single trailing '.', we're ok with that. */
-                       return true;
-               }
-               /* Anything else is not a match. */
-               return false;
-       }
-
-       return true;
-}
-
-#define kSecPolicySHA1Size 20
-static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = {
-    0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1,
-    0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE
-};
-
-/* Check whether hostname is in a particular set of allowed domains.
-   Returns true if OK, false if not allowed.
- */
-static bool SecPolicyCheckDomain(SecPVCRef pvc, CFStringRef hostname)
-{
-       CFIndex count = SecPVCGetCertificateCount(pvc);
-       SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
-       CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
-
-       /* is this chain anchored by kAppleCorpCASHA1? */
-       CFDataRef corpSHA1 = CFDataCreateWithBytesNoCopy(NULL,
-           kAppleCorpCASHA1, kSecPolicySHA1Size, kCFAllocatorNull);
-       bool isCorpSHA1 = (corpSHA1 && CFEqual(anchorSHA1, corpSHA1));
-       CFReleaseSafe(corpSHA1);
-       if (isCorpSHA1) {
-               /* limit hostname to specified domains */
-               const CFStringRef dnlist[] = {
-                   CFSTR("apple.com"),
-                       CFSTR("icloud.com"),
-               };
-               unsigned int idx, dncount=2;
-               for (idx = 0; idx < dncount; idx++) {
-                       if (SecDomainSuffixMatch(hostname, dnlist[idx])) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-       /* %%% other CA pinning checks TBA */
-
-       return true;
-}
-
 /* AUDIT[securityd](done):
    policy->_options is a caller provided dictionary, only its cf type has
    been checked.
@@ -714,61 +418,13 @@ static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
     }
 
        SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
-       bool dnsMatch = false;
-       CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
-       if (dnsNames) {
-               CFIndex ix, count = CFArrayGetCount(dnsNames);
-               for (ix = 0; ix < count; ++ix) {
-                       CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
-                       if (SecDNSMatch(hostName, dns)) {
-                               dnsMatch = true;
-                               break;
-                       }
-               }
-               CFRelease(dnsNames);
-       }
-
-    if (!dnsMatch) {
-        /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
-           the values returned by SecCertificateCopyIPAddresses() instead. */
-        CFArrayRef ipAddresses = SecCertificateCopyIPAddresses(leaf);
-        if (ipAddresses) {
-            CFIndex ix, count = CFArrayGetCount(ipAddresses);
-            for (ix = 0; ix < count; ++ix) {
-                CFStringRef ipAddress = (CFStringRef)CFArrayGetValueAtIndex(ipAddresses, ix);
-                if (!CFStringCompare(hostName, ipAddress, kCFCompareCaseInsensitive)) {
-                    dnsMatch = true;
-                    break;
-                }
-            }
-            CFRelease(ipAddresses);
-        }
-    }
+    bool dnsMatch = SecPolicyCheckCertSSLHostname(leaf, hostName);
 
        if (!dnsMatch) {
                /* Hostname mismatch or no hostnames found in certificate. */
                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
        }
-       else if (!SecPolicyCheckDomain(pvc, hostName)) {
-               /* Hostname match, but domain not allowed for this CA */
-               SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-       }
 
-    if ((dnsMatch || pvc->details)
-        && SecPolicySubscriberCertificateCouldBeEV(leaf)) {
-        secdebug("policy", "enabling optionally_ev");
-        pvc->optionally_ev = true;
-        /* optionally_ev => check_revocation, so we don't enable revocation
-           checking here, since we don't want it on for non EV ssl certs.  */
-#if 0
-        /* Check revocation status if the certificate asks for it (and we
-           support it) currently we only support ocsp. */
-        CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(leaf);
-        if (ocspResponders) {
-            SecPVCSetCheckRevocation(pvc);
-        }
-#endif
-    }
 }
 
 /* AUDIT[securityd](done):
@@ -778,7 +434,6 @@ static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
 static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
        SecPolicyRef policy = SecPVCGetPolicy(pvc);
        CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key);
-       bool match = false;
     if (!isString(email)) {
         /* We can't return an error here and making the evaluation fail
          won't help much either. */
@@ -786,20 +441,8 @@ static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
     }
 
        SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
-       CFArrayRef addrs = SecCertificateCopyRFC822Names(leaf);
-       if (addrs) {
-               CFIndex ix, count = CFArrayGetCount(addrs);
-               for (ix = 0; ix < count; ++ix) {
-                       CFStringRef addr = (CFStringRef)CFArrayGetValueAtIndex(addrs, ix);
-                       if (!CFStringCompare(email, addr, kCFCompareCaseInsensitive)) {
-                               match = true;
-                               break;
-                       }
-               }
-               CFRelease(addrs);
-       }
 
-       if (!match) {
+       if (!SecPolicyCheckCertEmail(leaf, email)) {
                /* Hostname mismatch or no hostnames found in certificate. */
                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
     }
@@ -865,13 +508,9 @@ static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-    CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
-    if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
-        !CFEqual(commonName, CFArrayGetValueAtIndex(commonNames, 0))) {
-               /* Common Name mismatch. */
-               SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-       }
-    CFReleaseSafe(commonNames);
+    if (!SecPolicyCheckCertSubjectCommonName(cert, commonName)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
 }
 
 /* AUDIT[securityd](done):
@@ -889,13 +528,9 @@ static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-       CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
-       if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
-               !CFEqual(common_name, CFArrayGetValueAtIndex(commonNames, 0))) {
-               /* Common Name mismatch. */
+    if (!SecPolicyCheckCertSubjectCommonName(cert, common_name)) {
                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-       }
-       CFReleaseSafe(commonNames);
+    }
 }
 
 /* AUDIT[securityd](done):
@@ -913,13 +548,9 @@ static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-    CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
-    if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
-        !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames, 0), prefix)) {
-               /* Common Name prefix mismatch. */
-               SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-       }
-    CFReleaseSafe(commonNames);
+    if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert, prefix)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
 }
 
 /* AUDIT[securityd](done):
@@ -937,20 +568,9 @@ static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-       CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
-       if (!commonNames || CFArrayGetCount(commonNames) != 1) {
-        CFStringRef cert_common_name = CFArrayGetValueAtIndex(commonNames, 0);
-        CFStringRef test_common_name = common_name ?
-            CFStringCreateWithFormat(kCFAllocatorDefault,
-                NULL, CFSTR("TEST %@ TEST"), common_name) :
-            NULL;
-               if (!CFEqual(common_name, cert_common_name) &&
-            (!test_common_name || !CFEqual(test_common_name, cert_common_name)))
-                /* Common Name mismatch. */
-                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-        CFReleaseSafe(test_common_name);
-       }
-       CFReleaseSafe(commonNames);
+    if (!SecPolicyCheckCertSubjectCommonNameTEST(cert, common_name)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
 }
 
 /* AUDIT[securityd](done):
@@ -967,9 +587,7 @@ static void SecPolicyCheckNotValidBefore(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-       CFAbsoluteTime at = CFDateGetAbsoluteTime(date);
-       if (SecCertificateNotValidBefore(cert) <= at) {
-               /* Leaf certificate has not valid before that is too old. */
+    if (!SecPolicyCheckCertNotValidBefore(cert, date)) {
                if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
                        return;
        }
@@ -999,32 +617,51 @@ static void SecPolicyCheckChainLength(SecPVCRef pvc,
     }
 }
 
-/* AUDIT[securityd](done):
-   policy->_options is a caller provided dictionary, only its cf type has
-   been checked.
- */
-static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
-       CFStringRef key) {
-    CFIndex count = SecPVCGetCertificateCount(pvc);
-       SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
-       SecPolicyRef policy = SecPVCGetPolicy(pvc);
+static bool isDigestInPolicy(SecPVCRef pvc, CFStringRef key, CFDataRef digest) {
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
-    CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
 
     bool foundMatch = false;
-
     if (isData(value))
-        foundMatch = CFEqual(anchorSHA1, value);
+        foundMatch = CFEqual(digest, value);
     else if (isArray(value))
-        foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), anchorSHA1);
+        foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest);
     else {
         /* @@@ We only support Data and Array but we can't return an error here so.
-               we let the evaluation fail (not much help) and assert in debug. */
+         we let the evaluation fail (not much help) and assert in debug. */
         assert(false);
     }
 
-    if (!foundMatch)
-        if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, 0, kCFBooleanFalse))
+    return foundMatch;
+}
+
+static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc, CFStringRef key) {
+    CFIndex count = SecPVCGetCertificateCount(pvc);
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
+    CFDataRef anchorSHA256 = NULL;
+    anchorSHA256 = SecCertificateCopySHA256Digest(cert);
+
+    if (!isDigestInPolicy(pvc, key, anchorSHA256)) {
+        SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA256, count-1, kCFBooleanFalse);
+    }
+
+    CFReleaseNull(anchorSHA256);
+    return;
+}
+
+
+/* AUDIT[securityd](done):
+   policy->_options is a caller provided dictionary, only its cf type has
+   been checked.
+ */
+static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
+       CFStringRef key) {
+    CFIndex count = SecPVCGetCertificateCount(pvc);
+       SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
+    CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
+
+    if (!isDigestInPolicy(pvc, key, anchorSHA1))
+        if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, count-1, kCFBooleanFalse))
             return;
 
     return;
@@ -1037,11 +674,8 @@ static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
  */
 static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc,
                                                  CFStringRef key) {
-    SecPolicyRef policy = SecPVCGetPolicy(pvc);
-    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
     SecCertificateRef cert = NULL;
     CFDataRef digest = NULL;
-    bool foundMatch = false;
 
     if (SecPVCGetCertificateCount(pvc) < 2) {
         SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse);
@@ -1051,21 +685,10 @@ static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc,
     cert = SecPVCGetCertificateAtIndex(pvc, 1);
     digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert);
 
-    if (isData(value))
-        foundMatch = CFEqual(digest, value);
-    else if (isArray(value))
-        foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest);
-    else {
-        /* @@@ We only support Data and Array but we can't return an error here so.
-         we let the evaluation fail (not much help) and assert in debug. */
-        assert(false);
+    if (!isDigestInPolicy(pvc, key, digest)) {
+        SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 1, kCFBooleanFalse);
     }
-
     CFReleaseNull(digest);
-
-    if (!foundMatch) {
-        SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse);
-    }
 }
 
 /*
@@ -1076,14 +699,8 @@ static void SecPolicyCheckAnchorApple(SecPVCRef pvc,
                                       CFStringRef key) {
     CFIndex count = SecPVCGetCertificateCount(pvc);
     SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
-    SecPolicyRef policy = SecPVCGetPolicy(pvc);
-    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
     SecAppleTrustAnchorFlags flags = 0;
 
-    if (isDictionary(value)) {
-        if (CFDictionaryGetValue(value, kSecPolicyAppleAnchorIncludeTestRoots))
-            flags |= kSecAppleTrustAnchorFlagsIncludeTestAnchors;
-    }
 
     bool foundMatch = SecIsAppleTrustAnchor(cert, flags);
 
@@ -1110,13 +727,10 @@ static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-       CFArrayRef organization = SecCertificateCopyOrganization(cert);
-       if (!organization || CFArrayGetCount(organization) != 1 ||
-               !CFEqual(org, CFArrayGetValueAtIndex(organization, 0))) {
+    if (!SecPolicyCheckCertSubjectOrganization(cert, org)) {
                /* Leaf Subject Organization mismatch. */
                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
        }
-       CFReleaseSafe(organization);
 }
 
 static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
@@ -1130,13 +744,10 @@ static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
            won't help much either. */
         return;
     }
-       CFArrayRef organizationalUnit = SecCertificateCopyOrganizationalUnit(cert);
-       if (!organizationalUnit || CFArrayGetCount(organizationalUnit) != 1 ||
-               !CFEqual(orgUnit, CFArrayGetValueAtIndex(organizationalUnit, 0))) {
-               /* Leaf Subject Organizational Unit mismatch. */
-               SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-       }
-       CFReleaseSafe(organizationalUnit);
+    if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert, orgUnit)) {
+        /* Leaf Subject Organization mismatch. */
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
 }
 
 /* AUDIT[securityd](done):
@@ -1157,43 +768,8 @@ static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
         return;
     }
 
-    CFIndex tsnCount = CFArrayGetCount(trustedServerNames);
        SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
-       bool dnsMatch = false;
-       CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
-       if (dnsNames) {
-               CFIndex ix, count = CFArrayGetCount(dnsNames);
-        // @@@ This is O(N^2) unfortunately we can't do better easily unless
-        // we don't do wildcard matching. */
-               for (ix = 0; !dnsMatch && ix < count; ++ix) {
-                       CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
-            CFIndex tix;
-            for (tix = 0; tix < tsnCount; ++tix) {
-                CFStringRef serverName =
-                    (CFStringRef)CFArrayGetValueAtIndex(trustedServerNames, tix);
-                if (!isString(serverName)) {
-                    /* @@@ We can't return an error here and making the
-                       evaluation fail won't help much either. */
-                    CFReleaseSafe(dnsNames);
-                    return;
-                }
-                /* we purposefully reverse the arguments here such that dns names
-                   from the cert are matched against a server name list, where
-                   the server names list can contain wildcards and the dns name
-                   cannot.  References: http://support.microsoft.com/kb/941123
-                   It's easy to find occurrences where people tried to use
-                   wildcard certificates and were told that those don't work
-                   in this context. */
-                if (SecDNSMatch(dns, serverName)) {
-                    dnsMatch = true;
-                    break;
-                }
-            }
-               }
-               CFRelease(dnsNames);
-       }
-
-       if (!dnsMatch) {
+    if (!SecPolicyCheckCertEAPTrustedServerNames(leaf, trustedServerNames)) {
                /* Hostname mismatch or no hostnames found in certificate. */
                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
        }
@@ -1260,6 +836,7 @@ static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
                         serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
                     {
                         SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+                        pvc->result = kSecTrustResultFatalTrustFailure;
                         CFReleaseSafe(serial);
                         return;
                     }
@@ -1284,6 +861,7 @@ static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
                                if (CFSetContainsValue(blackListedKeys, dgst))
                                {
                                        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+                    pvc->result = kSecTrustResultFatalTrustFailure;
                                }
                                CFRelease(dgst);
                        }
@@ -1316,7 +894,7 @@ static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key)
                        CFRelease(grayListedKeys);
                }
        }
- }
+}
 
 static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
 {
@@ -1324,227 +902,103 @@ static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
     SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
 
-    if (value && SecCertificateHasMarkerExtension(cert, value))
-        return;
-
-    SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    if (!SecPolicyCheckCertLeafMarkerOid(cert, value)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
 }
 
-static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
+static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key)
 {
-    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
     SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
 
-    for (ix = 1; ix < count - 1; ix++) {
-        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-        if (SecCertificateHasMarkerExtension(cert, value))
-            return;
+    if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
     }
-    SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
 }
 
-/* Returns true if path is on the allow list, false otherwise */
-static bool SecPVCCheckCertificateAllowList(SecPVCRef pvc)
+/*
+ * The value is a dictionary. The dictionary contains keys indicating
+ * whether the value is for Prod or QA. The values are the same as
+ * in the options dictionary for SecPolicyCheckLeafMarkerOid.
+ */
+static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc, CFStringRef key)
 {
-    bool result = false;
-    CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
-    CFStringRef authKey = NULL;
-    SecOTAPKIRef otapkiRef = NULL;
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFDictionaryRef value = CFDictionaryGetValue(policy->_options, key);
+    CFTypeRef prodValue = CFDictionaryGetValue(value, kSecPolicyLeafMarkerProd);
 
-    //get authKeyID from the last chain in the cert
-    if (count < 1) {
-        return result;
-    }
-    SecCertificateRef lastCert = SecPVCGetCertificateAtIndex(pvc, count - 1);
-    CFDataRef authKeyID = SecCertificateGetAuthorityKeyID(lastCert);
-    if (NULL == authKeyID) {
-        return result;
-    }
-    authKey = CFDataCopyHexString(authKeyID);
-
-    //if allowList && key is in allowList, this would have chained up to a now-removed anchor
-    otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
-    if (NULL == otapkiRef) {
-        goto errout;
-    }
-    CFDictionaryRef allowList = SecOTAPKICopyAllowList(otapkiRef);
-    if (NULL == allowList) {
-        goto errout;
+    if (!SecPolicyCheckCertLeafMarkerOid(cert, prodValue)) {
+        bool result = false;
+        if (!result) {
+            SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+        }
     }
+}
 
-    CFArrayRef allowedCerts = CFDictionaryGetValue(allowList, authKey);
-    if (!allowedCerts || !CFArrayGetCount(allowedCerts)) {
-        goto errout;
-    }
+static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
+{
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
 
-    //search sorted array for the SHA256 hash of a cert in the chain
-    CFRange range = CFRangeMake(0, CFArrayGetCount(allowedCerts));
-    for (ix = 0; ix < count; ix++) {
+    for (ix = 1; ix < count - 1; ix++) {
         SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-        if (!cert) {
-            goto errout;
-        }
-
-        CFDataRef certHash = SecCertificateCopySHA256Digest(cert);
-        if (!certHash) {
-            goto errout;
-        }
-
-        CFIndex position = CFArrayBSearchValues(allowedCerts, range, certHash,
-                                                (CFComparatorFunction)CFDataCompare, NULL);
-        if (position < CFArrayGetCount(allowedCerts)) {
-            CFDataRef possibleMatch = CFArrayGetValueAtIndex(allowedCerts, position);
-            if (!CFDataCompare(certHash, possibleMatch)) {
-                //this cert is in the allowlist
-                result = true;
-            }
-        }
-
-        CFRelease(certHash);
+        if (SecCertificateHasMarkerExtension(cert, value))
+            return;
     }
-
-errout:
-    CFRelease(authKey);
-    CFReleaseNull(otapkiRef);
-    CFReleaseNull(allowList);
-    return result;
+    SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
 }
 
+static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc, CFStringRef key)
+{
+       CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+       SecPolicyRef policy = SecPVCGetPolicy(pvc);
+       CFTypeRef peku = CFDictionaryGetValue(policy->_options, key);
 
-/****************************************************************************
- *********************** New rfc5280 Chain Validation ***********************
- ****************************************************************************/
-
-#if 0
-typedef struct cert_path *cert_path_t;
-struct cert_path {
-    int length;
-};
-
-typedef struct x500_name *x500_name_t;
-struct x500_name {
-};
-
-typedef struct algorithm_id *algorithm_id_t;
-struct algorithm_id {
-    oid_t algorithm_oid;
-    der_t parameters;
-};
-
-typedef struct trust_anchor *trust_anchor_t;
-struct trust_anchor {
-    x500_name_t issuer_name;
-    algorithm_id_t public_key_algorithm; /* includes optional params */
-    SecKeyRef public_key;
-};
-
-typedef struct certificate_policy *certificate_policy_t;
-struct certificate_policy {
-    policy_qualifier_t qualifiers;
-    oid_t oid;
-    SLIST_ENTRY(certificate_policy) policies;
-};
-
-typedef struct policy_mapping *policy_mapping_t;
-struct policy_mapping {
-    SLIST_ENTRY(policy_mapping) mappings;
-    oid_t issuer_domain_policy;
-    oid_t subject_domain_policy;
-};
-
-typedef struct root_name *root_name_t;
-struct root_name {
-};
-#endif
-
-struct policy_tree_add_ctx {
-    oid_t p_oid;
-    policy_qualifier_t p_q;
-};
-
-/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */
-static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
-    struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
-    policy_set_t policy_set;
-    for (policy_set = node->expected_policy_set;
-        policy_set;
-        policy_set = policy_set->oid_next) {
-        if (oid_equal(policy_set->oid, info->p_oid)) {
-            policy_tree_add_child(node, &info->p_oid, info->p_q);
-            return true;
-        }
-    }
-    return false;
+       for (ix = 1; ix < count - 1; ix++) {
+               SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (!SecPolicyCheckCertExtendedKeyUsage(cert, peku)) {
+                       SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
+               }
+       }
 }
 
-/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */
-static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
-    struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
-    if (oid_equal(node->valid_policy, oidAnyPolicy)) {
-        policy_tree_add_child(node, &info->p_oid, info->p_q);
-        return true;
-    }
-    return false;
-}
+static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc, CFStringRef key)
+{
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFTypeRef organization = CFDictionaryGetValue(policy->_options, key);
 
-/* Return true iff node has a child with a valid_policy equal to oid. */
-static bool policy_tree_has_child_with_oid(policy_tree_t node,
-    const oid_t *oid) {
-    policy_tree_t child;
-    for (child = node->children; child; child = child->siblings) {
-        if (oid_equal(child->valid_policy, (*oid))) {
-            return true;
+    for (ix = 1; ix < count - 1; ix++) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (!SecPolicyCheckCertSubjectOrganization(cert, organization)) {
+            SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
         }
     }
-    return false;
 }
 
-/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */
-static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
-    policy_qualifier_t p_q = (policy_qualifier_t)ctx;
-    policy_set_t policy_set;
-    bool added_node = false;
-    for (policy_set = node->expected_policy_set;
-        policy_set;
-        policy_set = policy_set->oid_next) {
-        if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
-            policy_tree_add_child(node, &policy_set->oid, p_q);
-            added_node = true;
+static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc, CFStringRef key)
+{
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFTypeRef country = CFDictionaryGetValue(policy->_options, key);
+
+    for (ix = 1; ix < count - 1; ix++) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (!SecPolicyCheckCertSubjectCountry(cert, country)) {
+            SecPVCSetResult(pvc, key, ix, kCFBooleanFalse);
         }
     }
-    return added_node;
 }
 
-#if 0
-/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
-static bool policy_tree_map(policy_tree_t node, void *ctx) {
-    /* Can't map oidAnyPolicy. */
-    if (oid_equal(node->valid_policy, oidAnyPolicy))
-        return false;
-
-    const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
-    uint32_t mapping_ix, mapping_count = pm->numMappings;
-    policy_set_t policy_set = NULL;
-    /* First count how many mappings match this nodes valid_policy. */
-    for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
-        const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
-        if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
-            policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
-            p_node->oid = mapping->subjectDomainPolicy;
-            p_node->oid_next = policy_set ? policy_set : NULL;
-            policy_set = p_node;
-        }
-    }
-    if (policy_set) {
-        policy_tree_set_expected_policy(node, policy_set);
-        return true;
-    }
-    return false;
-}
-#endif
+/****************************************************************************
+ *********************** New rfc5280 Chain Validation ***********************
+ ****************************************************************************/
 
-#define POLICY_MAPPING 0
+#define POLICY_MAPPING 1
 #define POLICY_SUBTREES 1
 
 /* rfc5280 basic cert processing. */
@@ -1553,44 +1007,66 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
     /* Inputs */
     //cert_path_t path;
     CFIndex count = SecPVCGetCertificateCount(pvc);
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
     /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
     assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
     uint32_t n = (uint32_t)count;
-    bool is_anchored = SecPVCIsAnchored(pvc);
+
+    bool is_anchored = SecPathBuilderIsAnchored(pvc->builder);
+    bool is_anchor_trusted = false;
     if (is_anchored) {
-        /* If the anchor is trusted we don't procces the last cert in the
+        CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, n - 1);
+        if (CFArrayGetCount(constraints) == 0) {
+            /* Given that the path builder has already indicated the last cert in this chain has
+             * trust set on it, empty constraints means trusted. */
+            is_anchor_trusted = true;
+        } else {
+            /* Determine whether constraints say to trust this cert for this PVC. */
+            SecTrustSettingsResult tsResult = SecPVCGetTrustSettingsResult(pvc, SecCertificatePathVCGetCertificateAtIndex(path, n - 1),
+                                                                           constraints);
+            if (tsResult == kSecTrustSettingsResultTrustRoot || tsResult == kSecTrustSettingsResultTrustAsRoot) {
+                is_anchor_trusted = true;
+            }
+        }
+    }
+
+    if (is_anchor_trusted) {
+        /* If the anchor is trusted we don't process the last cert in the
            chain (root). */
         n--;
     } else {
-        /* trust may be restored for a path with an untrusted root that matches the allow list */
-        if (!SecPVCCheckCertificateAllowList(pvc)) {
+        /* trust may be restored for a path with an untrusted root that matches the allow list.
+           (isAllowlisted is set by revocation check, which is performed prior to path checks) */
+        if (!SecCertificatePathVCIsAllowlisted(path)) {
             /* Add a detail for the root not being trusted. */
-            if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
-                                      n - 1, kCFBooleanFalse, true))
+            if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
+                                      n - 1, kCFBooleanFalse, true)) {
                 return;
+            }
         }
     }
 
     CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
     //policy_set_t user_initial_policy_set = NULL;
     //trust_anchor_t anchor;
-    bool initial_policy_mapping_inhibit = false;
-    bool initial_explicit_policy = false;
-    bool initial_any_policy_inhibit = false;
 
     /* Initialization */
-    pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
 #if POLICY_SUBTREES
     CFMutableArrayRef permitted_subtrees = NULL;
     CFMutableArrayRef excluded_subtrees = NULL;
     permitted_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
     excluded_subtrees = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-    assert(permitted_subtrees != NULL);
-    assert(excluded_subtrees != NULL);
+    require_action_quiet(permitted_subtrees != NULL, errOut,
+                         SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true));
+    require_action_quiet(excluded_subtrees != NULL, errOut,
+                         SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true));
 #endif
-    uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
-    uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
-    uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
+
+    if (!SecCertificatePathVCVerifyPolicyTree(path, is_anchor_trusted)) {
+        if (!SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true)) {
+            goto errOut;
+        }
+    }
 
 #if 0
     /* Path builder ensures we only get cert chains with proper issuer
@@ -1604,7 +1080,7 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
     for (i = 1; i <= n; ++i) {
         /* Process Cert */
         cert = SecPVCGetCertificateAtIndex(pvc, n - i);
-        bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i);
+        bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc->builder), n - i);
 
         /* (a) Verify the basic certificate information. */
         /* @@@ Ensure that cert was signed with working_public_key_algorithm
@@ -1613,15 +1089,16 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
         /* Already done by chain builder. */
         if (!SecCertificateIsValid(cert, verify_time)) {
             CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
-            if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse))
-                return;
+            if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) {
+                goto errOut;
+            }
         }
-#endif
-#if 0
-        /* Check revocation status if the certificate asks for it. */
-        CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
-        if (ocspResponders) {
-            SecPVCSetCheckRevocation(pvc);
+        if (SecCertificateIsWeakKey(cert)) {
+            CFStringRef fail_key = i == n ? kSecPolicyCheckWeakLeaf : kSecPolicyCheckWeakIntermediates;
+            if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) {
+                goto errOut;
+            }
+            pvc->result = kSecTrustResultFatalTrustFailure;
         }
 #endif
         /* @@@ cert.issuer == working_issuer_name. */
@@ -1633,115 +1110,28 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
             /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */
             if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) {
                 if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) {
-                    if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) return;
+                    secnotice("policy", "name in excluded subtrees");
+                    if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) { goto errOut; }
                 }
             }
             /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */
             if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) {
                if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) {
-                   if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) return;
+                   secnotice("policy", "name not in permitted subtrees");
+                   if(!SecPVCSetResultForced(pvc, key, n - i, kCFBooleanFalse, true)) { goto errOut; }
                }
             }
         }
 #endif
-        /* (d) */
-        if (pvc->valid_policy_tree) {
-            const SecCECertificatePolicies *cp =
-                SecCertificateGetCertificatePolicies(cert);
-            size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
-            for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
-                const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
-                oid_t p_oid = policy->policyIdentifier;
-                policy_qualifier_t p_q = &policy->policyQualifiers;
-                struct policy_tree_add_ctx ctx = { p_oid, p_q };
-                if (!oid_equal(p_oid, oidAnyPolicy)) {
-                    if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
-                        policy_tree_add_if_match, &ctx)) {
-                        policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
-                        policy_tree_add_if_any, &ctx);
-                    }
-                }
-            }
-            /* The certificate policies extension includes the policy
-               anyPolicy with the qualifier set AP-Q and either
-               (a) inhibit_anyPolicy is greater than 0 or
-               (b) i < n and the certificate is self-issued. */
-            if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
-                for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
-                    const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
-                    oid_t p_oid = policy->policyIdentifier;
-                    policy_qualifier_t p_q = &policy->policyQualifiers;
-                    if (oid_equal(p_oid, oidAnyPolicy)) {
-                        policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
-                            policy_tree_add_expected, (void *)p_q);
-                    }
-                }
-            }
-            policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
-            /* (e) */
-            if (!cp) {
-                if (pvc->valid_policy_tree)
-                    policy_tree_prune(&pvc->valid_policy_tree);
-            }
-        }
-        /* (f) Verify that either explicit_policy is greater than 0 or the
-           valid_policy_tree is not equal to NULL. */
-        if (!pvc->valid_policy_tree && explicit_policy == 0) {
-            /* valid_policy_tree is empty and explicit policy is 0, illegal. */
-            if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true))
-                return;
-        }
+        /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */
+
         /* If Last Cert in Path */
         if (i == n)
             break;
 
         /* Prepare for Next Cert */
-#if POLICY_MAPPING
-        /* (a) verify that anyPolicy does not appear as an
-           issuerDomainPolicy or a subjectDomainPolicy */
-        CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert);
-        if (pm) {
-            uint32_t mapping_ix, mapping_count = pm->numMappings;
-            for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
-                const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
-                if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
-                    || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
-                    /* Policy mapping uses anyPolicy, illegal. */
-                    if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse))
-                        return;
-                }
-            }
-            /* (b) */
-            /* (1) If the policy_mapping variable is greater than 0 */
-            if (policy_mapping > 0) {
-                if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
-                    policy_tree_map, (void *)pm)) {
-                        /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows:
-
-            (i)    set the valid_policy to ID-P;
-
-            (ii)   set the qualifier_set to the qualifier set of the
-                   policy anyPolicy in the certificate policies
-                   extension of certificate i; and
-    (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
-                    }
-            } else {
-    #if 0
-                /* (i)    delete each node of depth i in the valid_policy_tree
-                   where ID-P is the valid_policy. */
-                struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid };
-                policy_tree_walk_depth(pvc->valid_policy_tree, i,
-                    policy_tree_delete_if_match, &ctx);
-    #endif
-                /* (ii)   If there is a node in the valid_policy_tree of depth
-                   i-1 or less without any child nodes, delete that
-                   node.  Repeat this step until there are no nodes of
-                   depth i-1 or less without children. */
-                policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
-            }
-        }
-#endif /* POLICY_MAPPING */
-        /* (c)(d)(e)(f) */
+        /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */
+        /* (c)(d)(e)(f)  Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */
         //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
         //working_public_key = SecCertificateCopyPublicKey(cert);
         //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
@@ -1762,42 +1152,18 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
             CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range);
         }
 #endif
-        /* (h) */
-        if (!is_self_issued) {
-            if (explicit_policy)
-                explicit_policy--;
-            if (policy_mapping)
-                policy_mapping--;
-            if (inhibit_any_policy)
-                inhibit_any_policy--;
-        }
-        /* (i) */
-        const SecCEPolicyConstraints *pc =
-            SecCertificateGetPolicyConstraints(cert);
-        if (pc) {
-            if (pc->requireExplicitPolicyPresent
-                && pc->requireExplicitPolicy < explicit_policy) {
-                explicit_policy = pc->requireExplicitPolicy;
-            }
-            if (pc->inhibitPolicyMappingPresent
-                && pc->inhibitPolicyMapping < policy_mapping) {
-                policy_mapping = pc->inhibitPolicyMapping;
-            }
-        }
-        /* (j) */
-        uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
-        if (iap < inhibit_any_policy) {
-            inhibit_any_policy = iap;
-        }
+        /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */
+
         /* (k) */
                const SecCEBasicConstraints *bc =
                        SecCertificateGetBasicConstraints(cert);
-#if 0 /* Checked in chain builder pre signature verify already. */
+#if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
         if (!bc || !bc->isCA) {
             /* Basic constraints not present or not marked as isCA, illegal. */
-            if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
-                n - i, kCFBooleanFalse))
-                return;
+            if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints,
+                                 n - i, kCFBooleanFalse)) {
+                goto errOut;
+            }
         }
 #endif
         /* (l) */
@@ -1806,9 +1172,10 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
                 max_path_length--;
             } else {
                 /* max_path_len exceeded, illegal. */
-                if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
-                    n - i, kCFBooleanFalse))
-                    return;
+                if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints,
+                                     n - i, kCFBooleanFalse)) {
+                    goto errOut;
+                }
             }
         }
         /* (m) */
@@ -1816,36 +1183,27 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
             && bc->pathLenConstraint < max_path_length) {
             max_path_length = bc->pathLenConstraint;
         }
-#if 0 /* Checked in chain builder pre signature verify already. */
+#if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */
         /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
         SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
         if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
             if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
-                n - i, kCFBooleanFalse, true))
-                return;
+                                       n - i, kCFBooleanFalse, true)) {
+                goto errOut;
+            }
         }
 #endif
         /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */
         if (SecCertificateHasUnknownCriticalExtension(cert)) {
                        /* Certificate contains one or more unknown critical extensions. */
                        if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
-                n - i, kCFBooleanFalse))
-                               return;
+                                 n - i, kCFBooleanFalse)) {
+                goto errOut;
+            }
                }
     } /* end loop over certs in path */
     /* Wrap up */
-    cert = SecPVCGetCertificateAtIndex(pvc, 0);
-    /* (a) */
-    if (explicit_policy)
-        explicit_policy--;
-    /* (b) */
-    const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
-    if (pc) {
-        if (pc->requireExplicitPolicyPresent
-            && pc->requireExplicitPolicy == 0) {
-            explicit_policy = 0;
-        }
-    }
+    /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */
     /* (c) */
     //working_public_key = SecCertificateCopyPublicKey(cert);
     /* (d) */
@@ -1858,28 +1216,13 @@ working_public_key_algorithm are different, set the working_public_key_parameter
     if (SecCertificateHasUnknownCriticalExtension(cert)) {
         /* Certificate contains one or more unknown critical extensions. */
         if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
-                             0, kCFBooleanFalse))
-            return;
-    }
-    /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
-
-    if (pvc->valid_policy_tree) {
-#if !defined(NDEBUG)
-        policy_tree_dump(pvc->valid_policy_tree);
-#endif
-        /* (g3c4) */
-        //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
-    }
-
-    /* If either (1) the value of explicit_policy variable is greater than
-       zero or (2) the valid_policy_tree is not NULL, then path processing
-       has succeeded. */
-    if (!pvc->valid_policy_tree && explicit_policy == 0) {
-        /* valid_policy_tree is empty and explicit policy is 0, illegal. */
-        if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true))
-            return;
+                             0, kCFBooleanFalse)) {
+            goto errOut;
+        }
     }
+    /* (g) done by SecCertificatePathVCVerifyPolicyTree */
 
+errOut:
     CFReleaseNull(permitted_subtrees);
     CFReleaseNull(excluded_subtrees);
 }
@@ -1900,6 +1243,19 @@ static void SecPolicyCheckEV(SecPVCRef pvc,
        CFIndex ix, count = SecPVCGetCertificateCount(pvc);
     policy_set_t valid_policies = NULL;
 
+    /* 6.1.7. Key Usage Purposes */
+    if (count) {
+        CFAbsoluteTime jul2016 = 489024000;
+        SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
+        if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) {
+            /* Root CAs may not sign subscriber certificates after 30 June 2016. */
+            if (SecPVCSetResultForced(pvc, key,
+                    0, kCFBooleanFalse, true)) {
+                return;
+            }
+        }
+    }
+
        for (ix = 0; ix < count; ++ix) {
                SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
         policy_set_t policies = policies_for_cert(cert);
@@ -1914,7 +1270,7 @@ static void SecPolicyCheckEV(SecPVCRef pvc,
         } else if (ix < count - 1) {
             /* Subordinate CA */
             if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
-                secdebug("ev", "subordinate certificate is not ev");
+                secnotice("ev", "subordinate certificate is not ev");
                 if (SecPVCSetResultForced(pvc, key,
                     ix, kCFBooleanFalse, true)) {
                     policy_set_free(valid_policies);
@@ -1926,7 +1282,7 @@ static void SecPolicyCheckEV(SecPVCRef pvc,
         } else {
             /* Root CA */
             if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
-                secdebug("ev", "anchor certificate is not ev");
+                secnotice("ev", "anchor certificate is not ev");
                 if (SecPVCSetResultForced(pvc, key,
                     ix, kCFBooleanFalse, true)) {
                     policy_set_free(valid_policies);
@@ -1937,7 +1293,7 @@ static void SecPolicyCheckEV(SecPVCRef pvc,
         }
         policy_set_free(policies);
         if (!valid_policies) {
-            secdebug("ev", "valid_policies set is empty: chain not ev");
+            secnotice("ev", "valid_policies set is empty: chain not ev");
             /* If we ever get into a state where no policies are valid anymore
                this can't be an ev chain. */
             if (SecPVCSetResultForced(pvc, key,
@@ -2116,20 +1472,46 @@ out:
     return data;
 }
 
-/* If the 'sct' is valid, return the operator ID of the log that signed this sct.
+static
+CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts)
+{
+    return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970;
+}
+
+static
+uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at)
+{
+    return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000;
+}
+
+
+
+
+/*
+   If the 'sct' is valid, add it to the validatingLogs dictionary.
+
+   Inputs:
+    - validatingLogs: mutable dictionary to which to add the log that validate this SCT.
+    - sct: the SCT date
+    - entry_type: 0 for x509 cert, 1 for precert.
+    - entry: the cert or precert data.
+    - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch)
+    - trustedLog: Dictionary contain the Trusted Logs.
 
    The SCT is valid if:
     - It decodes properly.
     - Its timestamp is less than 'verifyTime'.
     - It is signed by a log in 'trustedLogs'.
-    - The signing log expiryTime (if any) is less than 'verifyTime' (entry_type==0) or 'issuanceTime' (entry_type==1).
+    - If entry_type = 0, the log must be currently qualified.
+    - If entry_type = 1, the log may be expired.
 
-   If the SCT is valid, the returned CFStringRef is the identifier for the log operator. That value is not retained.
-   If the SCT is valid, '*validLogAtVerifyTime' is set to true if the log is not expired at 'verifyTime'
+   If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value.
+   If an entry for the same log already existing in the dictionary, the entry is replaced only if the timestamp of this SCT is earlier.
 
-   If the SCT is not valid this function return NULL.
  */
-static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataRef entry, CFAbsoluteTime verifyTime, CFAbsoluteTime issuanceTime, CFArrayRef trustedLogs, bool *validLogAtVerifyTime)
+
+
+static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFArrayRef trustedLogs, CFAbsoluteTime *sct_at)
 {
     uint8_t version;
     const uint8_t *logID;
@@ -2141,15 +1523,15 @@ static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataR
     uint8_t sigAlg;
     size_t signatureLen;
     const uint8_t *signatureData;
-    CFStringRef result = NULL;
     SecKeyRef pubKey = NULL;
     uint8_t *signed_data = NULL;
     const SecAsn1Oid *oid = NULL;
     SecAsn1AlgId algId;
+    CFDataRef logIDData = NULL;
+    CFDictionaryRef result = 0;
 
     const uint8_t *p = CFDataGetBytePtr(sct);
     size_t len = CFDataGetLength(sct);
-    uint64_t vt =(uint64_t)( verifyTime + kCFAbsoluteTimeIntervalSince1970) * 1000;
 
     require(len>=43, out);
 
@@ -2196,7 +1578,7 @@ static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataR
     q = SSLEncodeUint16(q, extensionsLen);
     memcpy(q, extensionsData, extensionsLen);
 
-    CFDataRef logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, NULL);
+    logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull);
 
     CFDictionaryRef logData = CFArrayGetValueMatching(trustedLogs, ^bool(const void *dict) {
         const void *key_data;
@@ -2210,18 +1592,9 @@ static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataR
     });
     require(logData, out);
 
-    /* If an expiry date is specified, and is a valid CFDate, then we check it against issuanceTime or verifyTime */
-    const void *expiry_date;
-    if(CFDictionaryGetValueIfPresent(logData, CFSTR("expiry"), &expiry_date) && isDate(expiry_date)) {
-        CFAbsoluteTime expiryTime = CFDateGetAbsoluteTime(expiry_date);
-        if(entry_type == 1) {/* pre-cert: check the validity of the log at issuanceTime */
-            require(issuanceTime<=expiryTime, out);
-        } else {
-            require(verifyTime<=expiryTime, out);
-        }
-        *validLogAtVerifyTime = (verifyTime<=expiryTime);
-    } else {
-        *validLogAtVerifyTime = true;
+    if(entry_type==0) {
+        // For external SCTs, only keep SCTs from currently valid logs.
+        require(!CFDictionaryContainsKey(logData, CFSTR("expiry")), out);
     }
 
     CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
@@ -2237,17 +1610,31 @@ static CFStringRef get_valid_sct_operator(CFDataRef sct, int entry_type, CFDataR
     algId.parameters.Length = 0;
 
     if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
-        result = CFDictionaryGetValue(logData, CFSTR("operator"));
+        *sct_at = TimestampToCFAbsoluteTime(timestamp);
+        result = logData;
     } else {
         secerror("SCT signature failed (log=%@)\n", logData);
     }
 
 out:
+    CFReleaseSafe(logIDData);
     CFReleaseSafe(pubKey);
     free(signed_data);
     return result;
 }
 
+
+static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at)
+{
+    CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log);
+
+    if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) {
+        CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at);
+        CFDictionarySetValue(validatingLogs, log, sct_time);
+        CFReleaseSafe(sct_time);
+    }
+}
+
 static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
 {
     CFMutableArrayRef SCTs = NULL;
@@ -2283,8 +1670,8 @@ static CFArrayRef copy_ocsp_scts(SecPVCRef pvc)
                 }
                 SecOCSPSingleResponseDestroy(ocspSingleResponse);
             }
-            SecOCSPResponseFinalize(ocspResponse);
         }
+        if(ocspResponse) SecOCSPResponseFinalize(ocspResponse);
     });
 
     if(CFArrayGetCount(SCTs)==0) {
@@ -2309,91 +1696,131 @@ static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key)
     CFDataRef precertEntry = copy_precert_entry_from_chain(pvc);
     CFDataRef x509Entry = copy_x509_entry_from_chain(pvc);
 
-    // This eventually contain the list of operators who validated the SCT.
-    CFMutableSetRef operatorsValidatingEmbeddedScts = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
-    CFMutableSetRef operatorsValidatingExternalScts = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
+    // This eventually contain list of logs who validated the SCT.
+    CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+    uint64_t vt = TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc));
 
-    __block bool atLeastOneValidAtVerifyTime = false;
-    __block int lifetime; // in Months
+    __block bool at_least_one_currently_valid_external = 0;
+    __block bool at_least_one_currently_valid_embedded = 0;
 
-    require(operatorsValidatingEmbeddedScts, out);
-    require(operatorsValidatingExternalScts, out);
+    require(logsValidatingEmbeddedScts, out);
+    require(currentLogsValidatingScts, out);
 
     if(trustedLogs) { // Don't bother trying to validate SCTs if we don't have any trusted logs.
-        if(embeddedScts) {
+        if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert.
             CFArrayForEach(embeddedScts, ^(const void *value){
-                bool validLogAtVerifyTime = false;
-                CFStringRef operator = get_valid_sct_operator(value, 1, precertEntry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
-                if(operator) CFSetAddValue(operatorsValidatingEmbeddedScts, operator);
-                if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
+                CFAbsoluteTime sct_at;
+                CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, trustedLogs, &sct_at);
+                if(log) {
+                    addValidatingLog(logsValidatingEmbeddedScts, log, sct_at);
+                    if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
+                        addValidatingLog(currentLogsValidatingScts, log, sct_at);
+                        at_least_one_currently_valid_embedded = true;
+                    }
+                }
             });
         }
 
-        if(builderScts) {
+        if(builderScts && x509Entry) { // Don't bother if we could not get the cert.
             CFArrayForEach(builderScts, ^(const void *value){
-                bool validLogAtVerifyTime = false;
-                CFStringRef operator = get_valid_sct_operator(value, 0, x509Entry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
-                if(operator) CFSetAddValue(operatorsValidatingExternalScts, operator);
-                if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
+                CFAbsoluteTime sct_at;
+                CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
+                if(log) {
+                    addValidatingLog(currentLogsValidatingScts, log, sct_at);
+                    at_least_one_currently_valid_external = true;
+                }
             });
         }
 
-        if(ocspScts) {
+        if(ocspScts && x509Entry) {
             CFArrayForEach(ocspScts, ^(const void *value){
-                bool validLogAtVerifyTime = false;
-                CFStringRef operator = get_valid_sct_operator(value, 0, x509Entry, pvc->verifyTime, SecCertificateNotValidBefore(leafCert), trustedLogs, &validLogAtVerifyTime);
-                if(operator) CFSetAddValue(operatorsValidatingExternalScts, operator);
-                if(validLogAtVerifyTime) atLeastOneValidAtVerifyTime = true;
+                CFAbsoluteTime sct_at;
+                CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, trustedLogs, &sct_at);
+                if(log) {
+                    addValidatingLog(currentLogsValidatingScts, log, sct_at);
+                    at_least_one_currently_valid_external = true;
+                }
             });
         }
     }
 
-    /* We now have 2 sets of operators that validated those SCTS, count them and make a final decision.
-       Current Policy:
-        is_ct = (A1 OR A2) AND B.
 
-       A1: 2+ to 5+ SCTs from the cert from independent logs valid at issuance time
-         (operatorsValidatingEmbeddedScts)
-       A2: 2+ SCTs from external sources (OCSP stapled response and TLS extension)
-         from independent logs valid at verify time. (operatorsValidatingExternalScts)
-       B: All least one SCTs from a log valid at verify time.
+    /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision.
 
-       Policy is based on: https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxjZXJ0aWZpY2F0ZXRyYW5zcGFyZW5jeXxneDo0ODhjNGRlOTIyMzYwNTcz
-        with one difference: we consider SCTs from OCSP and TLS extensions as a whole.
-       It sounds like this is what Google will eventually do, per:
-        https://groups.google.com/forum/?fromgroups#!topic/certificate-transparency/VdXuzA3TLWY
+     Current Policy:
+     is_ct = (A1 AND A2) OR (B1 AND B2).
 
-     */
+     A1: embedded SCTs from 2+ to 5+ logs valid at issuance time
+     A2: At least one embedded SCT from a currently valid log.
 
-    SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
-        int _lifetime;
-        CFCalendarGetComponentDifference(zuluCalendar,
-                                         SecCertificateNotValidBefore(leafCert),
-                                         SecCertificateNotValidAfter(leafCert),
-                                         0, "M", &_lifetime);
-        lifetime = _lifetime;
-    });
+     B1: SCTs from 2 currently valid logs (from any source)
+     B2: At least 1 external SCT from a currently valid log.
 
-    CFIndex requiredEmbeddedSctsCount;
+     */
 
-    if (lifetime < 15) {
-        requiredEmbeddedSctsCount = 2;
-    } else if (lifetime <= 27) {
-        requiredEmbeddedSctsCount = 3;
-    } else if (lifetime <= 39) {
-        requiredEmbeddedSctsCount = 4;
-    } else {
-        requiredEmbeddedSctsCount = 5;
-    }
+    SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc->builder), false);
+
+    if(at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2) {
+        SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc->builder), true);
+    } else if(at_least_one_currently_valid_embedded) {
+        __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc);
+        __block int lifetime; // in Months
+        __block unsigned once_or_current_qualified_embedded = 0;
+
+        /* Calculate issuance time base on timestamp of SCTs from current logs */
+        CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) {
+            CFDictionaryRef log = key;
+            if(!CFDictionaryContainsKey(log, CFSTR("expiry"))) {
+                // Log is still qualified
+                CFDateRef ts = (CFDateRef) value;
+                CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts);
+                if(timestamp < issuanceTime) {
+                    issuanceTime = timestamp;
+                }
+            }
+        });
+
+        /* Count Logs */
+        CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) {
+            CFDictionaryRef log = key;
+            CFDateRef ts = value;
+            CFDateRef expiry = CFDictionaryGetValue(log, CFSTR("expiry"));
+            if(expiry == NULL || CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan) {
+                once_or_current_qualified_embedded++;
+            }
+        });
+
+        SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+            int _lifetime;
+            CFCalendarGetComponentDifference(zuluCalendar,
+                                             SecCertificateNotValidBefore(leafCert),
+                                             SecCertificateNotValidAfter(leafCert),
+                                             0, "M", &_lifetime);
+            lifetime = _lifetime;
+        });
+
+        unsigned requiredEmbeddedSctsCount;
+
+        if (lifetime < 15) {
+            requiredEmbeddedSctsCount = 2;
+        } else if (lifetime <= 27) {
+            requiredEmbeddedSctsCount = 3;
+        } else if (lifetime <= 39) {
+            requiredEmbeddedSctsCount = 4;
+        } else {
+            requiredEmbeddedSctsCount = 5;
+        }
 
-    pvc->is_ct = ((CFSetGetCount(operatorsValidatingEmbeddedScts) >= requiredEmbeddedSctsCount) ||
-                  (CFSetGetCount(operatorsValidatingExternalScts) >= 2)
-                 ) && atLeastOneValidAtVerifyTime;
+        if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){
+            SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc->builder), true);
+        }
+    }
 
 out:
-
-    CFReleaseSafe(operatorsValidatingEmbeddedScts);
-    CFReleaseSafe(operatorsValidatingExternalScts);
+    CFReleaseSafe(logsValidatingEmbeddedScts);
+    CFReleaseSafe(currentLogsValidatingScts);
     CFReleaseSafe(builderScts);
     CFReleaseSafe(embeddedScts);
     CFReleaseSafe(ocspScts);
@@ -2402,515 +1829,279 @@ out:
     CFReleaseSafe(x509Entry);
 }
 
+static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) {
+       CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    DERItem    key_value;
+    key_value.data = (DERByte *)CFDataGetBytePtr(oid);
+    key_value.length = (DERSize)CFDataGetLength(oid);
+
+    for (ix = 0; ix < count; ix++) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        policy_set_t policies = policies_for_cert(cert);
+
+        if (policy_set_contains(policies, &key_value)) {
+            policy_set_free(policies);
+            return true;
+        }
+        policy_set_free(policies);
+    }
+    return false;
+}
+
 static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key)
 {
-       CFIndex ix, count = SecPVCGetCertificateCount(pvc);
     SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
-       DERItem key_value;
-       key_value.data = NULL;
-       key_value.length = 0;
+    bool result = false;
 
        if (CFGetTypeID(value) == CFDataGetTypeID())
        {
-               CFDataRef key_data = (CFDataRef)value;
-               key_value.data = (DERByte *)CFDataGetBytePtr(key_data);
-               key_value.length = (DERSize)CFDataGetLength(key_data);
-
-               for (ix = 0; ix < count; ix++) {
-               SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-            policy_set_t policies = policies_for_cert(cert);
-
-                       if (policy_set_contains(policies, &key_value)) {
-                               return;
-                       }
-               }
+        result = checkPolicyOidData(pvc, value);
+    } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
+        CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value);
+        if (dataOid) {
+            result = checkPolicyOidData(pvc, dataOid);
+            CFRelease(dataOid);
+        }
+    }
+    if(!result) {
                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
-       }
+    }
 }
 
 
 static void SecPolicyCheckRevocation(SecPVCRef pvc,
        CFStringRef key) {
-    SecPVCSetCheckRevocation(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
+    if (isString(value)) {
+        SecPathBuilderSetRevocationMethod(pvc->builder, value);
+    }
 }
 
 static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc,
        CFStringRef key) {
-    SecPVCSetCheckRevocationResponseRequired(pvc);
+    pvc->require_revocation_response = true;
+    secdebug("policy", "revocation response required");
 }
 
-static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
-       CFStringRef key) {
-    SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
+static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) {
+    SecPathBuilderSetCheckRevocationOnline(pvc->builder);
 }
 
-// MARK: -
-// MARK: SecRVCRef
-/********************************************************
- ****************** SecRVCRef Functions *****************
- ********************************************************/
-
-const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
-
-/* Revocation verification context. */
-struct OpaqueSecRVC {
-    /* Will contain the response data. */
-    asynchttp_t http;
-
-    /* Pointer to the pvc for this revocation check. */
-    SecPVCRef pvc;
-
-    /* The ocsp request we send to each responder. */
-    SecOCSPRequestRef ocspRequest;
-
-    /* The freshest response we received so far, from stapling or cache or responder. */
-    SecOCSPResponseRef ocspResponse;
-
-    /* The best validated candidate single response we received so far, from stapling or cache or responder. */
-    SecOCSPSingleResponseRef ocspSingleResponse;
-
-    /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
-    CFIndex certIX;
-
-    /* Index in array returned by SecCertificateGetOCSPResponders() for current
-       responder. */
-    CFIndex responderIX;
-
-    /* URL of current responder. */
-    CFURLRef responder;
-
-    /* Date until which this revocation status is valid. */
-    CFAbsoluteTime nextUpdate;
+static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
+    CFStringRef key) {
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
+    if (value == kCFBooleanTrue) {
+        SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
+    } else {
+        SecPathBuilderSetCanAccessNetwork(pvc->builder, true);
+    }
+}
 
-    bool done;
-};
-typedef struct OpaqueSecRVC *SecRVCRef;
-
-static void SecRVCDelete(SecRVCRef rvc) {
-    secdebug("alloc", "%p", rvc);
-    asynchttp_free(&rvc->http);
-    SecOCSPRequestFinalize(rvc->ocspRequest);
-    if (rvc->ocspResponse) {
-        SecOCSPResponseFinalize(rvc->ocspResponse);
-        rvc->ocspResponse = NULL;
-        if (rvc->ocspSingleResponse) {
-            SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
-            rvc->ocspSingleResponse = NULL;
-        }
-    }
-}
-
-/* Return the next responder we should contact for this rvc or NULL if we
-   exhausted them all. */
-static CFURLRef SecRVCGetNextResponder(SecRVCRef rvc) {
-    SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
-    CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
-    if (ocspResponders) {
-        CFIndex responderCount = CFArrayGetCount(ocspResponders);
-        while (rvc->responderIX < responderCount) {
-            CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
-            rvc->responderIX++;
-            CFStringRef scheme = CFURLCopyScheme(responder);
-            if (scheme) {
-                /* We only support http and https responders currently. */
-                bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
-                                        CFEqual(CFSTR("https"), scheme));
-                CFRelease(scheme);
-                if (valid_responder)
-                    return responder;
-            }
+static void SecPolicyCheckWeakIntermediates(SecPVCRef pvc,
+    CFStringRef key) {
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    for (ix = 1; ix < count - 1; ++ix) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (cert && SecCertificateIsWeakKey(cert)) {
+            /* Intermediate certificate has a weak key. */
+            if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
+                return;
+            pvc->result = kSecTrustResultFatalTrustFailure;
         }
     }
-    return NULL;
 }
 
-/* Fire off an async http request for this certs revocation status, return
-   false if request was queued, true if we're done. */
-static bool SecRVCFetchNext(SecRVCRef rvc) {
-    while ((rvc->responder = SecRVCGetNextResponder(rvc))) {
-        CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
-        if (!request)
-            goto errOut;
-
-        secdebug("ocsp", "Sending http ocsp request for cert %ld", rvc->certIX);
-        if (!asyncHttpPost(rvc->responder, request, &rvc->http)) {
-            /* Async request was posted, wait for reply. */
-            return false;
-        }
+static void SecPolicyCheckWeakLeaf(SecPVCRef pvc,
+    CFStringRef key) {
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
+    if (cert && SecCertificateIsWeakKey(cert)) {
+        /* Leaf certificate has a weak key. */
+        if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
+            return;
+        pvc->result = kSecTrustResultFatalTrustFailure;
     }
+}
 
-errOut:
-    rvc->done = true;
-    return true;
+static void SecPolicyCheckWeakRoot(SecPVCRef pvc,
+    CFStringRef key) {
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    ix = count - 1;
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+    if (cert && SecCertificateIsWeakKey(cert)) {
+        /* Root certificate has a weak key. */
+        if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
+            return;
+        pvc->result = kSecTrustResultFatalTrustFailure;
+    }
 }
 
-/* Process a verified ocsp response for a given cert. Return true if the
-   certificate status was obtained. */
-static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
-    SecRVCRef rvc) {
-    bool processed;
-    switch (this->certStatus) {
-    case CS_Good:
-        secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
-        /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
-           in the info dictionary. */
-        //cert.revokeCheckGood(true);
-        rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate;
-        processed = true;
-        break;
-    case CS_Revoked:
-        secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
-        /* @@@ Mark cert as revoked (with reason) at revocation date in
-           the info dictionary, or perhaps we should use a different key per
-           reason?   That way a client using exceptions can ignore some but
-           not all reasons. */
-        SInt32 reason = this->crlReason;
-        CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
-        SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
-            cfreason, true);
-        if (rvc->pvc && rvc->pvc->info) {
-            /* make the revocation reason available in the trust result */
-            CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason);
-        }
-        CFRelease(cfreason);
-        processed = true;
-        break;
-    case CS_Unknown:
-        /* not an error, no per-cert status, nothing here */
-        secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
-        processed = false;
-        break;
-    default:
-        secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
-            (int)this->certStatus, rvc->certIX);
-        processed = false;
-        break;
-    }
-
-    return processed;
-}
-
-static void SecRVCUpdatePVC(SecRVCRef rvc) {
-    if (rvc->ocspSingleResponse) {
-        SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
-    }
-    if (rvc->ocspResponse) {
-        rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
-    }
-}
-
-static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecRVCRef rvc, CFAbsoluteTime verifyTime) {
-    bool trusted;
-    SecCertificatePathRef issuer = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
-    SecCertificatePathRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
-    CFRelease(issuer);
-
-    if (signer) {
-        if (signer == issuer) {
-            /* We already know we trust issuer since it's the path we are
-               trying to verify minus the leaf. */
-            secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
-                rvc->responder);
-            trusted = true;
-        } else {
-            secdebug("ocsp",
-                "ocsp responder: %@ response signed by cert issued by issuer",
-                rvc->responder);
-            /* @@@ Now check that we trust signer. */
-            const void *ocspSigner = SecPolicyCreateOCSPSigner();
-            CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
-                &ocspSigner, 1, &kCFTypeArrayCallBacks);
-            CFRelease(ocspSigner);
-            struct OpaqueSecPVC ospvc;
-            SecPVCInit(&ospvc, rvc->pvc->builder, policies, verifyTime);
-            CFRelease(policies);
-            SecPVCSetPath(&ospvc, signer, NULL);
-            SecPVCLeafChecks(&ospvc);
-            if (ospvc.result) {
-                bool completed = SecPVCPathChecks(&ospvc);
-                /* If completed is false we are waiting for a callback, this
-                   shouldn't happen since we aren't asking for details, no
-                   revocation checking is done. */
-                if (!completed) {
-                    ocspdErrorLog("SecPVCPathChecks unexpectedly started "
-                        "background job!");
-                    /* @@@ assert() or abort here perhaps? */
-                }
-            }
-            if (ospvc.result) {
-                secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
-                    rvc->responder);
-                trusted = true;
-            } else {
-                /* @@@ We don't trust the cert so don't use this response. */
-                ocspdErrorLog("ocsp response signed by certificate which "
-                    "does not satisfy ocspSigner policy");
-                trusted = false;
-            }
-            SecPVCDelete(&ospvc);
+static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) {
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key);
+    for (ix = 0; ix < count; ++ix) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) {
+            if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
+                return;
         }
-
-        CFRelease(signer);
-    } else {
-        /* @@@ No signer found for this ocsp response, discard it. */
-        secdebug("ocsp", "ocsp responder: %@ no signer found for response",
-            rvc->responder);
-        trusted = false;
     }
-
-#if DUMP_OCSPRESPONSES
-    char buf[40];
-    snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
-        rvc->certIX, (trusted ? "t" : "u"));
-    secdumpdata(ocspResponse->data, buf);
-#endif
-
-    return trusted;
 }
 
-static void SecRVCConsumeOCSPResponse(SecRVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) {
-    SecOCSPSingleResponseRef sr = NULL;
-    require_quiet(ocspResponse, errOut);
-    SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
-    require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
-                         secdebug("ocsp", "responder: %@ returned status: %d",  rvc->responder, orStatus));
-    require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
-            secdebug("ocsp",  "ocsp responder: %@ did not include status of requested cert", rvc->responder));
-    // Check if this response is fresher than any (cached) response we might still have in the rvc.
-    require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut);
+static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc,
+    CFStringRef key) {
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key);
+    for (ix = 0; ix < count; ++ix) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) {
+            if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
+                return;
+        }
+    }
+}
 
-    CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
-    /* TODO: If the responder doesn't have the ocsp-nocheck extension we should
-       check whether the leaf was revoked (we are already checking the rest of
-       the chain). */
-    /* Check the OCSP response signature and verify the response. */
-    require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
-                                        sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
+static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) {
+    SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
+    require_quiet(leaf, out);
 
-    // If we get here, we have a properly signed ocsp response
-    // but we haven't checked dates yet.
+    /* And now a special snowflake from our tests */
 
-    bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime);
-    if (sr->certStatus == CS_Good) {
-        // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime
-        require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut);
-    } else if (sr->certStatus == CS_Revoked) {
-        // Expire revoked responses when the subject certificate itself expires.
-        ocspResponse->expireTime = SecCertificateNotValidAfter(SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX));
-    }
+    /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */
+    /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */
+    /* Not After : May 26 09:37:50 2017 GMT */
+    static const uint8_t vodafone[] = {
+        0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a,
+        0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18
+    };
 
-    // Ok we like the new response, let's toss the old one.
-    if (updateCache)
-        SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
+    /* subject:/C=US/ST=Kansas/L=Overland Park/O=Sprint/CN=oma.ssprov.sprint.com */
+    /* issuer :/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C */
+    /* Not After : Aug 16 05:04:29 2017 GMT */
+    static const uint8_t sprint[] = {
+        0xa3, 0x18, 0x70, 0x4f, 0xf7, 0xbf, 0xfb, 0x2b, 0xe2, 0x64,
+        0x3a, 0x2d, 0x2b, 0xb8, 0x10, 0x5f, 0x77, 0xd5, 0x01, 0xab
+    };
 
-    if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
-    rvc->ocspResponse = ocspResponse;
-    ocspResponse = NULL;
+    CFDataRef leafFingerprint = SecCertificateGetSHA1Digest(leaf);
+    require_quiet(leafFingerprint, out);
+    const unsigned int len = 20;
+    const uint8_t *dp = CFDataGetBytePtr(leafFingerprint);
+    if (dp && (!memcmp(vodafone, dp, len) || !memcmp(sprint,dp,len))) {
+        return true;
+    }
 
-    if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
-    rvc->ocspSingleResponse = sr;
-    sr = NULL;
+out:
+    return false;
+}
 
-    rvc->done = sr_valid;
+static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key);
 
-errOut:
-    if (sr) SecOCSPSingleResponseDestroy(sr);
-    if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
-}
+static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc,
+    CFStringRef key) {
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
 
-/* Callback from async http code after an ocsp response has been received. */
-static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
-    SecRVCRef rvc = (SecRVCRef)http->info;
-    SecPVCRef pvc = rvc->pvc;
-    SecOCSPResponseRef ocspResponse = NULL;
-    if (http->response) {
-        CFDataRef data = CFHTTPMessageCopyBody(http->response);
-        if (data) {
-            /* Parse the returned data as if it's an ocspResponse. */
-            ocspResponse = SecOCSPResponseCreate(data);
-            CFRelease(data);
+    Boolean keyInPolicy = false;
+    CFArrayRef policies = pvc->policies;
+    CFIndex policyIX, policyCount = CFArrayGetCount(policies);
+    for (policyIX = 0; policyIX < policyCount; ++policyIX) {
+               SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
+        if (policy && CFDictionaryContainsKey(policy->_options, key)) {
+            keyInPolicy = true;
         }
     }
 
-    SecRVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true);
-    // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale
+    /* We only enforce this check when *both* of the following are true:
+     *  1. One of the certs in the path has this usage constraint, and
+     *  2. One of the policies in the PVC has this key
+     * (As compared to normal policy options which require only one to be true..) */
+    require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
+                  keyInPolicy, out);
 
-    if (!rvc->done) {
-        /* Clear the data for the next response. */
-        asynchttp_free(http);
-        SecRVCFetchNext(rvc);
+    /* Ignore the anchor if it's trusted */
+    if (SecPathBuilderIsAnchored(pvc->builder)) {
+        count--;
     }
-
-    if (rvc->done) {
-        SecRVCUpdatePVC(rvc);
-        SecRVCDelete(rvc);
-        if (!--pvc->asyncJobCount) {
-            SecPathBuilderStep(pvc->builder);
+    for (ix = 0; ix < count; ++ix) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (SecCertificateIsWeakHash(cert)) {
+            if (!leaf_is_on_weak_hash_whitelist(pvc)) {
+                if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
+                    return;
+                }
+            }
         }
     }
+out:
+    return;
 }
 
-static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
-    secdebug("alloc", "%p", rvc);
-    rvc->pvc = pvc;
-    rvc->certIX = certIX;
-    rvc->http.queue = SecPathBuilderGetQueue(pvc->builder);
-    rvc->http.token = SecPathBuilderCopyClientAuditToken(pvc->builder);
-    rvc->http.completed = SecOCSPFetchCompleted;
-    rvc->http.info = rvc;
-    rvc->ocspRequest = NULL;
-    rvc->responderIX = 0;
-    rvc->responder = NULL;
-    rvc->nextUpdate = NULL_TIME;
-    rvc->ocspResponse = NULL;
-    rvc->ocspSingleResponse = NULL;
-    rvc->done = false;
-}
-
+static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc,
+                                                CFStringRef key) {
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
 
-static bool SecPVCCheckRevocation(SecPVCRef pvc) {
-    secdebug("ocsp", "checking revocation");
-       CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
-    bool completed = true;
-    if (certCount <= 1) {
-               /* Can't verify without an issuer; we're done */
-        return completed;
-    }
-    if (!SecPVCIsAnchored(pvc)) {
-        /* We can't check revocation for chains without a trusted anchor. */
-        return completed;
+    Boolean keyInPolicy = false;
+    CFArrayRef policies = pvc->policies;
+    CFIndex policyIX, policyCount = CFArrayGetCount(policies);
+    for (policyIX = 0; policyIX < policyCount; ++policyIX) {
+        SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
+        if (policy && CFDictionaryContainsKey(policy->_options, key)) {
+            keyInPolicy = true;
+        }
     }
-    certCount--;
 
-#if 0
-    /* TODO: Implement getting this value from the client.
-       Optional responder passed in though policy. */
-    CFURLRef localResponder = NULL;
-    /* Generate a nonce in outgoing request if true. */
-       bool genNonce = false;
-    /* Require a nonce in response if true. */
-       bool requireRespNonce = false;
-       bool cacheReadDisable = false;
-       bool cacheWriteDisable = false;
-#endif
+    /* We only enforce this check when *both* of the following are true:
+     *  1. One of the certs in the path has this usage constraint, and
+     *  2. One of the policies in the PVC has this key
+     * (As compared to normal policy options which require only one to be true..) */
+    require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) &&
+                  keyInPolicy, out);
 
-    if (pvc->rvcs) {
-        /* We have done revocation checking already, we're done. */
-        secdebug("ocsp", "Not rechecking revocation");
-        return completed;
+    /* Ignore the anchor if it's trusted */
+    if (SecPathBuilderIsAnchored(pvc->builder)) {
+        count--;
     }
-
-    /* Setup things so we check revocation status of all certs except the
-       anchor. */
-    pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
-
-#if 0
-    /* Lookup cached revocation data for each certificate. */
-       for (certIX = 0; certIX < certCount; ++certIX) {
-               SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
-        CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
-               if (ocspResponders) {
-            /* First look though passed in ocsp responses. */
-            //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
-
-            /* Then look though shared cache (we don't care which responder
-               something came from here). */
-            CFDataRef ocspResponse = SecOCSPCacheCopyMatching(SecCertIDRef certID, NULL);
-
-            /* Now let's parse the response. */
-            if (decodeOCSPResponse(ocspResp)) {
-                secdebug("ocsp", "response ok: %@", ocspResp);
-            } else {
-                secdebug("ocsp", "response bad: %@", ocspResp);
-                /* ocsp response not ok. */
-                if (!SecPVCSetResultForced(pvc, key, ix, kCFBooleanFalse, true))
-                    return completed;
-            }
-            CFReleaseSafe(ocspResp);
-               } else {
-            /* Check if certificate has any crl distributionPoints. */
-            CFArrayRef distributionPoints = SecCertificateGetCRLDistributionPoints(cert);
-            if (distributionPoints) {
-                /* Look for a cached CRL and potentially delta CRL for this certificate. */
+    for (ix = 0; ix < count; ++ix) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+        if (!SecCertificateIsStrongKey(cert)) {
+            if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) {
+                return;
             }
         }
-       }
-#endif
 
-    /* Note that if we are multi threaded and a job completes after it
-       is started but before we return from this function, we don't want
-       a callback to decrement asyncJobCount to zero before we finish issuing
-       all the jobs. To avoid this we pretend we issued certCount async jobs,
-       and decrement pvc->asyncJobCount for each cert that we don't start a
-       background fetch for. */
-    pvc->asyncJobCount = (unsigned int) certCount;
-
-    /* Loop though certificates again and issue an ocsp fetch if the
-       revocation status checking isn't done yet. */
-    for (certIX = 0; certIX < certCount; ++certIX) {
-        secdebug("ocsp", "checking revocation for cert: %ld", certIX);
-        SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
-        SecRVCInit(rvc, pvc, certIX);
-        if (rvc->done)
-            continue;
+    } /* Cert loop */
+out:
+    return;
+}
 
-        SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc,
-            rvc->certIX);
-        /* The certIX + 1 is ok here since certCount is always at least 1
-           less than the actual number of certs. */
-        SecCertificateRef issuer = SecPVCGetCertificateAtIndex(rvc->pvc,
-            rvc->certIX + 1);
-
-        rvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
-
-        /* Get stapled OCSP responses */
-        CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder);
-
-        /* If we have any OCSP stapled responses, check those first */
-        if(ocspResponsesData) {
-            secdebug("ocsp", "Checking stapled responses for cert %ld", certIX);
-            CFArrayForEach(ocspResponsesData, ^(const void *value) {
-                /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */
-                SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
-                SecRVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false);
-            });
-            CFRelease(ocspResponsesData);
+static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) {
+    /* Pinning is disabled on the system, skip. */
+    if (SecIsInternalRelease()) {
+        if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"),
+                                            CFSTR("com.apple.security"), NULL)) {
+            return;
         }
+    }
 
-        /* Then check the cached response */
-        secdebug("ocsp", "Checking cached responses for cert %ld", certIX);
-        SecRVCConsumeOCSPResponse(rvc, SecOCSPCacheCopyMatching(rvc->ocspRequest, NULL), NULL_TIME, false);
-
-        /* Unless we successfully checked the revocation status of this cert
-           based on the cache or stapled responses, attempt to fire off an async http request
-           for this cert's revocation status. */
-        bool fetch_done = true;
-        if (rvc->done || !SecPathBuilderCanAccessNetwork(pvc->builder) ||
-            (fetch_done = SecRVCFetchNext(rvc))) {
-            /* We got a cache hit or we aren't allowed to access the network,
-               or the async http post failed. */
-            SecRVCUpdatePVC(rvc);
-            SecRVCDelete(rvc);
-            /* We didn't really start a background job for this cert. */
-            pvc->asyncJobCount--;
-        } else if (!fetch_done) {
-            /* We started at least one background fetch. */
-            completed = false;
+    CFArrayRef policies = pvc->policies;
+    CFIndex policyIX, policyCount = CFArrayGetCount(policies);
+    for (policyIX = 0; policyIX < policyCount; ++policyIX) {
+        SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
+        CFStringRef policyName = SecPolicyGetName(policy);
+        if (CFEqualSafe(policyName, CFSTR("sslServer"))) {
+            /* policy required pinning, but we didn't use a pinning policy */
+            if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) {
+                return;
+            }
         }
     }
-
-    /* Return false if we started any background jobs. */
-    /* We can't just return !pvc->asyncJobCount here, since if we started any
-       jobs the completion callback will be called eventually and it will call
-       SecPathBuilderStep(). If for some reason everything completed before we
-       get here we still want the outer SecPathBuilderStep() to terminate so we
-       keep track of whether we started any jobs and return false if so. */
-    return completed;
 }
 
-
-void SecPolicyServerInitalize(void) {
+void SecPolicyServerInitialize(void) {
        gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                &kCFTypeDictionaryKeyCallBacks, NULL);
        gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
@@ -2932,9 +2123,9 @@ void SecPolicyServerInitalize(void) {
                kSecPolicyCheckExtendedKeyUsage,
                SecPolicyCheckExtendedKeyUsage);
        CFDictionaryAddValue(gSecPolicyLeafCallbacks,
-               kSecPolicyCheckBasicContraints,
-               SecPolicyCheckBasicContraints);
-       CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+               kSecPolicyCheckBasicConstraints,
+               SecPolicyCheckBasicConstraints);
+       CFDictionaryAddValue(gSecPolicyPathCallbacks,
                kSecPolicyCheckNonEmptySubject,
                SecPolicyCheckNonEmptySubject);
        CFDictionaryAddValue(gSecPolicyLeafCallbacks,
@@ -2973,9 +2164,9 @@ void SecPolicyServerInitalize(void) {
        CFDictionaryAddValue(gSecPolicyPathCallbacks,
                kSecPolicyCheckAnchorSHA1,
                SecPolicyCheckAnchorSHA1);
-       CFDictionaryAddValue(gSecPolicyPathCallbacks,
-               kSecPolicyCheckIntermediateSPKISHA256,
-               SecPolicyCheckIntermediateSPKISHA256);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckAnchorSHA256,
+        SecPolicyCheckAnchorSHA256);
        CFDictionaryAddValue(gSecPolicyPathCallbacks,
                kSecPolicyCheckAnchorApple,
                SecPolicyCheckAnchorApple);
@@ -2997,6 +2188,9 @@ void SecPolicyServerInitalize(void) {
        CFDictionaryAddValue(gSecPolicyLeafCallbacks,
                kSecPolicyCheckRevocationResponseRequired,
                SecPolicyCheckRevocationResponseRequired);
+    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+        kSecPolicyCheckRevocationOnline,
+        SecPolicyCheckRevocationOnline);
        CFDictionaryAddValue(gSecPolicyLeafCallbacks,
                kSecPolicyCheckNoNetworkAccess,
                SecPolicyCheckNoNetworkAccess);
@@ -3009,59 +2203,54 @@ void SecPolicyServerInitalize(void) {
        CFDictionaryAddValue(gSecPolicyLeafCallbacks,
                kSecPolicyCheckLeafMarkerOid,
                SecPolicyCheckLeafMarkerOid);
+    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+        kSecPolicyCheckLeafMarkerOidWithoutValueCheck,
+        SecPolicyCheckLeafMarkerOidWithoutValueCheck);
+    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+        kSecPolicyCheckLeafMarkersProdAndQA,
+        SecPolicyCheckLeafMarkersProdAndQA);
+       CFDictionaryAddValue(gSecPolicyPathCallbacks,
+               kSecPolicyCheckIntermediateSPKISHA256,
+               SecPolicyCheckIntermediateSPKISHA256);
+       CFDictionaryAddValue(gSecPolicyPathCallbacks,
+               kSecPolicyCheckIntermediateEKU,
+               SecPolicyCheckIntermediateEKU);
        CFDictionaryAddValue(gSecPolicyPathCallbacks,
                kSecPolicyCheckIntermediateMarkerOid,
                SecPolicyCheckIntermediateMarkerOid);
-       CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+       CFDictionaryAddValue(gSecPolicyPathCallbacks,
                kSecPolicyCheckCertificatePolicy,
                SecPolicyCheckCertificatePolicyOid);
-}
-
-/* AUDIT[securityd](done):
-   array (ok) is a caller provided array, only its cf type has
-   been checked.
-   The options (ok) field ends up in policy->_options unchecked, so every access
-   of policy->_options needs to be validated.
- */
-static SecPolicyRef SecPolicyCreateWithArray(CFArrayRef array) {
-    SecPolicyRef policy = NULL;
-    require_quiet(array && CFArrayGetCount(array) == 2, errOut);
-    CFStringRef oid = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
-    require_quiet(isString(oid), errOut);
-    CFDictionaryRef options = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 1);
-    require_quiet(isDictionary(options), errOut);
-    policy = SecPolicyCreate(oid, options);
-errOut:
-    return policy;
-}
-
-/* AUDIT[securityd](done):
-   value (ok) is an element in a caller provided array.
- */
-static void deserializePolicy(const void *value, void *context) {
-    CFArrayRef policyArray = (CFArrayRef)value;
-    if (isArray(policyArray)) {
-        CFTypeRef deserializedPolicy = SecPolicyCreateWithArray(policyArray);
-        if (deserializedPolicy) {
-            CFArrayAppendValue((CFMutableArrayRef)context, deserializedPolicy);
-            CFRelease(deserializedPolicy);
-        }
-    }
-}
-
-/* AUDIT[securityd](done):
-   serializedPolicies (ok) is a caller provided array, only its cf type has
-   been checked.
- */
-CFArrayRef SecPolicyArrayDeserialize(CFArrayRef serializedPolicies) {
-    CFMutableArrayRef result = NULL;
-    require_quiet(isArray(serializedPolicies), errOut);
-    CFIndex count = CFArrayGetCount(serializedPolicies);
-    result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
-    CFRange all_policies = { 0, count };
-    CFArrayApplyFunction(serializedPolicies, all_policies, deserializePolicy, result);
-errOut:
-    return result;
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckWeakIntermediates,
+        SecPolicyCheckWeakIntermediates);
+    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+        kSecPolicyCheckWeakLeaf,
+        SecPolicyCheckWeakLeaf);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckWeakRoot,
+        SecPolicyCheckWeakRoot);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckKeySize,
+        SecPolicyCheckKeySize);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckSignatureHashAlgorithms,
+        SecPolicyCheckSignatureHashAlgorithms);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckSystemTrustedWeakHash,
+        SecPolicyCheckSystemTrustedWeakHash);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckSystemTrustedWeakKey,
+        SecPolicyCheckSystemTrustedWeakKey);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckIntermediateOrganization,
+        SecPolicyCheckIntermediateOrganization);
+    CFDictionaryAddValue(gSecPolicyPathCallbacks,
+        kSecPolicyCheckIntermediateCountry,
+        SecPolicyCheckIntermediateCountry);
+    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
+        kSecPolicyCheckPinningRequired,
+        SecPolicyCheckPinningRequired);
 }
 
 // MARK: -
@@ -3070,99 +2259,203 @@ errOut:
  ****************** SecPVCRef Functions *****************
  ********************************************************/
 
-void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
-    CFAbsoluteTime verifyTime) {
+void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) {
     secdebug("alloc", "%p", pvc);
     // Weird logging policies crashes.
     //secdebug("policy", "%@", policies);
+
+    // Zero the pvc struct so only non-zero fields need to be explicitly set
+    memset(pvc, 0, sizeof(struct OpaqueSecPVC));
     pvc->builder = builder;
     pvc->policies = policies;
     if (policies)
         CFRetain(policies);
-    pvc->verifyTime = verifyTime;
-    pvc->path = NULL;
-    pvc->details = NULL;
-    pvc->info = NULL;
-    pvc->valid_policy_tree = NULL;
-    pvc->callbacks = NULL;
-    pvc->policyIX = 0;
-    pvc->rvcs = NULL;
-    pvc->asyncJobCount = 0;
-    pvc->check_revocation = false;
-    pvc->response_required = false;
-    pvc->optionally_ev = false;
-    pvc->is_ev = false;
-    pvc->result = true;
-}
+    pvc->result = kSecTrustResultUnspecified;
 
-static void SecPVCDeleteRVCs(SecPVCRef pvc) {
-    secdebug("alloc", "%p", pvc);
-    if (pvc->rvcs) {
-        free(pvc->rvcs);
-        pvc->rvcs = NULL;
-    }
+    CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                                  &kCFTypeDictionaryKeyCallBacks,
+                                                                  &kCFTypeDictionaryValueCallBacks);
+    pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail,
+                                         1, &kCFTypeArrayCallBacks);
+    CFRelease(certDetail);
 }
 
 void SecPVCDelete(SecPVCRef pvc) {
     secdebug("alloc", "%p", pvc);
     CFReleaseNull(pvc->policies);
     CFReleaseNull(pvc->details);
-    CFReleaseNull(pvc->info);
-    if (pvc->valid_policy_tree) {
-        policy_tree_prune(&pvc->valid_policy_tree);
-    }
-    SecPVCDeleteRVCs(pvc);
+    CFReleaseNull(pvc->leafDetails);
 }
 
-void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
-    CF_CONSUMED CFArrayRef details) {
+void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) {
     secdebug("policy", "%@", path);
-    if (pvc->path != path) {
-        /* Changing path makes us clear the Revocation Verification Contexts */
-        SecPVCDeleteRVCs(pvc);
-        pvc->path = path;
-    }
-    pvc->details = details;
-    CFReleaseNull(pvc->info);
-    if (pvc->valid_policy_tree) {
-        policy_tree_prune(&pvc->valid_policy_tree);
-    }
     pvc->policyIX = 0;
-       pvc->result = true;
+    pvc->result = kSecTrustResultUnspecified;
+    CFReleaseNull(pvc->details);
+}
+
+void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) {
+    pvc->policyIX = 0;
+
+    /* Since we don't run the LeafChecks again, we need to preserve the
+     * result the leaf had. */
+    CFIndex ix, pathLength = SecCertificatePathVCGetCount(path);
+    CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
+                                                         pathLength, pvc->leafDetails);
+    for (ix = 1; ix < pathLength; ++ix) {
+        CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                                      &kCFTypeDictionaryKeyCallBacks,
+                                                                      &kCFTypeDictionaryValueCallBacks);
+        CFArrayAppendValue(details, certDetail);
+        CFRelease(certDetail);
+    }
+    CFRetainAssign(pvc->details, details);
+    pvc->result = pvc->leafResult;
+    CFReleaseSafe(details);
 }
 
 SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
        return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
 }
 
-CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
-       return SecCertificatePathGetCount(pvc->path);
+static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
+       return SecPathBuilderGetCertificateCount(pvc->builder);
 }
 
-SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
-       return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
+static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
+       return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
 }
 
-bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) {
-    return SecCertificatePathSelfSignedIndex(pvc->path) == ix;
+static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
+    return SecPathBuilderGetVerifyTime(pvc->builder);
 }
 
-void SecPVCSetCheckRevocation(SecPVCRef pvc) {
-    pvc->check_revocation = true;
-    secdebug("ocsp", "deferred revocation checking enabled");
+static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) {
+    CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder);
+    if (!exceptions) { return false; }
+    CFIndex exceptionsCount = CFArrayGetCount(exceptions);
+
+    /* There are two types of exceptions:
+     *  1. Those that are built from SecTrustCopyExceptions, which are particular to the
+     *  certs in the chain -- as indicated by the SHA1 digest in the exception dictionary.
+     *  2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors.
+     */
+#if TARGET_OS_OSX
+    CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0);
+    /* Type 2 */
+    if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) {
+        /* SHA1Digest not allowed */
+        if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; }
+        /* Key excepted */
+        if (CFDictionaryContainsKey(options, key)) {
+            /* Special case -- AnchorTrusted only for self-signed certs */
+            if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) {
+                Boolean isSelfSigned = false;
+                SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
+                if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+#endif
+
+    /* Type 1 */
+    if (ix >= exceptionsCount) { return false; }
+    CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix);
+
+    /* Compare the cert hash */
+    if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; }
+    SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix);
+    if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) {
+        return false;
+    }
+
+    /* Key Excepted */
+    CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key);
+    if (exceptionValue && CFEqual(value, exceptionValue)) {
+        /* Only change result if PVC is already ok */
+        if (SecPVCIsOkResult(pvc)) {
+            // Chains that pass due to exceptions get Proceed result.
+            pvc->result = kSecTrustResultProceed;
+        }
+        return true;
+    }
+
+    return false;
 }
 
-void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc) {
-    pvc->response_required = true;
-    secdebug("ocsp", "revocation response required");
+static int32_t detailKeyToCssmErr(CFStringRef key) {
+    int32_t result = 0;
+
+    if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
+        result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH
+    }
+    else if (CFEqual(key, kSecPolicyCheckEmail)) {
+        result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
+    }
+    else if (CFEqual(key, kSecPolicyCheckValidLeaf) ||
+             CFEqual(key, kSecPolicyCheckValidIntermediates) ||
+             CFEqual(key, kSecPolicyCheckValidRoot)) {
+        result = -2147409654; // CSSMERR_TP_CERT_EXPIRED
+    }
+
+    return result;
 }
 
-bool SecPVCIsAnchored(SecPVCRef pvc) {
-    return SecCertificatePathIsAnchored(pvc->path);
+static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint);
+
+static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) {
+    bool result = false;
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+    CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix);
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+    CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
+
+    for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
+        CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
+        CFNumberRef allowedErrorNumber = NULL;
+        if (!isDictionary(constraint)) {
+            continue;
+        }
+        allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError);
+        int32_t allowedErrorValue = 0;
+        if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) {
+            continue;
+        }
+
+        if (SecPVCMeetsConstraint(pvc, cert, constraint)) {
+            if (allowedErrorValue == detailKeyToCssmErr(key)) {
+                result = true;
+                break;
+            }
+        }
+    }
+    return result;
 }
 
-CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
-    return pvc->verifyTime;
+static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) {
+    CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
+    for (certIX = 0; certIX < certCount; certIX++) {
+        SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+        CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
+        CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
+        for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
+            CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
+            if (!isDictionary(constraint)) {
+                continue;
+            }
+
+            CFDictionaryRef policyOptions = NULL;
+            policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
+            if (policyOptions && isDictionary(policyOptions) &&
+                CFDictionaryContainsKey(policyOptions, key)) {
+                return true;
+            }
+        }
+    }
+    return false;
 }
 
 /* AUDIT[securityd](done):
@@ -3172,7 +2465,7 @@ CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
 bool SecPVCSetResultForced(SecPVCRef pvc,
        CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
 
-    secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
+    secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
         (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
             : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
                 : "custom")),
@@ -3181,17 +2474,31 @@ bool SecPVCSetResultForced(SecPVCRef pvc,
     /* If this is not something the current policy cares about ignore
        this error and return true so our caller continues evaluation. */
     if (!force) {
-        /* @@@ The right long term fix might be to check if none of the passed
-           in policies contain this key, since not all checks are run for all
-           policies. */
+        /* Either the policy or the usage constraints have to have this key */
         SecPolicyRef policy = SecPVCGetPolicy(pvc);
-        if (policy && !CFDictionaryContainsKey(policy->_options, key))
+        if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) ||
+            (policy && CFDictionaryContainsKey(policy->_options, key)))) {
             return true;
+        }
     }
 
-       /* @@@ Check to see if the SecTrustSettings for the certificate in question
+       /* Check to see if the SecTrustSettings for the certificate in question
           tell us to ignore this error. */
-       pvc->result = false;
+       if (SecPVCIsAllowedError(pvc, ix, key)) {
+        secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key);
+               return true;
+       }
+
+    /* Check to see if exceptions tells us to ignore this error. */
+    if (SecPVCIsExceptedError(pvc, ix, key, result)) {
+        secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key);
+        return true;
+    }
+
+       /* Check SecPVCIsOkResult to avoid resetting deny or fatal to recoverable */
+       if (SecPVCIsOkResult(pvc)) {
+               pvc->result = kSecTrustResultRecoverableTrustFailure;
+       }
        if (!pvc->details)
                return false;
 
@@ -3220,32 +2527,26 @@ static void SecPVCValidateKey(const void *key, const void *value,
 
        /* If our caller doesn't want full details and we failed earlier there is
           no point in doing additional checks. */
-       if (!pvc->result && !pvc->details)
+       if (!SecPVCIsOkResult(pvc) && !pvc->details)
                return;
 
        SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
                CFDictionaryGetValue(pvc->callbacks, key);
 
        if (!fcn) {
-#if 0
-    /* Why not to have optional policy checks rant:
-       Not all keys are in all dictionaries anymore, so why not make checks
-       optional?  This way a client can ask for something and the server will
-       do a best effort based on the supported flags.  It works since they are
-       synchronized now, but we need some debug checking here for now. */
-               pvc->result = false;
-#endif
         if (pvc->callbacks == gSecPolicyLeafCallbacks) {
             if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
-                pvc->result = false;
+                pvc->result = kSecTrustResultOtherError;
             }
         } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
             if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
-                pvc->result = false;
+                pvc->result = kSecTrustResultOtherError;
             }
         } else {
-            /* Non standard validation phase, nothing is optional. */
-            pvc->result = false;
+            /* Non standard validation phase. This may be a new key from the
+             * pinning DB which is not implemented in this OS version. Log
+             * a warning. */
+            secwarning("policy: unknown policy key %@, skipping", key);
         }
                return;
        }
@@ -3257,8 +2558,10 @@ static void SecPVCValidateKey(const void *key, const void *value,
    policy->_options is a caller provided dictionary, only its cf type has
    been checked.
  */
-bool SecPVCLeafChecks(SecPVCRef pvc) {
-    pvc->result = true;
+SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) {
+    /* We need to compute details for the leaf. */
+    CFRetainAssign(pvc->details, pvc->leafDetails);
+
     CFArrayRef policies = pvc->policies;
        CFIndex ix, count = CFArrayGetCount(policies);
        for (ix = 0; ix < count; ++ix) {
@@ -3267,25 +2570,46 @@ bool SecPVCLeafChecks(SecPVCRef pvc) {
         /* Validate all keys for all policies. */
         pvc->callbacks = gSecPolicyLeafCallbacks;
         CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
-        if (!pvc->result && !pvc->details)
-            return pvc->result;
        }
 
+    pvc->leafResult = pvc->result;
+    CFRetainAssign(pvc->leafDetails, pvc->details);
+
     return pvc->result;
 }
 
+bool SecPVCIsOkResult(SecPVCRef pvc) {
+    if (pvc->result == kSecTrustResultRecoverableTrustFailure ||
+        pvc->result == kSecTrustResultDeny ||
+        pvc->result == kSecTrustResultFatalTrustFailure ||
+        pvc->result == kSecTrustResultOtherError) {
+        return false;
+    }
+    return true;
+}
+
 bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
     /* Check stuff common to intermediate and anchors. */
-       CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
-       SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-    bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
-        && SecPVCIsAnchored(pvc));
-       if (!SecCertificateIsValid(cert, verifyTime)) {
-               /* Certificate has expired. */
-               if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
-            : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
+    CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
+    SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+    CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1;
+    bool is_anchor = (ix == anchor_ix && SecPathBuilderIsAnchored(pvc->builder));
+
+    if (!SecCertificateIsValid(cert, verifyTime)) {
+        /* Certificate has expired. */
+        if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
+            : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse)) {
             goto errOut;
-       }
+        }
+    }
+
+    if (SecCertificateIsWeakKey(cert)) {
+        /* Certificate uses weak key. */
+        if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckWeakRoot
+            : kSecPolicyCheckWeakIntermediates, ix, kCFBooleanFalse)) {
+            goto errOut;
+        }
+    }
 
     if (is_anchor) {
         /* Perform anchor specific checks. */
@@ -3293,31 +2617,47 @@ bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
     } else {
         /* Perform intermediate specific checks. */
 
-        /* (k) */
-               const SecCEBasicConstraints *bc =
-                       SecCertificateGetBasicConstraints(cert);
-        if (!bc || !bc->isCA) {
-            /* Basic constraints not present or not marked as isCA, illegal. */
-            if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicContraints,
-                ix, kCFBooleanFalse, true))
-                goto errOut;
+        /* (k) Basic constraints only relevant for v3 and later. */
+        if (SecCertificateVersion(cert) >= 3) {
+            const SecCEBasicConstraints *bc =
+                SecCertificateGetBasicConstraints(cert);
+            if (!bc || !bc->isCA) {
+                /* Basic constraints not present or not marked as isCA, illegal. */
+                if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
+                            ix, kCFBooleanFalse, true)) {
+                    goto errOut;
+                }
+            }
+        }
+        /* For a v1 or v2 certificate in an intermediate slot (not a leaf and
+           not an anchor), we additionally require that the certificate chain
+           does not end in a v3 or later anchor. [rdar://32204517] */
+        else if (ix > 0 && ix < anchor_ix) {
+            SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix);
+            if (SecCertificateVersion(anchor) >= 3) {
+                if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints,
+                            ix, kCFBooleanFalse, true)) {
+                    goto errOut;
+                }
+            }
         }
-        /* Consider adding (l) max_path_length checking here. */
+        /* (l) max_path_length is checked elsewhere. */
 
         /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
         SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
         if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
             if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
-                ix, kCFBooleanFalse, true))
+                ix, kCFBooleanFalse, true)) {
                 goto errOut;
+            }
         }
     }
 
 errOut:
-    return pvc->result;
+    return SecPVCIsOkResult(pvc);
 }
 
-bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
+static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
     /* Check stuff common to intermediate and anchors. */
 
        SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
@@ -3328,31 +2668,40 @@ bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
                if (NULL != blackListedKeys)
                {
                        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-                   bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
-                                     && SecPVCIsAnchored(pvc));
-                   if (!is_anchor) {
-                       /* Check for blacklisted intermediates keys. */
-                       CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
-                       if (dgst) {
-                           /* Check dgst against blacklist. */
-                           if (CFSetContainsValue(blackListedKeys, dgst)) {
-                               SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
-                                                     ix, kCFBooleanFalse, true);
-                           }
-                           CFRelease(dgst);
-                       }
-                   }
+                       CFIndex count = SecPVCGetCertificateCount(pvc);
+                       bool is_last = (ix == count - 1);
+                       bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
+                       if (!is_anchor) {
+                               /* Check for blacklisted intermediate issuer keys. */
+                               CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
+                               if (dgst) {
+                                       /* Check dgst against blacklist. */
+                                       if (CFSetContainsValue(blackListedKeys, dgst)) {
+                                               /* Check allow list for this blacklisted issuer key,
+                                                  which is the authority key of the issued cert at ix-1.
+                                               */
+                                               SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+                                               bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
+                                               if (!allowed) {
+                                                       SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
+                                                                             ix, kCFBooleanFalse, true);
+                            pvc->result = kSecTrustResultFatalTrustFailure;
+                                               }
+                                       }
+                                       CFRelease(dgst);
+                               }
+                       }
                        CFRelease(blackListedKeys);
-                   return pvc->result;
+                       return SecPVCIsOkResult(pvc);
                }
        }
        // Assume OK
        return true;
 }
 
-bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
+static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
 {
-    /* Check stuff common to intermediate and anchors. */
+       /* Check stuff common to intermediate and anchors. */
        SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
        if (NULL != otapkiRef)
        {
@@ -3361,139 +2710,546 @@ bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
                if (NULL != grayListKeys)
                {
                        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
-                   bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
-                                     && SecPVCIsAnchored(pvc));
-                   if (!is_anchor) {
-                       /* Check for gray listed intermediates keys. */
-                       CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
-                       if (dgst) {
-                           /* Check dgst against gray list. */
-                           if (CFSetContainsValue(grayListKeys, dgst)) {
-                               SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
-                                                     ix, kCFBooleanFalse, true);
-                           }
-                           CFRelease(dgst);
-                       }
-                   }
+                       CFIndex count = SecPVCGetCertificateCount(pvc);
+                       bool is_last = (ix == count - 1);
+                       bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder));
+                       if (!is_anchor) {
+                               /* Check for gray listed intermediate issuer keys. */
+                               CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
+                               if (dgst) {
+                                       /* Check dgst against gray list. */
+                                       if (CFSetContainsValue(grayListKeys, dgst)) {
+                                               /* Check allow list for this graylisted issuer key,
+                                                  which is the authority key of the issued cert at ix-1.
+                                               */
+                                               SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+                                               bool allowed = path && SecCertificatePathVCIsAllowlisted(path);
+                                               if (!allowed) {
+                                                       SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
+                                                                             ix, kCFBooleanFalse, true);
+                                               }
+                                       }
+                                       CFRelease(dgst);
+                               }
+                       }
                        CFRelease(grayListKeys);
-                   return pvc->result;
+                       return SecPVCIsOkResult(pvc);
                }
        }
        // Assume ok
        return true;
 }
 
+static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) {
+    if (!isString(searchName) && !isString(searchOid)) {
+        return false;
+    }
+       CFArrayRef policies = pvc->policies;
+       CFIndex ix, count = CFArrayGetCount(policies);
+       for (ix = 0; ix < count; ++ix) {
+               SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
+               CFStringRef policyName = SecPolicyGetName(policy);
+        CFStringRef policyOid = SecPolicyGetOidString(policy);
+        /* Prefer a match of both name and OID */
+        if (searchOid && searchName && policyOid && policyName) {
+            if (CFEqual(searchOid, policyOid) &&
+                CFEqual(searchName, policyName)) {
+                if (policyIX) { *policyIX = ix; }
+                return true;
+            }
+        }
+        /* Next best is just OID. */
+        if (!searchName && searchOid && policyOid) {
+            if (CFEqual(searchOid, policyOid)) {
+                if (policyIX) { *policyIX = ix; }
+                return true;
+            }
+        }
+        if (!searchOid && searchName && policyName) {
+            if (CFEqual(searchName, policyName)) {
+                if (policyIX) { *policyIX = ix; }
+                return true;
+            }
+        }
+       }
+       return false;
+}
+
+static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) {
+    if (!isString(stringValue)) {
+        return false;
+    }
+    bool result = false;
+
+    CFStringRef tmpStringValue = NULL;
+    if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) {
+        tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1);
+    } else {
+        tmpStringValue = CFStringCreateCopy(NULL, stringValue);
+    }
+    if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
+        SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
+        /* Have to look for all the possible locations of name string */
+        CFStringRef policyString = NULL;
+        policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
+        if (!policyString) {
+            policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail);
+        }
+        if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
+            result = true;
+            goto out;
+        }
+
+        CFArrayRef policyStrings = NULL;
+        policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames);
+        if (policyStrings && CFArrayContainsValue(policyStrings,
+                                                  CFRangeMake(0, CFArrayGetCount(policyStrings)),
+                                                  tmpStringValue)) {
+            result = true;
+            goto out;
+        }
+    }
+
+out:
+    CFReleaseNull(tmpStringValue);
+    return result;
+}
+
+
+static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) {
+    uint32_t ourTSKeyUsage = 0;
+    uint32_t keyUsage = 0;
+    if (keyUsageNumber &&
+        CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) {
+        if (keyUsage & kSecKeyUsageDigitalSignature) {
+            ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature;
+        }
+        if (keyUsage & kSecKeyUsageDataEncipherment) {
+            ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData;
+        }
+        if (keyUsage & kSecKeyUsageKeyEncipherment) {
+            ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey;
+        }
+        if (keyUsage & kSecKeyUsageKeyAgreement) {
+            ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange;
+        }
+        if (keyUsage == kSecKeyUsageAll) {
+            ourTSKeyUsage = kSecTrustSettingsKeyUseAny;
+        }
+    }
+    return ourTSKeyUsage;
+}
+
+static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) {
+    uint32_t ourTSKeyUsage = 0;
+    CFTypeRef policyKeyUsageType = NULL;
+
+    policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage);
+    if (isArray(policyKeyUsageType)) {
+        CFIndex ix, count = CFArrayGetCount(policyKeyUsageType);
+        for (ix = 0; ix < count; ix++) {
+            CFNumberRef policyKeyUsageNumber = NULL;
+            policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix);
+            ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber);
+        }
+    } else if (isNumber(policyKeyUsageType)) {
+        ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType);
+    }
+
+    return ourTSKeyUsage;
+}
+
+static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc,
+    SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) {
+    int64_t keyUsageValue = 0;
+    uint32_t ourKeyUsage = 0;
+
+    if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) {
+        return false;
+    }
+
+    if (keyUsageValue == kSecTrustSettingsKeyUseAny) {
+        return true;
+    }
+
+    /* We're using the key for revocation if we have the OCSPSigner policy.
+     * @@@ If we support CRLs, we'd need to check for that policy here too.
+     */
+    if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) {
+        ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation;
+    }
+
+    /* We're using the key for verifying a cert if it's a root/intermediate
+     * in the chain. If the cert isn't in the path yet, we're about to add it,
+     * so it's a root/intermediate. If there is no path, this is the leaf.
+     */
+    CFIndex pathIndex = -1;
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+    if (path) {
+        pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate);
+    } else {
+        pathIndex = 0;
+    }
+    if (pathIndex != 0) {
+        ourKeyUsage |= kSecTrustSettingsKeyUseSignCert;
+    }
+
+    /* The rest of the key usages may be specified by the policy(ies). */
+    if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) {
+        SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX);
+        ourKeyUsage |= ts_key_usage_for_policy(policy);
+    } else {
+        /* Get key usage from ALL policies */
+        CFIndex ix, count = CFArrayGetCount(pvc->policies);
+        for (ix = 0; ix < count; ix++) {
+            SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix);
+            ourKeyUsage |= ts_key_usage_for_policy(policy);
+        }
+    }
+
+    if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) {
+        return true;
+    }
+
+    return false;
+}
+
+#if TARGET_OS_OSX
+#include <Security/SecTrustedApplicationPriv.h>
+#include <Security/SecTask.h>
+#include <Security/SecTaskPriv.h>
+#include <bsm/libbsm.h>
+#include <libproc.h>
+
+extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
+
+static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) {
+    bool result = false;
+    audit_token_t auditToken = {};
+    SecTaskRef task = NULL;
+    SecRequirementRef requirement = NULL;
+    CFStringRef stringRequirement = NULL;
+
+    require(appRef && clientAuditToken, out);
+    require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
+    require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out);
+    require(requirement, out);
+    require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out);
+    require(stringRequirement, out);
+
+    require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out);
+    CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken);
+    require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out);
+
+    if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) {
+        result = true;
+    }
+
+out:
+    CFReleaseNull(task);
+    CFReleaseNull(requirement);
+    CFReleaseNull(stringRequirement);
+    return result;
+}
+#endif
+
+static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) {
+    if (!isDictionary(options)) {
+        return false;
+    }
+
+    /* Push */
+    CFDictionaryRef currentCallbacks = pvc->callbacks;
+
+    /* We need to run the leaf and path checks using these options. */
+    pvc->callbacks = gSecPolicyLeafCallbacks;
+    CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
+
+    pvc->callbacks = gSecPolicyPathCallbacks;
+    CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc);
+
+    /* Pop */
+    pvc->callbacks = currentCallbacks;
+
+    /* Our work here is done; no need to claim a match */
+    return false;
+}
+
+static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) {
+    CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL;
+    CFNumberRef keyUsageNumber = NULL;
+    CFTypeRef trustedApplicationData = NULL;
+    CFDictionaryRef policyOptions = NULL;
+
+    bool policyMatch = false, policyStringMatch = false, applicationMatch = false ,
+         keyUsageMatch = false, policyOptionMatch = false;
+    bool result = false;
+
+#if TARGET_OS_MAC && !TARGET_OS_IPHONE
+    /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */
+    SecPolicyRef policy = NULL;
+    policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
+    policyOid = (policy) ? policy->_oid : NULL;
+#else
+    policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy);
+#endif
+    policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName);
+    policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString);
+    keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage);
+    policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions);
+
+    CFIndex policyIX = -1;
+    policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX);
+    policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString);
+    keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber);
+    policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions);
+
+#if TARGET_OS_MAC && !TARGET_OS_IPHONE
+    trustedApplicationData =  CFDictionaryGetValue(constraint, kSecTrustSettingsApplication);
+    CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder);
+    applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData);
+    CFReleaseNull(clientAuditToken);
+#else
+    if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) {
+        secerror("kSecTrustSettingsApplication is not yet supported on this platform");
+    }
+#endif
+
+    /* If we either didn't find the parameter in the dictionary or we got a match
+     * against that parameter, for all possible parameters in the dictionary, then
+     * this trust setting result applies to the output. */
+    if (((!policyOid && !policyName) || policyMatch) &&
+        (!policyString || policyStringMatch) &&
+        (!trustedApplicationData || applicationMatch) &&
+        (!keyUsageNumber || keyUsageMatch) &&
+        (!policyOptions || policyOptionMatch)) {
+        result = true;
+    }
+
+    return result;
+}
+
+SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) {
+    SecTrustSettingsResult result = kSecTrustSettingsResultInvalid;
+    CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints);
+    for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) {
+        CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX);
+        if (!isDictionary(constraint)) {
+            continue;
+        }
+
+        CFNumberRef resultNumber = NULL;
+        resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult);
+        uint32_t resultValue = kSecTrustSettingsResultInvalid;
+        if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
+            /* no SecTrustSettingsResult entry defaults to TrustRoot*/
+            resultValue = kSecTrustSettingsResultTrustRoot;
+        }
+
+        if (SecPVCMeetsConstraint(pvc, certificate, constraint)) {
+            result = resultValue;
+            break;
+        }
+    }
+    return result;
+}
+
+static void SecPVCCheckUsageConstraints(SecPVCRef pvc) {
+    CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
+    for (certIX = 0; certIX < certCount; certIX++) {
+        SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+        CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX);
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
+        SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints);
+
+        /* Set the pvc trust result based on the usage constraints and anchor source. */
+        if (result == kSecTrustSettingsResultDeny) {
+            SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true);
+            pvc->result = kSecTrustResultDeny;
+        } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot ||
+                    result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(pvc)) {
+            /* If we already think the PVC is ok and this cert is from one of the user/
+             * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
+             * all mean we should use the special "Proceed" trust result. */
+#if TARGET_OS_IPHONE
+            if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) &&
+                SecCertificateSourceContains(kSecUserAnchorSource, cert)) {
+#else
+            if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) &&
+                SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) {
+#endif
+                pvc->result = kSecTrustResultProceed;
+            }
+        }
+    }
+}
+
+#define kSecPolicySHA256Size 32
+static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = {
+    0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C,
+    0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D
+};
+static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = {
+    0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2,
+    0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16
+};
+static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = {
+    0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47,
+    0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08
+};
+static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = {
+    0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39,
+    0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54
+};
+static const UInt8 kWS_ECC[kSecPolicySHA256Size] = {
+    0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB,
+    0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02
+};
+static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = {
+    0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13,
+    0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA
+};
+static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = {
+    0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37,
+    0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11
+};
+static const UInt8 kSC_G2[kSecPolicySHA256Size] = {
+    0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37,
+    0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95
+};
+
+static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
+    static CFSetRef sConstrainedRoots = NULL;
+    static dispatch_once_t _t;
+    dispatch_once(&_t, ^{
+        const UInt8 *v_hashes[] = {
+            kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC,
+            kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot
+        };
+        CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+        CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes);
+        for (ix=0; ix<count; ix++) {
+            CFDataRef hash = CFDataCreateWithBytesNoCopy(NULL, v_hashes[ix],
+                kSecPolicySHA256Size, kCFAllocatorNull);
+            if (hash) {
+                CFSetAddValue(set, hash);
+                CFRelease(hash);
+            }
+        }
+        sConstrainedRoots = set;
+    });
+
+    bool shouldDeny = false;
+    CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
+    for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) {
+        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX);
+        CFDataRef sha256 = SecCertificateCopySHA256Digest(cert);
+        if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) {
+            /* matched a constrained root; check notBefore dates on all its children. */
+            CFIndex childIX = certIX;
+            while (--childIX >= 0) {
+                SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX);
+                /* 1 Dec 2016 00:00:00 GMT */
+                if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) {
+                    SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true);
+                    pvc->result = kSecTrustResultFatalTrustFailure;
+                    shouldDeny = true;
+                    break;
+                }
+            }
+        }
+        CFReleaseNull(sha256);
+    }
+}
+
 /* AUDIT[securityd](done):
    policy->_options is a caller provided dictionary, only its cf type has
    been checked.
  */
-bool SecPVCPathChecks(SecPVCRef pvc) {
-    secdebug("policy", "begin path: %@", pvc->path);
-    bool completed = true;
+void SecPVCPathChecks(SecPVCRef pvc) {
+    secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder));
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
     /* This needs to be initialized before we call any function that might call
        SecPVCSetResultForced(). */
     pvc->policyIX = 0;
     SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
-    if (pvc->result || pvc->details) {
+    if (SecPVCIsOkResult(pvc) || pvc->details) {
+        /* @@@ This theoretically only needs to be done once per path, but since
+           this function affects the pvc result, we'll run it every time. */
         SecPolicyCheckBasicCertificateProcessing(pvc,
             kSecPolicyCheckBasicCertificateProcessing);
     }
 
     CFArrayRef policies = pvc->policies;
-       CFIndex count = CFArrayGetCount(policies);
-       for (; pvc->policyIX < count; ++pvc->policyIX) {
+    CFIndex count = CFArrayGetCount(policies);
+    for (; pvc->policyIX < count; ++pvc->policyIX) {
         /* Validate all keys for all policies. */
         pvc->callbacks = gSecPolicyPathCallbacks;
-               SecPolicyRef policy = SecPVCGetPolicy(pvc);
+        SecPolicyRef policy = SecPVCGetPolicy(pvc);
         CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
-        if (!pvc->result && !pvc->details)
-            return completed;
-       }
+        if (!SecPVCIsOkResult(pvc) && !pvc->details)
+            return;
+    }
 
-    /* Check the things we can't check statically for the certificate path. */
-    /* Critical Extensions, chainLength. */
+    // Reset
+    pvc->policyIX = 0;
 
-    /* Policy tests. */
-    pvc->is_ev = false;
-    if ((pvc->result || pvc->details) && pvc->optionally_ev) {
-        bool pre_ev_check_result = pvc->result;
-        SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
-        pvc->is_ev = pvc->result;
-        /* If ev checking failed, we still want to accept this chain
-           as a non EV one, if it was valid as such. */
-        pvc->result = pre_ev_check_result;
-    }
-    /* Check revocation only if the chain is valid so far.  Then only check
-       revocation if the client asked for it explicitly or is_ev is
-       true. */
-    if (pvc->result && (pvc->is_ev || pvc->check_revocation)) {
-        completed = SecPVCCheckRevocation(pvc);
-    }
+    /* Check whether the TrustSettings say to deny a cert in the path. */
+    SecPVCCheckUsageConstraints(pvc);
+
+    /* Check for Blocklisted certs */
+    SecPVCCheckIssuerDateConstraints(pvc);
+    CFIndex ix;
+    count = SecCertificatePathVCGetCount(path);
+    for (ix = 1; ix < count; ix++) {
+        SecPVCGrayListedKeyChecks(pvc, ix);
+        SecPVCBlackListedKeyChecks(pvc, ix);
+    }
+
+    /* Path-based check tests. */
+    if (!SecCertificatePathVCIsPathValidated(path)) {
+        bool ev_check_ok = false;
+        if (SecCertificatePathVCIsOptionallyEV(path)) {
+            SecTrustResultType pre_ev_check_result = pvc->result;
+            SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
+            ev_check_ok = SecPVCIsOkResult(pvc);
+            /* If ev checking failed, we still want to accept this chain
+             as a non EV one, if it was valid as such. */
+            pvc->result = pre_ev_check_result;
+        }
 
-    /* Check for CT */
-    if (pvc->result || pvc->details) {
+        /* Check for CT */
         /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */
         SecPolicyCheckCT(pvc, kSecPolicyCheckCertificateTransparency);
-    }
 
+        /* Certs are only EV if they are also CT verified */
+        if (ev_check_ok && SecCertificatePathVCIsCT(path)) {
+            SecCertificatePathVCSetIsEV(path, true);
+        }
+    }
 
 //errOut:
-    secdebug("policy", "end %strusted completed: %d path: %@",
-        (pvc->result ? "" : "not "), completed, pvc->path);
-    return completed;
-}
-
-/* This function returns 0 to indicate revocation checking was not completed
-   for this certificate chain, otherwise return to date at which the first
-   piece of revocation checking info we used expires.  */
-CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
-       CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
-    CFAbsoluteTime enu = 0;
-    if (certCount <= 1 || !pvc->rvcs) {
-        return enu;
-    }
-    certCount--;
-
-       for (certIX = 0; certIX < certCount; ++certIX) {
-        SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
-        if (rvc->nextUpdate == 0) {
-            if (certIX > 0) {
-                /* We allow for CA certs to not be revocation checked if they
-                   have no ocspResponders to check against, but the leaf
-                   must be checked in order for us to claim we did revocation
-                   checking. */
-                SecCertificateRef cert =
-                    SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
-                CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
-                if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) {
-                    /* We can't check this cert so we don't consider it a soft
-                       failure that we didn't. Ideally we should support crl
-                       checking and remove this workaround, since that more
-                       strict. */
-                    continue;
-                }
+    secdebug("policy", "end %strusted path: %@",
+        (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder));
+
+    SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
+    return;
+}
+
+void SecPVCPathCheckRevocationRequired(SecPVCRef pvc) {
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+    CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
+    for (ix = 0; ix < certCount; ix++) {
+        /* If we require revocation (for that cert per the SecCertificateVCRef or
+         * per the pvc) */
+        if (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) ||
+            ((ix == 0) && pvc->require_revocation_response)) {
+            /* Do we have a valid revocation response? */
+            SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix);
+            if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) {
+                SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired,
+                                      ix, kCFBooleanFalse, true);
             }
-            secdebug("ocsp", "revocation checking soft failure for cert: %ld",
-                certIX);
-            enu = rvc->nextUpdate;
-            break;
-        }
-        if (enu == 0 || rvc->nextUpdate < enu) {
-            enu = rvc->nextUpdate;
         }
-#if 0
-        /* Perhaps we don't want to do this since some policies might
-           ignore the certificate expiration but still use revocation
-           checking. */
-
-        /* Earliest certificate expiration date. */
-               SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
-        CFAbsoluteTime nva = SecCertificateNotValidAfter(cert);
-        if (nva && (enu == 0 || nva < enu)
-            enu = nva;
-#endif
     }
-
-    secdebug("ocsp", "revocation valid until: %lg", enu);
-    return enu;
 }