TLS Internals
Overview
Section titled “Overview”This document goes deeper into TLS internals than the TLS fundamentals document, covering the record Layer architecture, detailed handshake message formats for TLS 1.3, cipher suite construction, key Exchange mechanisms, and common implementation pitfalls. This is the material you need to understand When debugging TLS connections, configuring servers, or evaluating cryptographic strength.
TLS Architecture
Section titled “TLS Architecture”TLS is structured as a layered protocol with four sub-protocols operating over a reliable transport (TCP):
+-----------------------------------+| Application Data |+-----------------------------------+| Handshake Protocol |+-----------------------------------+| Change Cipher Spec |+-----------------------------------+| Alert Protocol |+-----------------------------------+| Record Layer |+-----------------------------------+| TCP |+-----------------------------------+Record Layer
Section titled “Record Layer”The TLS record layer fragments application data (and handshake messages) into records. Each record Has:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Content Type (8) | |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Version (16) || +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| | |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Length (16) || +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| | |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Fragment (variable) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Content types:
| Type | Value | Description |
|---|---|---|
| CHANGE_CIPHER_SPEC | 20 | Deprecated in TLS 1.3 (replaced by KeyUpdate) |
| ALERT | 21 | Error or warning notifications |
| HANDSHAKE | 22 | Handshake protocol messages |
| APPLICATION_DATA | 23 | Encrypted application data |
Handshake Protocol
Section titled “Handshake Protocol”The handshake protocol is responsible for authentication, key exchange, and negotiation of Cryptographic parameters. Handshake messages are carried inside TLS records with content type 22.
Alert Protocol
Section titled “Alert Protocol”Alert messages convey errors and state changes:
| Level | Description | Common Alerts |
|---|---|---|
| Warning (1) | Non-fatal; connection continues | close_notify, no_certificate, bad_certificate |
| Fatal (2) | Connection must be terminated | handshake_failure, decode_error, illegal_parameter |
Change Cipher Spec Protocol
Section titled “Change Cipher Spec Protocol”In TLS 1.2, this protocol signals the transition to encrypted communication. In TLS 1.3, it is Deprecated. Key changes are signaled within the handshake protocol itself.
TLS 1.2 vs TLS 1.3
Section titled “TLS 1.2 vs TLS 1.3”Removed in TLS 1.3
Section titled “Removed in TLS 1.3”| Feature | TLS 1.2 | TLS 1.3 | Reason |
|---|---|---|---|
| Renegotiation | Supported | Removed | Complex, caused RC4 injection attacks |
| Compression | Supported | Removed | CRIME attack (compression oracle) |
| Static RSA key exchange | Supported | Removed | No forward secrecy |
| Non-AEAD ciphers | Supported | Removed | CBC ciphers vulnerable to padding oracles |
| Custom DHE groups | Supported | Removed | Weak groups (e.g., export-grade) |
| SHA-1 in signatures | Supported | Removed | SHA-1 is cryptographically weak |
| MD5 in signatures | Supported | Removed | MD5 is broken |
Added in TLS 1.3
Section titled “Added in TLS 1.3”| Feature | Description |
|---|---|
| 0-RTT data | Send application data in the first flight (repeat connections) |
| Signature algorithms | Explicit negotiation of hash+signature pairs (RFC 8446 Section 4.2.3) |
| Key schedule | Derived key hierarchy using HKDF (RFC 5869) |
| Post-handshake auth | Server can request client certificate after the handshake |
| Encrypted Server Hello | Server Hello is encrypted (hides server identity from observers) |
| KeyUpdate | In-band key rotation without renegotiation |
Cipher Suite Simplification
Section titled “Cipher Suite Simplification”TLS 1.2 cipher suites are complex strings like TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. TLS 1.3 Cipher suites only specify the AEAD algorithm:
| TLS 1.3 Cipher Suite | AEAD Algorithm | Hash (HKDF) |
|---|---|---|
| TLS_AES_128_GCM_SHA256 | AES-128-GCM | SHA-256 |
| TLS_AES_256_GCM_SHA384 | AES-256-GCM | SHA-384 |
| TLS_CHACHA20_POLY1305_SHA256 | ChaCha20-Poly1305 | SHA-256 |
| TLS_AES_128_CCM_SHA256 | AES-128-CCM | SHA-256 |
| TLS_AES_128_CCM_8_SHA256 | AES-128-CCM-8 | SHA-256 |
The key exchange algorithm is no longer part of the cipher suite. It is negotiated separately via The supported_groups extension.
TLS 1.3 Handshake in Detail
Section titled “TLS 1.3 Handshake in Detail”Full Handshake (1-RTT)
Section titled “Full Handshake (1-RTT)”Client Server | | |--- ClientHello -------------------------------->| Flight 1 | supported_versions, supported_groups, | | signature_algorithms, key_share | | | |<-- ServerHello ---------------------------------| Flight 2 | selected_version, selected_group, | | key_share | |<-- EncryptedExtensions ------------------------| |<-- Certificate ---------------------------------| |<-- CertificateVerify ---------------------------| |<-- Finished ------------------------------------| | | |--- Finished ----------------------------------->| Flight 3 | | |==== Application Data =========================|ClientHello Fields
Section titled “ClientHello Fields”The ClientHello carries the client”s capabilities and parameters:
| Field | Description |
|---|---|
| legacy_version | 0x0303 (TLS 1.2) for compatibility with middleboxes |
| random | 32 bytes of random (used in key derivation) |
| legacy_session_id | Session ID for compatibility (TLS 1.3 uses PSK) |
| cipher_suites | List of supported TLS 1.3 cipher suites |
| legacy_compression_methods | [0x00] (no compression) |
| extensions | supported_versions, supported_groups, key_share, |
| signature_algorithms, psk_key_exchange_modes, | |
| server_name (SNI), etc. |
ServerHello Fields
Section titled “ServerHello Fields”| Field | Description |
|---|---|
| legacy_version | 0x0303 (always, even for TLS 1.3) |
| random | 32 bytes of random |
| legacy_session_id_echo | Echo of client’s session_id |
| cipher_suite | Selected cipher suite |
| legacy_compression_method | 0x00 |
| extensions | supported_version (TLS 1.3), key_share, |
| pre_shared_key (if PSK selected) |
EncryptedExtensions
Section titled “EncryptedExtensions”After the ServerHello, all subsequent handshake messages are encrypted. EncryptedExtensions carries Server-side configuration that does not affect the cryptographic parameters:
server_nameindication (whether SNI was used)max_fragment_length(negotiate smaller records)application_layer_protocol_negotiation(ALPN)early_data(whether 0-RTT is accepted)
Certificate
Section titled “Certificate”The server sends its certificate chain. In TLS 1.3, the Certificate message is sent encrypted. The Certificate chain includes:
- Leaf certificate: The server’s end-entity certificate
- Intermediate certificates: One or more intermediate CA certificates
- Root certificate: NOT included (the client must already trust it)
CertificateVerify
Section titled “CertificateVerify”This message proves that the server holds the private key corresponding to the certificate’s public Key. It contains a digital signature over a transcript hash of all handshake messages so far.
Signature = Sign(private_key, Hash("TLS 1.3, server CertificateVerify" || 0x20...0x20 || transcript_hash))The 0x20...0x20 is 64 bytes of spaces (0x20), a context string that binds the signature to TLS 1.3 Specifically.
Finished
Section titled “Finished”Both sides send a Finished message, which contains a verify_data value derived from the handshake Transcript:
verify_data = HMAC(finished_key, Hash(transcript))The Finished message is the first message encrypted with the newly derived traffic keys. If the Verify_data does not match, the handshake has been tampered with and the connection is terminated.
Key Exchange Mechanisms
Section titled “Key Exchange Mechanisms”ECDHE (Elliptic Curve Diffie-Hellman Ephemeral)
Section titled “ECDHE (Elliptic Curve Diffie-Hellman Ephemeral)”The most widely used key exchange in TLS 1.3. Both sides generate an ephemeral (temporary) key pair On an elliptic curve, exchange public keys, and derive a shared secret.
Client generates: (priv_c, pub_c)Server generates: (priv_s, pub_s)
Shared secret = ECDH(priv_c, pub_s) = ECDH(priv_s, pub_c) = x-coordinate of (priv_c * pub_s)Supported curves (RFC 8446):
| Curve | Key Size | Security Level |
|---|---|---|
| X25519 | 256 bits | 128 bits |
| secp256r1 (P-256) | 256 bits | 128 bits |
| secp384r1 (P-384) | 384 bits | 192 bits |
| secp521r1 (P-521) | 521 bits | 256 bits |
X25519 is the recommended default. It is faster than NIST curves, has simpler implementation (fewer Edge cases), and uses a constant-time algorithm that is resistant to timing attacks.
DHE (Finite Field Diffie-Hellman Ephemeral)
Section titled “DHE (Finite Field Diffie-Hellman Ephemeral)”Traditional Diffie-Hellman over a finite field. Slower than ECDHE for equivalent security levels. Supported groups:
| Group (ffdhe) | Prime Size | Security Level |
|---|---|---|
| ffdhe2048 | 2048 bits | 112 bits |
| ffdhe3072 | 3072 bits | 128 bits |
| ffdhe4096 | 4096 bits | 150 bits |
| ffdhe6144 | 6144 bits | 175 bits |
| ffdhe8192 | 8192 bits | 200+ bits |
PSK (Pre-Shared Key)
Section titled “PSK (Pre-Shared Key)”TLS 1.3 supports PSK-based key exchange, which can be used alone or combined with (EC)DHE (called “PSK with (EC)DHE” or “psk_dhe_ke”).
| PSK Mode | Forward Secrecy | Use Case |
|---|---|---|
| PSK only | No | IoT devices, resumption tickets |
| PSK + (EC)DHE | Yes | Recommended for resumption (security) |
PSKs are established either externally (configured on both sides) or via a previous TLS handshake (session resumption via NewSessionTicket).
PSK Key Exchange Modes
Section titled “PSK Key Exchange Modes”The client indicates which PSK modes it supports in the psk_key_exchange_modes extension:
psk_ke: PSK-only key establishment (no forward secrecy)psk_dhe_ke: PSK combined with (EC)DHE (forward secrecy maintained)
TLS 1.3 implementations should prefer psk_dhe_ke for session resumption. This provides forward Secrecy even for resumed sessions. If the PSK is compromised, past traffic remains secure because The (EC)DHE exchange was ephemeral.
Cipher Suites Breakdown
Section titled “Cipher Suites Breakdown”AEAD Ciphers
Section titled “AEAD Ciphers”AEAD (Authenticated Encryption with Associated Data) provides both confidentiality and integrity in A single operation. TLS 1.3 requires AEAD ciphers exclusively.
AES-GCM (Galois/Counter Mode):
- AES-128-GCM: 128-bit key, 96-bit nonce, 128-bit authentication tag
- AES-256-GCM: 256-bit key, 96-bit nonce, 128-bit authentication tag
- Hardware-accelerated on most modern CPUs (AES-NI instruction set)
- The most widely deployed AEAD cipher
ChaCha20-Poly1305:
- 256-bit key, 96-bit nonce, 128-bit authentication tag
- Software-optimized design (no special hardware needed)
- Preferred on mobile devices and ARM platforms without AES-NI
- Designed by Daniel J. Bernstein
AES-CCM:
- AES-128-CCM: 128-bit key, CBC-MAC mode
- AES-128-CCM-8: Same but with truncated 64-bit tag (faster but weaker)
- Required for compatibility with constrained IoT devices (RFC 8446 mandates support for at least one CCM cipher)
- Slower than GCM
Key Derivation: HKDF
Section titled “Key Derivation: HKDF”TLS 1.3 uses HKDF (HMAC-based Extract-and-Expand Key Derivation Function, RFC 5869) for all key Derivation. The key schedule is:
0-RTT |Early Secret = HKDF-Extract(PSK or 0) |Handshake Secret = HKDF-Extract(DHE shared secret, Early Secret) |Master Secret = HKDF-Extract(DHE shared secret, Handshake Secret) |Application Traffic Secret 0Application Traffic Secret 1 (after KeyUpdate)...Each secret is expanded into multiple keys:
Traffic Keys = { client_write_key, server_write_key, client_write_iv, server_write_iv}Nonce Construction
Section titled “Nonce Construction”The per-record nonce is derived from the IV and a sequence number:
nonce = IV XOR (sequence_number << 64)The sequence number is a 64-bit counter that increments for each record. Since the sequence number Is included in the nonce, every record has a unique nonce, even with the same IV.
Certificate Verification Path
Section titled “Certificate Verification Path”Chain Building
Section titled “Chain Building”When the server presents a certificate chain, the client builds a verification path:
- Parse the leaf certificate and extract the issuer’s distinguished name
- Find the issuer in the chain (or in the client’s trust store)
- Repeat until a trusted root certificate is reached
- Verify signatures at each step (each certificate is signed by its issuer)
Signature Validation
Section titled “Signature Validation”For each certificate in the chain:
- Verify the signature algorithm is acceptable (not MD5, not SHA-1)
- Verify the certificate is within its validity period (not_before to not_after)
- Verify the certificate has not been revoked (OCSP or CRL)
- Verify the certificate’s intended purpose (serverAuth for TLS)
- Verify the certificate’s constraints (name constraints, path length)
Revocation Checking
Section titled “Revocation Checking”OCSP (Online Certificate Status Protocol, RFC 6960):
The client sends a query to the CA’s OCSP responder asking whether a specific certificate is Revoked. The responder returns “good”, “revoked”, or “unknown”.
# Check certificate revocation with opensslopenssl ocsp -issuer intermediate.pem -cert server.pem \ -url http://ocsp.example.com/ -resp_textOCSP Stapling (RFC 6066):
The server periodically obtains an OCSP response from the CA and “staples” it to the TLS handshake. The client does not need to contact the CA directly, improving performance and privacy.
# Test OCSP stapling with opensslopenssl s_client -connect example.com:443 -status -servername example.comCRL (Certificate Revocation List):
The CA publishes a list of revoked certificate serial numbers. The client downloads and checks the List. CRLs can be large and are not updated frequently, making them less practical for real-time Revocation checking.
CAA (Certification Authority Authorization, RFC 6844)
Section titled “CAA (Certification Authority Authorization, RFC 6844)”A DNS record that specifies which CAs are authorized to issue certificates for a domain:
example.com. IN CAA 0 issue "letsencrypt.org"example.com. IN CAA 0 issuewild "*.example.com" "letsencrypt.org"Record Layer Details
Section titled “Record Layer Details”Fragmentation
Section titled “Fragmentation”TLS records have a maximum size (configurable, default 16KB). Application data larger than this is Fragmented into multiple records. The receiver reassembles the fragments.
In TLS 1.3, the maximum record size is negotiated via the max_fragment_length extension:
| Value | Max Record Size |
|---|---|
| 1 | 2^9 (512 bytes) |
| 2 | 2^10 (1024 bytes) |
| 3 | 2^11 (2048 bytes) |
| 4 | 2^12 (4096 bytes) |
Smaller records reduce latency (the receiver can process data sooner) but increase overhead (more Records = more TLS record headers and MACs).
MAC-then-Encrypt vs Encrypt-then-MAC
Section titled “MAC-then-Encrypt vs Encrypt-then-MAC”TLS 1.2 with CBC cipher suites uses MAC-then-Encrypt (MAC the plaintext, then encrypt both). This is Vulnerable to padding oracle attacks (Lucky13, POODLE).
TLS 1.3 uses AEAD ciphers exclusively, which combine encryption and authentication in a single Operation (effectively encrypt-then-MAC). This eliminates padding oracle attacks entirely.
TLS Extensions
Section titled “TLS Extensions”SNI (Server Name Indication, RFC 6066)
Section titled “SNI (Server Name Indication, RFC 6066)”The client sends the server hostname in the ClientHello’s server_name extension. This allows a Single IP address to host multiple TLS-enabled websites (virtual hosting).
# Test SNIopenssl s_client -connect 93.184.216.1:443 -servername example.comALPN (Application-Layer Protocol Negotiation, RFC 7301)
Section titled “ALPN (Application-Layer Protocol Negotiation, RFC 7301)”Negotiates the application protocol (HTTP/1.1, HTTP/2, h2c, etc.) during the TLS handshake:
# Test ALPNopenssl s_client -connect example.com:443 -alpn h2,http/1.1Session Tickets (RFC 5077)
Section titled “Session Tickets (RFC 5077)”The server encrypts the session state into a ticket and sends it to the client. On a subsequent Connection, the client presents the ticket, and the server decrypts it to resume the session without Storing state.
In TLS 1.3, session tickets are sent via the NewSessionTicket post-handshake message.
supported_versions (TLS 1.3)
Section titled “supported_versions (TLS 1.3)”The client lists supported TLS versions in this extension. The server responds with the selected Version in the ServerHello. This extension allows TLS 1.3 to be negotiated without changing the Legacy_version field.
pre_shared_key (TLS 1.3)
Section titled “pre_shared_key (TLS 1.3)”Contains the PSK identity and the binder value (an HMAC over the transcript up to this point, using The PSK). The binder prevents a man-in-the-middle from substituting a different PSK.
Forward Secrecy
Section titled “Forward Secrecy”Why It Matters
Section titled “Why It Matters”Forward secrecy (also called perfect forward secrecy, PFS) ensures that compromising the server’s Private key does not compromise past session keys. Each session uses an ephemeral key exchange, so Recording encrypted traffic and later obtaining the server’s private key does not allow decryption Of past sessions.
Without forward secrecy (static RSA key exchange), the session key is encrypted with the server’s Static RSA private key. If an attacker records the handshake and later obtains the private key (through theft, court order, or cryptanalysis), they can decrypt all past sessions.
Which Cipher Suites Provide Forward Secrecy
Section titled “Which Cipher Suites Provide Forward Secrecy”| Key Exchange | Forward Secrecy |
|---|---|
| Static RSA | No |
| ECDHE | Yes |
| DHE | Yes |
| PSK only | No |
| PSK + (EC)DHE | Yes |