Skip to main content
RunBook Academy

← All runbooks in Secrets, PKI & Certificates

medium risksecurity relevant~45 min

Runbook: Revoke a Certificate

1 · Prerequisites

Confirm every item is in place before any state change.

  • The exact identity of the certificate to be revoked: its serial number and its SHA-256 fingerprint, not just a hostname
  • Authority over the issuing path: an internal CA operator role, or the ACME account that ordered the certificate, or the certificate private key itself
  • A replacement certificate already issued, or the ability to issue one now, because revocation on its own removes nothing from service
  • Knowledge of who consumes this certificate and which of those consumers checks revocation at all
  • For an internal PKI, write access to wherever the CRL is published and the ability to make relying parties fetch it
  • A security incident record if the reason is key compromise, since the reason code becomes a public statement

2 · Pre-checks

Read-only diagnostic commands. If any of these don't match expected output, stop and investigate further.

  • · Pin down which certificate you mean. openssl x509 -in app.crt -noout -subject -issuer -serial -dates and openssl x509 -in app.crt -noout -fingerprint -sha256. A hostname is not an identity: the same name may have three valid certificates from two issuers, and revoking the wrong one is an outage you caused for no security benefit.
  • · Confirm the certificate is still deployed somewhere. Compare the serial on disk with the serial the service is sending on the wire. If they already differ, the certificate you are about to revoke may be out of service, which changes the urgency but not the decision.
  • · Decide what revocation is meant to achieve here. Write the answer down. If the honest answer is that it makes an audit finding go away, say so, and be clear that it does not shorten the window in which the old certificate is accepted by mainstream clients.
  • · Confirm the replacement is ready. For a compromise the replacement must be over a freshly generated key. For a superseded or cessation case a replacement may not be needed at all, but that is a decision, not an omission.
  • · Establish who actually enforces revocation for these relying parties. Browsers largely do not perform online revocation checks by default. A private PKI enforces revocation only if the relying parties are configured to fetch and check a CRL, and someone has to name that configuration.
  • · Check the CRL you are about to extend. openssl crl -in crl.pem -noout -lastupdate -nextupdate shows when it was issued and by when the next one is due. A CRL whose nextUpdate has already passed may be rejected outright, which means your revocation lands nowhere.
  • · Agree the reason code with whoever owns the incident. The reason is durable, visible to relying parties, and in the key compromise case it may prevent the CA from ever signing that public key again, including for you.

3 · Procedure

Execute each step in order. Verify the expected output of a step before moving to the next.

  1. 1Record the certificate identity in the change or incident before touching anything. Serial, SHA-256 fingerprint, subject, issuer, notBefore, notAfter, and the hosts it is installed on. Everything after this refers back to that record, and a revocation with an ambiguous target cannot be audited.
  2. 2Issue and deploy the replacement first. Revocation does not remove a certificate from a server. Until the listener is serving a different certificate, the one you revoked is still being presented to every client that connects, and most of them will accept it.
  3. 3Verify the replacement is genuinely in service from outside the host. Read the serial off the wire, not off the disk. Only when the serial on the wire is the new one has the old certificate stopped being the service's identity.
  4. 4Choose the reason code deliberately. Use key compromise only when key material was or may have been exposed, superseded when the certificate was simply replaced, and cessation of operation when the name is being retired. RFC 5280 defines the enumeration; the operational meaning of each value comes from the CA policy that governs your issuer.
  5. 5Do not plan to use certificate hold on a public certificate. The CA/Browser Forum Baseline Requirements state that the Repository must not include entries indicating that a certificate is suspended. Hold exists in the standard, and it is usable in a private PKI you operate yourself, but it is not a pause button for the Web PKI.
  6. 6Submit the revocation through the path that issued the certificate. For ACME this is the revokeCert request, authorised either by the account that ordered the certificate or by the certificate's own private key. For an internal CA, openssl ca -config ca.cnf -revoke app.crt -crl_reason superseded marks the entry in the CA database.
  7. 7Regenerate and publish the CRL immediately for an internal PKI. openssl ca -config ca.cnf -gencrl -out crl.pem, then copy it to the distribution point named in the certificates. A revocation that lives only in the CA database changes nothing for any relying party.
  8. 8Prove the CRL is fetchable from where relying parties sit. Read the distribution point out of the certificate with openssl x509 -in app.crt -noout -ext crlDistributionPoints, fetch that URL from a client host, and parse it. A distribution point that is unreachable, or that returns HTML, is the same as no revocation at all.
  9. 9Confirm the revoked serial is present in the published CRL. openssl crl -in crl.pem -noout -text lists the revoked serials with their revocation dates. Match the serial from the first step character for character.
  10. 10Verify enforcement against a relying party, not against the CA. openssl verify -crl_check -CAfile root.crt -untrusted srv-ca.crt -CRLfile crl.pem app.crt should now fail for the revoked certificate and still pass for the replacement. If nothing in the estate is configured to check, record that as the finding it is.
  11. 11Update the trust configuration that consumes the CRL. A web server directive, a Java trust store refresh, or a client library cache all have their own reload semantics. Publishing a new CRL that nothing reloads is a common and quiet failure.
  12. 12Record what revocation did not achieve. Name the client populations that will keep accepting the old certificate, and state the date the old certificate expires. That date, not the revocation, is when the exposure genuinely ends for those clients.

4 · Verification

Confirm the procedure actually fixed the problem.

  • The service presents the replacement certificate on the wire, confirmed by reading the serial from a host outside the service.
  • The revoked serial appears in the published CRL, matching the serial recorded in the first procedure step exactly.
  • The CRL is fetchable from the distribution point named inside the certificate, from a network position a relying party actually occupies.
  • A verification run with CRL checking enabled rejects the revoked certificate and accepts the replacement.
  • The relying party that was supposed to enforce revocation has reloaded the new CRL, verified through its own logs or status endpoint rather than by inspecting the file on disk.
  • The incident or change record names the reason code submitted, the revocation timestamp, and the expiry date of the revoked certificate.
  • The certificate inventory no longer lists the revoked certificate as active, so the next expiry alert does not fire against something already withdrawn.

5 · Rollback

If verification fails, undo the procedure in reverse order.

  • Revocation in the Web PKI is not reversible. If the wrong certificate was revoked, the recovery is an emergency reissuance over a new key, not an attempt to withdraw the revocation, and it should be treated as an outage from the moment it is discovered.
  • In a private PKI you operate, a certificate hold entry can be removed with the removeFromCRL reason and a regenerated CRL. This works only because you control every relying party, and only for entries that were placed on hold in the first place.
  • If the replacement fails after the old certificate is revoked, restore service with a newly issued certificate rather than by putting the revoked one back. A revoked certificate that still works is worse than an outage, because it proves publicly that revocation is not enforced.
  • If the CRL publication broke relying parties, for example because a stale or malformed CRL is now being fetched, revert the published CRL to the previous known-good file while you regenerate. Relying parties that hard-fail on a bad CRL will refuse connections that would otherwise have succeeded.
  • If the reason code was wrong, most CAs will not amend it. Record the correction in the incident rather than revoking again with a different reason, and treat the published reason as final.

6 · Escalation

When the runbook isn't enough, contact:

  • · The reason is key compromise: escalate to the security on-call and treat this as an incident, because the certificate is the smallest part of the problem and the key may be in use elsewhere.
  • · The certificate to be revoked is a CA certificate rather than a leaf: stop. Revoking an issuer invalidates every certificate beneath it, and that is a separate procedure with a separate approval.
  • · The CA will not accept the revocation, or the account that ordered the certificate is unavailable: escalate to the PKI owner, who may be able to revoke using the certificate private key instead of the account key.
  • · Relying parties begin failing after the CRL is published: escalate to the service owners of those relying parties, since a hard-failing CRL check turns a security action into an availability incident.
  • · The estate turns out to have no relying party that checks revocation at all: escalate the gap to the platform owner as a finding, and rely on replacement and short lifetimes in the meantime.

Revocation is a statement by the issuer that a certificate should no longer be trusted. It is not an eraser. The certificate file still exists, the server still sends it, and whether any given client notices depends entirely on whether that client asks, and on whether it refuses to proceed when it cannot get an answer. In the public web the honest summary is that most clients do neither.

That is why this procedure puts replacement before revocation. Getting the compromised or superseded certificate out of service is the step that actually changes what an attacker can do. Revocation is the second step: it closes the record, it satisfies the policy obligation, and in a private estate that you control end to end it can genuinely be enforced. Doing it first, or doing it instead, leaves the certificate in production while the paperwork says it is gone.

Read the reason code as a public and durable statement. In the key compromise case some issuers will refuse to sign that public key again for anyone, which is exactly what you want and also exactly what will surprise a colleague who tries to reuse the key next week.

When this runbook applies, and when it does not

It applies when a specific issued certificate must be withdrawn: its key was exposed, it was issued with the wrong contents, the name is being decommissioned, or a policy requires that a replaced certificate is formally revoked rather than left to expire quietly.

It does not apply when:

  • You have not replaced the certificate yet. Revocation removes nothing from a running server. Do the replacement, verify it on the wire, and come back. Revoking first buys no security and guarantees a period where the record and the reality disagree.
  • The certificate is a CA certificate. Revoking an issuer invalidates everything beneath it at once. That is an intermediate or root transition with its own runbook, its own approval and its own rehearsal.
  • You want to suspend a public certificate temporarily. The Baseline Requirements state that the Repository must not include entries indicating that a certificate is suspended. There is no pause button in the Web PKI.
  • The certificate expires within days and nothing enforces revocation in your estate. Say so honestly, replace it, and spend the effort on shortening lifetimes instead.

Blast radius

ActionReversible?What it costs if wrong
Reading the serial and fingerprintYesNothing
Issuing and deploying the replacementYesA reload, and a rollback path if it fails
Choosing a reason codeNoThe reason is published and generally cannot be amended
Revoking a leaf certificateNo, outside a private holdAn outage for every relying party that does check, until a replacement is issued
Revoking the wrong certificateNoA live service loses its identity with no way back except emergency reissuance
Publishing a malformed or stale CRLOnly if you kept the previous fileRelying parties that hard-fail refuse connections that were previously fine
Revoking a CA certificateNoEvery certificate beneath it fails at once

Step 1 - Pin down exactly which certificate you mean

Read-only / SafeCaptured in the course lab: the identity fields that go into the record
$ openssl x509 -in app.crt -noout -subject -issuer -serial -dates
subject=CN=app.lab.example
issuer=O=RunBook Academy Lab, CN=RunBook Lab Server Issuing CA
serial=21173B360D80F4A69A91164F1067F4F81A1B1B6E
notBefore=Aug 26 21:19:00 2026 GMT
notAfter=Nov 24 21:19:00 2026 GMT

Copy those five lines into the incident. Add the SHA-256 fingerprint from openssl x509 -in app.crt -noout -fingerprint -sha256. Every later step compares against this record, and a revocation whose target is described only as the certificate for that hostname cannot be reviewed afterwards by anyone who was not in the room.

Step 2 - Replace and redeploy before you revoke

HOST=app.lab.example

# What is the service sending right now?
openssl s_client -connect "$HOST:443" -servername "$HOST" </dev/null 2>/dev/null | openssl x509 -noout -serial

# Deploy the replacement, then read the wire again. The serial must change.
systemctl reload nginx
openssl s_client -connect "$HOST:443" -servername "$HOST" </dev/null 2>/dev/null | openssl x509 -noout -serial

If the reason is key compromise, the replacement must be issued over a freshly generated key. Reissuing over the same key produces a new certificate that the person holding the stolen key can present just as well as you can, and revoking the old one accomplishes nothing against them.

Step 3 - Choose a reason you can defend

SituationReason to submitWhat it commits you to
Private key exposed, or possibly exposedkeyCompromiseSome issuers permanently blocklist that public key
Certificate replaced during routine rotationsupersededNothing beyond the record
Hostname or service being decommissionedcessationOfOperationThe name should not be reissued casually
Contents wrong, for example a missing namesupersededReissue is expected immediately
You genuinely do not knowunspecifiedLittle, which is also the problem

RFC 5280 defines the list of values. What each value obliges the CA and the subscriber to do comes from the policy that governs your issuer, so read that policy rather than assuming. Do not confuse the reason codes carried on a CRL entry with the reason flags that appear in a distribution point extension: they are different fields with different meanings and only one of them describes your certificate.

Step 4 - Submit the revocation

# Internal CA: mark the entry in the CA database.
openssl ca -config /etc/ssl/ca/ca.cnf -revoke /etc/ssl/certs/app.crt \
  -crl_reason superseded

# ACME client: revoke through the account that ordered it,
# or through the certificate's own private key.
certbot revoke \
  --cert-path /etc/letsencrypt/live/web.lab.example/cert.pem \
  --reason superseded

The ACME protocol allows a revocation request to be signed either by the account key that ordered the certificate or by the private key inside the certificate itself. That second path matters when the ordering account is gone, and it is also why a stolen private key lets a third party revoke your certificate. Treat availability of revocation as another reason to keep the key private.

Step 5 - Publish the CRL and prove it is fetchable

openssl ca -config /etc/ssl/ca/ca.cnf -gencrl -out /srv/pki/crl.pem
openssl crl -in /srv/pki/crl.pem -noout -lastupdate -nextupdate
openssl x509 -in /etc/ssl/certs/app.crt -noout -ext crlDistributionPoints

# From a relying party, not from the CA host. Published CRLs are
# normally DER encoded even when the CA generated a PEM file.
curl -sS -o /tmp/fetched.crl http://pki.example.com/crl.der
openssl crl -in /tmp/fetched.crl -inform DER -noout -text | grep -A1 21173B36

The nextUpdate field is the date by which the next CRL will be issued, not the date this one stops being true. Relying parties use it to decide when to come back, and many refuse a CRL whose nextUpdate has passed. If your CRL is regenerated by hand, you have an availability dependency on somebody remembering, which is a poor foundation for a control you are relying on.

Step 6 - Verify enforcement where enforcement happens

# Expect this to fail now for the revoked certificate.
openssl verify -crl_check -CAfile root.crt -untrusted srv-ca.crt \
  -CRLfile /srv/pki/crl.pem app.crt

# Expect this to pass for the replacement.
openssl verify -crl_check -CAfile root.crt -untrusted srv-ca.crt \
  -CRLfile /srv/pki/crl.pem app-replacement.crt

This proves the CRL is well formed and that the serial is in it. It does not prove that anything in production checks. Go and find the relying party configuration that consumes the CRL, name it in the record, and reload it. In an internal estate that is usually a web server directive, a load balancer trust profile, or a language runtime trust store, and each has its own reload semantics.

Step 7 - Record what revocation did not achieve

Write down, in the incident, which client populations will continue to accept the revoked certificate and until when. For a public certificate that list is normally most browsers and many library clients, and the end date is the certificate’s own notAfter. This is not a confession of failure. It is the reason the industry moved to short lifetimes, and it is the sentence that stops someone closing the incident believing the exposure ended at the revocation timestamp.

Common pitfalls

SymptomCauseAction
The revoked certificate still works everywhereThe relying parties do not check revocationConfirm the replacement is deployed and rely on expiry; record the gap
A relying party now refuses every connectionIt hard-fails on a CRL it cannot fetch or parseRestore the previous CRL file, fix the distribution point, republish
The serial is not in the CRLThe CRL was generated before the revocation, or from a different CA databaseRegenerate, then re-read the published file rather than the local one
Revocation is rejected by the CAThe account that ordered the certificate is not the one authenticatingRevoke using the certificate private key, or escalate to the PKI owner
The reason code is wrong after submissionReason codes are not amendable at most issuersCorrect the record, do not revoke a second time
The service went down at the revocationThe replacement was never actually in serviceDeploy the replacement now; verify the serial on the wire, not on disk

Verification

The revocation is complete when the service is presenting the replacement certificate on the wire, confirmed from outside the host, and the revoked serial appears in the published CRL exactly as recorded in the first step. The CRL must be fetchable from the distribution point named inside the certificate, from a network position a relying party actually occupies, and a verification run with CRL checking enabled must reject the revoked certificate while accepting the replacement. The relying party that enforces revocation has reloaded the new CRL, evidenced by its own logs rather than by the file on disk. The record names the reason code, the revocation timestamp and the expiry date of the revoked certificate, and the inventory no longer lists it as active so that the next expiry alert does not fire against something withdrawn.

Rollback

There is no rollback for a Web PKI revocation. If the wrong certificate was revoked, treat it as an outage and issue an emergency replacement over a new key; do not wait to see whether anyone notices, because the relying parties that do check will fail closed. In a private PKI you operate end to end, a hold entry can be withdrawn with the removeFromCRL reason and a regenerated CRL, but that path exists only for entries placed on hold, and hold is not available for certificates governed by the Baseline Requirements. If publishing the CRL broke relying parties, restore the previous known-good CRL file while you regenerate, since a hard-failing check turns a security action into an availability incident. If the reason code was wrong, correct the incident record rather than revoking again; the published reason is final.

References

  1. RFC 5280: Internet X.509 PKI Certificate and CRL Profile
  2. RFC 6960: X.509 Internet PKI Online Certificate Status Protocol
  3. RFC 9654: Online Certificate Status Protocol Nonce Extension
  4. RFC 8555: Automatic Certificate Management Environment (ACME)
  5. CA/Browser Forum TLS Baseline Requirements
  6. Let's Encrypt: Revoking Certificates
  7. openssl-ca(1)
  8. openssl-crl(1)