OpenSSL: TLS Certificate Verification and Parsing in CLI
Certificates expiring on prod at the worst moment — a familiar story. OpenSSL answers TLS certificate questions faster than any marketplace checker. Here are the key scenarios without the fluff.
Basic Certificate Parsing
The first command for any diagnostics is the text dump:
Output shows Subject, Issuer, validity dates, signature algorithm, and public key. For a quick summary without the wall of text:
The -in flag accepts a file path. Certificates downloaded from browsers usually come in PEM or DER format. OpenSSL handles both, but DER requires an extra flag:
-noout suppresses the base64 block from output. Useful when you need only structured data, not a copy of the certificate.
Expiration: dates and Overdue Checks
For monitoring, getting only the dates is more convenient:
Typical output:
For automation, extracting the timestamp and calculating the difference is cleaner:
If days_left is negative, the certificate has already expired.
For checking multiple hosts from inventory, a one-liner works well:
-servername sends SNI — without it some hosts return the default certificate.
Chain Verification: s_client and verify
Connect and display certificates:
Output includes the chain from leaf certificate to root CA. To filter certificates only:
Verify chain against the system store:
If verification fails with error 20 at 0 depth lookup, the intermediate CA is missing. A common cause is incorrect chain configuration on the server.
openssl verify uses the system store by default. In Ubuntu this is /etc/ssl/certs/ca-certificates.crt, in Alpine it is a separate ca-certificates package. If verification fails, check that the package is installed.
Quick check without saving to file:
Output Verify return code: 0 (ok) means success.
To stay out of interactive mode and fail the process on a bad chain:
Force a protocol or cipher when you need to confirm the server still accepts a specific handshake:
For an internal CA, pass the bundle explicitly. Without -CAfile, a private PKI typically returns Verify return code: 21 (unable to get local issuer certificate):
Extracting CN and SAN
Common Name extracts directly:
But CN has not been sufficient for years — modern certificates use Subject Alternative Names (SAN). OpenSSL 1.1.1+ pulls them cleanly:
Output:
To get only the DNS names:
If SAN is missing (old certificate), browsers fall back to CN. When checking API endpoints, this explains why curl complains but the browser opens the page.
Comparing Expiration Across Multiple Hosts
A script for checking a host list serves as a practical monitoring foundation:
Typical output:
Negative values are expired certificates. In production, wrapping this in cron with chat notifications at a 30-day threshold is practical.
Quick Flag Reference
| Command | Flag | Purpose |
|---|---|---|
x509 | -text | Full text dump |
x509 | -noout | Suppress base64 block |
x509 | -dates | NotBefore, NotAfter |
x509 | -subject | Subject (CN, O, OU) |
x509 | -issuer | Issuing CA |
x509 | -fingerprint -sha256 | Certificate fingerprint |
x509 | -enddate | Expiration date only |
x509 | -ext subjectAltName | Alternative names |
s_client | -connect host:port | TLS connection |
s_client | -servername name | SNI (required for vhost) |
s_client | -showcerts | Display full chain |
s_client | -quiet | Skip interactive mode |
s_client | -tls1_2 / -tls1_3 | Force a TLS version |
s_client | -verify_return_error | Non-zero exit on validation failure |
verify | -CAfile path | Trusted CA file |
verify | -partial_chain | Accept partial chain |
openssl s_client does more than read certificates. With -starttls smtp or -starttls pop3 it checks mail servers. -http retrieves HTTP headers over TLS. Useful for diagnosing miTM filters.
All commands work out of the box in any Linux distribution. No dependencies beyond OpenSSL itself — the tool is present on every server. If missing, install in seconds: apt install openssl or apk add openssl.