certkit

Note: certkit is under active development. CLI flags, output formats, and library APIs may change between releases. Do not rely on interface stability for scripting or automation until a 1.0 release.

A Swiss Army knife for TLS/SSL certificates. Inspect, verify, bundle, scan, and generate certificates and keys — all from a single tool.

What can it do?

  • Inspect any certificate, key, or CSR and see exactly what’s in it
  • Verify that a cert chains to a trusted root, matches its key, and isn’t about to expire
  • Connect to a TLS server and display its certificate chain, cipher suite, and ALPN
  • Bundle a leaf cert into a full chain for your web server (nginx, Apache, HAProxy, etc.)
  • Convert between PEM, DER, PKCS#12, JKS, and PKCS#7
  • Sign certificates — self-signed CAs or issue certs from CSRs
  • Scan a directory full of certs and keys to understand what you have
  • Generate new key pairs and CSRs for certificate renewals
  • Check revocation via OCSP or CRL

Works with every common format out of the box. No OpenSSL gymnastics required.

Web App

Use certkit directly in your browser at certkit.pages.dev. Drop certificate and key files to inspect, match, and export organized bundles — all processing happens locally via WebAssembly. No files are uploaded.

Install

Homebrew (macOS)

brew install sensiblebit/tap/certkit

Homebrew Nightly (main snapshots)

Nightly cask updates are published automatically on every push to main.

brew install sensiblebit/tap/certkit@nightly
certkit --version

Debian/Ubuntu (Linux)

Download the .deb package from the latest release and install:

sudo dpkg -i certkit_*.deb

From source

Requires Go 1.27+.

go build -o certkit ./cmd/certkit/

Shell Completion

certkit supports tab completion for bash, zsh, fish, and PowerShell. Run certkit completion --help for details, or set it up with:

# Bash
source <(certkit completion bash)

# Zsh
source <(certkit completion zsh)

# Fish
certkit completion fish | source

# PowerShell
certkit completion powershell | Out-String | Invoke-Expression

To load completions for every new session, see certkit completion <shell> --help for persistent installation instructions.

Quick Start

See what’s in a certificate:

certkit inspect cert.pem

Check if it’s valid and not expiring soon:

certkit verify cert.pem --expiry 30d

Build the full chain your web server needs:

certkit bundle cert.pem -o chain.pem

See EXAMPLES.md for a walkthrough of the main certificate workflows and real-world scenarios.

Common Commands

CommandWhat it does
certkit inspect <file>Show what’s in a cert, key, or CSR
certkit verify <file>Check chain, key match, and expiry
certkit connect <host>Test a TLS connection and display the certificate chain
certkit probe ssh <host>Inspect SSH banner and advertised transport algorithms
certkit bundle <file>Build a certificate chain from a leaf cert
certkit convert <file>Convert between PEM, DER, PKCS#12, JKS, and PKCS#7
certkit sign self-signedCreate a self-signed certificate
certkit sign csr <file>Sign a CSR with a CA certificate and key
certkit scan <path>Scan a directory and catalog everything found
certkit treePrint the full CLI command tree (--flags / --inherited for details)
certkit keygenGenerate a new key pair (and optionally a CSR)
certkit csrGenerate a CSR from a template, cert, or existing CSR
certkit ocsp <file>Check certificate revocation status via OCSP
certkit crl <file-or-url>Parse a CRL and check for revoked certificates

License

MIT


Reference

Global Flags

FlagDefaultDescription
--allow-expiredfalseInclude expired certificates
--jsonfalseOutput in JSON format
--log-level, -linfoLog level: debug, info, warn, error
--password-fileFile containing passwords, one per line, for encrypted keys and PKCS#12/JKS export output
--passwords, -pComma-separated passwords for encrypted keys and PKCS#12/JKS export output
--verbose, -vfalseExtended details in output (serial, key info, signature algorithm, key usage, EKU, extensions)

Common passwords ("", "password", "changeit", "keypassword") are always tried automatically.

Inspect Flags

FlagDefaultDescription
--allow-private-networkfalseAllow AIA fetches to private/internal endpoints
--formattextOutput format: text, json
--trust-storemozillaTrust store: system, mozilla

JSON certificate records include trust_anchors and trust_warnings.

Verify Flags

FlagDefaultDescription
--allow-private-networkfalseAllow AIA/OCSP/CRL fetches to private/internal endpoints
--crlfalseCheck CRL distribution points for revocation
--diagnosefalseShow diagnostics when chain verification fails
--expiry, -eCheck if cert expires within duration (e.g., 30d, 720h)
--formattextOutput format: text, json
--keyPrivate key file to check against the certificate
--ocspfalseCheck OCSP revocation status
--rootsAdditional root certificates file (PEM, DER, PKCS#7, PKCS#12, or JKS)
--trust-storemozillaTrust store: system, mozilla

Chain verification uses the embedded Mozilla roots by default; use --trust-store system to switch to the host trust store. Use --roots to add a file-backed trust source for private PKI, including pinned or legacy trust anchors loaded from PEM, DER, PKCS#7, PKCS#12, or JKS. 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).

JSON output includes trust_anchors and trust_warnings for the leaf and displayed chain entries.

Connect Flags

FlagDefaultDescription
--allow-private-networkfalseAllow AIA/OCSP/CRL fetches to private/internal endpoints
--ciphersfalseEnumerate all supported cipher suites with security ratings
--crlfalseCheck CRL distribution points for revocation
--fips-140-2falseApply conservative FIPS 140-2 heuristic checks to negotiated/offered TLS algorithms
--fips-140-3falseApply conservative FIPS 140-3 heuristic checks to negotiated/offered TLS algorithms
--formattextOutput format: text, json
--no-ocspfalseDisable automatic OCSP revocation check
--servernameOverride SNI hostname (defaults to host)
--tls-versionPin TLS version: 1.0, 1.1, 1.2, or 1.3 (default: auto)
--trust-storemozillaTrust store: system, mozilla

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, extensions) plus a PEM-formatted copy of the server-sent certificate chain with # Subject, # Issuer, and validity headers.

JSON output includes per-certificate trust_anchors and trust_warnings.

Probe SSH Flags

FlagDefaultDescription
--fips-140-2falseApply conservative FIPS 140-2 heuristic checks to advertised SSH algorithms
--fips-140-3falseApply conservative FIPS 140-3 heuristic checks to advertised SSH algorithms
--formattextOutput format: text, json

Port defaults to 22 if not specified.

Bundle Flags

FlagDefaultDescription
--allow-private-networkfalseAllow AIA fetches to private/internal endpoints
--force, -ffalseSkip chain verification
--formatpemOutput format: pem, chain, fullchain, p12, jks
--keyPrivate key file (PEM)
--out-file, -o(stdout)Output file
--trust-storemozillaTrust store: system, mozilla

Convert Flags

FlagDefaultDescription
--keyPrivate key file (PEM). Keys are matched to certificates automatically.
--out-file, -o(stdout for PEM)Output file (required for binary formats)
--to(required)Output format: pem, der, p12, jks, p7b

Input format is auto-detected.

Sign Self-Signed Flags

FlagDefaultDescription
--cn(required)Common Name for the certificate
--days3650Validity period in days
--is-catrueSet CA:TRUE basic constraint
--keyExisting private key file (generates EC P-256 if omitted)
--out-file, -o(stdout)Output file

Sign CSR Flags

FlagDefaultDescription
--ca(required)CA certificate file (PEM)
--ca-key(required)CA private key file (PEM)
--copy-sanstrueCopy SANs from CSR to issued certificate
--days365Validity period in days
--out-file, -o(stdout)Output file

Scan Flags

FlagDefaultDescription
--aia-timeout2sTimeout for AIA certificate fetches (e.g. 2s, 500ms)
--allow-private-networkfalseAllow AIA fetches to private/internal endpoints
--bundle-pathExport bundles to this directory
--config, -c./bundles.yamlPath to bundle config YAML
--dump-certsDump all discovered certificates to a single PEM file
--dump-keysDump all discovered keys to a single PEM file
--duplicatesfalseExport all certificates per bundle, not just the newest
--force, -ffalseAllow export of untrusted certificate bundles
--formattextOutput format: text, json
--load-dbLoad an existing database into memory before scanning
--max-file-size10485760Skip files larger than this size in bytes (0 to disable)
--save-dbSave the in-memory database to disk after scanning
--trust-storemozillaTrust store: system, mozilla

Keygen Flags

FlagDefaultDescription
--algorithm, -aecdsaKey algorithm: rsa, ecdsa, ed25519
--bits, -b4096RSA key size in bits
--cnCommon Name (triggers CSR generation)
--curveP-256ECDSA curve: P-256, P-384, P-521
--out-path, -o(stdout)Output directory
--sansComma-separated SANs (triggers CSR generation)

CSR Flags

FlagDefaultDescription
--algorithm, -aecdsaKey algorithm for generated keys
--bits, -b4096RSA key size in bits
--curveP-256ECDSA curve
--from-certPEM certificate to use as CSR template
--from-csrExisting PEM CSR to re-sign with a new key
--keyExisting private key file (PEM); generates new if omitted
--out-path, -o(stdout)Output directory
--templateJSON template file for CSR generation

Exactly one of --template, --from-cert, or --from-csr is required.

OCSP Flags

FlagDefaultDescription
--allow-private-networkfalseAllow OCSP fetches to private/internal endpoints
--formattextOutput format: text, json
--issuerIssuer certificate file (PEM); auto-resolved from input if omitted

The OCSP responder URL is read from the certificate’s AIA extension.

CRL Flags

FlagDefaultDescription
--checkCertificate file to check against the CRL
--formattextOutput format: text, json

Accepts local files (PEM or DER) or HTTP/HTTPS URLs.

Exit Codes

CodeMeaning
0Success
1General error (bad input, missing file, etc.)
2Validation failure (chain invalid, key mismatch, expired, revoked)

Bundle Configuration

Bundles are defined in a YAML file that maps certificate Common Names to named bundles. An optional defaultSubject provides fallback X.509 subject fields for CSR generation.

defaultSubject:
  country: [US]
  province: [California]
  locality: [San Diego]
  organization: [Company, Inc.]
  organizationalUnit: [DevOps]

bundles:
  - bundleName: examplecom-tls
    commonNames:
      - "*.example.com"
      - example.com

  - bundleName: exampleio-tls
    commonNames:
      - "*.example.io"
      - example.io
    subject: # overrides defaultSubject for this bundle
      country: [GB]
      province: [London]
      locality: [London]
      organization: [Company UK, Ltd.]
      organizationalUnit: [Platform Engineering]

Bundles without an explicit subject block inherit from defaultSubject. Certificate-to-bundle matching uses exact Common Name comparison against the commonNames list (a CN of *.example.com matches the literal wildcard string, not subdomains).

Bundle Output Files

When running certkit scan --bundle-path, each bundle produces the following files under <dir>/<bundleName>/. If --duplicates keeps older matching certificates, those extra exports are written under suffixed directories like <bundleName>_<RFC3339>_<serial>/:

FileContents
<cn>.pemLeaf certificate
<cn>.chain.pemLeaf + intermediates
<cn>.fullchain.pemLeaf + intermediates + root
<cn>.intermediates.pemIntermediate certificates
<cn>.root.pemRoot certificate
<cn>.keyPrivate key (PKCS#8 PEM, mode 0600). When an export password is supplied, contains an ENCRYPTED PRIVATE KEY block (PKCS#8 v2, PBES2/AES-256-CBC)
<cn>.p12PKCS#12 archive (uses first non-empty export password from --passwords / --password-file, or defaults to changeit with a warning, mode 0600)
<cn>.k8s.yamlKubernetes kubernetes.io/tls Secret (mode 0600)
<cn>.jsonCertificate metadata
<cn>.yamlCertificate and key metadata (mode 0600). When an export password is supplied, the key field contains an ENCRYPTED PRIVATE KEY block
<cn>.csrCertificate Signing Request
<cn>.csr.jsonCSR details (subject, SANs, key algorithm)

Wildcard characters in the CN are replaced with _ in filenames (e.g., *.example.com becomes _.example.com). The .intermediates.pem and .root.pem files are only created when those certificates exist in the chain.

Library

The certkit Go package provides reusable certificate utilities:

import "github.com/sensiblebit/certkit"

// Parse certificates and keys
certs, _ := certkit.ParsePEMCertificates(pemData)
key, _ := certkit.ParsePEMPrivateKey(keyPEM)

// Compute identifiers
fingerprint := certkit.CertFingerprint(cert)
colonFP := certkit.CertFingerprintColonSHA256(cert)  // AA:BB:CC format
ski := certkit.CertSKI(cert)

// Check expiry
if certkit.CertExpiresWithin(cert, 30*24*time.Hour) {
    // cert expires within 30 days
}

// Build verified chains (library defaults to mozilla trust store)
opts := certkit.DefaultOptions()
opts.TrustStore = "system" // override the default mozilla trust store if needed
bundle, _ := certkit.Bundle(ctx, certkit.BundleInput{Leaf: leaf, Options: opts})

// Generate keys
ecKey, _ := certkit.GenerateECKey(elliptic.P256())
rsaKey, _ := certkit.GenerateRSAKey(4096)

// Generate CSRs
csrPEM, keyPEM, _ := certkit.GenerateCSR(leaf, nil) // auto-generates EC P-256 key

// Sign certificates
selfSigned, _ := certkit.CreateSelfSigned(certkit.SelfSignedInput{Signer: caKey, Subject: pkix.Name{CommonName: "My CA"}, IsCA: true})
issued, _ := certkit.SignCSR(certkit.SignCSRInput{CSR: csr, CACert: caCert, CAKey: caKey, Days: 365, CopySANs: true})

// TLS connection probing
result, _ := certkit.ConnectTLS(ctx, certkit.ConnectTLSInput{Host: "example.com"})

// Revocation checking
ocspResp, _ := certkit.CheckOCSP(ctx, certkit.CheckOCSPInput{Cert: cert, Issuer: issuer})

// PKCS operations
p12, _ := certkit.EncodePKCS12(key, leaf, intermediates, "password")
p7, _ := certkit.EncodePKCS7(certs)
jks, _ := certkit.EncodeJKS(key, leaf, intermediates, "changeit")

// Encrypt a private key to PEM (PKCS#8 v2, PBES2/AES-256-CBC)
encPEM, _ := certkit.MarshalEncryptedPrivateKeyToPEM(key, "secret")

Scan Notes

Expired certificates are always ingested; expiry filtering is output-only (--allow-expired overrides). SKI computation uses RFC 7093 Method 1 (SHA-256 truncated to 160 bits). Non-root issuer linkage is resolved after ingestion by checking for raw ASN.1 subject/issuer matches among CA certificates and falling back to AIA fetching when the issuer is still missing.

  • mkchain (OSS) — the older, narrower shell cousin (383★, GPL-3, last pushed 2024-11): builds a valid SSL chain from provided PEMs; certkit covers the same ground in Go plus inspect/convert/scan/sign