7. I protocolli di handshake TLS (The TLS Handshaking Protocols)
Il protocollo di handshake TLS (TLS Handshake Protocol) è responsabile delle seguenti funzioni:
- Negoziazione della versione TLS e della suite di cifratura
- Autenticazione del server e del client
- Negoziazione dei parametri di crittografia e delle chiavi
- Rilevamento degli errori di trasmissione
Il protocollo di handshake è composto da tre sotto-protocolli:
7.1. Protocollo di modifica delle specifiche di cifratura (Change Cipher Spec Protocol)
Il protocollo di modifica delle specifiche di cifratura (Change Cipher Spec Protocol) viene utilizzato per notificare al peer che i record successivi saranno protetti con la CipherSpec e le chiavi appena negoziate. Il protocollo consiste in un singolo messaggio, che viene crittografato e compresso con la CipherSpec corrente (non quella in attesa). Il messaggio consiste in un singolo byte di valore 1.
struct {
enum { change_cipher_spec(1), (255) } type;
} ChangeCipherSpec;
Il messaggio ChangeCipherSpec viene inviato durante l'handshake dopo che i parametri di sicurezza sono stati concordati. Il destinatario di un messaggio ChangeCipherSpec DEVE (MUST) aggiornare lo stato di lettura in attesa allo stato di lettura corrente. Un messaggio Finished viene inviato immediatamente dopo questo messaggio, utilizzando i nuovi algoritmi, chiavi e segreti. Le implementazioni NON DEVONO (MUST NOT) inviare messaggi ChangeCipherSpec fino al completamento dell'handshake. Il primo messaggio ricevuto dopo questo messaggio DEVE (MUST) essere un messaggio Finished.
7.2. Protocollo di avviso (Alert Protocol)
TLS fornisce messaggi Alert per trasmettere avvisi alle entità peer. Come per gli altri messaggi, i messaggi di avviso sono crittografati e compressi utilizzando lo stato di connessione corrente.
enum { warning(1), fatal(2), (255) } AlertLevel;
enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed_RESERVED(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
no_certificate_RESERVED(41),
bad_certificate(42),
unsupported_certificate(43),
certificate_revoked(44),
certificate_expired(45),
certificate_unknown(46),
illegal_parameter(47),
unknown_ca(48),
access_denied(49),
decode_error(50),
decrypt_error(51),
export_restriction_RESERVED(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
unsupported_extension(110),
(255)
} AlertDescription;
struct {
AlertLevel level;
AlertDescription description;
} Alert;
7.2.1. Avvisi di chiusura (Closure Alerts)
Il client e il server DEVONO (MUST) condividere informazioni di chiusura prima di chiudere il lato di scrittura della connessione. Entrambe le parti possono avviare la chiusura della propria connessione inviando un avviso close_notify. Qualsiasi parte che riceve un avviso di chiusura DEVE (MUST) cessare immediatamente di inviare nuovi dati sulla connessione. Dopo aver trasmesso un close_notify, un'implementazione NON DEVE (MUST NOT) inviare dati su quella connessione.
7.2.2. Avvisi di errore (Error Alerts)
La gestione degli errori nel protocollo TLS è molto semplice. Quando viene rilevato un errore, la parte che lo rileva invia un messaggio al suo peer. Alla trasmissione o ricezione di un avviso fatale, entrambe le parti DEVONO (MUST) chiudere immediatamente la connessione. I server e i client DEVONO (MUST) dimenticare i valori segreti e le chiavi stabilite nelle connessioni fallite.
Sono definiti i seguenti avvisi di errore:
- unexpected_message: È stato ricevuto un messaggio inappropriato. Questo avviso non dovrebbe mai essere osservato da parti correttamente implementate.
- bad_record_mac: Questo avviso viene restituito se viene ricevuto un record con un MAC errato. Questo messaggio è sempre fatale.
- record_overflow: È stato ricevuto un record TLSCiphertext che aveva una lunghezza superiore a 2^14+2048 byte, oppure un record è stato decrittografato in un record TLSCompressed con più di 2^14 byte (o qualche altro limite negoziato per lo stato di connessione). Questo messaggio è sempre fatale.
- handshake_failure: La ricezione di un messaggio di avviso handshake_failure indica che il mittente non è stato in grado di negoziare un insieme accettabile di parametri di sicurezza date le opzioni disponibili.
- bad_certificate: Un certificato era corrotto, conteneva firme che non venivano verificate correttamente, ecc.
- unsupported_certificate: Un certificato era di un tipo non supportato.
- certificate_revoked: Un certificato è stato revocato dal suo firmatario.
- certificate_expired: Un certificato è scaduto o non è attualmente valido.
- certificate_unknown: È sorto qualche altro problema (non specificato) nell'elaborazione del certificato, rendendolo inaccettabile.
- illegal_parameter: Un campo nell'handshake era fuori intervallo o incoerente con altri campi. Questo messaggio è sempre fatale.
- unknown_ca: È stata ricevuta una catena di certificati valida o parziale, ma il certificato non è stato accettato perché il certificato CA non poteva essere localizzato o non poteva essere abbinato a una CA nota e fidata.
- access_denied: È stato ricevuto un certificato valido, ma quando è stato applicato il controllo degli accessi, il mittente ha deciso di non procedere con la negoziazione.
- decode_error: Un messaggio non poteva essere decodificato perché un campo era fuori dall'intervallo specificato o la lunghezza del messaggio era errata. Questo messaggio è sempre fatale.
- decrypt_error: Un'operazione crittografica di handshake è fallita, inclusa l'impossibilità di verificare correttamente una firma o convalidare un messaggio Finished.
- protocol_version: La versione del protocollo che il peer ha tentato di negoziare è riconosciuta ma non supportata.
- insufficient_security: Restituito al posto di handshake_failure quando una negoziazione è fallita specificamente perché il server richiede cifrari più sicuri di quelli supportati dal client.
- internal_error: Un errore interno non correlato al peer o alla correttezza del protocollo (come un fallimento di allocazione della memoria) rende impossibile continuare. Questo messaggio è sempre fatale.
- user_canceled: Questo handshake viene annullato per un motivo non correlato a un fallimento del protocollo.
- no_renegotiation: Inviato da un client in risposta a una richiesta hello o dal server in risposta a un client hello dopo l'handshake iniziale. Questo messaggio è sempre un avviso.
- unsupported_extension: Inviato da server che non sono in grado di comprendere un'estensione.
7.3. Panoramica del protocollo di handshake (Handshake Protocol Overview)
Il protocollo di handshake TLS comporta i seguenti passaggi:
- Scambiare messaggi hello per concordare gli algoritmi, scambiare valori casuali e verificare la ripresa della sessione.
- Scambiare i parametri crittografici necessari per consentire al client e al server di concordare un segreto pre-master.
- Scambiare certificati e informazioni crittografiche per consentire al client e al server di autenticarsi.
- Generare un segreto master dal segreto pre-master e dai valori casuali scambiati.
- Fornire parametri di sicurezza al livello di record.
- Consentire al client e al server di verificare che il loro peer abbia calcolato gli stessi parametri di sicurezza e che l'handshake sia avvenuto senza essere manomesso da un attaccante.
Nota: Questo documento fornisce solo una panoramica del protocollo di handshake TLS 1.2. Per dettagli tecnici completi, consultare la sezione 7.4 e le sezioni successive della RFC 5246.
7.4. Protocollo di handshake (Handshake Protocol)
Il protocollo di handshake TLS è uno dei client di livello superiore definiti del livello di record TLS. Questo protocollo viene utilizzato per negoziare gli attributi di sicurezza di una connessione. I messaggi di handshake vengono forniti al livello di record TLS, dove vengono incapsulati in una o più strutture TLSPlaintext, che vengono elaborate e trasmesse come specificato dallo stato di connessione attivo corrente.
enum {
hello_request(0), client_hello(1), server_hello(2),
certificate(11), server_key_exchange (12),
certificate_request(13), server_hello_done(14),
certificate_verify(15), client_key_exchange(16),
finished(20), (255)
} HandshakeType;
struct {
HandshakeType msg_type;
uint24 length;
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;
I messaggi del protocollo di handshake sono presentati con lunghezze esplicite e non possono essere frammentati attraverso i confini dei record di handshake. Cioè, ogni messaggio di handshake deve adattarsi interamente a un singolo record di handshake o estendersi su più record di handshake, ciascuno contenente un numero intero di messaggi di handshake. I destinatari DEVONO (MUST) verificare che non vi siano altri dati che seguono un messaggio di handshake nello stesso record di handshake, a meno che tali dati non costituiscano essi stessi messaggi di handshake validi.
Per i tipi di messaggi di handshake completi e i formati dettagliati, consultare le sottosezioni della sezione 7.4 nella RFC 5246.