]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_apple_x509_tp / lib / tpOcspVerify.cpp
diff --git a/Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp b/Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp
deleted file mode 100644 (file)
index ae11caf..0000000
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright (c) 2004,2011-2012,2014 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@
- */
-
-/*
- * tpOcspVerify.cpp - top-level OCSP verification
- */
-
-#include "tpOcspVerify.h"
-#include "tpdebugging.h"
-#include "ocspRequest.h"
-#include "tpOcspCache.h"
-#include "tpOcspCertVfy.h"
-#include <security_ocspd/ocspResponse.h>
-#include "certGroupUtils.h"
-#include <Security/certextensions.h>
-#include <Security/oidsattr.h>
-#include <Security/oidscert.h>
-#include <security_asn1/SecNssCoder.h>
-#include <security_ocspd/ocspdClient.h>
-#include <security_ocspd/ocspdUtils.h>
-#include "tpTime.h"
-
-#pragma mark ---- private routines ----
-
-/*
- * Get a smart CertID for specified cert and issuer
- */
-static CSSM_RETURN tpOcspGetCertId(
-       TPCertInfo                      &subject,
-       TPCertInfo                      &issuer,
-       OCSPClientCertID        *&certID)               /* mallocd by coder and RETURNED */
-{
-       CSSM_RETURN crtn;
-       CSSM_DATA_PTR issuerSubject = NULL;
-       CSSM_DATA_PTR issuerPubKeyData = NULL;
-       CSSM_KEY_PTR issuerPubKey;
-       CSSM_DATA issuerPubKeyBytes;
-       CSSM_DATA_PTR subjectSerial = NULL;
-
-       crtn = subject.fetchField(&CSSMOID_X509V1SerialNumber, &subjectSerial);
-       if(crtn) {
-               return crtn;
-       }
-       crtn = subject.fetchField(&CSSMOID_X509V1IssuerNameStd, &issuerSubject);
-       if(crtn) {
-               return crtn;
-       }
-       crtn = issuer.fetchField(&CSSMOID_CSSMKeyStruct, &issuerPubKeyData);
-       if(crtn) {
-               return crtn;
-       }
-       assert(issuerPubKeyData->Length == sizeof(CSSM_KEY));
-       issuerPubKey = (CSSM_KEY_PTR)issuerPubKeyData->Data;
-       ocspdGetPublicKeyBytes(NULL, issuerPubKey, issuerPubKeyBytes);
-       certID = new OCSPClientCertID(*issuerSubject, issuerPubKeyBytes, *subjectSerial);
-
-       subject.freeField(&CSSMOID_X509V1SerialNumber, subjectSerial);
-       issuer.freeField(&CSSMOID_X509V1IssuerNameStd, issuerSubject);
-       issuer.freeField(&CSSMOID_CSSMKeyStruct, issuerPubKeyData);
-       return CSSM_OK;
-}
-
-/*
- * Examine cert, looking for AuthorityInfoAccess, with id-ad-ocsp URIs. Create
- * an NULL_terminated array of CSSM_DATAs containing the URIs if found.
- */
-static CSSM_DATA **tpOcspUrlsFromCert(
-       TPCertInfo &subject,
-       SecNssCoder &coder)
-{
-       CSSM_DATA_PTR extField = NULL;
-       CSSM_RETURN crtn;
-
-       crtn = subject.fetchField(&CSSMOID_AuthorityInfoAccess, &extField);
-       if(crtn) {
-               tpOcspDebug("tpOcspUrlsFromCert: no AIA extension");
-               return NULL;
-       }
-       if(extField->Length != sizeof(CSSM_X509_EXTENSION)) {
-               tpErrorLog("tpOcspUrlsFromCert: malformed CSSM_FIELD");
-               return NULL;
-       }
-       CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)extField->Data;
-       if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
-               tpErrorLog("tpOcspUrlsFromCert: malformed CSSM_X509_EXTENSION");
-               return NULL;
-       }
-
-       CE_AuthorityInfoAccess *aia =
-               (CE_AuthorityInfoAccess *)cssmExt->value.parsedValue;
-       CSSM_DATA **urls = NULL;
-       unsigned numUrls = 0;
-       for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) {
-               CE_AccessDescription *ad = &aia->accessDescriptions[dex];
-               if(!tpCompareCssmData(&ad->accessMethod, &CSSMOID_AD_OCSP)) {
-                       continue;
-               }
-               CE_GeneralName *genName = &ad->accessLocation;
-               if(genName->nameType != GNT_URI) {
-                       tpErrorLog("tpOcspUrlsFromCert: CSSMOID_AD_OCSP, but not type URI");
-                       continue;
-               }
-
-               /* got one */
-               if(urls == NULL) {
-                       urls = coder.mallocn<CSSM_DATA_PTR>(2);
-               }
-               else {
-                       /* realloc */
-                       CSSM_DATA **oldUrls = urls;
-                       urls = coder.mallocn<CSSM_DATA_PTR>(numUrls + 2);
-                       for(unsigned i=0; i<numUrls; i++) {
-                               urls[i] = oldUrls[i];
-                       }
-               }
-               urls[numUrls] = coder.mallocn<CSSM_DATA>();
-               coder.allocCopyItem(genName->name, *urls[numUrls++]);
-               urls[numUrls] = NULL;
-               #ifndef NDEBUG
-               {
-                       CSSM_DATA urlStr;
-                       coder.allocItem(urlStr, genName->name.Length + 1);
-                       memmove(urlStr.Data, genName->name.Data, genName->name.Length);
-                       urlStr.Data[urlStr.Length-1] = '\0';
-                       tpOcspDebug("tpOcspUrlsFromCert: found URI %s", urlStr.Data);
-               }
-               #endif
-       }
-       subject.freeField(&CSSMOID_AuthorityInfoAccess, extField);
-       return urls;
-}
-
-/*
- * Create an SecAsn1OCSPDRequest for one cert. This consists of:
- *
- * -- cooking up an OCSPRequest if net fetch is enabled or a local responder
- *    is configured;
- * -- extracting URLs from subject cert if net fetch is enabled;
- * -- creating an SecAsn1OCSPDRequest, mallocd in coder's space;
- */
-static SecAsn1OCSPDRequest *tpGenOcspdReq(
-       TPVerifyContext         &vfyCtx,
-       SecNssCoder                     &coder,
-       TPCertInfo                      &subject,
-       TPCertInfo                      &issuer,
-       OCSPClientCertID        &certId,
-       const CSSM_DATA         **urls,         // from subject's AuthorityInfoAccess
-       CSSM_DATA                       &nonce)         // possibly mallocd in coder's space and RETURNED
-{
-       OCSPRequest                             *ocspReq = NULL;
-       SecAsn1OCSPDRequest             *ocspdReq = NULL;       // to return
-       OCSPClientCertID                *certID = NULL;
-       CSSM_RETURN                             crtn;
-       bool                                    deleteCertID = false;
-
-       /* gather options or their defaults */
-       CSSM_APPLE_TP_OCSP_OPT_FLAGS optFlags = 0;
-       const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
-       CSSM_DATA_PTR localResponder = NULL;
-       CSSM_DATA_PTR localResponderCert = NULL;
-       if(ocspOpts != NULL) {
-               optFlags = vfyCtx.ocspOpts->Flags;
-               localResponder = ocspOpts->LocalResponder;
-               localResponderCert = ocspOpts->LocalResponderCert;
-       }
-       bool genNonce = optFlags & CSSM_TP_OCSP_GEN_NONCE ? true : false;
-       bool requireRespNonce = optFlags & CSSM_TP_OCSP_REQUIRE_RESP_NONCE ? true : false;
-
-       /*
-        * One degenerate case in case we can't really do anything.
-        * If no URI and no local responder, only proceed if cache is not disabled
-        * and we're requiring full OCSP per cert.
-        */
-       if( ( (optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) ||
-                 !(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT)
-               ) &&
-          (localResponder == NULL) &&
-          (urls == NULL)) {
-          tpOcspDebug("tpGenOcspdReq: no route to OCSP; NULL return");
-          return NULL;
-       }
-
-       /* do we need an OCSP request? */
-       if(!(optFlags & CSSM_TP_ACTION_OCSP_DISABLE_NET) || (localResponder != NULL)) {
-               try {
-                       ocspReq = new OCSPRequest(subject, issuer, genNonce);
-                       certID = ocspReq->certID();
-               }
-               catch(...) {
-                       /* not sure how this could even happen but that was a fair amount of code */
-                       tpErrorLog("tpGenOcspdReq: error cooking up OCSPRequest\n");
-                       if(ocspReq != NULL) {
-                               delete ocspReq;
-                               return NULL;
-                       }
-               }
-       }
-
-       /* certID needed one way or the other */
-       if(certID == NULL) {
-               crtn = tpOcspGetCertId(subject, issuer, certID);
-               if(crtn) {
-                       goto errOut;
-               }
-               deleteCertID = true;
-       }
-
-       /*
-        * Create the SecAsn1OCSPDRequest. All fields optional.
-        */
-       ocspdReq = coder.mallocn<SecAsn1OCSPDRequest>();
-       memset(ocspdReq, 0, sizeof(*ocspdReq));
-       if(optFlags & CSSM_TP_ACTION_OCSP_CACHE_WRITE_DISABLE) {
-               ocspdReq->cacheWriteDisable = coder.mallocn<CSSM_DATA>();
-               ocspdReq->cacheWriteDisable->Data = coder.mallocn<uint8>();
-               ocspdReq->cacheWriteDisable->Data[0] = 0xff;
-               ocspdReq->cacheWriteDisable->Length = 1;
-       }
-       /*
-        * Note we're enforcing a not-so-obvious policy here: if nonce match is
-        * required, disk cache reads by ocspd are disabled. In-core cache is
-        * still enabled and hits in that cache do NOT require nonce matches.
-        */
-       if((optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) || requireRespNonce) {
-               ocspdReq->cacheReadDisable = coder.mallocn<CSSM_DATA>();
-               ocspdReq->cacheReadDisable->Data = coder.mallocn<uint8>();
-               ocspdReq->cacheReadDisable->Data[0] = 0xff;
-               ocspdReq->cacheReadDisable->Length = 1;
-       }
-       /* CertID, only required field */
-       coder.allocCopyItem(*certID->encode(), ocspdReq->certID);
-       if(ocspReq != NULL) {
-               ocspdReq->ocspReq = coder.mallocn<CSSM_DATA>();
-               coder.allocCopyItem(*ocspReq->encode(), *ocspdReq->ocspReq);
-               if(genNonce) {
-                       /* nonce not available until encode() called */
-                       coder.allocCopyItem(*ocspReq->nonce(), nonce);
-               }
-       }
-       if(localResponder != NULL) {
-               ocspdReq->localRespURI = localResponder;
-       }
-       if(!(optFlags & CSSM_TP_ACTION_OCSP_DISABLE_NET)) {
-               ocspdReq->urls = const_cast<CSSM_DATA **>(urls);
-       }
-
-errOut:
-       delete ocspReq;
-       if(deleteCertID) {
-               delete certID;
-       }
-       return ocspdReq;
-}
-
-static bool revocationTimeAfterVerificationTime(CFAbsoluteTime revokedTime, CSSM_TIMESTRING verifyTimeStr)
-{
-    // Return true if the revocation time is after the specified verification time (i.e. "good")
-    // If verifyTime not specified, use now for the verifyTime
-
-    CFAbsoluteTime verifyTime = 0;
-
-    if (verifyTimeStr)
-    {
-        CFDateRef cfVerifyTime = NULL;  // made with CFDateCreate
-        int rtn = timeStringToCfDate((char *)verifyTimeStr, (unsigned)strlen(verifyTimeStr), &cfVerifyTime);
-        if (!rtn)
-            if (cfVerifyTime)
-            {
-                verifyTime = CFDateGetAbsoluteTime(cfVerifyTime);
-                CFRelease(cfVerifyTime);
-            }
-    }
-
-    if (verifyTime == 0)
-        verifyTime = CFAbsoluteTimeGetCurrent();
-
-    return verifyTime < revokedTime;
-}
-
-/*
- * Apply a verified OCSPSingleResponse to a TPCertInfo.
- */
-static CSSM_RETURN tpApplySingleResp(
-       OCSPSingleResponse                              &singleResp,
-       TPCertInfo                                              &cert,
-       unsigned                                                dex,                    // for debug
-       CSSM_APPLE_TP_OCSP_OPT_FLAGS    flags,                  // for OCSP_SUFFICIENT
-    CSSM_TIMESTRING                            verifyTime,     // Check revocation at specific time
-       bool                                                    &processed)             // set true iff CS_Good or CS_Revoked found
-{
-       SecAsn1OCSPCertStatusTag certStatus = singleResp.certStatus();
-       CSSM_RETURN crtn = CSSM_OK;
-    if ((certStatus == CS_Revoked) &&
-        revocationTimeAfterVerificationTime(singleResp.revokedTime(), verifyTime))
-    {
-        tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u, but revoked after verification time", dex);
-        certStatus = CS_Good;
-    }
-
-       switch(certStatus) {
-               case CS_Good:
-                       tpOcspDebug("tpApplySingleResp: CS_Good for cert %u", dex);
-                       cert.revokeCheckGood(true);
-                       if(flags & CSSM_TP_ACTION_OCSP_SUFFICIENT) {
-                               /* no more revocation checking necessary for this cert */
-                               cert.revokeCheckComplete(true);
-                       }
-                       processed = true;
-                       break;
-               case CS_Revoked:
-                       tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u", dex);
-                       switch(singleResp.crlReason()) {
-                               case CE_CR_CertificateHold:
-                                       crtn = CSSMERR_TP_CERT_SUSPENDED;
-                                       break;
-                               default:
-                                       /* FIXME - may want more detailed CRLReason-specific errors */
-                                       crtn = CSSMERR_TP_CERT_REVOKED;
-                                       break;
-                       }
-                       if(!cert.addStatusCode(crtn)) {
-                               crtn = CSSM_OK;
-                       }
-                       processed = true;
-                       break;
-               case CS_Unknown:
-                       /* not an error, no per-cert status, nothing here */
-                       tpOcspDebug("tpApplySingleResp: CS_Unknown for cert %u", dex);
-                       break;
-               default:
-                       tpOcspDebug("tpApplySingleResp: BAD certStatus (%d) for cert %u",
-                                       (int)certStatus, dex);
-                       if(cert.addStatusCode(CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED)) {
-                               crtn = CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED;
-                       }
-                       break;
-       }
-       return crtn;
-}
-
-/*
- * An exceptional case: synchronously flush the OCSPD cache and send a new
- * resquest for just this one cert.
- */
-static OCSPResponse *tpOcspFlushAndReFetch(
-       TPVerifyContext         &vfyCtx,
-       SecNssCoder                     &coder,
-       TPCertInfo                      &subject,
-       TPCertInfo                      &issuer,
-       OCSPClientCertID        &certID)
-{
-       const CSSM_DATA *derCertID = certID.encode();
-       CSSM_RETURN crtn;
-
-       crtn = ocspdCacheFlush(*derCertID);
-       if(crtn) {
-               #ifndef NDEBUG
-               cssmPerror("ocspdCacheFlush", crtn);
-               #endif
-               return NULL;
-       }
-
-       /* Cook up an OCSPDRequests, one request, just for this */
-       /* send it to ocsdp */
-       /* munge reply into an OCSPRsponse and return it */
-       tpOcspDebug("pOcspFlushAndReFetch: Code on demand");
-       return NULL;
-}
-
-class PendingRequest
-{
-public:
-       PendingRequest(
-               TPCertInfo &subject,
-               TPCertInfo &issuer,
-               OCSPClientCertID &cid,
-               CSSM_DATA **u,
-               unsigned dex);
-       ~PendingRequest()       {}
-
-       TPCertInfo                      &subject;
-       TPCertInfo                      &issuer;
-       OCSPClientCertID        &certID;        // owned by caller
-       CSSM_DATA                       **urls;         // owner-managed array of URLs obtained from subject's
-                                                                       // AuthorityInfoAccess.id-ad-ocsp.
-       CSSM_DATA                       nonce;          // owner-managed copy of this requests' nonce, if it
-                                                                       //   has one
-       unsigned                        dex;            // in inputCerts, for debug
-       bool                            processed;
-};
-
-PendingRequest::PendingRequest(
-               TPCertInfo &subj,
-               TPCertInfo &iss,
-               OCSPClientCertID &cid,
-               CSSM_DATA **u,
-               unsigned dx)
-               : subject(subj), issuer(iss), certID(cid),
-                 urls(u), dex(dx), processed(false)
-{
-       nonce.Data = NULL;
-       nonce.Length = 0;
-}
-
-#pragma mark ---- public API ----
-
-CSSM_RETURN tpVerifyCertGroupWithOCSP(
-       TPVerifyContext &vfyCtx,
-       TPCertGroup     &certGroup)             // to be verified
-{
-       assert(vfyCtx.clHand != 0);
-       assert(vfyCtx.policy == kRevokeOcsp);
-
-       CSSM_RETURN ourRtn = CSSM_OK;
-       OcspRespStatus respStat;
-       SecNssCoder coder;
-       CSSM_RETURN crtn;
-       SecAsn1OCSPDRequests ocspdReqs;
-       SecAsn1OCSPReplies ocspdReplies;
-       unsigned numRequests = 0;                       // in ocspdReqs
-       CSSM_DATA derOcspdRequests = {0, NULL};
-       CSSM_DATA derOcspdReplies = {0, NULL};
-       uint8 version = OCSPD_REQUEST_VERS;
-       unsigned numReplies;
-       unsigned numCerts = certGroup.numCerts();
-       if(numCerts <= 1) {
-               /* Can't verify without an issuer; we're done */
-               return CSSM_OK;
-       }
-       numCerts--;
-
-       /* gather options or their defaults */
-       CSSM_APPLE_TP_OCSP_OPT_FLAGS optFlags = 0;
-       const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
-       CSSM_DATA_PTR localResponder = NULL;
-       CSSM_DATA_PTR localResponderCert = NULL;
-       bool cacheReadDisable = false;
-       bool cacheWriteDisable = false;
-       bool genNonce = false;                  // in outgoing request
-       bool requireRespNonce = false;  // in incoming response
-       PRErrorCode prtn;
-
-       if(ocspOpts != NULL) {
-               optFlags = vfyCtx.ocspOpts->Flags;
-               localResponder = ocspOpts->LocalResponder;
-               localResponderCert = ocspOpts->LocalResponderCert;
-       }
-       if(optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) {
-               cacheReadDisable = true;
-       }
-       if(optFlags & CSSM_TP_ACTION_OCSP_CACHE_WRITE_DISABLE) {
-               cacheWriteDisable = true;
-       }
-       if(optFlags & CSSM_TP_OCSP_GEN_NONCE) {
-               genNonce = true;
-       }
-       if(optFlags & CSSM_TP_OCSP_REQUIRE_RESP_NONCE) {
-               requireRespNonce = true;
-       }
-       if(requireRespNonce & !genNonce) {
-               /* no can do */
-               tpErrorLog("tpVerifyCertGroupWithOCSP: requireRespNonce, !genNonce\n");
-               return CSSMERR_TP_INVALID_REQUEST_INPUTS;
-       }
-
-       tpOcspDebug("tpVerifyCertGroupWithOCSP numCerts %u optFlags 0x%lx",
-               numCerts, (unsigned long)optFlags);
-
-       /*
-        * create list of pendingRequests parallel to certGroup
-        */
-       PendingRequest **pending = coder.mallocn<PendingRequest *>(numCerts);
-       memset(pending, 0, (numCerts * sizeof(PendingRequest *)));
-
-       for(unsigned dex=0; dex<numCerts; dex++) {
-               OCSPClientCertID *certID = NULL;
-               TPCertInfo *subject = certGroup.certAtIndex(dex);
-
-               if(subject->trustSettingsFound()) {
-                       /* functionally equivalent to root - we're done */
-                       tpOcspDebug("...tpVerifyCertGroupWithOCSP: terminate per user trust at %u",
-                               (unsigned)dex);
-                       goto postOcspd;
-               }
-               TPCertInfo *issuer = certGroup.certAtIndex(dex + 1);
-               crtn = tpOcspGetCertId(*subject, *issuer, certID);
-               if(crtn) {
-                       tpErrorLog("tpVerifyCertGroupWithOCSP: error extracting cert fields; "
-                               "aborting\n");
-                       goto errOut;
-               }
-
-               /*
-                * We use the URLs in the subject cert's AuthorityInfoAccess extension
-                * for two things - mainly to get the URL(s) for actual OCSP transactions,
-                * but also for CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT processing.
-                * So, we do the per-cert processing to get them right now even if we
-                * wind up using a local responder or getting verification from cache.
-                */
-               CSSM_DATA **urls = tpOcspUrlsFromCert(*subject, coder);
-               pending[dex] = new PendingRequest(*subject, *issuer, *certID, urls, dex);
-       }
-       /* subsequent errors to errOut: */
-
-       /*
-        * Create empty SecAsn1OCSPDRequests big enough for all certs
-        */
-       ocspdReqs.requests = coder.mallocn<SecAsn1OCSPDRequest *>(numCerts + 1);
-       memset(ocspdReqs.requests, 0, (numCerts + 1) * sizeof(SecAsn1OCSPDRequest *));
-       ocspdReqs.version.Data = &version;
-       ocspdReqs.version.Length = 1;
-
-       /*
-        * For each cert, either obtain a cached OCSPResponse, or create
-        * a request to get one.
-        *
-        * NOTE: in-core cache reads (via tpOcspCacheLookup() do NOT involve a
-        * nonce check, no matter what the app says. If nonce checking is required by the
-        * app, responses don't get added to cache if the nonce doesn't match, but once
-        * a response is validated and added to cache it's fair game for that task.
-        */
-       for(unsigned dex=0; dex<numCerts; dex++) {
-               PendingRequest *pendReq = pending[dex];
-               OCSPSingleResponse *singleResp = NULL;
-               if(!cacheReadDisable) {
-                       singleResp = tpOcspCacheLookup(pendReq->certID, localResponder);
-               }
-               if(singleResp) {
-                       tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache hit (1) dex %u",
-                               (unsigned)dex);
-                       crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags,
-                               vfyCtx.verifyTime, pendReq->processed);
-                       delete singleResp;
-                       if(pendReq->processed) {
-                               /* definitely done with this cert one way or the other */
-                               if(crtn && (ourRtn == CSSM_OK)) {
-                                       /* real cert error: first error encountered; we'll keep going */
-                                       ourRtn = crtn;
-                               }
-                               continue;
-                       }
-                       if(crtn) {
-                               /*
-                                * This indicates a bad cached response. Well that's kinda weird, let's
-                                * just flush this out and try a normal transaction.
-                                */
-                               tpOcspCacheFlush(pendReq->certID);
-                       }
-               }
-
-               /*
-                * Prepare a request for ocspd
-                */
-               SecAsn1OCSPDRequest *ocspdReq = tpGenOcspdReq(vfyCtx, coder,
-                       pendReq->subject, pendReq->issuer, pendReq->certID,
-                       const_cast<const CSSM_DATA **>(pendReq->urls),
-                       pendReq->nonce);
-               if(ocspdReq == NULL) {
-                       /* tpGenOcspdReq determined there was no route to OCSP responder */
-                       tpOcspDebug("tpVerifyCertGroupWithOCSP: no OCSP possible for cert %u", dex);
-                       continue;
-               }
-               ocspdReqs.requests[numRequests++] = ocspdReq;
-       }
-       if(numRequests == 0) {
-               /* no candidates for OCSP: almost done */
-               goto postOcspd;
-       }
-
-       /* ship requests off to ocspd, get ocspReplies back */
-       if(coder.encodeItem(&ocspdReqs, kSecAsn1OCSPDRequestsTemplate, derOcspdRequests)) {
-               tpErrorLog("tpVerifyCertGroupWithOCSP: error encoding ocspdReqs\n");
-               ourRtn = CSSMERR_TP_INTERNAL_ERROR;
-               goto errOut;
-       }
-       crtn = ocspdFetch(vfyCtx.alloc, derOcspdRequests, derOcspdReplies);
-       if(crtn) {
-               tpErrorLog("tpVerifyCertGroupWithOCSP: error during ocspd RPC\n");
-               #ifndef NDEBUG
-               cssmPerror("ocspdFetch", crtn);
-               #endif
-               /* But this is not necessarily fatal...update per-cert status and check
-                * caller requirements below */
-               goto postOcspd;
-       }
-       memset(&ocspdReplies, 0, sizeof(ocspdReplies));
-       prtn = coder.decodeItem(derOcspdReplies, kSecAsn1OCSPDRepliesTemplate,
-               &ocspdReplies);
-       /* we're done with this, mallocd in ocspdFetch() */
-       vfyCtx.alloc.free(derOcspdReplies.Data);
-       if(prtn) {
-               /*
-                * This can happen when an OCSP server provides bad data...we cannot
-                * determine which cert is associated with this bad response;
-                * just flag it with the first one and proceed to the loop that
-                * handles CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT.
-                */
-               tpErrorLog("tpVerifyCertGroupWithOCSP: error decoding ocspd reply\n");
-               pending[0]->subject.addStatusCode(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
-               goto postOcspd;
-       }
-       if((ocspdReplies.version.Length != 1) ||
-          (ocspdReplies.version.Data[0] != OCSPD_REPLY_VERS)) {
-               tpErrorLog("tpVerifyCertGroupWithOCSP: ocspd reply version mismatch\n");
-               if(ourRtn == CSSM_OK) {
-                       ourRtn = CSSMERR_TP_INTERNAL_ERROR;     // maybe something better?
-               }
-               goto errOut;
-       }
-
-       /* process each reply */
-       numReplies = ocspdArraySize((const void **)ocspdReplies.replies);
-       for(unsigned dex=0; dex<numReplies; dex++) {
-               SecAsn1OCSPDReply *reply = ocspdReplies.replies[dex];
-
-               /* Cook up our version of an OCSPResponse from the encoded data */
-               OCSPResponse *ocspResp = NULL;
-               try {
-                       ocspResp = new OCSPResponse(reply->ocspResp, TP_OCSP_CACHE_TTL);
-               }
-               catch(...) {
-                       tpErrorLog("tpVerifyCertGroupWithOCSP: error decoding ocsp response\n");
-                       /* what the heck, keep going */
-                       continue;
-               }
-
-               /*
-                * Find matching subject cert if possible (it's technically optional for
-                * verification of the response in some cases, e.g., local responder).
-                */
-               PendingRequest *pendReq = NULL;                         // fully qualified
-               PendingRequest *reqWithIdMatch = NULL;          // CertID match only, not nonce
-               for(unsigned pdex=0; pdex<numCerts; pdex++) {
-
-                       /* first check ID match; that is required no matter what */
-                       if((pending[pdex])->certID.compareToExist(reply->certID)) {
-                               reqWithIdMatch = pending[pdex];
-                       }
-                       if(reqWithIdMatch == NULL) {
-                               continue;
-                       }
-                       if(!genNonce) {
-                               /* that's good enough */
-                               pendReq = reqWithIdMatch;
-                               tpOcspDebug("OCSP process reply: CertID match, no nonce");
-                               break;
-                       }
-                       if(tpCompareCssmData(&reqWithIdMatch->nonce, ocspResp->nonce())) {
-                               tpOcspDebug("OCSP process reply: nonce MATCH");
-                               pendReq = reqWithIdMatch;
-                               break;
-                       }
-
-                       /*
-                        * In this case we keep going; if we never find a match, then we can
-                        * use reqWithIdMatch if !requireRespNonce.
-                        */
-                       tpOcspDebug("OCSP process reply: certID match, nonce MISMATCH");
-               }
-               if(pendReq == NULL) {
-                       if(requireRespNonce) {
-                               tpOcspDebug("OCSP process reply: tossing out response due to "
-                                               "requireRespNonce");
-                               delete ocspResp;
-                               if(ourRtn == CSSM_OK) {
-                                       ourRtn = CSSMERR_APPLETP_OCSP_NONCE_MISMATCH;
-                               }
-                               continue;
-                       }
-                       if(reqWithIdMatch != NULL) {
-                               /*
-                                * Nonce mismatch but caller thinks that's OK. Log it and proceed.
-                                */
-                               assert(genNonce);
-                               tpOcspDebug("OCSP process reply: using bad nonce due to !requireRespNonce");
-                               pendReq = reqWithIdMatch;
-                               pendReq->subject.addStatusCode(CSSMERR_APPLETP_OCSP_NONCE_MISMATCH);
-                       }
-               }
-               TPCertInfo *issuer = NULL;
-               if(pendReq != NULL) {
-                       issuer = &pendReq->issuer;
-               }
-
-               /* verify response and either throw out or add to local cache */
-               respStat = tpVerifyOcspResp(vfyCtx, coder, issuer, *ocspResp, crtn);
-               switch(respStat) {
-                       case ORS_Good:
-                               break;
-                       case ORS_Unknown:
-                               /* not an error but we can't use it */
-                               if((crtn != CSSM_OK) && (pendReq != NULL)) {
-                                       /* pass this info back to caller here... */
-                                       pendReq->subject.addStatusCode(crtn);
-                               }
-                               delete ocspResp;
-                               continue;
-                       case ORS_Bad:
-                               delete ocspResp;
-                               /*
-                                * An exceptional case: synchronously flush the OCSPD cache and send a
-                                * new request for just this one cert.
-                                * FIXME: does this really buy us anything? A DOS attacker who managed
-                                * to get this bogus response into our cache is likely to be able
-                                * to do it again and again.
-                                */
-                               tpOcspDebug("tpVerifyCertGroupWithOCSP: flush/refetch for cert %u", dex);
-                               ocspResp = tpOcspFlushAndReFetch(vfyCtx, coder, pendReq->subject,
-                                       pendReq->issuer, pendReq->certID);
-                               if(ocspResp == NULL) {
-                                       tpErrorLog("tpVerifyCertGroupWithOCSP: error on flush/refetch\n");
-                                       ourRtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
-                                       goto errOut;
-                               }
-                               respStat = tpVerifyOcspResp(vfyCtx, coder, issuer, *ocspResp, crtn);
-                               if(respStat != ORS_Good) {
-                                       tpErrorLog("tpVerifyCertGroupWithOCSP: verify error after "
-                                                       "flush/refetch\n");
-                                       if((crtn != CSSM_OK) && (pendReq != NULL)) {
-                                               /* pass this info back to caller here... */
-                                               if(pendReq->subject.addStatusCode(crtn)) {
-                                                       ourRtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
-                                               }
-                                       }
-                                       else {
-                                               ourRtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
-                                       }
-                                       goto errOut;
-                               }
-                               /* Voila! Recovery. Proceed. */
-                               tpOcspDebug("tpVerifyCertGroupWithOCSP: refetch for cert %u SUCCEEDED",
-                                               dex);
-                               break;
-               } /* switch response status */
-
-               if(!cacheWriteDisable) {
-                       tpOcspCacheAdd(reply->ocspResp, localResponder);
-               }
-
-               /* attempt to apply to pendReq */
-               if(pendReq != NULL) {
-                       OCSPSingleResponse *singleResp =
-                               ocspResp->singleResponseFor(pendReq->certID);
-                       if(singleResp) {
-                               crtn = tpApplySingleResp(*singleResp, pendReq->subject, pendReq->dex,
-                                       optFlags, vfyCtx.verifyTime, pendReq->processed);
-                               if(crtn && (ourRtn == CSSM_OK)) {
-                                       ourRtn = crtn;
-                               }
-                               delete singleResp;
-                       }
-               }       /* a reply which matches a pending request */
-
-               /*
-                * Done with this - note local OCSP response cache doesn't store this
-                * object; it stores an encoded copy.
-                */
-               delete ocspResp;
-       }       /* for each reply */
-
-postOcspd:
-
-       /*
-        * Now process each cert which hasn't had an OCSP response applied to it.
-        * This can happen if we get back replies which are not strictly in 1-1 sync with
-        * our requests but which nevertheless contain valid info for more than one
-        * cert each.
-        */
-       for(unsigned dex=0; dex<numCerts; dex++) {
-               PendingRequest *pendReq = pending[dex];
-               if(pendReq == NULL) {
-                       /* i.e. terminated due to user trust */
-                       tpOcspDebug("...tpVerifyCertGroupWithOCSP: NULL pendReq dex %u",
-                                       (unsigned)dex);
-                       break;
-               }
-               if(pendReq->processed) {
-                       continue;
-               }
-               OCSPSingleResponse *singleResp = NULL;
-               /* Note this corner case will not work if cache is disabled. */
-               if(!cacheReadDisable) {
-                       singleResp = tpOcspCacheLookup(pendReq->certID, localResponder);
-               }
-               if(singleResp) {
-                       tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache (2) hit dex %u",
-                                       (unsigned)dex);
-                       crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags,
-                                       vfyCtx.verifyTime, pendReq->processed);
-                       if(crtn) {
-                               if(ourRtn == CSSM_OK) {
-                                       ourRtn = crtn;
-                               }
-                       }
-                       delete singleResp;
-               }
-               if(!pendReq->processed) {
-                       /* Couldn't perform OCSP for this cert. */
-                       tpOcspDebug("tpVerifyCertGroupWithOCSP: OCSP_UNAVAILABLE for cert %u", dex);
-                       bool required = false;
-                       CSSM_RETURN responseStatus = CSSM_OK;
-                       if(pendReq->subject.numStatusCodes() > 0) {
-                               /*
-                                * Check whether we got a response for this cert, but it was rejected
-                                * due to being improperly signed. That should result in an actual
-                                * error, even under Best Attempt processing. (10743149)
-                                */
-                               if(pendReq->subject.hasStatusCode(CSSMERR_APPLETP_OCSP_BAD_RESPONSE)) {
-//                                     responseStatus = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;  <rdar://problem/10831157>
-                               } else if(pendReq->subject.hasStatusCode(CSSMERR_APPLETP_OCSP_SIG_ERROR)) {
-                                       responseStatus = CSSMERR_APPLETP_OCSP_SIG_ERROR;
-                               } else if(pendReq->subject.hasStatusCode(CSSMERR_APPLETP_OCSP_NO_SIGNER)) {
-                                       responseStatus = CSSMERR_APPLETP_OCSP_NO_SIGNER;
-                               }
-                       }
-                       if(responseStatus == CSSM_OK) {
-                               /* no response available (as opposed to getting an invalid response) */
-                               pendReq->subject.addStatusCode(CSSMERR_APPLETP_OCSP_UNAVAILABLE);
-                       }
-                       if(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT) {
-                               /* every cert needs OCSP */
-                               tpOcspDebug("tpVerifyCertGroupWithOCSP: response required for all certs, missing for cert %u", dex);
-                               required = true;
-                       }
-                       else if(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT) {
-                               /* this cert needs OCSP if it had an AIA extension with an OCSP URI */
-                               if(pendReq->urls) {
-                                       tpOcspDebug("tpVerifyCertGroupWithOCSP: OCSP URI present but no valid response for cert %u", dex);
-                                       required = true;
-                               }
-                       }
-                       if( (required && pendReq->subject.isStatusFatal(CSSMERR_APPLETP_OCSP_UNAVAILABLE)) ||
-                               (responseStatus != CSSM_OK && pendReq->subject.isStatusFatal(responseStatus)) ) {
-                               /* fatal error, but we keep on processing */
-                               if(ourRtn == CSSM_OK) {
-                                       ourRtn = (responseStatus != CSSM_OK) ? responseStatus : CSSMERR_APPLETP_OCSP_UNAVAILABLE;
-                               }
-                       }
-               }
-       }
-errOut:
-       for(unsigned dex=0; dex<numCerts; dex++) {
-               PendingRequest *pendReq = pending[dex];
-               if(pendReq == NULL) {
-                       /* i.e. terminated due to user trust */
-                       break;
-               }
-               delete &pendReq->certID;
-               delete pendReq;
-       }
-       return ourRtn;
-}