Inspecting certificates
Reading TLS certificates from the command line with openssl
Why inspect certificates at all?
Your browser inspects certificates automatically and shows a padlock if everything looks good. But as a developer you'll sometimes need to go deeper - debugging a cert that isn't being trusted, checking expiry dates, verifying the certificate chain is correct, or confirming which CA issued a cert. The browser UI surfaces almost none of this. The command line does.
The main tool is openssl - it ships with macOS and most Linux distributions. You almost certainly already have it.
Connecting to a server and reading its certificate
openssl s_client opens a raw TLS connection to a server and prints everything about the handshake - the full certificate chain, the cipher suite negotiated, the TLS version, and whether the cert validated successfully.
openssl s_client -connect example.com:443
The output is verbose. The useful parts:
- Certificate chain - each cert in the chain, from your site's cert up to the root CA.
- subject - the domain the cert is issued to.
- issuer - the CA that signed it.
- Verify return code: 0 (ok) - means the chain validated. Any non-zero code means something is wrong.
Add -servername if the server uses SNI (Server Name Indication) - which most do, since many servers host multiple domains on one IP:
openssl s_client -connect example.com:443 -servername example.com
Reading the certificate details
Pipe the output of s_client into openssl x509 to parse the certificate itself and print it in human-readable form:
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \ | openssl x509 -noout -text
This prints everything: the subject, issuer, validity window, Subject Alternative Names (the full list of domains the cert covers), the public key, the signature algorithm, and more. Usually more than you need. For just the bits you care about:
# Just the expiry dates openssl s_client -connect example.com:443 2>/dev/null \ | openssl x509 -noout -dates # Just the domains the cert covers openssl s_client -connect example.com:443 2>/dev/null \ | openssl x509 -noout -ext subjectAltName # Subject and issuer only openssl s_client -connect example.com:443 2>/dev/null \ | openssl x509 -noout -subject -issuer
Inspecting a certificate file directly
If you have a .pem or .crtfile on disk (e.g. one you've downloaded or that your server is configured to use), you can inspect it directly without making a network connection:
openssl x509 -in certificate.pem -noout -text
Same flags apply - -dates, -subject, -issuer etc. Useful for checking a cert before deploying it, or verifying a cert your infrastructure tooling has provisioned.
Checking expiry in scripts
One practical use: a quick shell script to alert you if a cert is expiring soon. -checkend takes a number of seconds and exits non-zero if the cert expires within that window:
# Exit code 1 if cert expires within 14 days (1209600 seconds) openssl s_client -connect example.com:443 2>/dev/null \ | openssl x509 -noout -checkend 1209600
Wrap this in a cron job or monitoring check and you'll never be surprised by an expired cert again.
Checking TLS version and cipher suite
The s_client output also tells you what TLS version and cipher suite was negotiated. Look for lines like:
Protocol : TLSv1.3 Cipher : TLS_AES_128_GCM_SHA256
You can also force a specific TLS version to test whether a server still accepts it - useful for confirming old versions are disabled:
# Test if TLS 1.1 is still accepted (it shouldn't be) openssl s_client -connect example.com:443 -tls1_1
A correctly configured server will refuse the connection. If it succeeds, the server needs updating.