Step through TLS 1.3, certificate validation, mTLS mutual auth, and common failure modes
TLS 1.3 Handshake
Certificate Validation
mTLS Mutual Auth
Session Resumption
Failure Modes
TCP ○TLS ○Cert ○Keys ○Data ○
OSI layers:
Steps ①②③ are L4 Transport (TCP) — pipe opens, no data yet. ·
Steps ④⑤⑥ are L5 Session — TLS handshake: cert validation, key exchange, session establishment. ·
L6 Presentation handles ongoing encryption after L5 completes. ·
No app data flows until step ⑥ completes.
⑥ Finished + First HTTP RequestEncrypted · Session keys active · 1-RTT complete ✓
⑦ Encrypted Application Data200 OK · JSON body — TLS fully established
🖩
Server
nginx / Cloudflare 104.21.1.1:443
*.example.com cert
Server Keys
Ks_pubephemeral public
Ks_privephemeral private
K_session= ECDH(Ks_priv, Kc_pub)
Subject*.example.com
IssuerLet's Encrypt R10
Valid from2024-01-01
Expires2024-04-01
Key algoECDSA P-256
SANapi.example.com ✓
Layer note: Certificate validation happens at L5 Session — it is part of the TLS handshake (session establishment), not L6 Presentation. L6 only runs after this validation completes and uses the session keys L5 derived.
🖥️
Client Browser
Validates server cert against trust store
Chain of Trust VerificationBrowser walks the chain
✓Leaf cert: *.example.com
↑ signed by
✓Intermediate: Let's Encrypt R10
↑ signed by
✓Root CA: ISRG Root X1 (in trust store)
Validation Checks
?
Chain complete and all sigs valid
?
Root CA in OS trust store
?
Hostname matches CN/SAN: api.example.com
?
Certificate not expired
?
OCSP — not revoked
?
Key usage allows TLS server auth
✓ Certificate Trusted — Handshake continues
🏛️
CA / OCSP
Let's Encrypt OCSP responder
Root trusted
⚙️
Service A
Envoy sidecar Client role
Client cert ready
CLIENT CERTIFICATE
Subjectservice-a.default.svc
IssuerInternal CA (Citadel)
SPIFFE IDspiffe://cluster/sa/svc-a
TTL24h (rotated auto)
① ClientHello + Client CertPresents its own certificate — unlike regular TLS
② ServerHello + Server Cert + CertRequestServer presents cert AND requests client cert
③ CertificateVerify + FinishedClient proves it owns private key by signing handshake hash
④ Finished ✓ — Both sides authenticatedMutual trust established — neither side can be impersonated
Regular TLS
✓ Server authenticated
✗ Client anonymous
Use: public websites, APIs with token auth
mTLS
✓ Server authenticated
✓ Client authenticated
Use: Kubernetes service mesh, zero-trust
⚙️
Service B
Envoy sidecar Server role
Server cert ready
SERVER CERTIFICATE
Subjectservice-b.default.svc
IssuerInternal CA (Citadel)
SPIFFE IDspiffe://cluster/sa/svc-b
TTL24h (rotated auto)
🖥️
Client
Has session ticket from prior connection
Session ticket cached
Full Handshake
2 RTT
SYN + ClientHello then data
0-RTT Resumption
0 RTT
Data sent with first packet
① ClientHello + Session Ticket + Early DataHTTP request piggybacks on handshake packet — 0 extra round trip
② ServerHello + Finished + ResponseServer decrypts early data with pre-shared key and responds
⚠ 0-RTT Replay Attack Risk
Early data can be replayed by a network attacker. Safe: GET requests (idempotent — replaying reads is harmless) Unsafe: POST /payments (replaying creates duplicate charges) Fix: Server must check nonce or use anti-replay window
🖩
Server
Issues session tickets on first connection
PSK on file
ERR_CERT_DATE_INVALID
Certificate expired — most common production incident