OpenSSL Cheatsheet

Inspecting Certificates

Use this OpenSSL reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Full decode

x509 reads a certificate and prints whatever you ask for. -noout suppresses the re-encoded PEM, which you almost always want.

openssl x509 -in cert.pem -noout -text          # everything, human readable
openssl x509 -in cert.pem -noout -text -certopt no_sigdump,no_pubkey
openssl x509 -in cert.der -inform DER -noout -text

-certopt trims the noise. Useful values: no_sigdump (drop the signature hex), no_pubkey (drop the key hex), no_header, no_version, no_serial, no_validity, no_extensions, compatible (drop almost everything).

The one-field questions

Each of these is a single line of output, so they compose into scripts.

CommandPrints
-subjectsubject=CN=example.com
-issuerissuer=C=US, O=Let's Encrypt, CN=R11
-datesboth notBefore= and notAfter=
-startdate / -enddateone date each
-serialserial=03A1... uppercase hex
-fingerprint -sha256colon-separated SHA-256 of the DER
-pubkeythe public key as PEM
-modulusModulus=A747..., RSA only
-purposewhich chain purposes this cert is valid for
-subject_hashthe 8 hex digits CApath symlinks use
-ext NAMEjust the named extensions
$ openssl x509 -in cert.pem -noout -dates
notBefore=Sep 16 02:06:48 2026 GMT
notAfter=Dec 15 02:06:47 2026 GMT

$ openssl x509 -in cert.pem -noout -fingerprint -sha256
sha256 Fingerprint=76:AD:5E:60:37:4B:95:8F:31:9E:26:46:03:DF:AE:9D:...

Extensions

-ext takes a comma separated list of extension names and prints only those. This is the fast way to answer "does it cover the hostname".

openssl x509 -in cert.pem -noout -ext subjectAltName
openssl x509 -in cert.pem -noout -ext basicConstraints,keyUsage
openssl x509 -in cert.pem -noout -ext extendedKeyUsage
openssl x509 -in cert.pem -noout -ext authorityInfoAccess   # OCSP and CA URLs
openssl x509 -in cert.pem -noout -ext crlDistributionPoints
X509v3 Subject Alternative Name:
    DNS:example.com, DNS:www.example.com, IP Address:10.0.0.5

Expiry checks

-checkend N exits 0 if the certificate is still valid N seconds from now and 1 if it is not, so it drops straight into a cron job or a health check.

openssl x509 -in cert.pem -noout -checkend 0          # expired right now?
openssl x509 -in cert.pem -noout -checkend 2592000    # within 30 days?

if ! openssl x509 -in cert.pem -noout -checkend 604800; then
  echo "cert expires within a week"
fi

Straight off a live host, no file needed:

openssl s_client -connect example.com:443 -servername example.com \
  </dev/null 2>/dev/null |
  openssl x509 -noout -subject -dates

Verify a chain

verify walks the chain and reports the first failure. -CAfile is the root you trust, -untrusted holds the intermediates.

openssl verify -CAfile ca.crt cert.pem
openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem
openssl verify -CAfile ca.crt -show_chain cert.pem
openssl verify -CAfile ca.crt -verify_hostname example.com cert.pem
openssl verify -CAfile ca.crt -purpose sslserver cert.pem
cert.pem: OK
Error textReal cause
unable to get local issuer certificateMissing intermediate, pass -untrusted
self-signed certificateLeaf is self-signed, no CA above it
self-signed certificate in certificate chainRoot not in -CAfile
certificate has expirednotAfter is in the past
certificate is not yet validClock skew, or notBefore in the future
unsupported certificate purposeMissing serverAuth in EKU
Hostname mismatchName is not in the SAN list

A server-side chain file is leaf first, then intermediates, root omitted:

cat cert.pem intermediate.pem > fullchain.pem
openssl crl2pkcs7 -nocrl -certfile fullchain.pem |
  openssl pkcs7 -print_certs -noout      # list what is in a bundle

Does this key match this cert

Compare public key digests. This works for every algorithm, unlike the classic -modulus trick, which is RSA only.

openssl x509 -in cert.pem -noout -pubkey | openssl sha256
openssl pkey -in key.pem  -pubout       | openssl sha256
openssl req  -in req.csr  -noout -pubkey | openssl sha256

Three identical digests means key, CSR, and certificate agree. The RSA-only version people still paste around:

openssl x509 -in cert.pem -noout -modulus | openssl md5
openssl rsa  -in key.pem  -noout -modulus | openssl md5

Gotchas

- -noout is not optional in scripts. Without it the PEM body lands in your output and breaks whatever parses the line. - verify still loads the system trust store unless you pass -no-CAfile -no-CApath -no-CAstore. A cert can pass because a public root is trusted, not because your -CAfile matched. - verify checks the chain, not the hostname, unless you add -verify_hostname. That is the mistake behind "openssl says OK but the browser complains". - Dates print in GMT in MMM D HH:MM:SS YYYY GMT form, which no date parser likes. On GNU coreutils, date -d "$(openssl x509 ... -enddate | cut -d= -f2)" normalizes it. - -modulus on an EC certificate errors out. Use -pubkey. - A certificate that is text-dumped and re-saved keeps only the PEM block. Anything above -----BEGIN CERTIFICATE----- is ignored by OpenSSL but not by every other parser, so strip it for portability.