跳至正文
老丹的足迹 —— 代码写给机器,游记写给自己,感悟写给时间
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面

安全传输层协议(TLS)全貌解析

一、协议概述

安全传输层协议(Transport Layer Security,简称TLS)是一种密码学协议,旨在为两个通信应用程序之间提供保密性和数据完整性。TLS是SSL(Secure Sockets Layer)协议的继承者,由IETF标准化,目前最新版本为TLS 1.3(RFC 8446,已被RFC 9846更新)。

TLS协议位于传输层(如TCP)与应用层之间,有时被称为”第6.5层协议”。它的设计目标是:认证(服务器端强制认证,客户端可选)、机密性(数据仅对通信端点可见)和完整性(数据不可被篡改而不被察觉)。即便攻击者完全控制网络,这些安全属性也应得到保障。

TLS最大的优势之一是独立于应用协议,HTTP(变为HTTPS)、SMTP、VPN等都可以透明地建立在TLS之上。TLS协议由两个主要组件构成:记录协议和握手协议。

二、TLS记录协议(Record Protocol)

记录协议是TLS的底层传输模块,位于可靠的传输协议(如TCP)之上,负责对上层数据进行封装、加密和完整性保护。记录协议的工作流程为:从高层接收数据 → 分片(每片不超过2^14字节即16KB)→ 可选的压缩(TLS 1.3已移除)→ 计算MAC并加密 → 添加头部 → 通过TCP发送。

2.1 明文记录(TLSPlaintext)

在握手早期,记录以明文形式传输,其结构如下:

字段名长度(字节)类型描述
type1ContentType内容类型。22=握手,23=应用数据,21=告警,20=变更密码规范(仅兼容性)
legacy_record_version2ProtocolVersionTLS 1.3中固定为0x0303(TLS 1.2版本号),仅用于向下兼容
length2uint16后续fragment字段的长度,最大值16384字节(2^14)
fragment可变(≤16KB)opaque实际负载数据,可以是握手消息、应用数据或告警信息的明文片段

2.2 密文记录(TLSCiphertext)

密钥协商完成后,所有记录都被加密传输,其结构如下:

字段名长度(字节)类型描述
opaque_type1ContentTypeTLS 1.3中恒为23(application_data),真实的内容类型被加密隐藏在负载内部
legacy_record_version2ProtocolVersion固定为0x0303
length2uint16后续encrypted_record字段的长度
encrypted_record可变opaque使用AEAD算法(如AES-GCM)加密后的数据,包含密文和认证标签,解密后才能还原真实内容类型

2.3 内容类型枚举

值常量名描述
20change_cipher_spec变更密码规范(TLS 1.3中已废弃,仅用于兼容性)
21alert告警消息
22handshake握手消息
23application_data应用数据

三、TLS握手协议(Handshake Protocol)

握手协议是TLS中最复杂的部分,负责对通信双方进行身份认证、协商加密算法和生成共享密钥。所有握手消息都遵循统一的头部格式:

3.1 握手消息通用头部

字段名长度(字节)类型描述
msg_type1HandshakeType握手消息类型(见下方各消息的具体值)
length3uint24后续消息体的长度
body可变opaque消息的具体内容,格式因msg_type而异

3.2 握手消息类型枚举

值常量名描述
1client_hello客户端发起握手
2server_hello服务器响应
4new_session_ticket新会话票据(用于恢复)
8encrypted_extensions加密扩展(TLS 1.3新增)
11certificate证书消息
13certificate_request请求客户端证书
15certificate_verify证书验证签名
20finished握手完成确认
24key_update密钥更新(TLS 1.3新增)
25message_hash消息哈希(TLS 1.3内部使用)

3.3 握手流程渲染图

完整的TLS 1.3握手可以清晰地分为三个阶段,如下图所示:

图例说明:{...} 表示消息已加密。从 EncryptedExtensions 开始到 Finished 的所有消息都已使用握手密钥加密传输。

四、握手消息字段详解

4.1 ClientHello 消息(msg_type = 1)

ClientHello是握手发起的第一条消息,客户端在此声明其能力和偏好。

字段名长度(字节)类型描述
legacy_version2ProtocolVersion固定为0x0303(TLS 1.2),实际版本在supported_versions扩展中协商
random32opaque客户端生成的32字节随机数,用于密钥派生和防重放攻击
legacy_session_id1 + 可变(≤32)opaque兼容旧版会话恢复,TLS 1.3中若无可用ID则生成32字节不可预测值
cipher_suites2 + 可变uint16数组客户端支持的加密套件列表,按优先级降序排列。如0x1301=TLS_AES_128_GCM_SHA256
legacy_compression_methods1 + 可变uint8数组TLS 1.3中必须只包含0x00(null压缩),不支持压缩功能
extensions2 + 可变Extension数组核心扩展区,包含supported_versions、key_share、pre_shared_key等

ClientHello中的关键扩展:

扩展名称类型值作用
supported_versions0x002B客户端列出所有支持的TLS版本
key_share0x0033携带(EC)DHE临时公钥,用于前向保密密钥交换
pre_shared_key0x0029PSK身份列表和绑定器,用于会话恢复(必须放在最后)
psk_key_exchange_modes0x002D声明PSK支持的交换模式(仅PSK或PSK+DHE)
signature_algorithms0x000D声明支持的签名算法(如rsa_pss_rsae_sha256)
supported_groups0x000A声明支持的椭圆曲线和有限域群组

4.2 ServerHello 消息(msg_type = 2)

服务器对ClientHello的响应,确认选定的参数。

字段名长度(字节)类型描述
legacy_version2ProtocolVersion固定为0x0303
random32opaque服务器生成的32字节随机数,最后8字节可用于版本降级防护(SCSV)
legacy_session_id_echo1 + 可变(≤32)opaque必须原样回显客户端发来的legacy_session_id
cipher_suite2uint16服务器从客户端列表中选择的一个加密套件
legacy_compression_method1uint8固定为0(null压缩)
extensions2 + 可变Extension数组必须包含key_share扩展,也可包含pre_shared_key等

4.3 EncryptedExtensions 消息(msg_type = 8)

服务器发送的已加密扩展,包含了在密钥交换后协商且需要保密的扩展信息。

字段名长度(字节)类型描述
extensions2 + 可变Extension数组加密传输的扩展,如server_name(用于SNI)、alpn(应用层协议协商)等

此消息在TLS 1.3中为新增,将之前版本中明文传输的扩展移入加密通道,显著增强了隐私保护。

4.4 CertificateRequest 消息(msg_type = 13,可选)

当服务器希望客户端提供证书进行身份认证时发送。

字段名长度(字节)类型描述
certificate_request_context1 + 可变opaque上下文标识符,服务器用于匹配证书请求和响应
extensions2 + 可变Extension数组指定可接受的证书参数,如signature_algorithms、authorized_keys等

4.5 Certificate 消息(msg_type = 11)

用于发送终端(通常是服务器,也可是客户端)的X.509数字证书链。

字段名长度(字节)类型描述
certificate_request_context1 + 可变opaque若响应CertificateRequest则原样回显,否则为空(0长度)
certificate_list3 + 可变CertificateEntry数组一个或多个X.509 DER格式证书组成的证书链
extensions2 + 可变Extension数组应用于整个证书链的扩展,如OCSP Stapling(status_request)

CertificateEntry内部结构:

字段名长度(字节)类型描述
cert_data3 + 可变opaqueX.509 DER编码的单个证书
extensions2 + 可变Extension数组该证书的扩展

4.6 CertificateVerify 消息(msg_type = 15)

使用证书对应的私钥对整个握手消息的哈希值进行签名,证明拥有该证书。

字段名长度(字节)类型描述
algorithm2SignatureScheme签名算法,如0x0804=rsa_pss_rsae_sha256,0x0805=rsa_pss_rsae_sha384
signature2 + 可变opaque数字签名值,签名覆盖整个握手过程的哈希(Transcript-Hash)

常见签名算法值:

值算法名称描述
0x0401rsa_pkcs1_sha256RSA PKCS#1 v1.5 + SHA-256(TLS 1.3中已废弃)
0x0804rsa_pss_rsae_sha256RSASSA-PSS + SHA-256
0x0805rsa_pss_rsae_sha384RSASSA-PSS + SHA-384
0x0806rsa_pss_rsae_sha512RSASSA-PSS + SHA-512
0x0603ecdsa_secp256r1_sha256ECDSA + SHA-256
0x0807ed25519Ed25519签名
0x0808ed448Ed448签名

4.7 Finished 消息(msg_type = 20)

这是握手过程中第一条使用当前密钥加密发送的消息,用于验证握手过程未被篡改,并提供密钥确认。

字段名长度(字节)类型描述
verify_data可变(32或48)opaque基于所有握手消息计算的验证数据,长度取决于哈希算法(SHA-256为32字节,SHA-384为48字节)

verify_data的计算方式为:

verify_data = HMAC_Hash(Secret, Transcript-Hash)

其中 Secret 是当前阶段的流量密钥,Transcript-Hash 是累积的所有握手消息的哈希值。

五、告警协议(Alert Protocol)

告警协议用于在通信过程中传递错误或警告信号,作为记录层type=21的fragment内容。

字段名长度(字节)类型描述
level1AlertLevel1=警告(Warning),2=致命(Fatal)。致命告警导致连接立即终止
description1AlertDescription具体告警类型,详见下表

常见告警描述值:

值常量名描述
10unexpected_message收到意外消息
20bad_record_macMAC校验失败
21decryption_failed解密失败(已废弃)
22record_overflow记录长度溢出
40handshake_failure握手失败
42bad_certificate证书损坏
43bad_certificate证书过期(注意:此描述值实际为43)
44decode_error解码错误
46certificate_unknown证书未知
47illegal_parameter非法参数
86internal_error内部错误
116missing_extension缺少必需扩展

六、扩展机制(Extensions)

扩展机制是TLS 1.3灵活性的核心基础,所有扩展使用统一的数据结构:

字段名长度(字节)类型描述
extension_type2ExtensionTypeIANA注册的扩展类型标识符
extension_data2 + 可变opaque扩展的具体数据,格式由extension_type决定

6.1 supported_versions 扩展(0x002B)

用于TLS 1.3真正的版本协商。

位置字段长度描述
ClientHelloversions2 + 可变客户端支持的所有版本列表,如{0x0303, 0x0304}
ServerHelloselected_version2服务器选择的版本,如0x0304(TLS 1.3)

6.2 key_share 扩展(0x0033)

携带(EC)DHE临时公钥,是提供前向保密的核心。

struct {
    NamedGroup group;           // 群组标识,如 secp256r1(0x0017)
    opaque key_exchange<1..2^16-1>;  // 公钥数据
} KeyShareEntry;
字段描述
ClientHello客户端可提供多个KeyShareEntry(每个支持的群组一个)
ServerHello服务器从客户端提供的列表中选择一个群组,回复对应的公钥
HelloRetryRequest若客户端未提供服务器支持的群组,服务器可要求客户端重试

常见命名群组值:

值群组名称描述
0x0017secp256r1NIST P-256椭圆曲线
0x0018secp384r1NIST P-384椭圆曲线
0x0019secp521r1NIST P-521椭圆曲线
0x001Dx25519Curve25519(推荐,高性能)
0x001Ex448Curve448
0x0100ffdhe2048有限域DH 2048位
0x0101ffdhe3072有限域DH 3072位

6.3 pre_shared_key 扩展(0x0029)

用于PSK身份认证和会话恢复。重要规则:在ClientHello中,此扩展必须放在最后。

struct {
    opaque identity<1..2^16-1>;      // PSK身份标识
    uint32 obfuscated_ticket_age;    // 混淆后的票据年龄(用于防重放)
} PskIdentity;

struct {
    PskIdentity identities<7..2^16-1>;  // PSK身份列表
    PskBinderEntry binders<33..2^16-1>; // 绑定器列表,用于验证PSK真实性
} OfferedPsks;

6.4 psk_key_exchange_modes 扩展(0x002D)

声明客户端在使用PSK时支持的密钥交换模式。

值模式名称描述
0psk_ke仅使用PSK,不使用(EC)DHE(不提供前向保密)
1psk_dhe_kePSK与(EC)DHE结合使用(提供前向保密,推荐)

规则:若提供了pre_shared_key扩展,则必须同时提供此扩展。服务器不得选择客户端未声明的模式。

6.5 signature_algorithms 扩展(0x000D)

声明支持的数字签名算法,用于证书验证。

字段长度描述
supported_signature_algorithms2 + 可变SignatureScheme值列表,按优先级降序排列

6.6 supported_groups 扩展(0x000A)

声明支持的椭圆曲线和有限域群组,用于ECDHE和DHE密钥交换。

字段长度描述
supported_groups2 + 可变NamedGroup值列表,按优先级降序排列

七、密钥派生与计算(Key Derivation)

TLS 1.3的密钥派生系统基于HKDF(HMAC-based Extract-and-Expand Key Derivation Function),整个派生过程像一条严密的生产线,逐级生产出不同用途的密钥。

7.1 密钥派生流程图

7.1.1 密钥派生阶段说明表

阶段输入核心操作输出用途
阶段一:输入PSK(或0)HKDF-ExtractEarly Secret早期秘密,作为后续派生的根
阶段二:早期密钥Early SecretDerive-Secretclient_early_traffic_secret保护0-RTT数据
Early SecretDerive-Secretderived_secret_1作为盐值输入下一阶段
阶段三:握手密钥derived_secret_1 + (EC)DHEHKDF-ExtractHandshake Secret握手秘密,作为后续派生的根
Handshake SecretDerive-Secretclient_handshake_traffic_secret保护客户端发送的握手消息
Handshake SecretDerive-Secretserver_handshake_traffic_secret保护服务器发送的握手消息
Handshake SecretDerive-Secretderived_secret_2作为盐值输入下一阶段
阶段四:主密钥derived_secret_2 + 0HKDF-ExtractMaster Secret主密钥,作为应用密钥的根
Master SecretDerive-Secretclient_application_traffic_secret_0保护客户端发送的应用数据
Master SecretDerive-Secretserver_application_traffic_secret_0保护服务器发送的应用数据
Master SecretDerive-Secretresumption_master_secret生成NewSessionTicket用于会话恢复

7.1.2 流量密钥派生公式表

在实际加密通信时,每个阶段的traffic_secret会被进一步展开为具体的加密密钥和IV:

密钥类型派生公式说明
[sender]_write_keyHKDF-Expand-Label(Secret, "key", "", key_length)对称加密密钥
[sender]_write_ivHKDF-Expand-Label(Secret, "iv", "", iv_length)初始化向量
密钥更新HKDF-Expand-Label(Secret_old, "traffic upd", "", Hash.length)新密钥由旧密钥派生

其中 Secret 根据阶段选择:

  • 握手阶段:client_handshake_traffic_secret 或 server_handshake_traffic_secret
  • 应用阶段:client_application_traffic_secret_0 或 server_application_traffic_secret_0

7.1.3 关键函数说明

函数全称作用
HKDF-ExtractHMAC-based Extract-and-Expand Key Derivation Function – Extract从输入材料中提取出固定长度的伪随机密钥,将熵集中化
Derive-SecretHKDF-Expand-Label 的封装使用特定的标签(Label)从现有秘密派生出新的秘密,确保不同用途的密钥相互独立
HKDF-Expand-LabelHKDF-Expand with Label在HKDF-Expand基础上加入”标签”和”上下文”,实现结构化派生,是TLS 1.3中所有密钥派生的原子操作

Derive-Secret 的完整定义:

Derive-Secret(Secret, Label, Messages) = 
    HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length)

其中 Transcript-Hash(Messages) 是截至当前所有握手消息的累积哈希值,这使得密钥与握手上下文绑定,防止重放和降级攻击。

7.2 流量密钥计算

最终用于加密记录层的密钥和初始化向量(IV)由对应阶段的Secret通过HKDF-Expand-Label函数派生:

密钥类型派生公式长度
写密钥(Write Key)HKDF-Expand-Label(Secret, "key", "", key_length)由密码套件决定(如AES-128为16字节)
写IV(Write IV)HKDF-Expand-Label(Secret, "iv", "", iv_length)由密码套件决定(如AES-GCM为12字节)

密钥更新机制:当需要更新密钥时,新密钥由旧密钥派生:

application_traffic_secret_N+1 = HKDF-Expand-Label(
    application_traffic_secret_N, 
    "traffic upd", 
    "", 
    Hash.length
)

7.3 密钥派生阶段说明

阶段输入输出用途
早期密钥(Early Secret)PSK(可选)或0client_early_traffic_secret保护0-RTT数据;若未使用PSK,输入为0
握手密钥(Handshake Secret)早期密钥派生结果 + (EC)DHE共享秘密client_handshake_traffic_secret
server_handshake_traffic_secret
保护EncryptedExtensions、Certificate等握手消息
主密钥(Master Secret)握手密钥派生结果 + 0client_application_traffic_secret_0
server_application_traffic_secret_0
resumption_master_secret
保护应用数据;生成会话恢复票据

八、TLS 1.3 vs TLS 1.2 关键差异

特性TLS 1.2TLS 1.3
握手延迟2-RTT(完整握手)1-RTT(完整握手),0-RTT(恢复)
前向保密可选,RSA密钥交换不提供强制,仅支持(EC)DHE和PSK+DHE
密码套件多种AEAD和非AEAD算法(CBC模式)仅AEAD(AES-GCM、ChaCha20-Poly1305)
证书加密明文传输(隐私风险)加密传输(增强了隐私保护)
ChangeCipherSpec独立消息已移除(仅用于兼容性)
压缩支持(有安全风险)不支持
签名算法支持多种(包括SHA-1)禁用SHA-1和RSA PKCS#1 v1.5
扩展灵活性有限高度灵活,大量使用扩展
密钥更新流程复杂简化的KeyUpdate消息
会话恢复Session ID/Session Ticket简化的PSK + 票据机制

九、安全影响与挑战

TLS 1.3的前向保密特性在提升安全性的同时,也给企业网络安全监控带来了挑战。传统的被动解密技术(依赖保存的私钥解密历史流量)在TLS 1.3中不再有效,因为每个会话的密钥都是临时生成的。企业需要采用替代方案来维持网络可见性,如端点日志收集、中间代理等,但这些方案各有局限。

此外,0-RTT模式虽然大幅减少了连接延迟,但由于数据在完成完整握手前就已发送,存在重放攻击风险,应用程序在使用0-RTT时需要采取适当的防护措施。

十、总结

TLS 1.3通过精妙的分层架构、严格的握手流程、基于HKDF的密钥派生系统和灵活的扩展机制,为互联网通信提供了坚实的安全底座。从记录层的加密封装,到握手阶段的复杂协商,再到不同密钥阶段的隔离设计,TLS 1.3在安全性、性能和隐私保护方面树立了新的标杆。其主要改进——强制前向保密、加密握手信息、精简密码套件——代表了密码协议设计的前沿方向,也为后量子时代的密码升级奠定了坚实基础。

作者

老丹

关注我
其他文章
上一个

HKDF:算法规范、C++11实现与可证明安全分析

下一个

Netlink 深度剖析:从内核实现到应用开发的完整图景

关于博主

    老丹是一名C/C++后台开发工程师,信奉“无抽象不设计,无性能不生产”。

  • 技术栈:Modern C++、Linux环境编程、多线程/并发、网络编程等。
  • 信条:能用constexpr解决的问题绝不拖到运行时,能靠RAII避免的泄漏绝不写析构。
  • 正在填坑:从解封装到渲染的C++全链路实现,正在驯服FFmpeg与H.264/H.265。
  • 输出原则:这里的每一段代码都经过-Wall -Wextra -Werror -O2的洗礼。

近期文章

  • Linux系统的安全基石:深入理解可插拔认证模块(PAM) 2026年7月27日
  • vsftpd 完全指南:从核心原理到Docker容器化部署 2026年7月27日
  • 互联网的”导航”安全卫士:深入解读DNSSEC 2026年7月27日
  • Ubuntu DNS 配置完全指南 2026年7月27日
  • 在 Ubuntu 中使用 Certbot 的操作指南 2026年7月27日

文章分类

  • C/C++开发 (13)
  • Docker容器 (3)
  • Linux工具包 (10)
  • Linux服务配置 (33)
  • Linux系统 (10)
  • OpenWrt路由 (2)
  • Shell脚本 (3)
  • 安防技术 (4)
  • 数据安全 (30)
  • 网络协议 (17)
  • 计算机理论 (22)
联系我们:📍 地址:中国·广东省深圳市   |   ✉️ 邮箱:support@tanglinux.com   |   💬 QQ:870866607
版权所有:老丹的足迹粤ICP备2026061170号-1       公安备案图标 粤公网安备44030002013274号