]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/securityd/SecRevocationServer.c
Security-59306.41.2.tar.gz
[apple/security.git] / OSX / sec / securityd / SecRevocationServer.c
diff --git a/OSX/sec/securityd/SecRevocationServer.c b/OSX/sec/securityd/SecRevocationServer.c
deleted file mode 100644 (file)
index b81b047..0000000
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * Copyright (c) 2008-2019 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * SecRevocationServer.c - Engine for evaluating certificate revocation.
- */
-
-#include <AssertMacros.h>
-
-#include <mach/mach_time.h>
-
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecCertificateInternal.h>
-#include <Security/SecPolicyPriv.h>
-#include <Security/SecTrustPriv.h>
-#include <Security/SecInternal.h>
-
-#include <utilities/debugging.h>
-#include <utilities/SecCFWrappers.h>
-#include <utilities/SecIOFormat.h>
-
-#include <securityd/SecTrustServer.h>
-#include <securityd/SecOCSPRequest.h>
-#include <securityd/SecOCSPResponse.h>
-#include <securityd/SecOCSPCache.h>
-#include <securityd/SecRevocationDb.h>
-#include <securityd/SecCertificateServer.h>
-#include <securityd/SecPolicyServer.h>
-#include <securityd/SecRevocationNetworking.h>
-
-#include <securityd/SecRevocationServer.h>
-
-// MARK: SecORVCRef
-/********************************************************
- ****************** OCSP RVC Functions ******************
- ********************************************************/
-const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
-const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0;
-#define OCSP_RESPONSE_TIMEOUT       (3 * NSEC_PER_SEC)
-
-static void SecORVCFinish(SecORVCRef orvc) {
-    secdebug("alloc", "finish orvc %p", orvc);
-    if (orvc->ocspRequest) {
-        SecOCSPRequestFinalize(orvc->ocspRequest);
-        orvc->ocspRequest = NULL;
-    }
-    if (orvc->ocspResponse) {
-        SecOCSPResponseFinalize(orvc->ocspResponse);
-        orvc->ocspResponse = NULL;
-        if (orvc->ocspSingleResponse) {
-            SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse);
-            orvc->ocspSingleResponse = NULL;
-        }
-    }
-    memset(orvc, 0, sizeof(struct OpaqueSecORVC));
-}
-
-/* Process a verified ocsp response for a given cert. Return true if the
- certificate status was obtained. */
-static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
-                                         SecORVCRef 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);
-            SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX,
-                                  cfreason, true);
-            SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
-            if (path) {
-                SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, 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:
-            secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
-                      (int)this->certStatus, rvc->certIX);
-            processed = false;
-            break;
-    }
-
-    return processed;
-}
-
-void SecORVCUpdatePVC(SecORVCRef rvc) {
-    if (rvc->ocspSingleResponse) {
-        SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
-    }
-    if (rvc->ocspResponse) {
-        rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
-    }
-}
-
-typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr);
-
-static void
-SecOCSPEvaluateCompleted(const void *userData,
-                         CFArrayRef chain, CFArrayRef details, CFDictionaryRef info,
-                         SecTrustResultType result) {
-    SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData;
-    evaluated(result);
-    Block_release(evaluated);
-
-}
-
-static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) {
-    __block bool evaluated = false;
-    bool trusted = false;
-    if (!signers || !issuers) {
-        return trusted;
-    }
-
-    /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */
-    const void *ocspSigner = SecPolicyCreateOCSPSigner();
-    CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
-                                        &ocspSigner, 1, &kCFTypeArrayCallBacks);
-    CFRelease(ocspSigner);
-
-    SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) {
-        if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
-            evaluated = true;
-        }
-    });
-
-    CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->builder);
-    SecPathBuilderRef oBuilder = SecPathBuilderCreate(NULL, clientAuditToken,
-                                                      signers, issuers, true, false,
-                                                      policies, NULL, NULL,  NULL,
-                                                      verifyTime, NULL, NULL,
-                                                      SecOCSPEvaluateCompleted, completed);
-    /* disable network access to avoid recursion */
-    SecPathBuilderSetCanAccessNetwork(oBuilder, false);
-
-    /* Build the chain(s), evaluate them, call the completed block, free the block and builder */
-    SecPathBuilderStep(oBuilder);
-    CFReleaseNull(clientAuditToken);
-    CFReleaseNull(policies);
-
-    /* verify the public key of the issuer signed the OCSP signer */
-    if (evaluated) {
-        SecCertificateRef issuer = NULL, signer = NULL;
-        SecKeyRef issuerPubKey = NULL;
-
-        issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0);
-        signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0);
-
-        if (issuer) {
-            issuerPubKey = SecCertificateCopyKey(issuer);
-        }
-        if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) {
-            trusted = true;
-        } else {
-            secnotice("ocsp", "ocsp signer cert not signed by issuer");
-        }
-        CFReleaseNull(issuerPubKey);
-    }
-
-    return trusted;
-}
-
-static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) {
-    bool trusted;
-    SecCertificatePathVCRef issuers = SecCertificatePathVCCopyFromParent(SecPathBuilderGetPath(rvc->builder), rvc->certIX + 1);
-    SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathVCGetCertificateAtIndex(issuers, 0)) : NULL;
-    CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse);
-    SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
-
-    if (signer && signers) {
-        if (issuer && CFEqual(signer, issuer)) {
-            /* We already know we trust issuer since it's the issuer of the
-             * cert we are verifying. */
-            secinfo("ocsp", "ocsp responder: %@ response signed by issuer",
-                    rvc->responder);
-            trusted = true;
-        } else {
-            secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer",
-                    rvc->responder);
-            CFMutableArrayRef signerCerts = NULL;
-            CFArrayRef issuerCerts = NULL;
-
-            /* Ensure the signer cert is the 0th cert for trust evaluation */
-            signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-            CFArrayAppendValue(signerCerts, signer);
-            CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers)));
-
-            if (issuers) {
-                issuerCerts = SecCertificatePathVCCopyCertificates(issuers);
-            }
-
-            if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) {
-                secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
-                         rvc->responder);
-                trusted = true;
-            } else {
-                /* @@@ We don't trust the cert so don't use this response. */
-                secnotice("ocsp", "ocsp response signed by certificate which "
-                          "does not satisfy ocspSigner policy");
-                trusted = false;
-            }
-            CFReleaseNull(signerCerts);
-            CFReleaseNull(issuerCerts);
-        }
-    } else {
-        /* @@@ No signer found for this ocsp response, discard it. */
-        secnotice("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
-    CFReleaseNull(issuers);
-    CFReleaseNull(issuer);
-    CFReleaseNull(signers);
-    CFReleaseNull(signer);
-    return trusted;
-}
-
-void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/,
-                                CFTimeInterval maxAge, bool updateCache, bool fromCache) {
-    SecOCSPSingleResponseRef sr = NULL;
-    require_quiet(ocspResponse, errOut);
-    SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
-    require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
-                         secnotice("ocsp", "responder: %@ returned status: %d",  rvc->responder, orStatus));
-    require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
-                         secnotice("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);
-
-    CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
-#if TARGET_OS_IPHONE
-    /* Check the OCSP response signature and verify the response if not pulled from the cache.
-     * Performance optimization since we don't write invalid responses to the cache. */
-    if (!fromCache) {
-        require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
-                                            sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
-    }
-#else
-    /* Always check the OCSP response signature and verify the response (since the cache is user-modifiable). */
-    require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
-                                        sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
-#endif
-
-    // If we get here, we have a properly signed ocsp response
-    // but we haven't checked dates yet.
-
-    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(SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX));
-    }
-
-    // Ok we like the new response, let's toss the old one.
-    if (updateCache)
-        SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
-
-    if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
-    rvc->ocspResponse = ocspResponse;
-    ocspResponse = NULL;
-
-    if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
-    rvc->ocspSingleResponse = sr;
-    sr = NULL;
-
-    rvc->done = sr_valid;
-
-errOut:
-    if (sr) SecOCSPSingleResponseDestroy(sr);
-    if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
-}
-
-static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) {
-    SecORVCRef orvc = NULL;
-    orvc = malloc(sizeof(struct OpaqueSecORVC));
-    secdebug("alloc", "orvc %p", orvc);
-    if (orvc) {
-        memset(orvc, 0, sizeof(struct OpaqueSecORVC));
-        orvc->builder = builder;
-        orvc->rvc = rvc;
-        orvc->certIX = certIX;
-
-        SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(builder, certIX);
-        if (SecPathBuilderGetCertificateCount(builder) > (certIX + 1)) {
-            SecCertificateRef issuer = SecPathBuilderGetCertificateAtIndex(builder, certIX + 1);
-            orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
-        }
-    }
-    return orvc;
-}
-
-static void SecORVCProcessStapledResponses(SecORVCRef rvc) {
-    /* Get stapled OCSP responses */
-    CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->builder);
-
-    if(ocspResponsesData) {
-        secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX);
-        CFArrayForEach(ocspResponsesData, ^(const void *value) {
-            SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
-            SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false, false);
-        });
-        CFRelease(ocspResponsesData);
-    }
-}
-
-void SecRVCDelete(SecRVCRef rvc) {
-    secdebug("alloc", "delete rvc %p", rvc);
-    if (rvc->orvc) {
-        SecORVCFinish(rvc->orvc);
-        free(rvc->orvc);
-        rvc->orvc = NULL;
-    }
-    if (rvc->valid_info) {
-        CFReleaseNull(rvc->valid_info);
-    }
-}
-
-// Forward declaration
-static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc);
-
-static void SecRVCInit(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) {
-    secdebug("alloc", "rvc %p", rvc);
-    rvc->builder = builder;
-    rvc->certIX = certIX;
-    rvc->orvc = SecORVCCreate(rvc, builder, certIX);
-    if (!rvc->orvc) {
-        SecRVCDelete(rvc);
-        SecRVCSetFinishedWithoutNetwork(rvc);
-    } else {
-        rvc->done = false;
-    }
-}
-
-static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) {
-    return true;
-}
-
-static bool SecRVCPolicyConstraintsPermitPolicy(SecValidPolicy *constraints, CFIndex count, SecPolicyRef policy) {
-    if (!constraints || !policy) {
-        return true; /* nothing to constrain */
-    }
-    SecValidPolicy policyType = kSecValidPolicyAny;
-    CFStringRef policyName = SecPolicyGetName(policy);
-    /* determine if the policy is a candidate for being constrained */
-    if (CFEqualSafe(policyName, kSecPolicyNameSSLServer) ||
-               CFEqualSafe(policyName, kSecPolicyNameEAPServer) ||
-               CFEqualSafe(policyName, kSecPolicyNameIPSecServer)) {
-        policyType = kSecValidPolicyServerAuthentication;
-    } else if (CFEqualSafe(policyName, kSecPolicyNameSSLClient) ||
-               CFEqualSafe(policyName, kSecPolicyNameEAPClient) ||
-               CFEqualSafe(policyName, kSecPolicyNameIPSecClient)) {
-        policyType = kSecValidPolicyClientAuthentication;
-    } else if (CFEqualSafe(policyName, kSecPolicyNameSMIME)) {
-        policyType = kSecValidPolicyEmailProtection;
-    } else if (CFEqualSafe(policyName, kSecPolicyNameCodeSigning)) {
-        policyType = kSecValidPolicyCodeSigning;
-    } else if (CFEqualSafe(policyName, kSecPolicyNameTimeStamping)) {
-        policyType = kSecValidPolicyTimeStamping;
-    }
-    if (policyType == kSecValidPolicyAny) {
-        return true; /* policy not subject to constraint */
-    }
-    /* policy is subject to constraint; do the constraints allow it? */
-    bool result = false;
-    for (CFIndex ix = 0; ix < count; ix++) {
-        SecValidPolicy allowedPolicy = constraints[ix];
-        if (allowedPolicy == kSecValidPolicyAny ||
-            allowedPolicy == policyType) {
-            result = true;
-            break;
-        }
-    }
-    if (!result) {
-        secnotice("rvc", "%@ not allowed by policy constraints on issuing CA", policyName);
-    }
-    return result;
-}
-
-static bool SecRVCGetPolicyConstraints(CFDataRef data, SecValidPolicy **constraints, CFIndex *count) {
-    /* Sanity-check the input policy constraints data, returning pointer and
-     * count values in output arguments. Function result is true if successful.
-     *
-     * The first byte of the policy constraints data contains the number of entries,
-     * followed by an array of 0..n policy constraint values of type SecValidPolicy.
-     * The maximum number of defined policies is not expected to approach 127, i.e.
-     * the largest value which can be expressed in a signed byte.
-     */
-    bool result = false;
-    CFIndex length = 0;
-    SecValidPolicy *p = NULL;
-    if (data) {
-        length = CFDataGetLength(data);
-        p = (SecValidPolicy *)CFDataGetBytePtr(data);
-    }
-    /* Verify that count is 0 or greater, and equal to remaining number of bytes */
-    CFIndex c = (length > 0) ? *p++ : -1;
-    if (c < 0 || c != (length - 1)) {
-        secerror("invalid policy constraints array");
-    } else {
-        if (constraints) {
-            *constraints = p;
-        }
-        if (count) {
-            *count = c;
-        }
-        result = true;
-    }
-    return result;
-}
-
-static void SecRVCProcessValidPolicyConstraints(SecRVCRef rvc) {
-    if (!rvc || !rvc->valid_info || !rvc->builder) {
-        return;
-    }
-    if (!rvc->valid_info->hasPolicyConstraints) {
-        return;
-    }
-    CFIndex count = 0;
-    SecValidPolicy *constraints = NULL;
-    if (!SecRVCGetPolicyConstraints(rvc->valid_info->policyConstraints, &constraints, &count)) {
-        return;
-    }
-    secdebug("rvc", "found policy constraints for cert at index %ld", rvc->certIX);
-
-    /* check that policies being verified are permitted by the policy constraints */
-    bool policyDeniedByConstraints = false;
-    CFIndex ix, initialPVCCount = SecPathBuilderGetPVCCount(rvc->builder);
-    for (ix = 0; ix < initialPVCCount; ix++) {
-        SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, ix);
-        CFArrayRef policies = CFRetainSafe(pvc->policies);
-        CFIndex policyCount = (policies) ? CFArrayGetCount(policies) : 0;
-        for (CFIndex policyIX = 0; policyIX < policyCount; policyIX++) {
-            SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
-            if (!SecRVCPolicyConstraintsPermitPolicy(constraints, count, policy)) {
-                policyDeniedByConstraints = true;
-                SecPVCSetResultForced(pvc, kSecPolicyCheckIssuerPolicyConstraints, rvc->certIX,
-                                      kCFBooleanFalse, true);
-                pvc->result = kSecTrustResultRecoverableTrustFailure;
-                if (!rvc->valid_info->overridable) {
-                    /* error for this check should be non-recoverable */
-                    pvc->result = kSecTrustResultFatalTrustFailure;
-                }
-            }
-        }
-        CFReleaseSafe(policies);
-    }
-    TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
-    if (analytics) {
-        TAValidStatus status = (policyDeniedByConstraints) ? TAValidPolicyConstrainedDenied : TAValidPolicyConstrainedOK;
-        analytics->valid_status |= status;
-    }
-}
-
-static void SecRVCProcessValidDateConstraints(SecRVCRef rvc) {
-    if (!rvc || !rvc->valid_info || !rvc->builder) {
-        return;
-    }
-    if (!rvc->valid_info->hasDateConstraints) {
-        return;
-    }
-    SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX);
-    if (!certificate) {
-        return;
-    }
-    CFAbsoluteTime certIssued = SecCertificateNotValidBefore(certificate);
-    CFAbsoluteTime caNotBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */
-    CFAbsoluteTime caNotAfter = 31556908800.0;  /* default: 3001-01-01 00:00:00-0000 */
-    if (rvc->valid_info->notBeforeDate) {
-        caNotBefore = CFDateGetAbsoluteTime(rvc->valid_info->notBeforeDate);
-    }
-    if (rvc->valid_info->notAfterDate) {
-        caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate);
-        /* per the Valid specification, if this date is in the past, we need to check CT. */
-        CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
-        if (caNotAfter < now) {
-            rvc->valid_info->requireCT = true;
-        }
-    }
-    if ((certIssued < caNotBefore) && (rvc->certIX > 0)) {
-        /* not-before constraint is only applied to leaf certificate, for now. */
-        return;
-    }
-
-    TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
-    if ((certIssued < caNotBefore) || (certIssued > caNotAfter)) {
-        /* We are outside the constrained validity period. */
-        secnotice("rvc", "certificate issuance date not within the allowed range for this CA%s",
-                  (rvc->valid_info->overridable) ? "" : " (non-recoverable error)");
-        if (analytics) {
-            analytics->valid_status |= TAValidDateConstrainedRevoked;
-        }
-        if (rvc->valid_info->overridable) {
-            /* error is recoverable, treat certificate as untrusted
-               (note this date check is different from kSecPolicyCheckTemporalValidity) */
-            SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedKey, rvc->certIX,
-                                          kCFBooleanFalse, true);
-        } else {
-            /* error is non-overridable, treat certificate as revoked */
-            SInt32 reason = 0; /* unspecified reason code */
-            CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
-            SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX,
-                                          cfreason, true);
-            SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
-            if (path) {
-                SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason);
-            }
-            CFReleaseNull(cfreason);
-        }
-    } else if (analytics) {
-        analytics->valid_status |= TAValidDateConstrainedOK;
-    }
-}
-
-bool SecRVCHasDefinitiveValidInfo(SecRVCRef rvc) {
-    if (!rvc || !rvc->valid_info) {
-        return false;
-    }
-    SecValidInfoRef info = rvc->valid_info;
-    /* outcomes as defined in Valid server specification */
-    if (info->format == kSecValidInfoFormatSerial ||
-        info->format == kSecValidInfoFormatSHA256) {
-        if (info->noCACheck || info->complete || info->isOnList) {
-            return true;
-        }
-    } else { /* info->format == kSecValidInfoFormatNto1 */
-        if (info->noCACheck || (info->complete && !info->isOnList)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool SecRVCHasRevokedValidInfo(SecRVCRef rvc) {
-    if (!rvc || !rvc->valid_info) {
-        return false;
-    }
-    SecValidInfoRef info = rvc->valid_info;
-    /* either not present on an allowlist, or present on a blocklist */
-    return (!info->isOnList && info->valid) || (info->isOnList && !info->valid);
-}
-
-void SecRVCSetValidDeterminedErrorResult(SecRVCRef rvc) {
-    if (!rvc || !rvc->valid_info || !rvc->builder) {
-        return;
-    }
-    if (rvc->valid_info->overridable) {
-        /* error is recoverable, treat certificate as untrusted */
-        SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedLeaf, rvc->certIX,
-                                      kCFBooleanFalse, true);
-        return;
-    }
-    /* error is fatal at this point */
-    if (!SecRVCHasRevokedValidInfo(rvc) || rvc->valid_info->noCACheck) {
-        /* result key should indicate blocked instead of revoked,
-         * but result must be non-recoverable */
-        SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckBlackListedLeaf, rvc->certIX,
-                                      kCFBooleanFalse, true);
-        return;
-    }
-    SInt32 reason = 0; /* unspecified, since the Valid db doesn't tell us */
-    CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
-    SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX,
-                                  cfreason, true);
-    SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
-    if (path) {
-        SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason);
-    }
-    CFReleaseNull(cfreason);
-}
-
-static void SecRVCProcessValidInfoResults(SecRVCRef rvc) {
-    if (!rvc || !rvc->valid_info || !rvc->builder) {
-        return;
-    }
-    SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
-    SecValidInfoRef info = rvc->valid_info;
-
-    bool definitive = SecRVCHasDefinitiveValidInfo(rvc);
-    bool revoked = SecRVCHasRevokedValidInfo(rvc);
-
-    /* set analytics */
-    TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
-    if (analytics) {
-        if (revoked) {
-            analytics->valid_status |= definitive ? TAValidDefinitelyRevoked : TAValidProbablyRevoked;
-        } else {
-            analytics->valid_status |= definitive ? TAValidDefinitelyOK : TAValidProbablyOK;
-        }
-        analytics->valid_require_ct |= info->requireCT;
-        analytics->valid_known_intermediates_only |= info->knownOnly;
-    }
-
-    /* Handle no-ca cases */
-    if (info->noCACheck) {
-        bool allowed = (info->valid && info->complete && info->isOnList);
-        if (revoked) {
-            /* definitely revoked */
-            SecRVCSetValidDeterminedErrorResult(rvc);
-        } else if (allowed) {
-            /* definitely not revoked (allowlisted) */
-            SecCertificatePathVCSetIsAllowlisted(path, true);
-        }
-        /* no-ca is definitive; no need to check further. */
-        secdebug("validupdate", "rvc: definitely %s cert %" PRIdCFIndex,
-                 (allowed) ? "allowed" : "revoked", rvc->certIX);
-        rvc->done = true;
-        return;
-    }
-
-    /* Handle policy constraints, if present. */
-    SecRVCProcessValidPolicyConstraints(rvc);
-
-    /* Handle date constraints, if present.
-     * Note: a not-after date may set the CT requirement,
-     * so check requireCT after this function is called. */
-    SecRVCProcessValidDateConstraints(rvc);
-
-    /* Set CT requirement on path, if present. */
-    if (info->requireCT) {
-        SecPathCTPolicy ctp = kSecPathCTRequired;
-        if (info->overridable) {
-            ctp = kSecPathCTRequiredOverridable;
-        }
-        SecCertificatePathVCSetRequiresCT(path, ctp);
-    }
-
-    /* Trigger OCSP for any non-definitive or revoked cases */
-    if (!definitive || revoked) {
-        info->checkOCSP = true;
-    }
-
-    if (info->checkOCSP) {
-        CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder);
-        CFIndex issuerIX = rvc->certIX + 1;
-        if (issuerIX >= count) {
-            /* cannot perform a revocation check on the last cert in the
-               chain, since we don't have its issuer. */
-            return;
-        }
-        secdebug("validupdate", "rvc: %s%s cert %" PRIdCFIndex " (will check OCSP)",
-                 (info->complete) ? "" : "possibly ", (info->valid) ? "allowed" : "revoked",
-                 rvc->certIX);
-        SecPathBuilderSetRevocationMethod(rvc->builder, kSecPolicyCheckRevocationAny);
-        if (analytics) {
-            /* Valid DB results caused us to do OCSP */
-            analytics->valid_trigger_ocsp = true;
-        }
-    }
-}
-
-static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) {
-    /* Skip checking for OCSP Signer verification */
-    if (SecPathBuilderGetPVCCount(rvc->builder) == 1) {
-        SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, 0);
-        if (!pvc) { return false; }
-        SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0);
-        CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL;
-        if (policyName && CFEqual(policyName, CFSTR("OCSPSigner"))) {
-            return false;
-        }
-    }
-
-    /* Make sure revocation db info is up-to-date.
-     * We don't care if the builder is allowed to access the network because
-     * the network fetching does not block the trust evaluation. */
-    SecRevocationDbCheckNextUpdate();
-
-    /* Check whether we have valid db info for this cert,
-     given the cert and its issuer */
-    SecValidInfoRef info = NULL;
-    CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder);
-    if (count) {
-        bool isSelfSigned = false;
-        SecCertificateRef cert = NULL;
-        SecCertificateRef issuer = NULL;
-        CFIndex issuerIX = rvc->certIX + 1;
-        if (count > issuerIX) {
-            issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, issuerIX);
-        } else if (count == issuerIX) {
-            CFIndex rootIX = SecCertificatePathVCSelfSignedIndex(SecPathBuilderGetPath(rvc->builder));
-            if (rootIX == rvc->certIX) {
-                issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, rootIX);
-                isSelfSigned = true;
-            }
-        }
-        cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX);
-        if (!isSelfSigned) {
-            /* skip revocation db check for self-signed certificates [33137065] */
-            info = SecRevocationDbCopyMatching(cert, issuer);
-        }
-        SecValidInfoSetAnchor(info, SecPathBuilderGetCertificateAtIndex(rvc->builder, count-1));
-    }
-    if (info) {
-        SecValidInfoRef old_info = rvc->valid_info;
-        rvc->valid_info = info;
-        if (old_info) {
-            CFReleaseNull(old_info);
-        }
-        return true;
-    }
-    return false;
-}
-
-static void SecRVCCheckRevocationCaches(SecRVCRef rvc) {
-    /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */
-    if (SecRVCShouldCheckOCSP(rvc) && (rvc->orvc->ocspRequest)) {
-        secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX);
-        SecOCSPResponseRef response = NULL;
-        if (SecPathBuilderGetCheckRevocationOnline(rvc->builder)) {
-            CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
-            response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL);
-        } else {
-            response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL);
-        }
-        SecORVCConsumeOCSPResponse(rvc->orvc, response, NULL_TIME, false, true);
-        TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
-        if (rvc->orvc->done && analytics) {
-            /* We found a valid OCSP response in the cache */
-            analytics->ocsp_cache_hit = true;
-        }
-    }
-}
-
-static void SecRVCUpdatePVC(SecRVCRef rvc) {
-    SecRVCProcessValidInfoResults(rvc); /* restore the results we got from Valid */
-    if (rvc->orvc) { SecORVCUpdatePVC(rvc->orvc); }
-}
-
-static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc) {
-    rvc->done = true;
-    SecRVCUpdatePVC(rvc);
-    (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder);
-}
-
-static bool SecRVCFetchNext(SecRVCRef rvc) {
-    bool OCSP_fetch_finished = true;
-    TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
-    /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */
-    if (SecRVCShouldCheckOCSP(rvc)) {
-        SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
-        SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX);
-        OCSP_fetch_finished = SecORVCBeginFetches(rvc->orvc, cert);
-        if (analytics && !OCSP_fetch_finished) {
-            /* We did a network OCSP fetch, set report appropriately */
-            analytics->ocsp_network = true;
-        }
-    }
-    if (OCSP_fetch_finished) {
-        /* we didn't start an OCSP background job for this cert */
-        (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder);
-    }
-    return OCSP_fetch_finished;
-}
-
-/* The SecPathBuilder state machine calls SecPathBuilderCheckRevocation twice --
- * once in the ValidatePath state, and again in the ComputeDetails state. In the
- * ValidatePath state we've not yet run the path checks, so for callers who set
- * kSecRevocationCheckIfTrusted, we don't do any networking on that first call.
- * Here, if we've already done revocation before (so we're in ComputeDetails now),
- * we need to recheck (and enable networking) for trusted chains and
- * kSecRevocationCheckIfTrusted. Otherwise, we skip the checks to save on the processing
- * but update the PVCs with the revocation results from the last check. */
-static bool SecRevocationDidCheckRevocation(SecPathBuilderRef builder, bool *first_check_done) {
-    SecCertificatePathVCRef path = SecPathBuilderGetPath(builder);
-    if (!SecCertificatePathVCIsRevocationDone(path)) {
-        return false;
-    }
-    if (first_check_done) {
-        *first_check_done = true;
-    }
-
-    SecPVCRef resultPVC = SecPathBuilderGetResultPVC(builder);
-    bool recheck = false;
-    if (SecPathBuilderGetCheckRevocationIfTrusted(builder) && SecPVCIsOkResult(resultPVC)) {
-        recheck = true;
-        secdebug("rvc", "Rechecking revocation because network now allowed");
-    } else {
-        secdebug("rvc", "Not rechecking revocation");
-    }
-
-    if (recheck) {
-        // reset the RVCs for the second pass
-        SecCertificatePathVCDeleteRVCs(path);
-    } else {
-        CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder);
-        for (certIX = 0; certIX < certCount; ++certIX) {
-            SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX);
-            if (rvc) {
-                SecRVCUpdatePVC(rvc);
-            }
-        }
-    }
-
-    return !recheck;
-}
-
-static bool SecRevocationCanAccessNetwork(SecPathBuilderRef builder, bool first_check_done) {
-    /* CheckRevocationIfTrusted overrides NoNetworkAccess for revocation */
-    if (SecPathBuilderGetCheckRevocationIfTrusted(builder)) {
-        if (first_check_done) {
-            /* We're on the second pass. We need to now allow networking for revocation.
-             * SecRevocationDidCheckRevocation takes care of not running a second pass
-             * if the chain isn't trusted. */
-            return true;
-        } else {
-            /* We're on the first pass of the revocation checks, where we aren't
-             * supposed to do networking because we don't know if the chain
-             * is trusted yet. */
-            return false;
-        }
-    }
-    return SecPathBuilderCanAccessNetwork(builder);
-}
-
-void SecPathBuilderCheckKnownIntermediateConstraints(SecPathBuilderRef builder) {
-    SecCertificatePathVCRef path = SecPathBuilderGetPath(builder);
-    if (!path) {
-        return;
-    }
-    /* only perform this check once per path! */
-    CFIndex certIX = kCFNotFound;
-    if (SecCertificatePathVCCheckedIssuers(path)) {
-        certIX = SecCertificatePathVCUnknownCAIndex(path);
-        goto checkedIssuers;
-    }
-    /* check full path: start with anchor and decrement to leaf */
-    bool parentConstrained = false;
-    CFIndex certCount = SecPathBuilderGetCertificateCount(builder);
-    for (certIX = certCount - 1; certIX >= 0; --certIX) {
-        SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX);
-        if (!rvc) {
-            continue;
-        }
-        if (parentConstrained && !rvc->valid_info) {
-            /* Parent had the known-only constraint, but our issuer is unknown.
-               Bump index to point back at the issuer since it fails the constraint. */
-            certIX++;
-            break;
-        }
-        parentConstrained = (rvc->valid_info && rvc->valid_info->knownOnly);
-        if (parentConstrained) {
-            secdebug("validupdate", "Valid db found a known-intermediate constraint on %@ (index=%ld)",
-                     rvc->valid_info->issuerHash, certIX+1);
-            if (certIX == 0) {
-                /* check special case: unknown constrained CA in leaf position */
-                SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
-                if (cert && SecCertificateIsCA(cert) && !SecRevocationDbContainsIssuer(cert)) {
-                    /* leaf is a CA which violates the constraint */
-                    break;
-                }
-            }
-        }
-    }
-    /* At this point, certIX will either be -1, indicating no CA was found
-       which failed a known-intermediates-only constraint on its parent, or it
-       will be the index of the first unknown CA which fails the constraint. */
-    if (certIX >= 0) {
-        secnotice("validupdate", "CA at index %ld violates known-intermediate constraint", certIX);
-        TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder);
-        if (analytics) {
-            analytics->valid_unknown_intermediate = true;
-        }
-    }
-    SecCertificatePathVCSetUnknownCAIndex(path, certIX);
-    SecCertificatePathVCSetCheckedIssuers(path, true);
-
-checkedIssuers:
-    if (certIX >= 0) {
-        /* Error is set on CA certificate which failed the constraint. */
-        SecRVCSetValidDeterminedErrorResult(SecCertificatePathVCGetRVCAtIndex(path, certIX));
-    }
-}
-
-bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder) {
-    secdebug("rvc", "checking revocation");
-    CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder);
-    SecCertificatePathVCRef path = SecPathBuilderGetPath(builder);
-    if (certCount <= 1) {
-        /* Can't verify without an issuer; we're done */
-        return true;
-    }
-
-    bool first_check_done = false;
-    if (SecRevocationDidCheckRevocation(builder, &first_check_done)) {
-        return true;
-    }
-
-    /* Setup things so we check revocation status of all certs. */
-    SecCertificatePathVCAllocateRVCs(path, certCount);
-
-    /* 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. We include the root, even though we'll never start
-     an async job for it so that we count all active threads for this eval. */
-    SecPathBuilderSetAsyncJobCount(builder, (unsigned int)(certCount));
-
-    /* Loop though certificates again and issue an ocsp fetch if the
-     revocation status checking isn't done yet (and we have an issuer!) */
-    for (certIX = 0; certIX < certCount; ++certIX) {
-        secdebug("rvc", "checking revocation for cert: %ld", certIX);
-        SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX);
-        if (!rvc) {
-            continue;
-        }
-
-        SecRVCInit(rvc, builder, certIX);
-
-        /* RFC 6960: id-pkix-ocsp-nocheck extension says that we shouldn't check revocation. */
-        if (SecCertificateHasOCSPNoCheckMarkerExtension(SecCertificatePathVCGetCertificateAtIndex(path, certIX)))
-        {
-            secdebug("rvc", "skipping revocation checks for no-check cert: %ld", certIX);
-            TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder);
-            if (analytics) {
-                /* This certificate has OCSP No-Check, so add to reporting analytics */
-                analytics->ocsp_no_check = true;
-            }
-            SecRVCSetFinishedWithoutNetwork(rvc);
-        }
-
-        if (rvc->done) {
-            continue;
-        }
-
-#if !TARGET_OS_BRIDGE
-        /* Check valid database first (separate from OCSP response cache) */
-        if (SecRVCCheckValidInfoDatabase(rvc)) {
-            SecRVCProcessValidInfoResults(rvc);
-        }
-#endif
-        /* Any other revocation method requires an issuer certificate to verify the response;
-         * skip the last cert in the chain since it doesn't have one. */
-        if (certIX + 1 >= certCount) {
-            continue;
-        }
-
-        /* Ignore stapled OCSP responses only if CRLs are enabled and the
-         * policy specifically requested CRLs only. */
-        if (SecRVCShouldCheckOCSP(rvc)) {
-            /*  If we have any OCSP stapled responses, check those first */
-            SecORVCProcessStapledResponses(rvc->orvc);
-        }
-
-#if TARGET_OS_BRIDGE
-        /* The bridge has no writeable storage and no network. Nothing else we can
-         * do here. */
-        SecRVCSetFinishedWithoutNetwork(rvc);
-        continue;
-#else // !TARGET_OS_BRIDGE
-        /* Then check the caches for revocation results. */
-        SecRVCCheckRevocationCaches(rvc);
-
-        /* The check is done if we found cached responses from either method. */
-        if (rvc->done || rvc->orvc->done) {
-            secdebug("rvc", "found cached response for cert: %ld", certIX);
-            SecRVCSetFinishedWithoutNetwork(rvc);
-            continue;
-        }
-
-        /* If we got a cached response that is no longer valid (which can only be true for
-         * revoked responses), let's try to get a fresher response even if no one asked.
-         * This check resolves unrevocation events after the nextUpdate time. */
-        bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse);
-
-        /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an
-         async http request for this cert's revocation status, unless we already successfully checked
-         the revocation status of this cert based on the cache or stapled responses.  */
-        bool allow_fetch = SecRevocationCanAccessNetwork(builder, first_check_done) &&
-            (SecCertificatePathVCIsEV(path) || SecCertificatePathVCIsOptionallyEV(path) ||
-             SecPathBuilderGetRevocationMethod(builder) || old_cached_response);
-        if (rvc->done || !allow_fetch) {
-            /* We got a cache hit or we aren't allowed to access the network */
-            SecRVCUpdatePVC(rvc);
-            /* We didn't really start any background jobs for this cert. */
-            (void)SecPathBuilderDecrementAsyncJobCount(builder);
-        } else {
-            (void)SecRVCFetchNext(rvc);
-        }
-#endif // !TARGET_OS_BRIDGE
-    }
-
-    /* Return false if there are still async jobs running. */
-    /* builder->asyncJobCount is atomic, so we know that if the job count is 0, all other
-     * threads are finished. If the job count is > 0, other threads will decrement the job
-     * count and SecPathBuilderStep to crank the state machine when the job count is 0. */
-    return (SecPathBuilderDecrementAsyncJobCount(builder) == 0);
-}
-
-CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) {
-    CFAbsoluteTime enu = NULL_TIME;
-    if (!rvc || !rvc->orvc) { return enu; }
-    enu = rvc->orvc->nextUpdate;
-    return enu;
-}