TLS and certificates — what you are trusting when you encrypt
Asked what the "s" in https does, "it encrypts" is half the answer. If it were only encryption, you wouldn't need certificates. Certificates exist to verify that the party you're encrypting to is actually the party you intended.
You can encrypt to an imposter. Safely conversing with an imposter is meaningless — that's why certificates exist.
What you'll learn in this chapter
- The three properties TLS guarantees, and which one the certificate carries
- Certificate chain verification, and that delivering intermediate certificates is the server's responsibility
- What changes with the location of TLS termination
- Reading certificate errors as five kinds
TLS guarantees three things
| Property | Meaning | If broken |
|---|---|---|
| Confidentiality | Third parties can't read | Contents get stolen |
| Integrity | Not rewritten in transit | Contents get tampered with |
| Identity | The other side is who they claim | You safely communicate with a fake site |
The certificate carries only the third. The first and second are done by key exchange and encryption algorithms.
Without the third, the first and second lose meaning. If an attacker in the middle encrypts correctly, confidentiality and integrity toward the attacker still hold.
What the handshake decides
Two things are decided: the cipher suite and the shared key. The certificate acts as the third-party attestation "the public key really belongs to this host" during this process.
Why SNI is needed
The ClientHello contains the target host name (SNI = Server Name Indication). Without it, the server can't tell which certificate to present.
As we saw in TCP/IP, TCP connections are identified by IP address and port. To serve multiple host names on the same IP:443, the host name must be conveyed before encryption starts.
SNI is sent before encryption, so it's plaintext. Which site you connected to is visible along the path. Contents are hidden, but the destination is not.
Certificate chain
A single certificate isn't enough on its own.
Root certificate (in the trust store)
└─ Intermediate certificate (issued by a CA)
└─ Server certificate (for example.com)
Verification walks from the server certificate upward, checking whether it reaches a root in the trust store. If not, verification fails.
Roots are pre-installed in the OS and browsers. Intermediates are not.
Delivering the intermediate is the server's responsibility
Here's the biggest operational pitfall. The server must send its certificate along with the intermediate.
Forget it and you get the symptom "browser connects but other clients fail". Browsers may have cached intermediates from previous connections, or fetch them via Authority Information Access, so missing intermediates can be compensated for. curl and server-side HTTP clients don't compensate.
"Browser works, only API calls fail" — suspect intermediate delivery first.
What is verified
| Item | Failing example |
|---|---|
| Expiry | Renewal forgotten |
| Host name | Connected to example.com using a cert for www.example.com |
| Chain | Intermediate missing; self-signed |
| Revocation | Cert revoked after a private key leak |
Host name matching uses SAN (Subject Alternative Name). Common Name is not used — major browsers only look at SAN. To use for both example.com and www.example.com, list both in SAN.
Revocation exists as a mechanism but doesn't reliably work. Two reasons:
- Lets it through when no response is received. OCSP queries that don't come back aren't refused — the connection is allowed. If they were refused, a CA outage would take down every site depending on it. Attackers who block the query can dodge the check
- Some browsers don't query at all. Chrome discontinued OCSP checking and switched to distributing its own revoked-certificate list
Assume revocation doesn't take effect immediately.
Short-lived certificates becoming mainstream is a response to this. If revocation doesn't work, shorten expiry — that's the design.
HSTS — don't allow plaintext access
Strict-Transport-Security: max-age=31536000; includeSubDomains
A browser receiving this won't access that host over http for the specified seconds. Even if the user types http://, the request is rewritten to https before sending.
What it protects is the first redirect. If you rely on "connect via http:// then 301 to https", that first hop is plaintext and interceptable. HSTS closes that gap.
Still, the very first access can't be protected — it happens before the header is received. Preloaded lists baked into browsers cover that.
Adding includeSubDomains targets every subdomain. If a subdomain isn't https-ready, it becomes unreachable, so verify every subdomain before extending max-age.
The location of TLS termination
Adding CDN or a load balancer terminates TLS there.
Browser to CDN is encrypted, but CDN to origin is a separate story. Depending on settings, it can be plaintext.
This is the same structure as HTTP caching and CDNs. There, the asymmetry was "CDN caches can be purged, but copies delivered to users can't be recalled". Here, it's "the guarantee from browser to CDN doesn't guarantee CDN to origin". In communication with intermediate devices, think of what's guaranteed per segment.
The certificate belongs to the CDN. What the origin server's certificate looks like isn't visible from the browser.
HTTP/3 is fast because it integrates TLS
In HTTP we said "HTTP/3 drops TCP to shorten connection setup". The substance of the shortening involves TLS.
| Version | Round trips for connection setup |
|---|---|
| HTTP/1.1 / HTTP/2 (TLS 1.2) | TCP three-way handshake + TLS handshake |
| HTTP/1.1 / HTTP/2 (TLS 1.3) | TCP + TLS 1.3 (one fewer round trip) |
| HTTP/3 | QUIC integrates TCP's role and TLS 1.3 into one round trip |
QUIC has no independent encryption layer; it folds TLS 1.3's handshake into its own connection setup (RFC 9001 defines this integration). That's why "setting up a connection" and "setting up a secure connection" don't split into separate round trips.
HTTP/3 has no unencrypted option. TLS is part of the connection.
Reading certificate errors
Browser warning screens look similar, but causes divide into five.
| Symptom | Cause | Direction to fix |
|---|---|---|
| "Certificate has expired" | Forgot to renew | Automate renewal; monitor expiry |
| "This certificate is for a different site" | Host name not in SAN | Re-issue with the name in SAN |
Browser works but curl fails | Intermediate not delivered | Fix the server's certificate chain settings |
| "Issuer not trusted" | Self-signed, or untrusted CA | Issue via a public CA |
| Client clock is off | Expiry judgment goes wrong | Sync the client's time |
Remembering the last one saves time. "Only I get cert errors on every site" — look at the client's clock before blaming servers. Expiry is judged by time comparison, so a clock off by years makes every certificate expired.
Mixed content
Loading http resources from an https page — browsers block or warn.
| Kind | Browser behavior |
|---|---|
| Scripts, stylesheets | Blocked (not executed) |
| Images, videos | Blocked or auto-rewritten to https |
The purpose matches Cookies's Secure attribute — don't leave a plaintext path next to https-protected communication. Cookies do it with "don't send under plaintext"; mixed content does it with "don't load plaintext resources".
Common misconceptions
"SSL and TLS are different things." — TLS is SSL's successor. SSL 3.0 and earlier aren't used anymore. "SSL certificate" is a legacy term; the substance is a certificate used with TLS.
"With https, nothing is visible to anyone." — Only up to the TLS termination point. Terminating at a CDN switches to a different guarantee beyond. And SNI and DNS queries also reveal the destination.
"Certificates are for encryption." — They're for identity. Encryption can happen without a certificate.
"Revoking a certificate instantly stops it from being trusted." — Doesn't. Revocation checks don't reliably work, so a revoked cert can remain usable until expiry.
"HSTS protects even the first access." — Doesn't. Before the header is received, the browser can't know — unless preloaded, the first access is bare.
Exercises
Q1. A site works fine in the browser but returns certificate errors from a server-side API call. What do you suspect?
Answer and explanation
Answer: The intermediate certificate isn't being delivered.
The server must send its own certificate along with the intermediate. Without it, clients can't walk the chain to the root.
Browsers may compensate.
- Cached the same intermediate from a previous connection
- Fetch it themselves from the location noted in the certificate
curl and server-side HTTP clients don't compensate; if it's missing, they simply fail.
"Confirming in the browser doesn't validate" is the point. Verify chain completeness with a non-browser client or a dedicated verification tool.
Q2. You put the origin behind a CDN. If the browser's address bar shows a padlock, is it encrypted all the way to the origin?
Answer and explanation
Answer: No. The padlock indicates only the browser-to-CDN segment.
TLS terminates at the CDN. From CDN to origin is a separate connection that can be plaintext depending on the setting.
Think per segment.
| Segment | What is guaranteed |
|---|---|
| Browser → CDN | What the padlock shows. Verified with the CDN's certificate |
| CDN → origin | Separate setting. Can be plaintext |
To also encrypt to origin, that has to be configured on the CDN. Whether the origin's certificate is verified is also a setting. If not, someone intercepting between CDN and origin isn't noticed.
Same shape as HTTP caching and CDNs. In communication with intermediate devices, not explicit about which segment you're discussing leads to wrong decisions.
Q3. You set HSTS with max-age=31536000; includeSubDomains. What do you check beforehand?
Answer and explanation
Answer: That every subdomain is served over https.
includeSubDomains targets every subdomain. Any subdomain that isn't https-ready becomes unreachable because the browser won't hit it over http.
Also, max-age=31536000 is one year. Once the browser records it, reverting server-side leaves that browser at http-less for one year. Serving max-age=0 clears it, but receiving that requires https to reach it. With https broken, even the deletion instruction can't be delivered.
Order of confirmation:
- Enumerate every subdomain the policy targets (watch out for wildcard DNS)
- Confirm each responds over https
- Start with a short
max-age(a few minutes) - Extend after confirming nothing breaks
Starting short makes any mistake naturally fade away.
Summary
- TLS guarantees confidentiality, integrity, and identity. Certificates carry identity
- Without identity, confidentiality and integrity hold only toward the attacker, so they lose meaning
- Certificate chain is valid only when it walks up to a trusted root. Intermediate delivery is the server's responsibility
- Browsers may compensate for missing intermediates. Confirming in the browser doesn't validate
- Host-name matching uses SAN.
Common Nameisn't used - Revocation isn't reliable. Short expiries are the mitigation
- TLS termination changes what's guaranteed. Think per segment
- Five kinds of certificate errors. If every site errors on your machine, suspect the client's clock
- Practical AWS Guide — Route 53 and ACM — ACM certificate issuance and DNS validation steps
- Practical AWS Guide — ALB — TLS termination configuration on the load balancer
- RFC 8446 — TLS 1.3
- RFC 5280 — X.509 certificates and chain validation
- RFC 6797 — HTTP Strict Transport Security
- RFC 9001 — Using TLS to Secure QUIC — How HTTP/3 integrates TLS 1.3 into connection setup
What to read next
- Recursion and divide-and-conquer — Starting Part 10, moving to algorithm patterns for solving
- HTTP — The protocol flowing over TLS
- Cookies — What the
Secureattribute is guarding - HTTP caching and CDNs — Another example where segment-by-segment guarantees change with intermediate devices