7. TLS 握手协议
TLS 握手协议负责协商连接的安全参数,并允许客户端和服务器相互进行身份认证(可选),然后建立共享密钥。握手协议封装在记录层之上,但可能在更改密码规范之前需要多次往返。
握手消息在记录层之上进行交换,并且必须按照本节中描述的顺序发送。除非另有说明,否则握手消息可以在握手期间发送,但必须按照下面显示的顺序发送。握手消息的发送和接收相对于握手的当前状态进行。
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;
握手协议消息类型:当 msg_type 为 hello_request 时,握手消息为 HelloRequest;当 msg_type 为 client_hello 时,握手消息为 ClientHello;依此类推。length 字段为握手消息剩余部分的长度(以字节为单位)。
7.1. 握手协议概述
TLS 握手协议包括以下步骤:
- 交换 hello 消息,以协商算法、交换随机值以及检查会话恢复。
- 交换必要的密码学参数,以允许客户端和服务器协商预主密钥。
- 交换证书和密码学信息,以允许客户端和服务器对自己进行身份认证(可选)。
- 生成主密钥,并从主密钥生成会话密钥。
- 向记录层提供安全参数。
- 允许客户端和服务器验证其对方已计算出相同的安全参数,并且握手是在无攻击者干扰的情况下完成的。
注意:由于握手过程可能会重新协商,因此在某些情况下,客户端和服务器可能会重新协商较新的安全参数,而无需重新执行整个握手过程。
7.2. 握手消息
7.2.1. Hello 消息
hello 消息用于协商连接的安全参数。
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
客户端通过发送 ClientHello 消息发起握手。该消息包含:客户端版本、客户端随机数、会话 ID、客户端支持的密码套件列表、客户端支持的压缩方法列表,以及可选的扩展。
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ServerHello;
服务器通过发送 ServerHello 消息进行响应,其中包含:服务器版本、服务器随机数、会话 ID、所选密码套件、所选压缩方法,以及可选的扩展。
7.2.2. 服务器密钥交换消息
ServerKeyExchange 消息在服务器未提供证书,或证书中不包含足够信息以允许客户端交换预主密钥时发送。该消息包含服务器密钥交换参数和签名。
struct {
select (KeyExchangeAlgorithm) {
case dhe_dss:
case dhe_rsa:
case dh_anon:
ServerDHParams params;
Signature signature;
case rsa:
case dh_rsa:
case dh_dss:
struct {};
};
} ServerKeyExchange;
7.2.3. 证书消息
Certificate 消息用于携带证书链。在 TLS 1.2 中,证书消息在服务器认证时发送,也可能在客户端认证时发送。
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
7.2.4. 服务器 hello done 消息
服务器通过发送 ServerHelloDone 消息来指示 hello 请求消息阶段已完成。
struct { } ServerHelloDone;
7.2.5. 客户端密钥交换消息
ClientKeyExchange 消息用于传输客户端密钥交换参数。
struct {
select (KeyExchangeAlgorithm) {
case rsa:
EncryptedPreMasterSecret;
case dhe_dss:
case dhe_rsa:
case dh_dss:
case dh_rsa:
case dh_anon:
ClientDiffieHellmanPublic;
} exchange_keys;
} ClientKeyExchange;
7.2.6. 证书验证消息
当客户端发送了含签名能力的证书时,会发送 CertificateVerify 消息以证明其对私钥的拥有权。
struct {
Signature signature;
} CertificateVerify;
7.2.7. 完成消息
Finished 消息用于验证握手过程是否成功完成。该消息是第一个使用刚刚协商的算法、密钥和密钥集保护的消息。
struct {
opaque verify_data[12];
} Finished;
verify_data 的值由 PRF 计算:
verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))[0..11]
其中 finished_label 在客户端为 "client finished",在服务器为 "server finished"。
7.3. 握手协议状态机
握手协议遵循明确的状态机。客户端和服务器按照上述消息顺序交换消息。任何一方在未完成当前握手步骤之前,都不得发送后续消息。
注意:本译文由 AI 翻译,可能包含错误。请参考 RFC 5246 官方英文原文进行核对。