---
title: TLS 1.2 Handshake
url: https://doc.liz6.com/en/networking/05-tls-and-pki/01-tls-1-2-handshake
locale: en
area: networking
tags:
- networking
- tls-and-pki
date: 2026-06-30
modified: 2026-07-16
description: 'TLS 1.2 Handshake: ClientHello→ServerHello→Certificate→KeyExchange→Finished, completing key negotiation in two round trips. Understanding the cryptographic operations at each step (RSA vs ECDHE, signature vs key exchange) is a prerequisite for understanding why TLS 1.3 can reduce this to 1-RTT.'
---

# TLS 1.2 Handshake

> TLS 1.2 Handshake: ClientHello→ServerHello→Certificate→KeyExchange→Finished, completing key negotiation in two round trips. Understanding the cryptographic operations at each step (RSA vs ECDHE, signature vs key exchange) is a prerequisite for understanding why TLS 1.3 can reduce this to 1-RTT.

## Overview

TLS (Transport Layer Security) is the foundation of secure internet communication, defined in RFC 5246 in 2008. It addresses three problems: authentication (who is the server), confidentiality (data is encrypted), and integrity (data is not tampered with). The TLS 1.2 handshake is the most widely deployed version—establishing a secure channel in 2-RTT, using ECDHE to ensure forward secrecy, and SNI allowing multiple domains to share a single IP. This article dissects the handshake process, key derivation, and session resumption mechanisms frame by frame.

## Full Handshake (2-RTT)

```mermaid
sequenceDiagram
    participant C as Client
    participant S as Server

    Note over C,S: ═══ RTT 1 ═══
    C->>S: ① ClientHello<br/>version + random + cipher_suites<br/>+ extensions (SNI, ALPN, supported_groups)

    S->>C: ② ServerHello + Certificate*<br/>+ ServerKeyExchange*<br/>+ CertificateRequest*<br/>+ ServerHelloDone

    Note over C: Verify certificate chain<br/>Compute pre_master_secret

    Note over C,S: ═══ RTT 2 ═══
    C->>S: ③ Certificate*<br/>ClientKeyExchange<br/>CertificateVerify*<br/>[ChangeCipherSpec]<br/>Finished

    Note over S: Decrypt pre_master_secret<br/>Derive session keys

    S->>C: ④ [ChangeCipherSpec]<br/>Finished

    Note over C,S: ✅ Secure channel established<br/>Encrypted application data transmission

    C->>S: Application Data (encrypted)
    S->>C: Application Data (encrypted)
```

\* = optional (depends on cipher suite and server configuration)

### ClientHello

```
struct {
    ProtocolVersion client_version;     // {3,3} = TLS 1.2
    Random random;                      // 32B: gmt_unix_time(4) + random_bytes(28)
    SessionID session_id;               // ≤32B (for resumption) or empty
    CipherSuite cipher_suites<2..2^16-2>;  // List of client-supported suites, prioritized
    CompressionMethod compression_methods; // {0} = null (null is mandatory in TLS 1.2)
    Extension extensions<0..2^16-1>;    // SNI, ALPN, supported_groups, signature_algorithms, ...
}
```

Key Extensions:

```
server_name (SNI): Domain name to access — server selects the correct certificate (multiple certs on one IP)
supported_groups: EC curves supported by the client (secp256r1, x25519, ...)
ec_point_formats: uncompressed (only value, practically useless)
signature_algorithms: Signature algorithms supported by the client (RSA-PKCS1-SHA256, ECDSA-SHA256, ...)
ALPN: Application layer protocol list ("h2", "http/1.1") — server selects one
Extended Master Secret: Prevents Triple Handshake attacks
SessionTicket TLS: Supports session tickets (stateless resumption)
```

### Cipher Suite Format

<svg viewBox="0 0 720 350" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="Cipher Suite Naming Breakdown: Key Exchange, Authentication, Encryption, PRF four-part parameters, comparison of two typical suites">
  <rect width="720" height="350" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">Cipher Suite Breakdown: Suite Name = Four Cryptographic Parameters</text>

  <rect x="40" y="50" width="300" height="28" rx="6" fill="#4f46e5"/>
  <text x="190" y="68" text-anchor="middle" font-size="10.5" font-weight="700" fill="#ffffff">TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</text>

  <line x1="46" y1="78" x2="46" y2="240" stroke="#c7d2fe" stroke-width="1.5"/>
  <line x1="46" y1="108" x2="52" y2="108" stroke="#c7d2fe" stroke-width="1.5"/>
  <line x1="46" y1="152" x2="52" y2="152" stroke="#c7d2fe" stroke-width="1.5"/>
  <line x1="46" y1="196" x2="52" y2="196" stroke="#c7d2fe" stroke-width="1.5"/>
  <line x1="46" y1="240" x2="52" y2="240" stroke="#c7d2fe" stroke-width="1.5"/>

  <rect x="52" y="90" width="276" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="66" y="104" font-size="12" font-weight="700" fill="#3730a3">ECDHE <tspan font-weight="400" fill="#4f46e5">Key Exchange Algorithm</tspan></text>
  <text x="66" y="119" font-size="10.5" fill="#4f46e5">Elliptic Curve Diffie-Hellman Ephemeral</text>

  <rect x="52" y="134" width="276" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="66" y="148" font-size="12" font-weight="700" fill="#3730a3">RSA <tspan font-weight="400" fill="#4f46e5">Server Authentication</tspan></text>
  <text x="66" y="163" font-size="10.5" fill="#4f46e5">Public key type in certificate — RSA signing</text>

  <rect x="52" y="178" width="276" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="66" y="192" font-size="12" font-weight="700" fill="#3730a3">AES_128_GCM <tspan font-weight="400" fill="#4f46e5">Symmetric Encryption</tspan></text>
  <text x="66" y="207" font-size="10.5" fill="#4f46e5">AES-128-GCM AEAD</text>

  <rect x="52" y="222" width="276" height="36" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="66" y="236" font-size="12" font-weight="700" fill="#3730a3">SHA256 <tspan font-weight="400" fill="#4f46e5">PRF</tspan></text>
  <text x="66" y="251" font-size="10.5" fill="#4f46e5">Pseudo-Random Function, key derivation</text>

  <rect x="380" y="50" width="300" height="28" rx="6" fill="#0d9488"/>
  <text x="530" y="68" text-anchor="middle" font-size="9.5" font-weight="700" fill="#ffffff">TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</text>

  <line x1="386" y1="78" x2="386" y2="240" stroke="#99f6e4" stroke-width="1.5"/>
  <line x1="386" y1="108" x2="392" y2="108" stroke="#99f6e4" stroke-width="1.5"/>
  <line x1="386" y1="152" x2="392" y2="152" stroke="#99f6e4" stroke-width="1.5"/>
  <line x1="386" y1="196" x2="392" y2="196" stroke="#99f6e4" stroke-width="1.5"/>
  <line x1="386" y1="240" x2="392" y2="240" stroke="#99f6e4" stroke-width="1.5"/>

  <rect x="392" y="90" width="276" height="36" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="113" font-size="12" font-weight="700" fill="#115e59">ECDHE <tspan font-weight="400" fill="#0f766e">Key Exchange</tspan></text>

  <rect x="392" y="134" width="276" height="36" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="148" font-size="12" font-weight="700" fill="#115e59">ECDSA <tspan font-weight="400" fill="#0f766e">Server Authentication</tspan></text>
  <text x="406" y="163" font-size="10.5" fill="#0f766e">EC Certificate</text>

  <rect x="392" y="178" width="276" height="36" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="192" font-size="12" font-weight="700" fill="#115e59">CHACHA20_POLY1305 <tspan font-weight="400" fill="#0f766e">Symmetric Encryption</tspan></text>
  <text x="406" y="207" font-size="10.5" fill="#0f766e">ChaCha20-Poly1305 AEAD</text>

  <rect x="392" y="222" width="276" height="36" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="406" y="245" font-size="12" font-weight="700" fill="#115e59">SHA256 <tspan font-weight="400" fill="#0f766e">PRF</tspan></text>

  <rect x="60" y="276" width="600" height="56" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="76" y="298" font-size="12.5" fill="#3730a3">The four parts of the suite name can be combined independently: Key exchange algorithm determines forward secrecy, authentication algorithm determines certificate type,</text>
  <text x="76" y="318" font-size="12.5" fill="#3730a3">symmetric encryption determines data encryption method, PRF (fixed to SHA256 in TLS 1.2) is responsible for key derivation.</text>
</svg>

### Key Derivation

```
1. From DH key exchange: pre_master_secret (computed jointly by server/client)
2. master_secret = PRF(pre_master_secret, "master secret",
                        ClientHello.random + ServerHello.random)[0..47]

3. From master_secret: 6 session keys
   key_block = PRF(master_secret, "key expansion",
                    ServerHello.random + ClientHello.random)
   → client_write_MAC_key, server_write_MAC_key,
     client_write_key, server_write_key,
     client_write_IV, server_write_IV

4. Finished message = PRF(master_secret, "client finished",
                           hash(all handshake messages))[0..11]
   → Ensures handshake was not tampered with
```

### Session Resumption

```
Session ID (Stateful, RFC 5246):
  1. Initial full handshake → ServerHello.session_id = <random ID>
  2. Server caches: session_id → master_secret + cipher_suite
  3. Reconnection: ClientHello.session_id = <cached ID>
     → Server finds session → Skips Certificate + ServerKeyExchange
     → 1-RTT

Session Ticket (Stateless, RFC 5077):
  1. Server: Encrypts (master_secret + cipher_suite + ticket_lifetime)
     (using server's ticket key) → Sends to client → SessionTicket extension
  2. Reconnection: ClientHello.session_ticket = <encrypted blob>
     → Server decrypts ticket → Restores session → 1-RTT
     → Server does not need to store session state (cipher from ticket)

  Security: Ticket key must be kept secret + rotated regularly (ticket leak → historical session leak)
```

## References

- **RFC**: 5246, 6066, 7301, 5077, 7627 (Extended Master Secret)
- **Tools**: `openssl s_client -connect host:443 -tls1_2`, Wireshark `ssl.handshake`

*Keywords: TLS 1.2, ECDHE, cipher suite, session resumption, session ticket, SNI, ALPN, PRF*
