Skip to content
Menu

Networking11 min read

TLS

Transport Layer Security — encryption, authentication, integrity

The Three Pillars of TLS

TLS (Transport Layer Security) sits between the application layer and the transport layer. It wraps a reliable transport (typically TCP; embedded in QUIC for HTTP/3) and provides three guarantees:

Confidentiality

Data is encrypted so that only the intended recipient can read it. Anyone intercepting packets on the wire sees ciphertext. Achieved via symmetric encryption (AES-GCM, ChaCha20-Poly1305) with keys established during the handshake.

Authentication

The server proves its identity via a certificate signed by a trusted Certificate Authority. The client verifies the certificate chain to confirm it's talking to the real server, not an impersonator. Optionally, the client can also authenticate (mTLS).

Integrity

Every TLS record includes a MAC (Message Authentication Code). If any bit of the ciphertext is modified in transit, the recipient detects it and rejects the record. In TLS 1.3, AEAD ciphers (AES-GCM) provide encryption + integrity in a single operation.

Note

Terminology: "SSL" and "TLS" are often used interchangeably in casual conversation, but SSL (Secure Sockets Layer) is the deprecated predecessor. SSL 3.0 was the last SSL version (1996). TLS 1.0 replaced it in 1999. As of 2021, only TLS 1.2 and TLS 1.3 are considered secure. TLS 1.0 and 1.1 are officially deprecated (RFC 8996).

TLS 1.3 Handshake

TLS 1.3 (RFC 8446, 2018) redesigned the handshake to be both faster and more secure than TLS 1.2. The key improvement: 1-RTT handshake — the client sends its key share in the first message, enabling the server to derive the shared secret immediately.

Full Handshake (1-RTT)

Client
Server
ClientHello
ServerHello + EncryptedExtensions + Cert + Finished
Finished + [Application Data]

Step-by-Step Breakdown

  1. Client Hello — The client sends:
    • Supported TLS versions (only 1.3 in the supported_versions extension)
    • Supported cipher suites (e.g., TLS_AES_256_GCM_SHA384)
    • Key share — the client's ECDHE public key (this is the 1.3 innovation: send key material upfront)
    • SNI (Server Name Indication) — the hostname (e.g., api.example.com)
    • Supported signature algorithms
    • ALPN list (e.g., h2, http/1.1)
  2. Server Hello — The server responds with:
    • Chosen cipher suite
    • Server's ECDHE public key (key share)
    At this point, both sides can compute the shared secret via ECDHE. Everything after this is encrypted.
    • Encrypted Extensions — additional server parameters
    • Certificate — the server's X.509 certificate
    • Certificate Verify — signature over the handshake transcript, proving the server owns the private key for the certificate
    • Finished — HMAC over the entire handshake transcript (integrity check)
  3. Client Finished — The client sends its Finished message (HMAC over the handshake). Application data can be sent immediately in this same flight. Total: 1 round trip.

TLS 1.2 vs TLS 1.3 Handshake Comparison

TLS 1.2 (2-RTT)
  1. ClientHello (cipher suites, random)
  2. ServerHello + Cert + ServerKeyExchange + Done
  3. ClientKeyExchange + ChangeCipherSpec + Finished
  4. ChangeCipherSpec + Finished
  5. Application Data

Key exchange happens in messages 2-3. Encryption begins only after step 4.

TLS 1.3 (1-RTT)
  1. ClientHello + key_share + SNI
  2. ServerHello + key_share + {Cert + Finished}
  3. Finished + Application Data

Client sends key material in message 1. Server encrypts from message 2 onwards. App data flows in message 3.

0-RTT Resumption (PSK)

When a client has connected to a server before, TLS 1.3 supports 0-RTT resumption. During the previous session, the server sends the client a PSK (Pre-Shared Key) — essentially a session ticket. On reconnection, the client includes application data in the very first message, encrypted with the PSK.

Client
Server
ClientHello + PSK + early_data (0-RTT)
ServerHello + Finished
Finished

Warning

0-RTT replay attack risk: Because the 0-RTT data is sent before the handshake completes, there's no anti-replay protection from the TLS protocol itself. An attacker who captures the initial packet can replay it. Servers MUST only accept 0-RTT for idempotent requests (GET, HEAD). Non-idempotent operations (POST, PUT) must wait for the full handshake. Many servers disable 0-RTT entirely because of this.

Cipher Suites

A cipher suite defines the algorithms used for the TLS session. TLS 1.3 dramatically simplified the cipher suite structure compared to TLS 1.2.

Anatomy of a TLS 1.3 Cipher Suite

bash
TLS_AES_256_GCM_SHA384
 │    │       │     │
 │    │       │     └── Hash algorithm: SHA-384 (for HKDF key derivation)
 │    │       └──────── Mode: GCM (Galois/Counter Mode — AEAD)
 │    └──────────────── Cipher: AES-256 (symmetric encryption)
 └───────────────────── Protocol: TLS

TLS 1.3 only supports 5 cipher suites, all using AEAD (Authenticated Encryption with Associated Data):

Cipher Suite AEAD Cipher Hash Notes
TLS_AES_128_GCM_SHA256 AES-128-GCM SHA-256 Most common, good performance
TLS_AES_256_GCM_SHA384 AES-256-GCM SHA-384 Higher security margin
TLS_CHACHA20_POLY1305_SHA256 ChaCha20-Poly1305 SHA-256 Fast on CPUs without AES-NI (mobile)
TLS_AES_128_CCM_SHA256 AES-128-CCM SHA-256 Counter with CBC-MAC, IoT use
TLS_AES_128_CCM_8_SHA256 AES-128-CCM-8 SHA-256 Shorter auth tag, constrained devices

Note

Key point: Notice that TLS 1.3 cipher suites do NOT specify the key exchange algorithm. That's because TLS 1.3 mandates ephemeral key exchange (ECDHE or DHE) — it's not negotiable. In TLS 1.2, the cipher suite included the key exchange (e.g., TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384), and you could negotiate static RSA key exchange (no forward secrecy).

What TLS 1.3 Removed

Removed in TLS 1.3 (security improvements)

Removed Why
RSA key exchange No forward secrecy — if the server's private key is compromised later, all past sessions can be decrypted
Static DH Same problem — no forward secrecy without ephemeral keys
CBC mode ciphers Vulnerable to padding oracle attacks (BEAST, POODLE, Lucky 13)
RC4 Broken — statistical biases in keystream allow plaintext recovery
MD5, SHA-1 Collision attacks practical (SHA-1 collision demonstrated by Google in 2017)
Compression CRIME/BREACH attacks — compression leaks information about plaintext
Renegotiation Complex, historically buggy, source of vulnerabilities
ChangeCipherSpec Entire message type removed — unnecessary in 1.3's cleaner design

Certificates (X.509)

Certificates are how TLS achieves authentication. The server presents a certificate that cryptographically binds a public key to an identity (domain name). The client verifies this certificate against a trusted set of Certificate Authorities (CAs).

X.509 Certificate Structure

Version v3 (0x2)
Serial Number Unique per CA
Issuer DN of the Certificate Authority that signed this cert
Validity (Not Before) Start of validity period
Validity (Not After) Expiration date
Subject DN of the entity (e.g., CN=example.com)
Subject Public Key Info Algorithm (RSA/ECDSA) + Public Key
Extensions (v3) SAN, Key Usage, Basic Constraints, CRL Distribution Points, OCSP, CT
Signature Algorithm + Signature CA's signature over all the above fields

Tip

Ops tip: The Subject CN (Common Name) is deprecated for hostname matching. Modern certificates use the SAN (Subject Alternative Name) extension, which supports multiple domains and wildcards: DNS:example.com, DNS:*.example.com, DNS:api.example.com.

Certificate Chain of Trust

  1. End-Entity Cert

    Your domain cert
    (e.g., api.example.com)
    Signed by Intermediate CA

  2. Intermediate CA

    Issued by Root CA
    Signs end-entity certs
    Signed by Root CA

  3. Root CA

    Self-signed
    Pre-installed in OS/browser
    ~150 root CAs in trust stores

Why Intermediate CAs Exist

Root CA private keys are kept offline in HSMs (Hardware Security Modules) in secure facilities. They are too valuable to risk exposure. Intermediate CAs are signed by root CAs but operate online to issue certificates. If an intermediate CA is compromised, it can be revoked without invalidating the root (which would break the entire trust chain for thousands of sites).

Certificate Validation Steps

  1. Chain building: Construct the chain from end-entity cert to a trusted root CA. The server should send all intermediate certs (the root is already in the trust store).
  2. Signature verification: For each cert in the chain, verify that the issuer's public key correctly signed the certificate.
  3. Validity period: Check that the current time is within the Not Before / Not After range for every cert in the chain.
  4. Revocation check: Verify the cert hasn't been revoked:
    • CRL (Certificate Revocation List): Download a list of revoked serial numbers from the CA. Downside: lists can be large, and clients must fetch and cache them.
    • OCSP (Online Certificate Status Protocol): Query the CA in real-time for a single cert's status. Downside: adds latency, privacy concern (CA sees what sites you visit).
    • OCSP Stapling: The server fetches its own OCSP response and "staples" it to the TLS handshake. Best of both worlds — no extra round trip, no privacy leak.
  5. Hostname matching: Check that the requested hostname matches a SAN entry in the end-entity cert.

SNI (Server Name Indication)

Problem: a single IP address can host many TLS domains (like virtual hosts). The server needs to know which certificate to present before the TLS handshake completes. But without decrypting anything, the server doesn't know which domain the client wants.

Solution: SNI — the client includes the target hostname in the ClientHello message (which is sent in plaintext). The server uses this to select the correct certificate.

SNI in the TLS ClientHello

bash
ClientHello
  TLS Version: 1.3
  Cipher Suites: [TLS_AES_256_GCM_SHA384, ...]
  Extensions:
    server_name (SNI): "api.example.com"    ← sent in PLAINTEXT
    supported_versions: [TLS 1.3]
    key_share: [x25519: 0x...]
    signature_algorithms: [ecdsa_secp256r1_sha256, ...]
    alpn: [h2, http/1.1]

Warning

Privacy concern: Because SNI is sent in cleartext, anyone on the network path (ISP, corporate firewall, surveillance systems) can see which domains you're connecting to, even though they can't see the content. This is how some censorship systems block specific sites. The solution is ECH (Encrypted Client Hello), which encrypts the entire ClientHello using a public key published in DNS. ECH is still being standardized and rolled out.

ALPN (Application-Layer Protocol Negotiation)

ALPN is a TLS extension that lets client and server negotiate which application protocol to use during the TLS handshake, avoiding an extra round trip after the handshake.

Client Offers
bash
alpn: ["h2", "http/1.1"]

"I support HTTP/2 and HTTP/1.1, in order of preference."

Server Selects
bash
alpn: "h2"

"We'll use HTTP/2."

Note

Why this matters: Without ALPN, the client would have to complete the TLS handshake, then use the HTTP Upgrade mechanism to switch from HTTP/1.1 to HTTP/2 — adding another round trip. ALPN piggybacks on the TLS handshake, so protocol selection is free. This is also how HTTP/3 is discovered — the server advertises h3 support via the Alt-Svc header in an HTTP/2 response.

Certificate Transparency (CT)

Certificate Transparency is a system of public, append-only logs that record every certificate issued by participating CAs. It's designed to detect rogue or mistakenly issued certificates.

How CT Works

  1. CA submits cert to CT logs — Before (or shortly after) issuance, the CA submits the certificate to multiple independent CT log servers.
  2. Log returns SCT — The log returns a Signed Certificate Timestamp (SCT), which is a promise that the cert will appear in the log within a maximum merge delay (typically 24h).
  3. Server delivers SCTs — The server includes SCTs in the TLS handshake (via certificate extension, OCSP stapling, or TLS extension). Chrome requires at least 2 SCTs from different logs.
  4. Monitors watch logs — Domain owners, researchers, and automated systems continuously monitor CT logs for unexpected certificates issued for their domains.

Tip

Ops action: You can monitor CT logs for your domains using tools like crt.sh or Google's CT search. If you see a certificate for your domain that you didn't request, it could indicate a CA compromise or a domain validation failure. Many organizations set up automated CT monitoring alerts.

Key Exchange: ECDHE and Forward Secrecy

TLS 1.3 mandates ephemeral key exchange — both sides generate fresh, temporary key pairs for every connection. The dominant algorithm is ECDHE (Elliptic Curve Diffie-Hellman Ephemeral).

How ECDHE Works (Conceptual)

Client
Server
Client's ephemeral public key (key_share)
Server's ephemeral public key (key_share)

ECDHE Key Exchange Steps

  1. Both sides agree on an elliptic curve (e.g., x25519 or P-256).
  2. Client generates a random ephemeral private key and computes the corresponding public key on the curve. Sends the public key in ClientHello.
  3. Server does the same — generates its own ephemeral key pair. Sends its public key in ServerHello.
  4. Both sides compute the same shared secret using their private key + the other's public key. This is the ECDH math: shared_secret = client_private * server_public = server_private * client_public.
  5. The shared secret is fed into HKDF (HMAC-based Key Derivation Function) to derive the actual encryption keys, IVs, and MAC keys for the session.

Forward Secrecy

Without Forward Secrecy (RSA Key Exchange)
  • Client encrypts the pre-master secret with the server's long-lived RSA public key
  • If the server's private key is compromised years later, an attacker can decrypt all previously recorded sessions
  • Passive eavesdropping + future key compromise = total exposure
With Forward Secrecy (ECDHE)
  • Fresh ephemeral keys for every session
  • Ephemeral private keys are discarded after the session ends
  • Compromising the server's long-lived key only affects authentication, not past encryption
  • Each session's encryption key is independent

Warning

Critical: Forward secrecy is not optional in TLS 1.3 — it's mandatory by design. This is one of the most important security improvements over TLS 1.2, where RSA key exchange (no FS) was still allowed and commonly used.

Note

Common curves: x25519 (Curve25519, Daniel Bernstein's design — fast, constant-time, hard to misuse) is the most widely used. P-256 (secp256r1, NIST curve) is the other common choice. TLS 1.3 implementations typically support both. Post-quantum key exchange (ML-KEM/Kyber) is being deployed as a hybrid alongside x25519 to protect against future quantum computers.

Solidnines — solidnines.com