/* * Perform CRL verification on a cert group. * The cert group has already passed basic issuer/subject and signature * verification. The status of the incoming CRLs is completely unknown. * * FIXME - No mechanism to get CRLs from net with non-NULL verifyTime. * How are we supposed to get the CRL which was valid at a specified * time in the past? */ CSSM_RETURN tpVerifyCertGroupWithCrls( TPVerifyContext &vfyCtx, TPCertGroup &certGroup) // to be verified { CSSM_RETURN crtn; CSSM_RETURN ourRtn = CSSM_OK; assert(vfyCtx.clHand != 0); assert(vfyCtx.policy == kRevokeCrlBasic); tpCrlDebug("tpVerifyCertGroupWithCrls numCerts %u", certGroup.numCerts()); CSSM_DATA issuers = { 0, NULL }; CSSM_APPLE_TP_CRL_OPT_FLAGS optFlags = 0; if(vfyCtx.crlOpts != NULL) { optFlags = vfyCtx.crlOpts->CrlFlags; } /* found & verified CRLs we need to release */ TPCrlGroup foundCrls(vfyCtx.alloc, TGO_Caller); try { unsigned certDex; TPCrlInfo *crl = NULL; /* get issuers as PEM-encoded data blob; we need to release */ certGroup.encodeIssuers(issuers); /* main loop, verify each cert */ for(certDex=0; certDex<certGroup.numCerts(); certDex++) { TPCertInfo *cert = certGroup.certAtIndex(certDex); tpCrlDebug("...verifying %s cert %u", cert->isAnchor() ? "anchor " : "", cert->index()); if(cert->isSelfSigned() || cert->trustSettingsFound()) { /* CRL meaningless for a root or trusted cert */ continue; } if(cert->revokeCheckComplete()) { /* Another revocation policy claimed that this cert is good to go */ tpCrlDebug(" ...cert at index %u revokeCheckComplete; skipping", cert->index()); continue; } crl = NULL; do { /* first, see if we have CRL status available for this cert */ crtn = tpGetCrlStatusForCert(*cert, issuers); tpCrlDebug("...tpGetCrlStatusForCert: %u", crtn); if(crtn == CSSM_OK) { tpCrlDebug("tpVerifyCertGroupWithCrls: cert %u verified by local .crl\n", cert->index()); cert->revokeCheckGood(true); if(optFlags & CSSM_TP_ACTION_CRL_SUFFICIENT) { /* no more revocation checking necessary for this cert */ cert->revokeCheckComplete(true); } break; } if(crtn == CSSMERR_TP_CERT_REVOKED) { tpCrlDebug("tpVerifyCertGroupWithCrls: cert %u revoked in local .crl\n", cert->index()); cert->addStatusCode(crtn); break; } if(crtn == CSSMERR_APPLETP_NETWORK_FAILURE) { /* crl is being fetched from net, but we don't have it yet */ if((optFlags & CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT) && tpCertHasCrlDistPt(*cert)) { /* crl is required; we don't have it yet, so we fail */ tpCrlDebug(" ...cert %u: REQUIRE_CRL_IF_PRESENT abort", cert->index()); break; } /* "Best Attempt" case, so give the cert a pass for now */ tpCrlDebug(" ...cert %u: no CRL; tolerating", cert->index()); crtn = CSSM_OK; break; } /* all other CRL status results: try to fetch the CRL */ /* find a CRL for this cert by hook or crook */ crtn = tpFindCrlForCert(*cert, crl, vfyCtx); if(crtn) { /* tpFindCrlForCert may have simply caused ocspd to start * downloading a CRL asynchronously; depending on the speed * of the network and the CRL size, this may return 0 bytes * of data with a CSSMERR_APPLETP_NETWORK_FAILURE result. * We won't know the actual revocation result until the * next time we call tpGetCrlStatusForCert after the full * CRL has been downloaded successfully. */ if(optFlags & CSSM_TP_ACTION_REQUIRE_CRL_PER_CERT) { tpCrlDebug(" ...cert %u: REQUIRE_CRL_PER_CERT abort", cert->index()); break; } if((optFlags & CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT) && tpCertHasCrlDistPt(*cert)) { tpCrlDebug(" ...cert %u: REQUIRE_CRL_IF_PRESENT abort", cert->index()); break; } /* * This is the only place where "Best Attempt" tolerates an error */ tpCrlDebug(" ...cert %u: no CRL; tolerating", cert->index()); crtn = CSSM_OK; assert(crl == NULL); break; } /* Keep track; we'll release all when done. */ assert(crl != NULL); foundCrls.appendCrl(*crl); /* revoked? */ crtn = crl->isCertRevoked(*cert, vfyCtx.verifyTime); if(crtn) { break; } tpCrlDebug(" ...cert %u VERIFIED by CRL", cert->index()); cert->revokeCheckGood(true); if(optFlags & CSSM_TP_ACTION_CRL_SUFFICIENT) { /* no more revocation checking necessary for this cert */ cert->revokeCheckComplete(true); } } while(0); /* done processing one cert */ if(crtn) { tpCrlDebug(" ...cert at index %u FAILED crl vfy", cert->index()); if(ourRtn == CSSM_OK) { ourRtn = crtn; } /* continue on to next cert */ } /* error on one cert */ } /* for each cert */ } catch(const CssmError &cerr) { if(ourRtn == CSSM_OK) { ourRtn = cerr.error; } } /* other exceptions fatal */ /* release all found CRLs */ for(unsigned dex=0; dex<foundCrls.numCrls(); dex++) { TPCrlInfo *crl = foundCrls.crlAtIndex(dex); assert(crl != NULL); tpDisposeCrl(*crl, vfyCtx); } /* release issuers */ if(issuers.Data) { free(issuers.Data); } return ourRtn; }