A lightweight, RFC 6960 compliant OCSP responder written in Go. Designed for use with Azure Gateway and compatible with any CA that provides CRL endpoints (including Smallstep step-ca).
- Fully RFC-6960 compliant OCSP responses
- HTTP GET and POST request support
- Nonce extension support (optional, doesn't break caching)
- Load certificates from URLs or files - Fetch issuer cert from PKI endpoints
- Multiple certificate status sources:
- URLSource - Fetch CRL from HTTP(S) endpoints
- FileSource - Read CRL from local files
- InMemorySource - Programmatic status management
- Automatic CRL refresh with configurable intervals
- Health check endpoint for load balancers
go install github.com/dotindustries/ocsp-responder@latestOr clone and build:
git clone https://github.com/dotindustries/ocsp-responder.git
cd ocsp-responder
make build# Pull from Azure Container Registry
podman pull dotinc.azurecr.io/ocsp-responder:latest
# or with Docker
docker pull dotinc.azurecr.io/ocsp-responder:latestOr build locally (Podman recommended for better caching):
make podman
# or with Docker
make docker./ocsp-responder \
-issuer ca.pem \
-responder ocsp.pem \
-key ocsp-key.pem./ocsp-responder \
-issuer ca.pem \
-responder ocsp.pem \
-key ocsp-key.pem \
-crl-url https://ca.example.com/crl \
-crl-refresh 5m./ocsp-responder \
-issuer ca.pem \
-responder ocsp.pem \
-key ocsp-key.pem \
-crl-file /path/to/crl.der \
-crl-refresh 5mThe -issuer and -responder flags accept both file paths and HTTP(S) URLs. This is useful when your certificates are published at a known PKI endpoint:
# Fetch issuer cert from URL, key from local file
./ocsp-responder \
-issuer https://pki.example.com/intermediate_ca.crt \
-responder https://pki.example.com/intermediate_ca.crt \
-key /certs/intermediate_ca_key \
-crl-url https://ca.example.com/crl
# Skip TLS verification (testing only!)
./ocsp-responder \
-issuer https://pki.staging.example.com/ca.crt \
-responder https://pki.staging.example.com/ca.crt \
-key /certs/ocsp.key \
-insecure-skip-verifyNote: The
-keyflag only accepts file paths (not URLs) for security reasons. Private keys should not be fetched over the network.
| Flag | Default | Description |
|---|---|---|
-addr |
:8080 |
Address to listen on |
-issuer |
(required) | Path or URL to issuer certificate (PEM) |
-responder |
(required) | Path or URL to responder certificate (PEM) |
-key |
(required) | Path to responder private key file (PEM) |
-interval |
24h |
OCSP response validity interval |
-crl-url |
URL to fetch CRL from | |
-crl-file |
Path to local CRL file | |
-crl-refresh |
5m |
CRL refresh interval |
-ca-cert |
Path or URL to CA certificate for TLS verification (CRL URL) | |
-insecure-skip-verify |
false |
Skip TLS verification (testing only) |
The responder supports three types of certificate status sources:
Fetches CRL from an HTTP(S) endpoint and caches it locally. Automatically refreshes at the configured interval.
source, err := ocsp.NewURLSource(ocsp.URLSourceConfig{
URL: "https://ca.example.com/crl",
RefreshInterval: 5 * time.Minute,
Timeout: 30 * time.Second,
RootCAs: certPool, // optional
InsecureSkipVerify: false, // optional
})
if err != nil {
log.Fatal(err)
}
defer source.Close()Reads CRL from a local file and watches for changes. Useful when the CRL is synced via other means.
source, err := ocsp.NewFileSource(ocsp.FileSourceConfig{
Path: "/path/to/crl.der",
RefreshInterval: 5 * time.Minute,
})
if err != nil {
log.Fatal(err)
}
defer source.Close()Programmatically manage certificate status. Useful for testing or custom integrations.
source := ocsp.NewInMemorySource()
// Mark a certificate as revoked
source.SetStatus(serialNumber, &ocsp.CertStatus{
Status: "revoked",
RevokedAt: time.Now(),
Reason: ocsp.KeyCompromise,
})- POST / - Submit OCSP request in body
- GET /{base64-encoded-request} - Submit URL-encoded OCSP request
- GET /health - Returns JSON health status with CRL statistics
{
"status": "healthy",
"crl": {
"revoked_count": 5,
"last_update": "2024-01-15T10:30:00Z",
"next_update": "2024-01-16T10:30:00Z"
}
}To use with step-ca, point the -crl-url to your step-ca CRL endpoint:
./ocsp-responder \
-issuer /path/to/step-ca/certs/root_ca.crt \
-responder /path/to/ocsp-responder.crt \
-key /path/to/ocsp-responder.key \
-crl-url https://your-step-ca:9000/crlOr fetch the issuer certificate directly from your PKI URL:
./ocsp-responder \
-issuer https://pki.example.com/intermediate_ca.crt \
-responder /path/to/ocsp-responder.crt \
-key /path/to/ocsp-responder.key \
-crl-url https://your-step-ca:9000/crl \
-insecure-skip-verifyMake sure CRL is enabled in your step-ca configuration (ca.json):
{
"crl": {
"enabled": true
}
}Run with Podman (recommended):
podman run -p 8080:8080 \
-v /path/to/certs:/certs:ro,Z \
dotinc.azurecr.io/ocsp-responder:latest \
-issuer /certs/ca.pem \
-responder /certs/ocsp.pem \
-key /certs/ocsp-key.pem \
-crl-url https://ca.example.com/crlOr with Docker:
docker run -p 8080:8080 \
-v /path/to/certs:/certs:ro \
dotinc.azurecr.io/ocsp-responder:latest \
-issuer /certs/ca.pem \
-responder /certs/ocsp.pem \
-key /certs/ocsp-key.pem \
-crl-url https://ca.example.com/crl- Go 1.24+
- Podman or Docker (optional, for container builds)
- goreleaser (for releases)
# Build binary
make build
# Run tests
make test
# Run tests with coverage report
make test-coverage
# Run linter
make lint
# Build container image (Podman - recommended)
make podman
# Build container image (Docker)
make docker
# Test release process (no publish)
make release-dry-run
# Show all available commands
make helpReleases are automated via GitHub Actions. To create a release:
-
Tag the commit:
git tag -a v1.0.0 -m "Release v1.0.0" git push origin v1.0.0 -
GitHub Actions will automatically:
- Build binaries for Linux, macOS, and Windows (amd64/arm64)
- Create GitHub release with artifacts
- Build and push container image to Azure Container Registry (using Podman)
For local testing:
make snapshot # Creates snapshot release in dist/MIT