Your site was fine yesterday. This morning every browser is throwing a full-page security warning, monitoring is screaming, and nobody deployed anything. A certificate expired. That's it. One of the most common self-inflicted outages in software, and it happens to companies with entire infrastructure teams who should know better.
You depend on certificates whether or not you understand them. And when they break, they break loudly and totally. There's no graceful degradation. Every visitor sees a scary red page.
Quick naming note: everyone says "SSL certificate" but SSL is the retired protocol. The artifact is actually an X.509 certificate and the protocol is TLS. The name stuck out of habit.
π What a certificate actually claims
A certificate is a signed statement that binds a public key to a domain name. Nothing more. It doesn't vouch for the operator's honesty or the quality of the site behind it (I covered that distinction in my HTTPS post, so I won't repeat it here).
The signature on that statement comes from a certificate authority the client already trusts. During the TLS handshake, the server presents this certificate and the client validates it before trusting anything else about the connection. That's where it fits in the process.
What's inside one
The X.509 format has a lot of fields, but in practice these are the ones that matter:
Certificate:
Subject: CN=example.com
Issuer: CN=FakeCA Intermediate G2, O=FakeCA Inc
Validity
Not Before: Jan 1 00:00:00 2025 GMT
Not After : Mar 31 23:59:59 2025 GMT
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com, DNS:api.example.com
X509v3 Basic Constraints: critical
CA:FALSE
Signature Algorithm: ecdsa-with-SHA384
Subject, issuer, validity window, the public key, the Subject Alternative Name (SAN) list, and the CA's signature. That's your cert.
The gotcha here: modern browsers ignore the Common Name field entirely for hostname matching. They only look at SAN. So a cert with CN=example.com but no SAN entry for example.com will fail validation. This confuses people who learned certificate basics years ago when CN was what mattered. It isn't anymore.
π The chain of trust
Certificates don't exist in isolation. They form chains:
[Root CA] β self-signed, lives in your OS/browser trust store
βββ [Intermediate CA] β signed by root
βββ [Leaf cert] β signed by intermediate, this is YOUR cert
Your browser walks up the chain from the leaf until it hits something it already trusts. Root certificates are self-signed and trusted solely because they're pre-installed in the client's trust store. That's the actual anchor of the whole system.
So why not just have roots sign leaf certs directly? Two reasons. First, the root's private key can stay offline in a vault, only brought out to sign new intermediates. Second, if an intermediate gets compromised, you revoke that one intermediate. You don't invalidate every certificate on earth that chains back to that root. Containment.
The "works on my laptop" misconfiguration
Your server has to send the leaf certificate AND the intermediate certificates. Not the root. If you omit an intermediate, some clients still succeed because they cached that intermediate from a previous connection to some other site. But other clients fail outright.
So it appears to work in your browser and breaks in curl. Or works on your phone and breaks on a colleague's laptop. This is a configuration bug on your server. Not a client bug. An incomplete chain is always wrong, even if some clients happen to paper over it.
π οΈ How you actually get a certificate
The flow:
- Generate a keypair on your server
- Build a Certificate Signing Request (CSR) containing your public key and the domain names you want
- Send the CSR to a CA
- The CA validates you control the domain
- The CA signs and returns your certificate
The private key never leaves your server. Only the CSR goes to the CA, and the CSR contains just the public key. This is the part that surprises people.
# Generate a private key
openssl ecparam -genkey -name prime256v1 -out example.com.key
# Create a CSR
openssl req -new -key example.com.key -out example.com.csr \
-subj "/CN=example.com" \
-addext "subjectAltName=DNS:example.com,DNS:www.example.com"
Let's Encrypt and the ACME protocol automated all of this. HTTP-01 challenges prove you control the domain by placing a file at a well-known path. DNS-01 challenges prove control by creating a TXT record. Both work without human intervention, which is the whole point.
Certificate lifetimes have been getting shorter over time. The industry keeps pushing them down specifically to force automation. If your renewal process can't run unattended, shorter lifetimes will hurt you.
Validation levels (briefly)
Domain Validation (DV) proves you control the domain. That's it. Organization Validation (OV) and Extended Validation (EV) add checks on the legal entity behind the domain.
Browsers removed the green-bar treatment for EV certs years ago. Users never see the difference now. Paying extra for EV buys very little for most sites. It's basically a trust signal that nobody looks at.
Revocation is the part that barely works
What happens when a private key gets stolen and you need to invalidate a cert before it expires?
CRLs (Certificate Revocation Lists) are large lists that clients rarely fetch. Impractical at scale.
OCSP asks the CA about a single cert in real time. Better, but it adds latency to every connection and leaks your browsing history to the CA.
OCSP stapling has the server periodically fetch a signed freshness proof from the CA and attach it to the handshake. No extra round-trip for the client, no privacy leak. This is the better approach.
But the underlying problem is soft-fail. If the revocation check times out, clients just... connect anyway. An attacker who can block the OCSP request defeats the entire system. Browsers moved toward pushed revocation lists (like CRLSets) for exactly this reason.
And then there's Certificate Transparency: append-only public logs recording issued certificates. Major browsers won't trust a cert that doesn't appear in them, which is what gives the logs teeth. It doesn't prevent mis-issuance, but it makes it auditable. If a CA issues a cert for your domain without your knowledge, the CT logs are how you'd catch it.
Why yours expired, and how to stop it
The usual story: renewal wasn't automated. Or it was automated but the reload step wasn't, so the new cert sat on disk while the old one stayed in memory. Or the ACME client ran fine in staging but the cron job didn't have the right permissions in production.
Don't trust the renewal job to be silent-but-working. Monitor certificate expiry as a metric with alerting well before the date:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -enddate
Set an alert at 30 days, another at 7. If the 30-day one fires, you have time. If the 7-day one fires, someone should be panicking.
Also worth knowing: wildcard certs (*.example.com) cover a single label level. They don't match a.b.example.com. People learn this the hard way.
π Takeaways
- A certificate binds a public key to domain names via a CA's signature. That's all it is.
- The server must send the full chain (leaf + intermediates) but not the root. Incomplete chains are a server bug.
- Browsers use Subject Alternative Name for hostname matching and ignore Common Name entirely.
- Revocation mostly relies on soft-fail checks, which means it barely works against active attackers. CT logs are the auditability backstop.
- Automate renewal AND the reload. Monitor expiry as a metric. Don't wait for the 3am page.
Keep reading
- HTTPS Explained: What the Padlock Actually Protects
- Understanding JWT: How Servers Remember You Without Sessions
More writing
The rest of my writing, plus what I'm currently building, lives at arnavsharma.dev.
Top comments (0)