Files
kca/ocsp-responder
woggioni 69d78939a1
CI / Build and push docker image (push) Successful in 3m23s
CI / Build and push OCSP image (push) Successful in 7m53s
Build static musl OCSP image in Gitea Actions
2026-10-23 10:00:36 +00:00
..

KCA OCSP responder

Standalone Rust/Axum responder. It reads one full JSON status snapshot per CA from S3-compatible object storage, caches it for one second with a single-flight refresh, and signs OCSP responses with a delegated responder certificate.

It has no KCA database access, no Redis access, and no KCA master key. It only needs:

  • s3:GetObject on the configured bucket/prefix;
  • the CA certificate for each issuer;
  • a delegated OCSP signer certificate and private key for each CA. The responder currently accepts RSA-SHA256 and ECDSA P-256 signers in PKCS#8, PKCS#1 RSA, or SEC1 EC PEM form.

Snapshot layout

KCA publishes objects as:

<prefix>/<CA certificate SHA-256>.json

KCA publishes these objects when KCA_OCSP_S3_BUCKET is configured. The JSON contains all certificates issued by that CA, both valid and revoked. The responder never infers status from a partial revoked-only list.

Run locally

  1. Create a config based on responder.example.yaml.
  2. Put your CA certificates and delegated signer files where the config points.
  3. Export standard AWS credentials / endpoint variables as needed.
  4. Make the signer key readable by the container user (65532:65532 in the published scratch image), or mount it via a Docker secret.
  5. Run:
OCSP_CONFIG=./responder.yaml cargo run

The default listen address is 0.0.0.0:2560.

The published image is built by Gitea Actions on release/* tags:

docker run --rm -p 2560:2560 \
  -v "$PWD/responder.yaml:/etc/ocsp/responder.yaml:ro" \
  -v "$PWD/ca:/etc/ocsp/ca:ro" \
  -v "$PWD/signers:/etc/ocsp/signers:ro" \
  -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY \
  gitea.woggioni.net/woggioni/kca-ocsp:latest

It runs FROM scratch and contains only a statically linked musl executable and a CA bundle for outbound S3 HTTPS. There is no shell or package manager in the image.

Verify with OpenSSL

For a CA certificate ca.crt and leaf certificate leaf.crt:

openssl ocsp \
  -issuer ca.crt \
  -cert leaf.crt \
  -url http://127.0.0.1:2560/ocsp \
  -resp_text \
  -noverify

-noverify skips local trust setup; the response still shows the signature algorithm and included responder certificate. For production verification, build a trust store containing the CA or validate with your normal PKI tooling.

Endpoints

  • POST /ocsp — application/ocsp-request
  • GET /ocsp/<base64url-request> — optional GET form
  • GET /healthz
  • GET /readyz

Cache and availability

  • Per-CA cache TTL: s3.cache_ttl_ms (default 1000 ms).
  • Concurrent requests for the same CA share one S3 GetObject.
  • If S3 fails, a previously cached snapshot is served for s3.stale_grace_seconds; otherwise the OCSP response is tryLater.
  • With multiple CAs, the TTL is per CA. If you need a global one-request-per- second limit across all CAs, that requires a shared rate limiter.