Revocation Validator¶
Checks whether the certificate has been revoked, using the pointers the certificate itself carries: its OCSP responder URL and its CRL distribution points.
Opt-in
revocation is registered but off by default. Enable it with enabled_validators=["revocation"], ENABLED_VALIDATORS=revocation, or certmonitor check -v revocation.
A revoked certificate is otherwise a perfectly healthy one: it chains to a trusted CA, its dates are fine, its hostname matches. Every other validator passes it. This is the one that doesn't.
Try it¶
from certmonitor import CertMonitor
with CertMonitor("example.com", enabled_validators=["revocation"]) as monitor:
result = monitor.validate()["revocation"]
print(result["status"], result["revocation_status"], result["source"])
A certificate that no source lists as revoked passes:
{
"is_valid": true,
"status": "pass",
"revocation_status": "good",
"source": "ocsp",
"signature_verified": true,
"this_update": "2026-09-06T00:00:00+00:00",
"next_update": "2026-09-13T00:00:00+00:00",
"revocation_time": null,
"revocation_reason": null,
"methods": {
"ocsp": {"status": "good", "signature_verified": true, "url": "http://ocsp.example", "responder_name": {"commonName": "Example Issuing CA"}}
}
}
A revoked one fails, and says when and why:
{
"is_valid": false,
"status": "fail",
"reason": "The certificate was revoked on 2026-09-01T00:00:00+00:00 (key_compromise) according to OCSP.",
"revocation_status": "revoked",
"source": "ocsp",
"revocation_time": "2026-09-01T00:00:00+00:00",
"revocation_reason": "key_compromise"
}
How the two sources are used¶
Each method in methods is consulted in order, OCSP first by default:
- Only a proven answer decides. The signature question comes before the answer's content, for
revokedas much as forgood(RFC 6960 §3.2). A response that fails verification was tampered with or signed by the wrong party, and acting on its "revoked" would let anyone on the path to the responder raise false alarms and skip a CRL that holds the truth. - A
goodanswer passes only when it is proven. OCSP answers are verified in-house: the response must be signed by the issuing CA, or by a responder certificate that the CA issued for OCSP signing and that is valid today (RFC 6960 §4.2.2.2), using RSA PKCS#1 v1.5 or ECDSA over P-256 or P-384. CRL answers are proven by OpenSSL: the CRL is loaded into a verifying TLS context and its signature, validity window, and the leaf's serial are checked in one extra handshake. Agoodthat cannot be verified, say a response signed with an algorithm CertMonitor does not implement, is reported aswarnwith the reason inverification_error, and the next method is consulted; if the CRL then confirms it, the result is a verifiedpasswithsource: "crl". - A response whose signature was checked and is wrong is no evidence at all, whether it says
goodorrevoked. It is discarded before its content is read, not evenaccept_unverifiedrescues it, the next method is consulted, and if nothing else answers the result isstatus: "error"witherror: "OCSPInvalidSignature". A response that could not be checked is held back instead: an unverifiedgoodis awarn, an unverifiedrevokedis anerrorwitherror: "OCSPUnverifiedRevocation"so it is visible without being treated as proof.methods.ocsp.verificationtells the cases apart:verified,unsupported(could not check), orfailed(checked and wrong). - Nothing usable is an error, never a pass. If every source is unreachable, stale, or answers about the wrong certificate, the result is
status: "error"with each source's problem inreason.
The per-method detail always lands in methods, so you can see what each source said even when the verdict came from the other one.
How verification stays dependency-free
The Python standard library has no primitive for checking an RSA or ECDSA signature, so CertMonitor's Rust extension carries its own: big-integer arithmetic, RSASSA-PKCS1-v1_5, and ECDSA over the two NIST curves CAs actually use for responders. It is verification only, tested against RFC 6979 vectors and against real openssl output. Responses signed with something else (RSA-PSS, Ed25519, other curves) are reported with signature_verified: false and the algorithm named in verification_error. Set accept_unverified=True if you are willing to take such a responder's word.
Arguments¶
| Argument | Type | Default | Meaning |
|---|---|---|---|
methods |
list[str] |
["ocsp", "crl"] |
Sources to consult, in order. Any subset of ocsp and crl. |
accept_unverified |
bool |
False |
Act on an OCSP answer whose signature could not be checked (unsupported algorithm) as if it were verified: good passes, revoked fails. Never applies to a signature that was checked and failed. |
monitor.validate({"revocation": {"methods": ["crl"]}})
monitor.validate({"revocation": {"methods": ["ocsp"], "accept_unverified": True}})
What it costs¶
- OCSP is one small HTTP
POSTto the responder. The request is built from the certificate's serial and its issuer's name and key, so the issuer certificate is needed; it comes from the served chain, or from the certificate'scaIssuerspointer when the server sends only the leaf. Verifying the response takes a few milliseconds of arithmetic. - CRL is one download plus one TLS handshake. CRLs range from a few kilobytes to many megabytes; the download is capped at 16 MiB.
- Both are cached process-wide until their
nextUpdateand never a second longer: the cache reuses signed evidence only while the signer said it was valid. A fleet scan therefore fetches each CA's CRL and each certificate's OCSP answer once per validity window. Setmethods=["crl"]when many hosts share a CA and you want one download for all of them. - Fetches respect the monitor's
timeoutandproxy, including SOCKS5, because they go through the same connection code as everything else.
When it reports unsupported¶
- The certificate carries no OCSP URL and no CRL distribution point. Some private CAs issue certificates like this.
- The monitor was built from a file with
CertMonitor.from_file(). Offline monitors never touch the network, so both methods reportunsupportedthere. - The only pointers are
ldap://URIs, which CertMonitor does not fetch.
Result fields¶
| Field | Meaning |
|---|---|
revocation_status |
good, revoked, or unknown (the source had no record of this certificate). |
source |
The method whose answer produced the verdict, ocsp or crl. |
signature_verified |
Whether that answer's signature was checked. Always true for CRL answers; true for OCSP when the responder's signature verified. methods.ocsp.verification is verified, unsupported, or failed, and verification_error explains anything but verified. |
this_update, next_update |
The answer's validity window, ISO 8601 UTC. |
revocation_time, revocation_reason |
Set when revoked; the reason uses RFC 5280 names such as key_compromise or superseded. |
methods |
Every method consulted, with its own status, URL, timing, and any error. |
See also RootCertificate, which establishes trust in the chain, and the result contract for status and code.