Skip to the tool workspace
Browser 123

How-to Keys and encryption

How to read what is actually in an SSL certificate

Read a certificate with openssl: the names it covers, when it expires, who issued it, its key and its fingerprint. Fetch a live site's chain, check expiry in a script, and convert PEM and DER.

A certificate is a small signed file that says which names a server may use, for which dates, and who vouches for it. When something breaks (a browser warning, a renewal that didn't take, a monitor that disagrees with you), the answer is almost always in five fields: the alternative names, the two dates, the issuer, the key, and the fingerprint. Here is how to read each of them.

The SSL Certificate Viewer after Read certificate: a Certificate card with a Valid chip and the days left, a validity bar with the two dates, the subject and issuer fixture.browserbasedtools.test, its subject alternative names and the public key

A certificate read in the browser: whether it is in date first, then who it is for.

The direct wayOpenSSLLinux · macOS · Windows (Git Bash)

One command prints everything in the file:

openssl x509 -in cert.pem -noout -text

And this one prints only the fields that usually matter:

openssl x509 -in cert.pem -noout -subject -issuer -dates \
    -ext subjectAltName -fingerprint -sha256

-noout stops it printing the certificate back at you. The rest of this guide goes through what each line means. On a Mac, read the note below first: the openssl that comes with macOS is older and has no -ext.

Get the certificate from a live site

If the certificate is on a server rather than in a file, ask the server for it. s_client opens a TLS connection and prints what the server sends:

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

-servername matters: one IP address often serves many sites, and without it you can get a different site's certificate. </dev/null closes the connection as soon as the handshake is done. This is what example.com sent on 18 October 2026 (OpenSSL 3.5.7), trimmed to the summary lines:

Certificate chain
 0 s:CN=example.com
   i:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
   a:PKEY: EC, (prime256v1); sigalg: ecdsa-with-SHA256
   v:NotBefore: Sep 26 22:49:11 2026 GMT; NotAfter: Dec 25 22:56:35 2026 GMT
 1 s:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
   i:C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2
...
Verify return code: 0 (ok)

Each certificate's s: (subject) is the next one's i: (issuer). That is the chain: the site's own certificate at 0, then the intermediates that vouch for it. Verify return code: 0 (ok) means OpenSSL followed that chain to a root it trusts. Any other code names what broke, and a missing intermediate is the usual one.

To read only the site's own certificate, pipe it straight into x509:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
subject=CN=example.com
issuer=C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
notBefore=Sep 26 22:49:11 2026 GMT
notAfter=Dec 25 22:56:35 2026 GMT
X509v3 Subject Alternative Name: 
    DNS:example.com, DNS:*.example.com

To keep the whole chain as a file, save the s_client -showcerts output and cut out the certificate blocks:

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
  | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' > chain.pem

For example.com that file held four certificates. Drop it on the SSL Certificate Viewer and each one gets its own card, in order.

The SSL Certificate Viewer with the four-certificate chain example.com served on 18 October 2026: the first card reads 1 of 4 in this file, for example.com, issued by Cloudflare TLS Issuing ECC CA 3, with the names example.com and *.example.com and an EC P-256 key

A saved chain: one card per certificate, the site's own first.

What to read, and why

The names: subject alternative names, not the common name

openssl x509 -in cert.pem -noout -ext subjectAltName
X509v3 Subject Alternative Name: 
    DNS:fixture.browserbasedtools.test, DNS:www.fixture.browserbasedtools.test, IP Address:127.0.0.1, email:[email protected]

This list is what a browser checks the address against. The common name (CN= in the subject) is ignored by browsers, so a certificate can have the right CN and still fail. A wildcard covers one label only: *.example.com matches www.example.com, not a.b.example.com and not example.com itself. OpenSSL will check a name for you:

openssl x509 -in example-com.pem -noout -checkhost www.example.com
Hostname www.example.com does match certificate

For a.b.example.com the same command prints does NOT match and exits with 1.

The dates

openssl x509 -in cert.pem -noout -dates
notBefore=Sep  6 06:05:24 2026 GMT
notAfter=Sep  3 06:05:24 2036 GMT

Both are in UTC. Public certificates now last months, not years: the example.com one above runs 90 days. To ask "does it expire within 30 days?" in a script, use -checkend with seconds (30 × 86400 = 2592000):

openssl x509 -in cert.pem -noout -checkend 2592000
Certificate will not expire

It exits with 0 when the certificate outlasts the window and 1 when it doesn't, so openssl x509 -in cert.pem -noout -checkend 2592000 || echo "renew it" works as a cron check. Put the s_client pipe in front to check a live site instead of a file.

The issuer

openssl x509 -in cert.pem -noout -subject -issuer

When the subject and the issuer are the same, the certificate is self-signed, as our test certificate is. That is normal for a root or an internal test server, and a browser warning on a public site. When they differ, the issuer is the next certificate up the chain, and the server has to send it too.

The key

openssl x509 -in cert.pem -noout -text | grep -E "Public Key Algorithm|Public-Key"
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)

RSA 2048 or larger, or an elliptic curve key (id-ecPublicKey, Public-Key: (256 bit), NIST CURVE: P-256 for example.com). Both are fine today. The key type matters when a client is old enough not to support EC, or when your private key and certificate don't belong together.

The fingerprint

openssl x509 -in cert.pem -noout -fingerprint -sha256
sha256 Fingerprint=12:5C:41:9D:B3:66:57:4A:AC:B5:26:DE:E7:49:5F:F1:F9:AF:15:23:64:9E:62:4F:BA:E3:B0:08:69:ED:0C:B4

A hash of the whole certificate. Two files with the same SHA-256 fingerprint are the same certificate, which is the quickest way to prove the server is serving the one you installed. Leave out -sha256 and you get SHA-1, which is a different string for the same certificate. The browser viewer shows both, without the colons, and copies them as one unbroken run.

On a Mac

/usr/bin/openssl on macOS 26.5 is LibreSSL 3.3.6. It reads certificates fine but has no -ext (unknown option -ext), needs -inform der for a DER file, and -checkend prints nothing (the exit code still works). For the names, use openssl x509 -in cert.pem -noout -text | grep -A1 "Subject Alternative Name", or install OpenSSL 3 with Homebrew. To look without a terminal, select the file in Finder and press Space: Quick Look has a certificate previewer built in. Double-clicking the file hands it to Keychain Access, which is for adding certificates to a keychain, more than you need to read one.

PEM, DER, .crt and .cer

The same certificate comes in two encodings. PEM is text, starting -----BEGIN CERTIFICATE-----, and one file can hold a whole chain. DER is the same bytes in binary, one certificate per file. The extensions .crt and .cer are used for both, so open the file in a text editor to tell: readable BEGIN line, PEM; gibberish, DER.

OpenSSL 3 detects DER on input by itself. With LibreSSL, or to be explicit, add -inform der:

openssl x509 -in cert.der -inform der -noout -subject

To convert, name the output format. PEM to DER:

openssl x509 -in cert.pem -outform der -out cert.der

DER to PEM:

openssl x509 -in cert.der -inform der -out cert.pem

Our test certificate went from 1,692 bytes of PEM to 1,207 bytes of DER, and back to a PEM file identical to the original (cmp found no difference). openssl x509 converts only the first certificate in a file; for a chain, use the browser converter, which converts every block.

Read one in the browser

  1. Open the SSL Certificate Viewer and drop the .pem, .crt, .cer or .der file on it, or paste the PEM text into the Certificate box.
  2. Click Read certificate.
  3. Read the chip at the top: Valid with the days left, Expires soon inside 30 days, Expired or Not valid yet. The dates under it are in UTC, the same as openssl prints.
  4. Check Subject alternative names for every hostname you need, then the Issuer, the Public key and the SHA-256 fingerprint. Copy puts a fingerprint on the clipboard without colons.

What it doesn't do, and says so on the page: it builds no chain, checks no trust store, no revocation and no hostname. "Valid" means today falls between the two dates, not that a browser would accept the certificate. For that, run the s_client command above and read the verify code.

Which to use

  • A live site: openssl s_client ... | openssl x509 -noout -subject -issuer -dates -ext subjectAltName. It also tells you whether the chain verifies, which nothing that reads a file can.
  • Expiry in a script or a cron job: -checkend and its exit code.
  • A file someone sent you, no OpenSSL to hand: the SSL Certificate Viewer. Every name, both dates in UTC, the key and both fingerprints, without uploading the file.
  • A chain you need to sort into leaf, intermediate and root: save it as one PEM and drop it on the viewer; each card says its place in the file, and each subject is the issuer on the card above it.

When the SAN list covers your hostnames, the dates are in range and the fingerprint matches what you installed, the certificate is the right one. If the browser still complains, it is the chain or the server configuration, and the s_client verify code is where to look next.

Questions people ask

The common name is right but the browser still says the name doesn't match. Why?

Browsers check the hostname against the subject alternative names and ignore the common name. A certificate whose CN is shop.example.com but whose SAN list doesn't include it fails in every current browser. Read the SAN list, or run openssl x509 -noout -checkhost shop.example.com, which answers match or no match.

Does *.example.com cover example.com and a.b.example.com?

Neither. A wildcard covers exactly one label: www.example.com matches, a.b.example.com doesn't, and example.com itself needs its own SAN entry. That is why most certificates list both example.com and *.example.com.

My .crt file won't open. Is it PEM or DER?

The extension doesn't say. Open it in a text editor: if it starts with -----BEGIN CERTIFICATE----- it is PEM, and if it is unreadable binary it is DER. OpenSSL 3 reads both without being told; the older LibreSSL on a Mac needs -inform der for DER.

Which fingerprint should I compare, SHA-1 or SHA-256?

SHA-256, which is what browsers, CT logs and pinning configs show today. Compare it with whatever your CA or monitor reports; colons and case don't matter. openssl prints SHA-1 when you ask for -fingerprint without naming a digest, which is why two people comparing can disagree.

Does a valid date range mean the certificate is trusted?

No. The dates only say the certificate hasn't expired. Trust also needs a chain to a root your system holds, the right hostname and no revocation. openssl s_client checks the chain and prints Verify return code: 0 (ok) when it holds; reading the certificate alone checks none of it.

Tools in this guide

Everything runs on your device

All guides

/
123 items
Runs in your browser·Your files stay on this device
Out0 B
Ready—