LinuxLXXI · TLS and PKITroubleshooting
Certificate revocation in practice - CRL, OCSP and short lifetimes
What you'll learn
- Describe how a CRL and an OCSP check each work and what they cost
- Explain why soft-fail revocation checking provides little protection
- Configure and verify OCSP stapling
- Plan revocation for a private CA, including the extensions that must exist at issuance
- Choose certificate lifetime as the primary revocation control
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-11
The renewal lesson listed revocation as the last step of the certificate lifecycle: if a private key is compromised, revoke the certificate. That is the correct instruction and it hides a difficult truth, which is that revocation on the public web barely works, and the reasons it does not work are the reasons the whole industry moved to short certificate lifetimes instead.
For a private PKI, revocation can be made to work properly. This lesson covers both cases and the trap that makes the private case impossible to retrofit.
The two mechanisms
A CRL is a signed list of revoked serial numbers, published
by the CA at a URL named in each certificate it issues. Clients
fetch it, cache it until nextUpdate, and reject any
certificate whose serial appears.
# Read a CRL
openssl crl -in crl.pem -noout -text | head -20
# Verify the CRL is genuinely from the CA
openssl crl -in crl.pem -noout -CAfile ca.crt
# Verify a certificate against it
openssl verify -CAfile ca.crt -CRLfile crl.pem -crl_check server.crt
A CRL is simple, cacheable and offline-friendly. Its problem is size: a busy CA revokes a lot of certificates, the list only grows until entries expire out of it, and every client fetches the whole thing.
OCSP replaces the list with a query. The client asks a
responder about one serial number and gets a signed
good, revoked or unknown.
# Where would a client ask?
openssl x509 -in server.crt -noout -ocsp_uri
# Ask, with the issuer supplied so the request can be built
openssl ocsp -issuer intermediate.crt -cert server.crt \
-url http://ocsp.example.com -CAfile ca-chain.crt -resp_text
Small responses, always current. Its problems are latency, privacy, and availability.
| CRL | OCSP | |
|---|---|---|
| Size | Whole list, grows with revocations | One response |
| Freshness | Up to nextUpdate stale | Current |
| Client latency | One fetch, then cached | A round trip per certificate, unless stapled |
| Privacy | Reveals nothing | The responder learns which sites you visit |
| Offline behaviour | Works from cache | Fails |
| Failure mode | Hard-fail if expired | Usually soft-fail |
Soft-fail is the problem
This is the point that makes the rest of the topic make sense.
If a client treats an unreachable OCSP responder as a hard failure, then a CA outage takes down every site the CA issued for. No browser vendor was willing to accept that, so clients soft-fail: if the check cannot be completed, the connection proceeds.
Now consider the attacker the check exists to stop. They hold a stolen private key and are already in a position to intercept the connection - otherwise the certificate is of no use to them. An attacker in that position can also drop the OCSP request. The client soft-fails and accepts the revoked certificate.
The check works against an attacker who cannot interfere with the network, and fails against one who can. The second group is the entire threat model.
OCSP stapling
Stapling fixes the latency and privacy problems, and part of the reliability one, by moving the query to the server.
The server periodically asks the OCSP responder about its own certificate and attaches the signed response to the handshake. The client gets a fresh, CA-signed status with no extra round trip and no third party learning where it is connecting.
HOST=service.example.com
echo | openssl s_client -connect "$HOST:443" -servername "$HOST" -status 2>&1 |
sed -n '/OCSP response/,/Next Update/p'
OCSP response:
======================================
OCSP Response Status: successful (0x0)
Cert Status: good
This Update: Aug 10 06:00:00 2026 GMT
Next Update: Aug 17 06:00:00 2026 GMT
OCSP response: no response sent means stapling is not
working, which is the normal state of a server where somebody
enabled it without a working resolver.
# nginx
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/certs/ca-chain.crt;
resolver 192.0.2.53 valid=300s;
resolver is the line people miss: nginx needs to resolve the
responder hostname itself, and without it stapling silently
does nothing. ssl_stapling_verify on makes nginx check the
responder signature before serving the response.
Stapling still soft-fails by default, because a client cannot tell whether a server that sent no staple is misconfigured or malicious. The must-staple extension closes that: a certificate carrying it tells clients to refuse the connection if no staple is present. It is a genuine hard-fail and it is rarely used, because a stapling outage then becomes a site outage.
Revocation for a private CA
Everything above describes the public web, where you control neither the clients nor the failure policy. Internally you control both, and revocation becomes a real control:
- You can hard-fail. Your clients, your policy.
- Your CRL is small, because you issue thousands rather than millions.
- Client certificates are the case where revocation genuinely matters: a departed contractor, a decommissioned host, a leaked service credential.
The workflow with openssl ca:
# Revoke, with a reason recorded in the index
openssl ca -config ca.conf -revoke certs/web-03.crt \
-crl_reason keyCompromise
# Regenerate the CRL with an explicit next-update window
openssl ca -config ca.conf -gencrl -crldays 7 -out crl/ca.crl.pem
# Publish it where the certificates say it lives, then verify
openssl crl -in crl/ca.crl.pem -noout -text | head -15
On the verifying side:
openssl verify -CAfile ca.crt -CRLfile crl/ca.crl.pem \
-crl_check -verify_hostname web-03.example.com web-03.crt
Server-side enforcement, for a service that authenticates clients:
# nginx client certificate verification with a CRL
ssl_client_certificate /etc/ssl/certs/internal-ca.crt;
ssl_crl /etc/ssl/crl/internal-ca.crl;
ssl_verify_client on;
ssl_verify_depth 2;
Short lifetimes are the mechanism that works
Follow the reasoning to its end and the conclusion is that the reliable way to stop a certificate being usable is for it to expire.
A 24-hour certificate has a worst-case exposure of 24 hours after a key compromise, with no CRL, no responder, no client support and no soft-fail hole. The control is the issuance process: stop reissuing to a compromised identity and the problem resolves itself within one lifetime.
This is why the public CA ecosystem has been shortening lifetimes for a decade, why ACME automation became mandatory in practice, and why internal PKI built on short-lived certificates issued by an agent has largely replaced the long-lived certificate with a revocation story.
The trade-offs to be honest about:
- Renewal must be fully automated. A 24-hour certificate with a manual renewal step is a daily outage.
- The issuing CA becomes an availability-critical dependency. Certificate lifetime is your maximum tolerable CA outage: if issuance is down longer than that, services stop trusting each other. This is the scaling constraint the fleet part covers.
- Monitoring shifts from “days until expiry” to “time since last successful renewal”, which is a better signal anyway because it detects the failure rather than its consequence.
Knowledge check
Knowledge check · 5 questions
Q1. Why does soft-fail OCSP provide little protection against a stolen private key?
Q2. What problem does OCSP stapling solve that plain OCSP does not?
Q3. Which of these must be true for revocation to work at all for a private CA? Select all that apply.
Q4. A CRL whose nextUpdate has passed is treated as invalid, so a client doing -crl_check rejects the certificate rather than assuming there are no revocations.
Q5. A private key is compromised. What order of operations actually removes the attacker capability?
Passing score: 75%. Answers are checked in this browser.