Skip to main content
RunBook Academy

LinuxLXXI · TLS and PKITroubleshooting

Certificate revocation in practice - CRL, OCSP and short lifetimes

Advanced⏱ ~16 minopenssl

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

Not yet marked complete on this device.

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.

CRLOCSP
SizeWhole list, grows with revocationsOne response
FreshnessUp to nextUpdate staleCurrent
Client latencyOne fetch, then cachedA round trip per certificate, unless stapled
PrivacyReveals nothingThe responder learns which sites you visit
Offline behaviourWorks from cacheFails
Failure modeHard-fail if expiredUsually 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

  1. Q1. Why does soft-fail OCSP provide little protection against a stolen private key?

  2. Q2. What problem does OCSP stapling solve that plain OCSP does not?

  3. Q3. Which of these must be true for revocation to work at all for a private CA? Select all that apply.

  4. 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.

  5. Q5. A private key is compromised. What order of operations actually removes the attacker capability?

Passing score: 75%. Answers are checked in this browser.