2. TLS协议栈与握手流程
TLS 并不是一个单一协议,而是一套分层协作的协议族。理解 TLS,关键不是背握手报文的顺序,而是看清两条主线:一条是握手层负责“谈条件、验身份、算密钥”,另一条是记录层负责“把应用数据切成记录、加密、加完整性保护再发出去”。两者分工明确,又通过握手阶段协商出的密钥与算法参数紧密耦合。
一、协议栈分层:谁负责什么
从下往上看,TLS 位于可靠的传输层(通常是 TCP)之上、应用层(HTTP、SMTP 等)之下。它自身分为两层:
- 记录层(Record Layer):TLS 的“运输底座”。它接收上层交来的数据,按不超过 2^14 字节(16384 字节)的明文分片上限切分为记录,然后依次执行压缩(现代 TLS 已禁用)、计算 MAC、加密,最后加上 5 字节记录头(内容类型 1 字节、版本 2 字节、长度 2 字节)发出。接收方反向执行解密、校验 MAC、重组。
- 握手层(Handshake Layer):包含握手协议、警报协议、变更密码规格协议和应用数据协议。握手协议负责协商版本、密码套件、交换密钥材料、认证对端;警报协议传递 close_notify、handshake_failure 等状态;变更密码规格协议在 TLS 1.2 中用于切换后续记录的加密状态。
需要特别强调:握手报文本身也是通过记录层传输的。握手初期,记录层以明文承载握手消息;当双方通过 ChangeCipherSpec 或 TLS 1.3 的密钥派生切换到加密状态后,后续握手消息(如 Finished)就在加密记录中传输。这就是“分层协作”的第一层含义。
二、握手流程:从 ClientHello 到 Finished
以 TLS 1.2 的完整握手(ECDHE 密钥交换)为例,典型报文序列如下:
- ClientHello:客户端发送支持的 TLS 版本、密码套件列表、随机数 ClientRandom、扩展(如 SNI、supported_groups、signature_algorithms)。
- ServerHello:服务端选定版本与密码套件,返回 ServerRandom,并附带密钥交换参数(如 ECDHE 的 ServerKeyExchange 中的公钥与签名)。
- Certificate:服务端发送证书链,供客户端验证身份。
- ServerHelloDone:服务端表示握手第一阶段结束。
- ClientKeyExchange:客户端生成 ECDHE 私钥,计算共享密钥,发送自己的公钥。
- ChangeCipherSpec + Finished:客户端切换加密状态,发送用新密钥保护的 Finished,其中包含对之前所有握手消息的哈希校验。
- 服务端 ChangeCipherSpec + Finished:服务端同样切换并回送 Finished。
握手完成后,双方各自持有:主密钥(Master Secret)→ 通过 PRF 派生出客户端写 MAC 密钥、服务端写 MAC 密钥、客户端写加密密钥、服务端写加密密钥、客户端写 IV、服务端写 IV。这些参数正是记录层后续加解密所依赖的“密钥材料”。
三、密钥交换、认证与完整性的协作
三者不是并列关系,而是有明确的因果链:
- 密钥交换解决“双方如何在不安全信道上得到相同的共享秘密”。ECDHE 利用椭圆曲线离散对数难题,双方各自生成临时私钥,交换公钥后独立计算出相同的共享点,即使长期私钥泄露也不影响本次会话密钥(前向保密)。
- 认证解决“我怎么确认对面真的是它”。服务端用证书私钥对握手参数签名,客户端用证书链中的公钥验签,并校验证书有效期、域名、吊销状态。认证失败则握手终止,不会进入加密通信。
- 完整性解决“数据有没有被篡改”。TLS 1.2 使用 HMAC(如 HMAC-SHA256)对记录内容计算 MAC,与密文一起发送;TLS 1.3 改用 AEAD(如 AES-GCM、ChaCha20-Poly1305),加密与认证一次完成。Finished 消息则是对全部握手消息的哈希做完整性校验,防止握手被中间人篡改。
协作要点:密钥交换产生共享秘密 → PRF 派生会话密钥 → 记录层用会话密钥加密并计算 MAC → Finished 用握手哈希验证整个握手过程未被篡改。任何一环失败,TLS 都会以警报终止连接,而不是降级继续。
四、TLS 1.3 的关键变化
TLS 1.3 对上述机制做了大幅精简:
- 废弃 RSA 密钥交换,只保留 (EC)DHE,强制前向保密。
- 握手从 2-RTT 缩短为 1-RTT,并支持 0-RTT 会话恢复(但 0-RTT 数据不具备前向保密,需谨慎使用)。
- 记录层统一使用 AEAD,删除显式 MAC-then-Encrypt 模式。
- ServerHello 之后立即派生握手密钥,后续握手消息全部加密,证书也不再明文暴露。
- ChangeCipherSpec 仅作为兼容性占位,不再承担密钥切换语义。
下面这张图展示了 TLS 1.2 完整握手中,握手层与记录层的协作关系,以及密钥交换、认证、完整性三条线索如何汇聚到记录层的加密通道。
五、实践中的观察与判断
在实际排障或验证时,可以用以下方式观察上述协作是否正常:
- 用
openssl s_client -connect example.com:443 -tls1_2 -msg可以看到每条握手报文的明文十六进制,确认 ClientHello 中的密码套件与 ServerHello 的选定结果是否匹配。 - 用 Wireshark 过滤
tls.handshake,观察 Certificate 之后是否出现 ServerKeyExchange;若使用 RSA 密钥交换则没有该报文,这也是判断是否具备前向保密的依据。 - 若握手在 Certificate 之后立即出现
alert(level=fatal, description=bad_certificate),说明认证环节失败,应检查证书链是否完整、SNI 是否匹配、系统时间是否正确。 - 若 Finished 校验失败,通常表现为
decrypt_error或bad_record_mac,说明密钥派生或握手哈希不一致,常见原因是中间设备篡改了握手报文或双方版本/套件协商不一致。
判断要点:只要握手成功完成,记录层就获得了可用的会话密钥;此后所有应用数据都走加密记录。若应用层出现明文或 MAC 错误,问题通常不在应用代码,而在记录层的密钥状态或中间设备干预。
总结来看,TLS 的协作机制可以概括为:握手层负责“建立信任与密钥”,记录层负责“用密钥保护数据”,密钥交换提供共享秘密,认证确认对端身份,完整性防止篡改。四者环环相扣,任何一环缺失或失败,TLS 都不会降级为明文继续通信,这正是它作为传输安全基石的可靠性来源。