Most TLS outages I have been called into did not start with a dramatic key leak. They started with a certificate someone never really read: a missing Subject Alternative Name, an incomplete chain file, a leaf that looked fine in a browser on one machine and failed everywhere else. Browser UIs hide the details. openssl x509 -text does not. Once you can walk a certificate by hand, half of "SSL is broken" tickets become a five-minute diagnosis instead of a day of guessing.
I wrote this with help from AI tools and checked every command and example myself against current OpenSSL behaviour. I build PixelValut, a set of free browser-based developer and network tools, and this is Part 2 of the series on Web PKI and certificate forensics. Part 1 covered leaked private keys and rotation. Here we slow down and learn to read what a certificate actually asserts.
📚 Series Roadmap — Web PKI & Certificate Forensics in Practice
- Part 1: Leaked TLS Private Keys: Proving Compromise, Finding Every Affected Cert & Rotating Safely
- Part 2 (This Post): Reading X.509 Certificates by Hand: SANs, Key Usage, Chains & Intermediates
- Part 3: Certificate Revocation in 2026: CRLs, the Decline of OCSP & Short-Lived Certificates
- Part 4: Certificate Transparency Monitoring: Catching Unexpected Certificates for Your Domains
- Part 5: ACME Automation Failures: Renewal Outages, Rate Limits & DNS-01 Pitfalls
- Part 6: Mutual TLS for Internal APIs: Private CAs, Rotation & Pinning Trade-offs
How do you read an X.509 TLS certificate by hand?
Direct answer: Dump the leaf with openssl x509 -text, confirm Subject and Issuer, verify every hostname lives in the Subject Alternative Name extension, check Key Usage and Extended Key Usage for server auth, then walk the chain until you reach a trusted root. Most production failures are a missing intermediate or a hostname that never made it into the SAN list.
Pull the leaf and read it
Fetch what the server actually presents, not what you think is on disk:
openssl s_client -connect example.com:443 -servername example.com \ -showcerts </dev/null 2>/dev/null \ | openssl x509 -noout -text Or inspect a PEM file from your load balancer:
openssl x509 -in leaf.pem -noout -text You want the same fields every time. An SSL certificate checker is useful for a quick browser-side view of issuer, SANs and expiry; the OpenSSL dump is what you use when you need exact extension flags.
Subject and Issuer
Subject: CN = example.com Issuer: C = US, O = Let's Encrypt, CN = R11 Subject is who the certificate claims to be. Issuer is who signed it. For publicly trusted TLS, the Issuer is almost always an intermediate, not the root. If Subject and Issuer are identical, you are looking at a self-signed certificate, which is fine for lab work and wrong for a public site.
SAN vs CN (the hostname trap)
Browsers and modern clients match hostnames against the Subject Alternative Name (SAN) extension, not against the Common Name. A certificate with CN=example.com and no SAN will fail hostname verification in current clients even when the CN "looks right."
openssl x509 -in leaf.pem -noout -ext subjectAltName Expect something like:
X509v3 Subject Alternative Name: DNS:example.com, DNS:www.example.com If api.example.com is missing from that list, clients talking to api.example.com will reject the certificate regardless of how clean the chain looks. Wildcard SANs (DNS:*.example.com) cover one label only; they do not cover a.b.example.com.
Key Usage and Extended Key Usage
These extensions constrain what the key is allowed to do:
openssl x509 -in leaf.pem -noout -ext keyUsage,extendedKeyUsage For a public HTTPS leaf you typically want:
| Extension | Expected on HTTPS leaf | Red flag |
|---|---|---|
| Key Usage | Digital Signature, Key Encipherment (RSA) or Digital Signature (ECDSA) | Certificate Sign / CRL Sign on a leaf |
| Extended Key Usage | TLS Web Server Authentication | Client Auth only, or empty when a client enforces EKU |
| basicConstraints | CA:FALSE | CA:TRUE on a leaf (mis-issued or wrong file) |
A leaf marked CA:TRUE is either a serious CA mistake or, more often, you opened an intermediate by accident and thought it was the site certificate.
basicConstraints and path length
openssl x509 -in intermediate.pem -noout -ext basicConstraints Intermediates should say CA:TRUE. Leaves should say CA:FALSE or omit CA entirely depending on profile. PathLen constraints on intermediates limit how deep a chain may go; you rarely edit these by hand, but you need to recognize them when a private CA chain fails to validate.
Building and verifying the chain
TLS clients need a path from the leaf to a trust anchor they already have. Servers must send the leaf and every intermediate. They should not send the root; clients already have roots.
# Show the full chain the server sends openssl s_client -connect example.com:443 -servername example.com \ -showcerts </dev/null 2>/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' Verify locally once you have leaf + intermediates in one PEM:
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \ -untrusted intermediates.pem leaf.pem -untrusted is where intermediates go. If verification fails with "unable to get local issuer certificate," the usual cause is a missing intermediate in what you serve, not a broken root store.
| Setup | What client receives | Typical symptom |
|---|---|---|
| Leaf only | Site cert, no intermediate | Works on some Android/desktop caches, fails elsewhere |
| Leaf + correct intermediate | Complete path to a public root | Clean verify |
| Leaf + wrong intermediate | Chain that does not link | unable to get local issuer certificate |
| Leaf + intermediate + root | Extra root in handshake | Usually tolerated; wastes bytes; some scanners warn |
| Expired intermediate | Path that ends early | Sudden multi-region outage after a quiet period |
Missing intermediates are still one of the most common production TLS failures, especially after a manual renewal where someone uploaded only cert.pem and forgot fullchain.pem.
Good vs broken setups at a glance
| Check | Healthy | Broken |
|---|---|---|
| Hostname | Appears in SAN | Only in CN, or wrong name |
| Chain | Leaf + intermediates, no required root | Leaf alone |
| EKU | Server Auth present | Missing where policy requires it |
| Not After | Days or weeks of validity left | Expired, or expires tonight with no automation |
| Signature | SHA-256 (or stronger) with expected key type | Legacy MD5/SHA-1 on anything public |
| Key size | RSA ≥ 2048 or P-256/P-384 ECDSA | RSA 1024 |
For a related attack surface where DNS and certificates interact, see the earlier note on dangling DNS and certificate reconnaissance. Wrong SANs also show up there when an abandoned hostname still has a live certificate.
Diagnostic checklist
- Does
openssl s_clientshow the certificate you expect for this hostname? - Is every served hostname listed in Subject Alternative Name?
- Is Issuer an intermediate you recognize, not a mystery private CA on a public site?
- Is
basicConstraintsCA:FALSE (or equivalent) on the leaf? - Do Key Usage / EKU allow server authentication?
- Does the server send intermediates (
fullchain), not leaf-only? - Does
openssl verifysucceed with your platform trust store? - Are Not Before / Not After in a sensible window (clock skew included)?
- Does the public key type and size match your policy?
- Did you compare the live handshake to the files on disk after the last deploy?
Browse more developer TLS and network tools when you need a second view without pasting private keys anywhere.
FAQ
Why does my browser show a padlock when openssl verify fails?
Browsers sometimes cache intermediates, fetch missing ones, or use a different trust store. Command-line verify against the system store is the harsher, more portable check. Trust the stricter result for server configuration.
Is the Common Name still required?
Profiles vary. Many CAs still set CN for compatibility, but hostname matching is SAN-based. Never rely on CN alone.
What is the difference between cert.pem and fullchain.pem?
cert.pem is usually the leaf. fullchain.pem is leaf plus intermediates. Almost every reverse proxy should be pointed at the full chain file.
Can I ignore Extended Key Usage?
Not if your clients enforce it. Mutual TLS and some enterprise proxies are strict. For public HTTPS leaves, Server Auth should be present.
Why did renewal break only mobile clients?
Often a missing intermediate: desktop browsers had it cached; mobile clients did not. Always test with a clean openssl s_client after renewal.
Should I pin intermediates?
Prefer pinning sparingly and prefer monitoring Certificate Transparency (covered in Part 4). Intermediate replacements by public CAs are normal; hard pins without a backup plan cause outages.
Next in this series, Part 3 covers revocation in 2026: CRLs, why OCSP is fading for many clients, and how short-lived certificates change the incident playbook.
Follow & Connect
- Website: PixelValut Tools
- YouTube: PixelValut (@pixel-valut)
- TikTok: PixelValut (@pixelvalut007)
- GitHub: Muhammad Ali Mughal (@ali111887)
- LinkedIn: Muhammad Ali Mughal
