Documentation menu

Revocation

Revoke a leaf by adding it to its intermediate's certificate revocation list, then give the CRL files to the servers that check them.

Revoke a leaf

homepki revoke adds a leaf's serial number to its intermediate's certificate revocation list (CRL) and re-signs the CRLs. Name the certificate with exactly one of --server, --client or --cert:

$ homepki revoke -d runlocal.dev -i bu1 --client my-client
$ homepki revoke -d runlocal.dev -i bu1 --server kong-gateway --reason keyCompromise
$ homepki revoke -d runlocal.dev -i bu1 --cert ./my-service.crt    # e.g. written by sign --out
$ homepki revoke -d runlocal.dev -i bu1 -c cli1 --reason keyCompromise
Revoking cli1.bu1.runlocal.dev (serial bd8e8dda8f064b8ec14bcea02c35f62b) under runlocal.dev/bu1
Wrote ~/.homepki/runlocal-dev/bu1/bu1-intermediate-ca.crl (1 revoked, next update 2027-09-26 12:21)
Wrote ~/.homepki/runlocal-dev/ca/runlocal-dev-root-ca.crl
Wrote ~/.homepki/runlocal-dev/bu1/bu1-crl-chain.crl
Certificate revoked. Reload servers that read the CRL.
  • The certificate must have been issued by that intermediate; a certificate from another CA is refused.
  • Revoking a certificate twice prints … is already revoked (since <date>) and exits 0 without writing anything.
  • The certificate and key files stay in place. Re-issuing the name with --force gives it a new serial number that is not revoked.

Revocation reasons

--reason takes an RFC 5280 reason name, case-insensitive. The default is unspecified, which omits the reason from the CRL entry.

--reasonCode
unspecified0
keyCompromise1
cACompromise2
affiliationChanged3
superseded4
cessationOfOperation5
certificateHold6
privilegeWithdrawn9

CRL files

Both revoke and crl write three PEM files:

FileContentGive it to
<int>/<int>-intermediate-ca.crlthe intermediate's CRL, with every revoked leafa verifier that checks the leaf only
ca/<root>-root-ca.crlthe root's CRL, always emptya verifier that wants one CRL file per CA
<int>/<int>-crl-chain.crlboth, intermediate firstnginx ssl_crl, openssl verify -crl_check_all: anything that checks every tier

The CRL is the only record of revocations. There is no CA database: revoke reads the existing intermediate CRL, checks that the intermediate signed it, appends the entry and increments the CRL number.

Write CRLs before revoking anything

A server configured with a CRL file refuses to start when the file is missing. homepki crl writes the three files with every revocation already recorded, or empty ones on a fresh intermediate:

$ homepki crl -d runlocal.dev -i bu1
$ homepki crl -d runlocal.dev -i bu1 --validity 7d

CRL lifetime

Each CRL carries a nextUpdate time. OpenSSL-based servers reject a CRL past it with CRL has expired, which then rejects every client. The default is 365 days; --validity on revoke or crl changes it, as days (90d) or a duration (24h). It is capped at the issuing CA's expiry.

Re-run homepki crl before nextUpdate to re-sign the CRLs with a new date. Revocations are kept.

Revoked leaves in list output

server-cert list and client-cert list read the intermediate's CRL and report revoked leaves as invalid:

$ homepki client-cert list -d runlocal.dev -i bu1
Client Certificates for runlocal.dev/bu1:
  NAME      EXPIRES     DAYS LEFT  CHAIN
  ────────  ──────────  ─────────  ──────────
  cli1.crt  2027-09-26  364        ✗ INVALID: revoked on 2026-09-26 (keyCompromise)

In JSON the row has "chain_valid": false and "chain_error": "revoked on 2026-09-26 (keyCompromise)". See Listing and verification.

Using the CRLs

OpenSSL

$ openssl verify -crl_check_all \
    -CAfile ~/.homepki/runlocal-dev/bu1/bu1-intermediate-ca-chain.crt \
    -CRLfile ~/.homepki/runlocal-dev/bu1/bu1-crl-chain.crl \
    -purpose sslclient ~/.homepki/runlocal-dev/bu1/client-tls/cli1.crt
O=runlocal-dev, OU=bu1, CN=cli1.bu1.runlocal.dev
error 23 at 0 depth lookup: certificate revoked
error ~/.homepki/runlocal-dev/bu1/client-tls/cli1.crt: verification failed

-crl_check_all needs a CRL for every CA in the chain, which is why the chain file carries the root's CRL too.

nginx mTLS

ssl_client_certificate /etc/nginx/pki/bu1-intermediate-ca-chain.crt;
ssl_verify_client      on;
ssl_verify_depth       2;
ssl_crl                /etc/nginx/pki/bu1-crl-chain.crl;

nginx checks the CRL of every CA in the chain, so give it the chain file. It reads the CRL at start-up: reload nginx after each revoke or crl.

Limits

  • No CRL distribution point. Certificates do not carry a URL to fetch the CRL from. Hand the file to the server directly.
  • No OCSP.
  • Intermediates cannot be revoked. The root CRL is always empty. Replace an intermediate with intermediate-ca --force instead.
  • Deleting a CRL un-revokes everything in it. The next revoke or crl starts from an empty list.
  • intermediate-ca --force deletes that intermediate's CRLs, since the replaced key signed them. root-ca --force deletes the root CRL.