Skip to content

Repository files navigation

sslcheck

Fetch a host's TLS certificate and check it against its CRL(s) — fast, concurrent, and scriptable.

$ sslcheck example.com
SERIAL                            TARGET       ISSUER                                    STATUS  EXPIRES     NOTE
1AA73FEA257BE3334B9A29552E6F878E  example.com  CN=Cloudflare TLS Issuing ECC CA 3,O=SS…  OK      2026-08-29

Install

Homebrew (macOS/Linux)

brew install --cask auth-it-center/tap/sslcheck

Debian/Ubuntu 22.04 "jammy" (apt)

sslcheck is published into our shared jammy apt-hosted repo on Nexus alongside other internal packages (not a repo of its own). Get the exact deb line and signing key from Nexus's repo summary page — the codename and component below may not match your instance:

curl -fsSL https://packages02.it.auth.gr/repository/jammy/pubkey.asc \
  | sudo tee /etc/apt/keyrings/it-auth-gr.asc > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/it-auth-gr.asc] https://packages02.it.auth.gr/repository/jammy jammy main" \
  | sudo tee /etc/apt/sources.list.d/it-auth-gr.list
sudo apt update
sudo apt install sslcheck

Fedora/RHEL/CentOS (dnf/yum)

sslcheck is published into its own yum-hosted repo on Nexus, yummy ($basearch below resolves automatically to x86_64 or aarch64):

sudo tee /etc/yum.repos.d/sslcheck.repo > /dev/null <<'EOF'
[sslcheck]
name=sslcheck
baseurl=https://packages02.it.auth.gr/repository/yummy/$basearch/
enabled=1
gpgcheck=0
EOF
sudo dnf install sslcheck

Direct download

Grab the tarball, .deb, or .rpm for your OS/arch from the Releases page and either install the package directly or extract the tarball and put the sslcheck binary on your PATH:

tar -xzf sslcheck_Darwin_arm64.tar.gz    # or the Linux/x86_64 tarball, etc.
sudo mv sslcheck /usr/local/bin/

macOS only: since sslcheck isn't Apple-signed/notarized, a tarball downloaded via a browser (or anything else that sets the quarantine attribute) will get Gatekeeper-blocked the first time you run it — "Apple could not verify 'sslcheck' is free of malware...". Clear the quarantine flag once, after extracting:

xattr -d com.apple.quarantine sslcheck

(The Homebrew Cask install path handles this automatically via a postflight hook — this manual step is only needed for direct tarball downloads.)

Every release also publishes checksums.txt and checksums.txt.sigstore.json — a Sigstore keyless signature bundle produced by the release workflow itself. There's no public key to fetch or import: cosign checks the bundle's certificate against the public Rekor transparency log and confirms it was signed by this exact GitHub Actions workflow:

cosign verify-blob checksums.txt \
  --bundle checksums.txt.sigstore.json \
  --certificate-identity-regexp "^https://github\.com/auth-it-center/sslcheck/\.github/workflows/release\.yml@refs/tags/.*$" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

sha256sum --check --ignore-missing checksums.txt

From source

go install github.com/auth-it-center/sslcheck@latest

Usage

sslcheck [flags] host [host...]
sslcheck [flags] -f hosts.txt
cat hosts.txt | sslcheck [flags]
sslcheck [flags] -incert cert.pem

Targets may be bare hostnames, host:port, or full URLs:

sslcheck example.com
sslcheck example.com:8443 internal.example.org
sslcheck https://example.com/whatever

Flags can go anywhere on the command line, not just before the targets — sslcheck example.com -json works the same as sslcheck -json example.com. Short flags also accept an attached value (-c4 as well as -c 4).

Or feed it a list (blank lines and #-comments are ignored):

cat hosts.txt | sslcheck -json -c 20

Or read targets from one or more files with -f/-file (comma-separated for multiple files; combine freely with targets given on the command line):

sslcheck -f hosts.txt
sslcheck -f hosts.txt,more-hosts.txt extra.example.com

Or validate certificate(s) already on disk with -incert (comma-separated, PEM or DER; a chain bundle's leading cert is treated as the leaf), skipping the network handshake entirely:

sslcheck -incert cert.pem
sslcheck -incert cert.pem,chain.pem

Flags

Flag Default Description
-c 10 number of concurrent workers
-timeout 8s per-connection / CRL-fetch timeout
-port 443 default port when a target doesn't specify one
-file read targets from file(s) (comma-separated)
-f shorthand for -file
-incert validate certificate(s) from local file(s) (comma-separated, PEM or DER) instead of connecting over the network
-json false output JSON instead of a table
-strict false require a valid TLS chain before inspecting the cert (default: fetch regardless)
-starttls false upgrade to TLS via STARTTLS instead of an implicit handshake (SMTP/IMAP/POP3/FTP/LDAP; dialect inferred from the port — see STARTTLS)
-revoked false display only targets that are revoked or that errored out
-noout false narrow output to just the fields selected below (same table/JSON shape, fewer columns/keys)
-subject false certificate subject (extra column; also selectable under -noout)
-issuer false certificate issuer (shown by default; also selectable under -noout)
-serial false certificate serial number (shown by default; also selectable under -noout)
-san false certificate Subject Alternative Names (extra column; also selectable under -noout)
-startdate false certificate notBefore date (extra column; also selectable under -noout)
-enddate false certificate notAfter date (extra column; also selectable under -noout)
-status false target status (shown by default; also selectable under -noout)
-notes false result note (shown by default; also selectable under -noout)

Selecting specific fields

By default the table always shows SERIAL/TARGET/ISSUER/STATUS/EXPIRES/NOTE. -subject, -san, -startdate, and -enddate append extra columns to that same table when passed on their own:

$ sslcheck example.com -san
SERIAL                            TARGET       ISSUER                                    STATUS  EXPIRES     NOTE  SAN
1AA73FEA257BE3334B9A29552E6F878E  example.com  CN=Cloudflare TLS Issuing ECC CA 3,O=SS…  OK      2026-08-29        example.com,*.example.com

A certificate with multiple SANs gets one per line, right under that row, without disturbing the table's column alignment:

$ sslcheck example.com -san
SERIAL                            TARGET       ISSUER                                    STATUS  EXPIRES     NOTE  SAN
1AA73FEA257BE3334B9A29552E6F878E  example.com  CN=Cloudflare TLS Issuing ECC CA 3,O=SS…  OK      2026-08-29        example.com
                                                                                                                     *.example.com

Add -noout to narrow the table down to only the fields you select — it's still a table (and still a -json array if you pass both), just with fewer columns/keys, mirroring openssl x509 -noout -subject -issuer:

$ sslcheck -noout -subject -issuer example.com
TARGET       SUBJECT         ISSUER
example.com  CN=example.com  CN=Cloudflare TLS Issuing ECC CA 3,O=SSL Corporation,C=US

-noout with no fields selected shows only TARGET.

STARTTLS

Some protocols (SMTP, IMAP, POP3, FTP, LDAP) start out in plaintext and switch to TLS mid-connection rather than negotiating TLS immediately like HTTPS does. Pass -starttls to do that upgrade instead of an implicit TLS handshake; the specific dialect is inferred from the target's port:

Port Protocol
25, 587 SMTP
143 IMAP
110 POP3
21 FTP
389 LDAP
sslcheck -starttls smtp.example.org:587

To override the protocol for just one target regardless of -starttls, append :starttls (force the plaintext-upgrade dance) or :tls (force an implicit TLS handshake) to that target:

sslcheck smtp.example.org:587:starttls ldaps.example.org:636:tls

JSON output

$ sslcheck -json example.com
[
  {
    "target": "example.com",
    "host": "example.com",
    "subject": "CN=example.com",
    "issuer": "CN=Cloudflare TLS Issuing ECC CA 3,O=SSL Corporation,C=US",
    "serial": "1aa73fea257be3334b9a29552e6f878e",
    "sans": [
      "example.com",
      "*.example.com"
    ],
    "not_before": "2026-05-31T21:39:12Z",
    "not_after": "2026-08-29T21:41:26Z",
    "crl_urls": [
      "http://c.cf-i.ssl.com/ae801ed1c55bb579d79208b0d772acfb8cc3a208.crl"
    ],
    "crl_checked": true,
    "revoked": false
  }
]

Exit codes

Useful for scripting/monitoring — checks all targets, then exits with the highest-severity result across all of them:

Code Meaning
0 all targets OK
1 at least one target errored (unreachable, TLS failure, CRL fetch failure, ...)
2 at least one target's certificate is revoked

-revoked only filters what's displayed — the exit code still reflects every target checked, revoked/errored or not.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages