TLS version negotiation
When a client connects to a server over TLS, the two sides negotiate which protocol version to use. The client advertises the highest version it supports in its ClientHello message, and the server selects a version both sides understand. The negotiated version determines the available cipher suites, handshake mechanics, and security properties of the connection.
The TLS versions in use today:
- TLS 1.3 (RFC 8446, 2018) -- the current standard. Removes all legacy cipher suites, requires forward secrecy, reduces the handshake to one round trip (1-RTT), and supports zero round trip resumption (0-RTT). All cipher suites in TLS 1.3 use AEAD encryption. This is the preferred version.
- TLS 1.2 (RFC 5246, 2008) -- still widely deployed and acceptable. Supports both modern and legacy cipher suites. Configuration matters: a TLS 1.2 server can be secure or insecure depending on which cipher suites it enables.
- TLS 1.1 and 1.0 -- deprecated by RFC 8996 (2021). All major browsers have removed support. Servers offering these versions expose themselves to downgrade attacks and known vulnerabilities (BEAST, POODLE). These must not be enabled.
- SSL 3.0 and earlier -- broken. SSL 3.0 is vulnerable to POODLE. SSL 2.0 is vulnerable to multiple attacks. No modern software should negotiate these.
Why TLS 1.3 matters
TLS 1.3 is not just a version bump -- it is a redesign. The protocol removes entire categories of attacks by eliminating the features they exploit:
- No RSA key exchange -- TLS 1.3 only supports ephemeral Diffie-Hellman (ECDHE, DHE). This guarantees forward secrecy for every connection, not just connections where the server happened to prefer an ephemeral cipher suite.
- No CBC mode ciphers -- eliminates padding oracle attacks (Lucky13, POODLE).
- No renegotiation -- removes the renegotiation vulnerability class entirely.
- Encrypted handshake -- the server's certificate is encrypted in TLS 1.3, reducing metadata leakage to passive observers.
- Simpler state machine -- fewer moving parts means fewer implementation bugs. The handshake is three messages instead of TLS 1.2's variable-length exchange.
The performance benefit is also significant: TLS 1.3's 1-RTT handshake completes in one network round trip instead of two, reducing connection latency by one RTT (typically 20-100ms depending on geography).
Checking TLS version
You can check which TLS version a server negotiates using command-line tools:
# Force a specific TLS version with openssl
openssl s_client -connect example.com:443 -tls1_3
openssl s_client -connect example.com:443 -tls1_2
# Check with curl
curl -v --tls-max 1.2 https://example.com 2>&1 | grep "SSL connection"
A well-configured server should negotiate TLS 1.3 when the client supports it, and fall back to TLS 1.2 for older clients. It should refuse TLS 1.1 and below.
Forward secrecy
Forward secrecy (also called perfect forward secrecy, PFS) is a property of key exchange protocols that ensures session keys cannot be compromised even if the server's long-term private key is later exposed. Without forward secrecy, an attacker who records encrypted traffic today can decrypt it all retroactively if they obtain the private key in the future -- through a server breach, a legal order, or hardware decommissioning.
How it works
In a key exchange with forward secrecy, both client and server generate ephemeral (single-use) key pairs for each connection. They use Diffie-Hellman or Elliptic Curve Diffie-Hellman to derive a shared session key from these ephemeral keys. After the handshake, the ephemeral private keys are discarded. Even if the server's long-term RSA or ECDSA key is compromised later, the session keys are gone -- there is nothing to reconstruct them from.
The key exchange algorithms that provide forward secrecy:
- ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) -- the standard choice. Uses curves like X25519 or P-256. Fast, small key sizes, widely supported.
- DHE (Diffie-Hellman Ephemeral) -- the older variant using finite field groups. Requires larger key sizes (2048+ bits) for equivalent security. Slower than ECDHE. Still acceptable but ECDHE is preferred.
Key exchange methods that do not provide forward secrecy:
- RSA key exchange -- the client encrypts the pre-master secret directly with the server's RSA public key. If the RSA private key is later compromised, all past sessions using RSA key exchange can be decrypted. TLS 1.3 removes RSA key exchange entirely for this reason.
- Static DH -- Diffie-Hellman with a reused (non-ephemeral) key pair. Rarely seen in practice but provides no forward secrecy.
Why it matters in practice
Forward secrecy is not a theoretical concern. Nation-state adversaries are known to record encrypted traffic at scale for later decryption (the "store now, decrypt later" strategy). Certificate private keys are compromised more often than operators expect: through Heartbleed-class vulnerabilities, cloud provider incidents, stolen backups, or employee mistakes. Forward secrecy limits the blast radius of a key compromise to active MITM attacks during the window of compromise, not all historical traffic.
For compliance, PCI DSS, HIPAA, and NIST SP 800-52 Rev. 2 all recommend or require forward secrecy. Browsers and security scanners flag connections without it.
AEAD cipher suites
AEAD (Authenticated Encryption with Associated Data) is a class of encryption algorithms that combines confidentiality, integrity, and authenticity in a single operation. Before AEAD, TLS used separate algorithms for encryption (e.g., AES-CBC) and integrity (e.g., HMAC-SHA256), applied in a specific order (MAC-then-encrypt or encrypt-then-MAC). The composition of these separate operations was the source of numerous vulnerabilities.
The problem with non-AEAD ciphers
In TLS 1.2 and earlier, CBC-mode ciphers encrypt first, then compute an HMAC for integrity. The server must decrypt before it can check the MAC, and the decryption process reveals information about the plaintext through timing differences and padding validation errors. This is the root cause of:
- BEAST (2011) -- exploits predictable IVs in TLS 1.0 CBC mode
- Lucky13 (2013) -- timing side-channel in CBC padding validation
- POODLE (2014) -- padding oracle in SSL 3.0 / TLS CBC fallback
These attacks are not theoretical -- they have been demonstrated in practice against real TLS implementations.
How AEAD works
AEAD ciphers process plaintext and associated data (like TLS record headers) in a single pass, producing ciphertext and an authentication tag simultaneously. Decryption verifies the tag before returning any plaintext. There is no separate MAC step, no padding to validate, and no timing oracle to exploit.
The AEAD ciphers used in TLS:
- AES-128-GCM and AES-256-GCM -- AES in Galois/Counter Mode. The most widely deployed AEAD cipher. Hardware-accelerated on virtually all modern CPUs (AES-NI instruction set). GCM provides both encryption and authentication with minimal overhead.
- ChaCha20-Poly1305 -- a stream cipher (ChaCha20) paired with a MAC (Poly1305), designed by Daniel J. Bernstein. Performs well in software on platforms without AES hardware acceleration (older ARM devices, embedded systems). Comparable security to AES-GCM.
- AES-128-CCM -- AES in Counter with CBC-MAC mode. Less common in TLS, mainly used in constrained IoT environments.
TLS 1.3 mandates AEAD: every cipher suite in TLS 1.3 uses AEAD encryption. There is no option for CBC or stream ciphers. In TLS 1.2, AEAD suites are available but not required -- the server must be configured to prefer them.
Recommended cipher suite configuration
For TLS 1.3, no configuration is needed beyond enabling it -- all TLS 1.3 suites are AEAD with forward secrecy. The standard suites are:
TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
For TLS 1.2, prefer ECDHE key exchange with AEAD ciphers. A reasonable configuration:
# Nginx
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers on;
This configuration ensures every negotiated cipher suite provides both forward secrecy (ECDHE) and authenticated encryption (GCM or Poly1305).
Reading a cipher suite name
TLS 1.2 cipher suite names encode the key exchange, authentication, encryption, and MAC algorithms:
ECDHE-RSA-AES128-GCM-SHA256
│ │ │ │ └── MAC / PRF hash
│ │ │ └────── Encryption mode (GCM = AEAD)
│ │ └───────────── Bulk cipher and key size
│ └───────────────── Authentication (server cert type)
└─────────────────────── Key exchange
What to look for: ECDHE (forward secrecy) + GCM or CHACHA20_POLY1305 (AEAD). What to avoid: RSA key exchange (no "ECDHE" or "DHE" prefix), CBC mode, RC4, DES, 3DES, MD5, or export ciphers.
Common configuration mistakes
- Leaving TLS 1.0/1.1 enabled "for compatibility" -- no mainstream browser has supported these since 2020. The only clients still requiring TLS 1.0 are legacy systems that should be upgraded, not accommodated with weakened security for everyone else.
- Preferring RSA key exchange in TLS 1.2 -- some default configurations still list RSA key exchange suites before ECDHE suites. With
ssl_prefer_server_ciphers on, the server's order wins -- make sure ECDHE suites come first. - Disabling TLS 1.2 prematurely -- while TLS 1.3 is preferred, disabling TLS 1.2 entirely will break connectivity for a non-trivial number of clients (older Android devices, enterprise proxies, some API clients). Monitor your TLS version distribution before removing 1.2.
- Using weak DH parameters -- if DHE (non-elliptic-curve) key exchange is enabled, the DH group must be at least 2048 bits. The Logjam attack (2015) demonstrated that 512-bit and 1024-bit DH groups are breakable. Most servers should use ECDHE instead.
- Missing ChaCha20 support -- mobile clients on older ARM hardware without AES-NI benefit significantly from ChaCha20-Poly1305. Including it in your cipher list improves performance for these clients at no security cost.