Il TLS handshake è la procedura di negoziazione con cui un client e un server stabiliscono una sessione TLS sicura prima di scambiare dati applicativi. Durante l’handshake le due parti concordano la versione del protocollo e la suite crittografica, il server dimostra la propria identità tramite certificato X.509, e vengono derivate le chiavi simmetriche che proteggeranno la comunicazione successiva. L’handshake è il momento in cui la sicurezza dell’intera sessione viene stabilita o compromessa.
TLS 1.3: handshake a 1-RTT
TLS 1.3 (RFC 8446, 2018) ha semplificato radicalmente il handshake rispetto a TLS 1.2, riducendo la latenza a 1 RTT (round-trip time) e migliorando la sicurezza eliminando le suite crittografiche deboli.
Client Server
| |
|── ClientHello ────────────────────────▶ |
| (versione, key_share, cipher_suites) |
| |
|◀─ ServerHello ──────────────────────── |
| (key_share, cipher_suite scelta) |
|◀─ {Certificate} ───────────────────── |
|◀─ {CertificateVerify} ──────────────── |
|◀─ {Finished} ───────────────────────── |
| |
|── {Finished} ───────────────────────▶ |
| |
|═══ Dati applicativi cifrati (AEAD) ════ |
I messaggi tra {} sono già cifrati con chiavi derivate dopo il primo scambio ECDHE.
ClientHello: il client invia le versioni TLS supportate, le suite crittografiche accettate e — novità TLS 1.3 — già le key shares ECDHE per le curve che si aspetta il server accetti (tipicamente X25519 e P-256). Questo permette al server di completare lo scambio di chiavi nella stessa risposta, risparmiando un RTT.
ServerHello + chiavi derivate: il server sceglie la suite crittografica, seleziona la key share del client, calcola il segreto condiviso ECDHE e da esso deriva le chiavi di cifratura della sessione (handshake keys). Tutto ciò che segue è già cifrato.
Certificate + CertificateVerify: il server invia il certificato (ora cifrato — non visibile a chi intercetta il traffico) e una firma sul transcript dell’handshake con la propria chiave privata. Questo prova che il server possiede la chiave privata corrispondente al certificato.
Finished: MAC sull’intero transcript dell’handshake. Garantisce che nessun messaggio sia stato alterato in transito.
TLS 1.3: 0-RTT (early data)
TLS 1.3 introduce la modalità 0-RTT: se client e server si sono già connessi in precedenza, il client può inviare dati applicativi già nel primo messaggio, prima del completamento dell’handshake, usando una pre-shared key (PSK) derivata dalla sessione precedente. Riduce la latenza a zero RTT ma con un costo: i dati 0-RTT non sono protetti dalla forward secrecy e sono vulnerabili a replay attack — un attaccante che cattura il messaggio 0-RTT può ritrasmetterlo al server. Va usato solo per operazioni idempotenti (es. GET, non POST che modificano stato).
TLS 1.2 vs. TLS 1.3
| Aspetto | TLS 1.2 | TLS 1.3 |
|---|---|---|
| RTT per handshake | 2 RTT | 1 RTT |
| Forward secrecy | Opzionale (dipende dalla suite) | Obbligatoria (solo ECDHE/DHE) |
| Suite crittografiche | Molte, incluse deboli (RC4, 3DES, export) | Solo AEAD moderne (AES-GCM, ChaCha20-Poly1305) |
| RSA key exchange | Sì (no forward secrecy) | Eliminato |
| Renegotiation | Sì (fonte di vulnerabilità) | Eliminata |
| Certificato visibile | Sì, in chiaro durante handshake | Cifrato (Encrypted Client Hello in bozza) |
Verifica del certificato lato client
Durante l’handshake, il client verifica il certificato del server:
- La catena di certificati risale a una CA root nel trust store del client
- Nessun certificato nella catena è scaduto
- Nessun certificato nella catena è stato revocato (OCSP stapling)
- Il Common Name o un Subject Alternative Name corrisponde al hostname richiesto
- Il certificato è stato firmato con l’algoritmo dichiarato
Se una qualsiasi verifica fallisce, la connessione viene interrotta con un alert TLS. Ignorare errori di certificato (certificate errors) — pratica purtroppo comune in sviluppo — apre la porta ad attacchi MitM.