Skip to content

Commit 23adf10

Browse files
danielewoodclaude
andauthored
feat: add OCSP and CRL revocation checking to connect command (#78)
* feat: add OCSP and CRL revocation checking to connect command OCSP is checked automatically (best-effort) on every connect — if the responder is unreachable or the cert has no OCSP URL, the field is silently omitted. CRL checking is opt-in via --crl. Both revoked statuses trigger exit code 2. Also extracts FetchCRL into the library so the standalone crl command and connect share the same fetching logic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: harden OCSP/CRL with SSRF validation, signature checks, and test consolidation - Add ValidateAIAURL and CheckRedirect to OCSP and CRL HTTP clients - Verify CRL signatures against issuer certificate - Surface OCSP failures as "unavailable" status instead of silent nil - Rename CRLCheckResult.URL to DistributionPoint (breaking) - Remove redundant http.Client timeouts (context deadlines suffice) - Consolidate connect tests from 1380 to 1015 lines (~26% reduction) - Extract generateTestCA, generateTestLeafCert, startTLSServer helpers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review — dedup formatters, changelog refs - Extract FormatOCSPLine and FormatCRLLine to eliminate duplication between library FormatConnectResult and CLI formatConnectVerbose - Add ([#78]) refs to all new CHANGELOG entries per CL-3 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: surface OCSP skip reasons, add test improvements from adversarial review - Show "OCSP: skipped (reason)" when no responder URL or no issuer in chain instead of silently omitting OCSP from output - Add Detail field to OCSPResult for skip/unavailable context - Add OCSP "unknown" status test case - Strengthen FormatOCSPResult assertions to check actual values, not just labels - Add empty CRL test (zero revoked entries) - Fix shared atomic counter in parallel OCSP test — create per-subtest servers - Switch ocsp_test.go to generateTestCA/generateTestLeafCert helpers - Merge TestCheckOCSP_NilInputs and TestCheckOCSP_NoOCSPURL into single table-driven TestCheckOCSP_InvalidInputs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add HTTP timeouts, CRL freshness check, and CS-5 input struct - Add 10s HTTP client Timeout to OCSP and CRL fetchers (SEC-1) - Reject expired CRLs (past NextUpdate) to prevent stale replay attacks - Refactor checkLeafCRL to use input struct per CS-5 (>2 non-ctx args) - Add TestConnectTLS_CRL_Expired test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: OCSP freshness check, improved output, and test hardening Security: - Reject expired OCSP responses (past NextUpdate) to prevent replay of stale "good" responses over HTTP - Propagate OCSP error details into "unavailable" Detail field UX: - OCSP "unavailable" now shows error reason instead of just URL - OCSP "unknown" explains: "responder does not recognize this certificate" - FormatCRLLine default case prints raw status instead of empty string Tests: - Fix misleading "no CRL distribution points" test (was testing "no issuer") - Add actual CDP-absent test case exercising checkLeafCRL - Add CRL "good" integration test (non-revoked leaf) - Add OCSP serial number verification in integration test - Add OCSP "unavailable with detail" and "unknown" format tests - Consolidate crl_test.go: use generateTestCA, merge empty CRL into table - Strengthen CRLInfoFromList assertions (CRL number, format content) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add --no-ocsp flag, unify serial JSON key (CLI-4) - Add --no-ocsp flag to connect for disabling automatic OCSP check - Rename OCSPResult JSON field serial_number → serial (CLI-4: same concept uses the same key everywhere — all other commands use serial) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add --ocsp and --crl flags to verify command Allow revocation checking from local certificate files via the verify command, consolidating the validation path so most users only need one command. Both flags are opt-in since they require network access. Export CheckLeafCRL/CheckLeafCRLInput for reuse across commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: surface OCSP skip reasons, add test improvements from adversarial review Add FetchCRL, CheckLeafCRL, FormatCRLLine, and verify OCSP/CRL unit tests. Improve revocation error messages to include revocation time and reason. Clarify --ocsp/--crl flag help text about chain dependency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: AIA issuer fallback, SSRF regression, test consolidation from adversarial review - Fix connect OCSP/CRL ignoring AIA-fetched issuer: fall back to VerifiedChains[0][1] when PeerCertificates has only the leaf - Add RootCAs field to ConnectTLSInput for custom root pools - Fix certkit crl rejecting private IPs: add FetchCRLInput struct with AllowPrivateNetworks flag, bypass SSRF for user-provided URLs - Fix verify --ocsp/--crl silently omitting results when chain fails: now reports "skipped" with explanation - Consolidate 4 CRL integration tests and 4 verify revocation tests into table-driven tests (T-12) - Merge standalone FetchCRL/CheckLeafCRL tests into parent tables (T-14) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: prefer verified chain for issuer resolution in connect When a server sends duplicate leaf certificates in the TLS chain (e.g., [leaf, leaf, intermediate]), PeerCertificates[1] is the duplicate leaf — not the actual issuer. This caused both OCSP and CRL checks to fail with signature verification errors. Swap priority to prefer VerifiedChains[0][1] (cryptographically validated by x509.Verify) over PeerCertificates[1] (raw server-sent). Fall back to PeerCertificates only when chain verification failed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add --no-ocsp to connect flags table, fix FetchCRL SSRF doc Address review comments: - Add --no-ocsp flag to README connect flags table - Clarify FetchCRL doc comment: SSRF blocks literal private/loopback IPs only (hostnames are allowed through) - Update PR description to match actual behavior (shows "unavailable" not "silently skipped") Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add OCSP coverage and detail assertion to duplicate-leaf test From adversarial test correctness review: - Enable OCSP in TestConnectTLS_CRL_DuplicateLeafInChain (was disabled) — verifies issuer resolution fix works for both OCSP and CRL, not just CRL - Assert CRL detail contains the revoked serial number - Add OCSP responder mock signed by the intermediate CA Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: unify OCSP/CRL URL field names for CLI-4 consistency Rename OCSPResult.ResponderURL and CRLCheckResult.DistributionPoint to URL (JSON: "url") on both types. The parent object (ocsp/crl) provides the context, so the field name should be consistent across revocation check types per CLI-4. Breaking: JSON field "responder_url" → "url" in ocsp object, "distribution_point" → "url" in crl object. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add --ocsp and --crl to verify flags table in README Address review comment: verify command's --ocsp and --crl flags were missing from the README flags table. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: guard PeerCertificates[0] access in revocation check block Add length check before accessing PeerCertificates[0] for revocation checks. The diagnostics and verification blocks above are guarded, but the revocation block was not — would panic on an empty peer chain from a partially-completed handshake. Also fix CHANGELOG link ordering ([#78] was out of numeric sequence). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address 5 review findings from PR #78 code review - Security: remove PeerCertificates[1] fallback for issuer resolution in revocation checks — only use cryptographically verified issuer from VerifiedChains to prevent forged OCSP/CRL responses from malicious servers - CS-5: checkVerifyOCSP now takes CheckOCSPInput struct instead of 3 positional arguments - ERR-5: startTLSServer test helper now logs Handshake() and Close() errors with slog.Debug instead of discarding them - DRY: extract FormatOCSPStatusLine and FormatCRLStatusLine shared helpers — formatVerifyOCSP/formatVerifyCRL now delegate to root package instead of duplicating switch logic - Fix FormatCRLLine/formatVerifyCRL missing "skipped" case — Detail was dropped when status was "skipped" Tests updated to provide RootCAs for chain verification, matching the new security requirement that revocation checks only run against verified issuers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address 3 review findings from PR #78 review round 7 - Fix data race in TestCheckLeafCRL — generate CRL bytes before starting the test HTTP server to avoid unsynchronized closure access (CC-3) - Fix CheckLeafCRL panic on nil Leaf/Issuer — return "unavailable" result with clear detail instead of dereferencing nil - Fix verify help text claiming "Exits with code 2 if revoked" — actually exits 2 for any verification error Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 91d8926 commit 23adf10

15 files changed

Lines changed: 1986 additions & 344 deletions

CHANGELOG.md

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- `connect` automatically checks OCSP revocation status on the leaf certificate (best-effort; shows "skipped" or "unavailable" when check cannot complete) ([#78])
13+
- Add `--crl` flag to `connect` for opt-in CRL revocation checking via distribution points ([#78])
14+
- Add `FetchCRL` library function for downloading CRLs from HTTP URLs with SSRF validation ([#78])
15+
- `connect` exits with code 2 when OCSP or CRL reports a revoked certificate ([#78])
16+
- `connect --crl` verifies CRL signatures against the issuer certificate — rejects CRLs signed by a different CA ([#78])
17+
- `connect --crl` rejects expired CRLs (past `NextUpdate`) to prevent replay of stale revocation data ([#78])
18+
- `connect` OCSP check rejects expired responses (past `NextUpdate`) to prevent replay of stale data ([#78])
19+
- `connect` OCSP "unavailable" output now shows the error reason instead of just the responder URL ([#78])
20+
- `connect` OCSP "unknown" output now explains the status: "responder does not recognize this certificate" ([#78])
21+
- Add `--no-ocsp` flag to `connect` to disable automatic OCSP revocation check ([#78])
22+
- Add `--ocsp` and `--crl` flags to `verify` for revocation checking against OCSP responders and CRL distribution points ([#78])
23+
- Add `RootCAs` field to `ConnectTLSInput` for chain verification against custom root pools ([#78])
24+
- Add `FetchCRLInput` struct with `AllowPrivateNetworks` flag — `certkit crl` now accepts private/loopback IPs for user-provided URLs ([#78])
25+
- Add `MarshalSANExtension` for building complete SAN extensions with OtherName support (UPN, XMPP, SRV, SmtpUTF8Mailbox, arbitrary OIDs) ([#74])
26+
- Add `ResolveOtherNameOID` for resolving OtherName labels or dotted-decimal OID strings ([#74])
27+
- Add `OtherNameSAN` and `MarshalSANExtensionInput` types for OtherName SAN generation ([#74])
28+
- Add `other_names` field to `CSRTemplate` for mTLS user identity certificate CSRs ([#74])
29+
- Add OtherName SAN preservation in `GenerateCSRFromCSR` — string-typed OtherName entries survive CSR-to-CSR key rotation; binary-typed OtherNames are silently skipped ([#74])
30+
- Add `ErrUnknownOtherNameType` sentinel error for invalid OtherName type strings ([#74])
31+
- Add `ErrEmptySANExtension` sentinel error for empty SAN extension input ([#74])
32+
- Add `aia_fetched` field to inspect results and "via aia" badge in web UI for AIA-fetched certificates ([#73])
33+
- Add multi-entry JKS support to `convert --key` — when multiple keys match different certificates, JKS output creates a multi-alias keystore with one `PrivateKeyEntry` per match
34+
- Add `EncodeJKSEntries` library function for creating multi-entry JKS keystores with alias sanitization and deduplication
35+
- Add `CollectCertificateSANs` library function for canonical SAN aggregation (DNS, IP, email, URI, OtherName) across all commands
36+
- Add `ParsePEMPrivateKeys` library function for extracting all private keys from a multi-key PEM bundle, skipping non-key blocks
37+
- Add chain diagnostics to `connect` command — detect root certificates in chain (RFC 8446 §4.4.2) and duplicate certificates
38+
- Add AIA walking to `connect` command — automatically fetch missing intermediates when server sends leaf-only chain, with `missing-intermediate` diagnostic warning
39+
- Add mTLS detection to `connect` command — shows whether the server requests a client certificate, acceptable CAs, and accepted signature algorithms
40+
- Add ALPN (negotiated application protocol) to `connect` command output
41+
- Add `--verbose` / `-v` global flag for extended certificate details in `connect`, `verify`, `scan`, and `ocsp` output (serial, key info, signature algorithm, key usage, EKU, fingerprints, SKI/AKI)
42+
- Add CRL number and authority key identifier to `crl` output
43+
- Add `convert` command for converting between PEM, DER, PKCS#12, JKS, and PKCS#7 formats
44+
- Add `sign` command with `self-signed` and `csr` subcommands for certificate signing
45+
- Add `connect` command for TLS connection testing with certificate chain display
46+
- Add `--diagnose` flag to `verify` command for chain failure diagnostics
47+
- Add `ocsp` command for checking certificate revocation status via OCSP
48+
- Add `crl` command for parsing and inspecting Certificate Revocation Lists
49+
1050
### Changed
1151

52+
- **Breaking:** Rename `CRLCheckResult.DistributionPoint` to `CRLCheckResult.URL` (JSON: `url`) and `OCSPResult.ResponderURL` to `OCSPResult.URL` (JSON: `url`) — consistent field name for the checked endpoint across both revocation types (CLI-4) ([#78])
53+
- **Breaking:** Rename OCSP JSON field `serial_number` to `serial` for CLI-4 consistency with all other commands ([#78])
54+
- **Breaking:** `FetchCRL` now takes `FetchCRLInput` struct instead of a URL string — enables `AllowPrivateNetworks` for user-provided URLs ([#78])
55+
- Export `CheckLeafCRL` and `CheckLeafCRLInput` for use by `verify` command — previously unexported ([#78])
1256
- Improve error messages when AIA certificate fetching fails — errors now include the URL and operation context ([#76])
1357

58+
### Security
59+
60+
- Add SSRF validation (`ValidateAIAURL`) to OCSP responder URLs and CRL distribution point URLs — previously only AIA certificate URLs were validated ([#78])
61+
- Add `CheckRedirect` handlers to OCSP and CRL HTTP clients — prevents redirect-based SSRF bypass to internal networks ([#78])
62+
- Fix `connect` OCSP/CRL checks using unverified issuer from `PeerCertificates` when chain verification fails — a malicious server could forge valid revocation responses; now only uses cryptographically verified issuer from `VerifiedChains` ([#78])
63+
1464
### Fixed
1565

66+
- Fix data race in `TestCheckLeafCRL` — CRL bytes are now generated before starting the test HTTP server (CC-3) ([#78])
67+
- Fix `CheckLeafCRL` panic on nil `Leaf` or `Issuer` — now returns "unavailable" result instead of panicking ([#78])
68+
- Fix `verify` help text claiming "Exits with code 2 if revoked" — actually exits 2 for any verification error including revocation ([#78])
69+
- Fix `connect` `FormatCRLLine` dropping `Detail` for "skipped" status — previously fell through to default which omitted the reason ([#78])
70+
- Fix `formatVerifyCRL` in `verify` missing "skipped" case — now delegates to shared `FormatCRLStatusLine` helper ([#78])
71+
- Fix silent error discard in test TLS server — `Handshake()` and `Close()` errors now logged with `slog.Debug` (ERR-5) ([#78])
72+
- Fix `checkVerifyOCSP` taking 3 positional arguments — now uses `CheckOCSPInput` struct (CS-5) ([#78])
73+
- Fix `formatVerifyOCSP`/`formatVerifyCRL` duplicating `FormatOCSPLine`/`FormatCRLLine` logic — extract shared `FormatOCSPStatusLine` and `FormatCRLStatusLine` helpers ([#78])
74+
- Fix `connect` OCSP/CRL checks failing when the server sends a duplicate leaf certificate in the chain (e.g., `[leaf, leaf, intermediate]`) — issuer resolution now prefers the cryptographically verified chain over the raw server-sent chain ([`2693116`])
75+
- Fix `connect` OCSP/CRL checks ignoring AIA-fetched issuer — when server sends leaf-only chain, revocation checks now fall back to `VerifiedChains` for the issuer ([#78])
76+
- Fix `certkit crl` rejecting private/loopback IPs — SSRF validation is now skipped for user-provided URLs ([#78])
77+
- `verify --ocsp`/`--crl` now reports "skipped" status when chain validation fails instead of silently omitting results ([#78])
78+
- `verify --ocsp` revocation error now includes revocation time and reason instead of a generic "certificate is revoked (OCSP)" message ([#78])
79+
- Add 10-second HTTP client timeout to OCSP and CRL fetchers — prevents indefinite hangs during DNS/connection phases ([#78])
1680
- Fix `--save-db` error messages formatting `*big.Int` serial numbers with `%s` instead of calling `.String()` ([#76])
1781
- Fix potential panic in TLS connection handling during remote certificate fetch ([#76])
1882
- Fix `--save-db` silently writing incomplete SAN data when JSON encoding fails — now returns an error ([#76])
@@ -68,40 +132,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
68132
- Fix `convert` command performing encoding before checking if `-o` is required for binary formats — binary format error is now returned immediately ([#75])
69133
- Fix `crl --check` verdict written to stderr instead of stdout (CLI-1) and absent from JSON output (CLI-3) — check result now included as `check_result` in JSON and printed to stdout in text mode ([#75])
70134

71-
### Added
72-
73-
- Add `MarshalSANExtension` for building complete SAN extensions with OtherName support (UPN, XMPP, SRV, SmtpUTF8Mailbox, arbitrary OIDs) ([#74])
74-
- Add `ResolveOtherNameOID` for resolving OtherName labels or dotted-decimal OID strings ([#74])
75-
- Add `OtherNameSAN` and `MarshalSANExtensionInput` types for OtherName SAN generation ([#74])
76-
- Add `other_names` field to `CSRTemplate` for mTLS user identity certificate CSRs ([#74])
77-
- Add OtherName SAN preservation in `GenerateCSRFromCSR` — string-typed OtherName entries survive CSR-to-CSR key rotation; binary-typed OtherNames are silently skipped ([#74])
78-
- Add `ErrUnknownOtherNameType` sentinel error for invalid OtherName type strings ([#74])
79-
- Add `ErrEmptySANExtension` sentinel error for empty SAN extension input ([#74])
80-
- Add `aia_fetched` field to inspect results and "via aia" badge in web UI for AIA-fetched certificates ([#73])
81-
- Add multi-entry JKS support to `convert --key` — when multiple keys match different certificates, JKS output creates a multi-alias keystore with one `PrivateKeyEntry` per match
82-
- Add `EncodeJKSEntries` library function for creating multi-entry JKS keystores with alias sanitization and deduplication
83-
- Add `CollectCertificateSANs` library function for canonical SAN aggregation (DNS, IP, email, URI, OtherName) across all commands
84-
- Add `ParsePEMPrivateKeys` library function for extracting all private keys from a multi-key PEM bundle, skipping non-key blocks
85-
- Add chain diagnostics to `connect` command — detect root certificates in chain (RFC 8446 §4.4.2) and duplicate certificates
86-
- Add AIA walking to `connect` command — automatically fetch missing intermediates when server sends leaf-only chain, with `missing-intermediate` diagnostic warning
87-
- Add mTLS detection to `connect` command — shows whether the server requests a client certificate, acceptable CAs, and accepted signature algorithms
88-
- Add ALPN (negotiated application protocol) to `connect` command output
89-
- Add `--verbose` / `-v` global flag for extended certificate details in `connect`, `verify`, `scan`, and `ocsp` output (serial, key info, signature algorithm, key usage, EKU, fingerprints, SKI/AKI)
90-
- Add CRL number and authority key identifier to `crl` output
91-
- Add `convert` command for converting between PEM, DER, PKCS#12, JKS, and PKCS#7 formats
92-
- Add `sign` command with `self-signed` and `csr` subcommands for certificate signing
93-
- Add `connect` command for TLS connection testing with certificate chain display
94-
- Add `--diagnose` flag to `verify` command for chain failure diagnostics
95-
- Add `ocsp` command for checking certificate revocation status via OCSP
96-
- Add `crl` command for parsing and inspecting Certificate Revocation Lists
97-
- Add `CreateSelfSigned` and `SignCSR` library functions for certificate signing
98-
- Add `ConnectTLS` library function for TLS connection probing
99-
- Add `CheckOCSP` library function for OCSP revocation checking
100-
- Add `ParseCRL`, `CRLContainsCertificate`, and `CRLInfoFromList` library functions for CRL handling
101-
- Add chain diagnostic checks (`--diagnose` flag) for `verify` command
102-
103135
### Tests
104136

137+
- Add `TestConnectTLS_CRL_AIAFetchedIssuer` — verifies CRL checking works when issuer is obtained via AIA walking ([#78])
138+
- Add `TestFetchCRL_AllowPrivateNetworks` — verifies loopback IPs succeed with `AllowPrivateNetworks` ([#78])
139+
- Add `TestFetchCRL` unit tests for HTTP handling, redirect limits, SSRF blocking, and error paths ([#78])
140+
- Add `TestCheckLeafCRL` table-driven tests covering revoked, good, expired CRL, wrong issuer, no CDPs, and non-HTTP CDPs ([#78])
141+
- Consolidate `TestVerifyCert_RevocationBehavior` table-driven test replacing 4 standalone verify revocation tests (T-12) ([#78])
142+
- Consolidate `TestConnectTLS_CRL` into single table-driven test with 4 cases replacing standalone WrongIssuer/Expired/Good tests (T-12) ([#78])
143+
- Add `TestFormatCRLLine` covering all status branches including unknown fallback ([#78])
105144
- Add `TestFindAllKeyLeafPairs` and `TestBuildChainFromPool` tests for `convert --key` matching logic — single/multi match, nil certs, CA fallback, leaf priority, chain building, cycle termination ([#75])
106145
- Fix `TestConnectTLS_AIAFetch` false positive — add atomic request counter to verify AIA HTTP server is actually contacted ([#75])
107146
- Strengthen `TestEncodeJKSEntries` round-trip assertions — verify cert CN identity survives encode/decode ([#75])
@@ -726,7 +765,7 @@ Initial release.
726765
[0.1.2]: https://github.com/sensiblebit/certkit/compare/v0.1.1...v0.1.2
727766
[0.1.1]: https://github.com/sensiblebit/certkit/compare/v0.1.0...v0.1.1
728767
[0.1.0]: https://github.com/sensiblebit/certkit/releases/tag/v0.1.0
729-
768+
[`2693116`]: https://github.com/sensiblebit/certkit/commit/2693116
730769
[`84c4edf`]: https://github.com/sensiblebit/certkit/commit/84c4edf
731770
[`2b8cb8c`]: https://github.com/sensiblebit/certkit/commit/2b8cb8c
732771
[`392878a`]: https://github.com/sensiblebit/certkit/commit/392878a
@@ -788,6 +827,7 @@ Initial release.
788827
[#74]: https://github.com/sensiblebit/certkit/pull/74
789828
[#75]: https://github.com/sensiblebit/certkit/pull/75
790829
[#76]: https://github.com/sensiblebit/certkit/pull/76
830+
[#78]: https://github.com/sensiblebit/certkit/pull/78
791831
[#73]: https://github.com/sensiblebit/certkit/pull/73
792832
[#64]: https://github.com/sensiblebit/certkit/pull/64
793833
[#63]: https://github.com/sensiblebit/certkit/pull/63

EXAMPLES.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,15 @@ Connect to a server and see its certificate chain, negotiated protocol, and ciph
168168
certkit connect example.com
169169
```
170170

171-
certkit shows the full chain with trust status, client auth requirements, and ALPN protocol. Missing intermediates are fetched via AIA automatically.
171+
certkit shows the full chain with trust status, client auth requirements, and ALPN protocol. Missing intermediates are fetched via AIA automatically. OCSP revocation status is checked on the leaf certificate (best-effort -- shows "OCSP: skipped" when no responder URL or issuer is available, or "OCSP: unavailable" when the responder cannot be reached).
172+
173+
To also check CRL distribution points:
174+
175+
```sh
176+
certkit connect example.com --crl
177+
```
178+
179+
certkit exits with code 2 if the certificate is revoked (via OCSP or CRL).
172180

173181
For machine-readable output:
174182

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,23 @@ Common passwords (`""`, `"password"`, `"changeit"`, `"keypassword"`) are always
138138
| `--key` | | Private key file to check against the certificate |
139139
| `--expiry`, `-e` | | Check if cert expires within duration (e.g., `30d`, `720h`) |
140140
| `--trust-store` | `mozilla` | Trust store: `system`, `mozilla` |
141+
| `--ocsp` | `false` | Check OCSP revocation status |
142+
| `--crl` | `false` | Check CRL distribution points for revocation |
141143
| `--format` | `text` | Output format: `text`, `json` |
142144
| `--diagnose` | `false` | Show diagnostics when chain verification fails |
143145

144-
Chain verification is always performed. When the input contains an embedded private key (PKCS#12, JKS), key match is checked automatically.
146+
Chain verification is always performed. When the input contains an embedded private key (PKCS#12, JKS), key match is checked automatically. Use `--ocsp` and/or `--crl` to check revocation status (requires network access and a valid chain).
145147

146148
### Connect Flags
147149

148-
| Flag | Default | Description |
149-
| -------------- | ------- | ---------------------------------------- |
150-
| `--servername` | | Override SNI hostname (defaults to host) |
151-
| `--format` | `text` | Output format: `text`, `json` |
150+
| Flag | Default | Description |
151+
| -------------- | ------- | -------------------------------------------- |
152+
| `--servername` | | Override SNI hostname (defaults to host) |
153+
| `--no-ocsp` | `false` | Disable automatic OCSP revocation check |
154+
| `--crl` | `false` | Check CRL distribution points for revocation |
155+
| `--format` | `text` | Output format: `text`, `json` |
152156

153-
Port defaults to 443 if not specified. Use `--verbose` for extended details (serial, key info, signature algorithm, key usage, EKU).
157+
Port defaults to 443 if not specified. OCSP revocation status is checked automatically (best-effort); use `--no-ocsp` to disable. Use `--verbose` for extended details (serial, key info, signature algorithm, key usage, EKU).
154158

155159
### Bundle Flags
156160

0 commit comments

Comments
 (0)