国密 TLS 协议详解:GM/T 0024 与 RFC 8998 的握手流程、消息格式与双证书体系
概述
传输层安全(Transport Layer Security, TLS)是互联网上应用最广泛的安全协议。标准 TLS 由 IETF 定义,从 SSL 3.0(1996)演进到 TLS 1.3(RFC 8446, 2018),支撑着 HTTPS、SMTPS、LDAPS 等几乎所有需要安全通信的协议。
中国的国密 TLS 经历了三条独立的技术路线:
| 路线 | 标准编号 | 发布年份 | 协议基础 | 适用场景 |
|---|---|---|---|---|
| TLCP | GB/T 38636-2020 | 2020 | 基于 TLS 1.1 框架改造 | 政务、金融内网 |
| SSL VPN | GM/T 0024-2014 | 2014 | 基于 TLS 1.1/1.2 | VPN、安全网关 |
| TLS 1.3 国密套件 | RFC 8998 / GM/T 0024-2023 | 2021/2023 | TLS 1.3 框架 | 通用 Web、API |
协议版本演进
TLCP(GB/T 38636-2020)
TLCP(Transport Layer Cryptography Protocol)是中国最早的国密传输层安全标准。其核心设计理念是与国际 TLS 平行发展——不是在国际 TLS 上"插拔"算法,而是定义一套完全独立的协议栈。
协议版本号:0x0101(区别于 TLS 的 0x0301/0x0302/0x0303)
握手流程(简化):
Client Server
| |
|--- ClientHello (支持的国密套件) ------------->|
|<-- ServerHello (选定套件) ---------------------|
|<-- Certificate (签名证书 + 加密证书) ----------|
|<-- ServerKeyExchange (SM2 公钥参数) ----------|
|<-- ServerHelloDone ----------------------------|
|--- ClientKeyExchange (用加密证书公钥封装) ----->|
|--- ChangeCipherSpec -------------------------->|
|--- Finished ----------------------------------->|
|<-- ChangeCipherSpec ----------------------------|
|<-- Finished ------------------------------------|TLCP 的核心特征:
- 协议版本号独立:使用
0x0101而非 TLS 的0x03xx,客户端和服务端通过版本号即可区分 TLCP 和标准 TLS - 强制双证书:服务端必须持有签名证书和加密证书两张证书
- 密钥交换使用 SM9:ServerKeyExchange 中使用 SM9 标识密码进行密钥协商(部分实现也支持 SM2 ECDHE)
- 与国际 TLS 不兼容:TLCP 客户端无法与标准 TLS 服务端建立连接,反之亦然
GM/T 0024-2014(SSL VPN 技术规范)
GM/T 0024-2014 定义了基于 TLS 1.1/1.2 框架的国密 SSL 协议。与 TLCP 不同,它复用国际 TLS 的协议版本号(0x0302 表示 TLS 1.1,0x0303 表示 TLS 1.2),只是在密码套件中定义国密算法。
密码套件定义(GM/T 0024-2014):
ECC-SM2-SM4-CBC-SM3 // SM2 密钥交换 + SM4-CBC 加密 + SM3 HMAC
ECC-SM2-SM4-GCM-SM3 // SM2 密钥交换 + SM4-GCM 加密认证 + SM3
ECDHE-SM2-SM4-CBC-SM3 // SM2 ECDHE + SM4-CBC 加密 + SM3 HMAC
ECDHE-SM2-SM4-GCM-SM3 // SM2 ECDHE + SM4-GCM 加密认证 + SM3
IBS-SM9-SM4-CBC-SM3 // SM9 标识密钥交换 + SM4-CBC + SM3
IBS-SM9-SM4-GCM-SM3 // SM9 标识密钥交换 + SM4-GCM + SM3关键差异:GM/T 0024-2014 的握手流程与国际 TLS 1.2 基本一致(ServerKeyExchange、CertificateRequest 等消息格式相同),只是算法被替换为国密。但它也引入了双证书的概念——当服务端使用 SM2 证书时,Certificate 消息中需要包含签名证书和加密证书两个证书链。
RFC 8998 / TLS_SM4_GCM_SM3(TLS 1.3 国密套件)
RFC 8998(2021 年 3 月发布)代表了国密 TLS 的最新方向:完全融入 TLS 1.3 框架,不做任何协议层面的修改。
新增密码套件:
TLS_SM4_GCM_SM3 (0x00C6) // SM4-GCM 加密认证 + SM3 哈希
新增签名算法:
sm2sig_sm3 (0x0708) // SM2 签名 + SM3 哈希
新增命名曲线:
curveSM2 (41) // SM2 椭圆曲线参数RFC 8998 的握手流程与标准 TLS 1.3 完全一致——1-RTT 握手、0-RTT early data、PSK 恢复等特性全部保留。唯一的变化是"算法积木"的替换。
双证书体系
设计动机
国密 TLS 最独特的架构特征是双证书体系(Dual Certificate System)。在国际 TLS 中,一张证书既用于身份验证(签名),也用于密钥交换(加密)。国密体系要求将这两个功能分离:
┌─────────────────────────────────────────────────────┐
│ 服务端证书资产 │
├────────────────────────┬────────────────────────────┤
│ 签名证书 │ 加密证书 │
├────────────────────────┼────────────────────────────┤
│ 用途:CertificateVerify │ 用途:密钥封装/密钥恢复 │
│ 中的身份签名 │ │
├────────────────────────┼────────────────────────────┤
│ 密钥生成:服务端自行生成 │ 密钥生成:CA 或 KMC 生成 │
├────────────────────────┼────────────────────────────┤
│ 私钥保管:不出服务端设备 │ 私钥可被第三方托管 │
├────────────────────────┼────────────────────────────┤
│ 安全属性:不可否认性 │ 安全属性:可恢复性 │
├────────────────────────┼────────────────────────────┤
│ KeyUsage: │ KeyUsage: │
│ digitalSignature │ keyEncipherment │
│ │ dataEncipherment │
├────────────────────────┼────────────────────────────┤
│ 证书链:SM2 签名 CA 体系 │ 证书链:SM2 加密 CA 体系 │
│ (可相同或不同) │ (通常与签名 CA 不同) │
└────────────────────────┴────────────────────────────┘为什么需要两张证书?
这一设计根植于中国的密码管理政策法规:
- 签名密钥自主可控:签名私钥由终端自行生成,任何第三方(包括 CA)不持有签名私钥。这保证了签名的不可否认性——只有持有者本人才能产生有效签名。
- 加密密钥可托管恢复:加密私钥由密钥管理中心(KMC)或 CA 生成并托管。在密钥丢失、员工离职、司法取证等场景下,KMC 可以使用加密私钥恢复加密数据。
- 职责分离:在组织内部,负责管理签名密钥的人员与管理加密密钥的人员不同,实现了密码资产的内部分权制约。
Certificate 消息格式
在 TLS 1.3 中,Certificate 消息的 certificate_list 是一个数组,可以携带多张证书。国密 TLS 利用这一机制携带双证书链:
Certificate 消息结构(简化):
CertificateRequestContext: <0..2^24-1> 字节
CertificateList:
[0] 签名叶子证书(KeyUsage: digitalSignature)
[1] 签名中间 CA 证书(可能多张)
[2] 加密叶子证书(KeyUsage: keyEncipherment)
[3] 加密中间 CA 证书(可能多张)客户端通过证书的 KeyUsage 扩展来区分签名证书和加密证书。Tongsuo(铜锁)等实现中,服务端在握手阶段根据 ClientHello 中的 signature_algorithms 扩展选择证书路径:
证书选择逻辑:
if (ClientHello 包含 sm2sig_sm3) {
// 国密路径
ServerHello.cipher_suite = TLS_SM4_GCM_SM3;
Certificate = [签名证书链 + 加密证书链];
CertificateVerify = SM2 签名密钥签名;
} else {
// 国际路径(降级)
ServerHello.cipher_suite = TLS_AES_128_GCM_SHA256;
Certificate = [ECDSA/RSA 证书链];
CertificateVerify = ECDSA/RSA 签名密钥签名;
}密钥调度机制
TLS 1.3 密钥调度回顾
RFC 8998 完全复用 TLS 1.3 的密钥调度框架,仅将底层哈希从 SHA-256 替换为 SM3。TLS 1.3 的密钥调度采用以下层级结构:
0×32(全零)
│
HKDF-Extract
│
Early Secret
│
Derive-Secret("derived")
│
┌─────── (作为 HKDF-Extract 的 salt) ───────┐
│ │
└──── ECDHE 共享密钥 ──── HKDF-Extract ──────┘
│
Handshake Secret
┌────────┴────────┐
Derive-Secret Derive-Secret
("c hs traffic") ("s hs traffic")
│ │
握手加密密钥 握手加密密钥
(SM4 key, IV) (SM4 key, IV)
│
Derive-Secret("derived")
│
┌──── 0×32 ──── HKDF-Extract ────┐
│ │
└──────────────────────────────────┘
│
Master Secret
┌────────┴────────┐
Derive-Secret Derive-Secret
("c ap traffic") ("s ap traffic")
│ │
应用数据加密密钥 应用数据加密密钥
(SM4 key, IV) (SM4 key, IV)SM3-HKDF 的具体构造
SM3 的输出长度也是 32 字节(256 位),与 SHA-256 相同。这意味着 HKDF 的每一步长度参数不需要调整:
HKDF-Extract(salt, IKM) → PRK
= HMAC-SM3(key=salt, message=IKM)
HMAC-SM3(key, message) 展开:
1. 如果 key 长度 > 64 字节:key = SM3(key)
2. 如果 key 长度 ≤ 64 字节:右填 0x00 到 64 字节 → K
3. ipad = K ⊕ (0x36 × 64)
4. opad = K ⊕ (0x5C × 64)
5. PRK = SM3(opad || SM3(ipad || message))
HKDF-Expand-Label(PRK, Label, Context, Length) → OKM
HkdfLabel {
length = Length; // 2 字节大端序
label = "tls13 " + Label; // 前缀 + 标签
context = Context; // 上下文数据
}
OKM = T[0..Length-1]
其中 T = HMAC-SM3(PRK, HkdfLabel)
(因为 Length ≤ 32,只需一轮 HMAC-SM3)TLS 1.2 密钥调度的差异
在 GM/T 0024-2014(基于 TLS 1.2 框架)中,密钥调度使用 TLS 1.2 传统的 PRF:
// TLS 1.2 PRF(国密适配版)
PRF(secret, label, seed) = P_SM3(secret, label + seed)
其中 P_SM3 展开:
P_SM3(secret, seed) = HMAC-SM3(secret, A(1) || seed)
A(0) = seed
A(i) = HMAC-SM3(secret, A(i-1))
// 密钥材料生成
key_block = PRF(master_secret, "key expansion",
server_random + client_random);
// 输出长度(SM4-GCM 需要的密钥材料):
// SM4 key: 16 字节
// SM4 IV: 12 字节(GCM 标准 nonce 长度)
// 每方向 16 + 12 = 28 字节,双向共 56 字节注意 TLS 1.2 和 TLS 1.3 在密钥调度上的根本区别:TLS 1.2 使用 PRF 直接从 master_secret 扩展出所有密钥材料;TLS 1.3 使用 HKDF 的 Extract-then-Expand 两阶段模型,提供更强的密钥隔离。
握手流程详解:TLS 1.3 国密套件
完整握手(Full Handshake)
以下展示 RFC 8998 定义的国密 TLS 1.3 完整握手流程,标注与标准 TLS 1.3 的差异:
Client Server
| |
|--- ClientHello ----------------------------------->|
| cipher_suites: [TLS_SM4_GCM_SM3, ...] |
| supported_groups: [curveSM2, ...] |
| signature_algorithms: [sm2sig_sm3, ...] |
| key_share: [curveSM2, 65 字节公钥] |
| |
|<-- ServerHello ------------------------------------|
| cipher_suite: TLS_SM4_GCM_SM3 (0x00C6) |
| key_share: [curveSM2, 65 字节服务端公钥] |
| |
|<-- EncryptedExtensions ----------------------------|
| (使用握手加密密钥 SM4-GCM 加密) |
| |
|<-- Certificate ------------------------------------|
| certificate_list: |
| [0] SM2 签名证书(叶子) |
| [1] SM2 签名中间 CA |
| [2] SM2 加密证书(叶子) |
| [3] SM2 加密中间 CA |
| |
|<-- CertificateVerify ------------------------------|
| 签名算法: sm2sig_sm3 |
| 签名内容: 64 空格 + context string + |
| 0x00 + SM3(transcript_hash) |
| |
|<-- Finished ---------------------------------------|
| verify_data = SM3(handshake_secret, |
| "server finished", |
| SM3(ClientHello...ServerHello)) |
| |
|--- EncryptedExtensions ----------------------------|
| (如果服务端未请求客户端证书,此消息为空) |
| |
|--- Finished --------------------------------------->|
| verify_data = SM3(handshake_secret, |
| "client finished", |
| SM3(ClientHello...Finished)) |
| |
|===== 应用数据(SM4-GCM 加密) ===================>|关键差异点
#### 1. ClientHello 长度差异
标准 TLS 1.3 ClientHello(X25519 + AES-128-GCM + SHA-256):
key_share 长度: 32 字节(Montgomery u 坐标)
ClientHello 总长度: ~200-300 字节(视扩展而定)
国密 TLS ClientHello(SM2 + SM4-GCM + SM3):
key_share 长度: 65 字节(04 || x(32) || y(32))
ClientHello 总长度: 比标准 TLS 多 33 字节这 33 字节的差异看似微小,但在大规模部署场景中(百万级连接),额外的带宽消耗和网络延迟累积是可观的。
#### 2. SM2 签名中的 Z 值
SM2 签名算法与 ECDSA 的一个关键区别是Z 值预处理:
SM2 签名的输入构造:
Z = SM3(ENTL || ID || a || b || xG || yG || xA || yA)
其中:
ENTL: ID 长度(位),2 字节大端序
ID: 签名者标识(默认 "1234567812345678")
a, b: SM2 曲线参数
xG, yG: 基点坐标
xA, yA: 签名者公钥
最终签名输入:Z || M(Z 值拼接原始消息 M)在 TLS 1.3 的 CertificateVerify 中,M 就是标准的签名输入(64 空格 + context string + 0x00 + transcript hash)。SM2 签名的 Z 值计算是隐含的——实现必须在签名前自动加入 Z 值,而不是由协议层传递。
#### 3. 共享密钥的提取
X25519 ECDHE:
shared_secret = X25519(private_key, peer_public_key)
// 直接得到 32 字节共享密钥
SM2 ECDHE:
shared_point = SM2_POINT_mul(private_key, peer_public_key)
// shared_point 是椭圆曲线上的一个点 (x, y)
// 取 x 坐标的 32 字节作为 shared_secret
shared_secret = shared_point.x这一差异意味着 SM2 的 ECDHE 实现需要额外注意:必须正确处理椭圆曲线点的无穷远点情况,以及点的压缩/解压格式。
密码套件对比与选型
三种路线的密码套件对比
┌──────────────────┬────────────────────┬────────────────────┬────────────────────┐
│ 特性 │ TLCP (GB/T 38636) │ GM/T 0024-2014 │ RFC 8998 │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 密钥交换 │ SM9 / SM2 │ SM2 ECDHE │ SM2 ECDHE │
│ │ │ SM9 IBDH │ │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 认证加密 │ SM4-CBC + SM3 HMAC │ SM4-CBC + SM3 HMAC │ SM4-GCM │
│ │ SM4-GCM │ SM4-GCM │ │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 哈希 │ SM3 │ SM3 │ SM3 │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 签名 │ SM2 │ SM2 │ SM2 (sm2sig_sm3) │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 证书 │ 双证书(强制) │ 双证书(SM2 时) │ 双证书(SM2 时) │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 协议版本 │ 0x0101 │ TLS 1.1/1.2 │ TLS 1.3 │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ RTT │ 2-RTT │ 2-RTT │ 1-RTT │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 0-RTT │ 不支持 │ 不支持 │ 支持 │
├──────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 前向安全 │ ECDHE 模式支持 │ ECDHE 模式支持 │ 强制 ECDHE │
└──────────────────┴────────────────────┴────────────────────┴────────────────────┘选型建议
应用场景 推荐方案
───────────────────────────────────────────────────────
政务内网、金融核心系统(高安全隔离) TLCP (GB/T 38636)
VPN 网关、SSL VPN GM/T 0024-2014
面向 Web 的 HTTPS 服务 RFC 8998 (TLS 1.3)
需要与国际系统互通 RFC 8998 + 双算法部署兼容性与部署挑战
浏览器支持现状
浏览器 国密 TLS 支持 备注
─────────────────────────────────────────────────────────
360 安全浏览器 ✅ TLCP + RFC 8998 最早支持国密的浏览器
奇安信可信浏览器 ✅ TLCP + RFC 8998 政企市场专用
密信浏览器 (MeSince) ✅ TLCP + RFC 8998 内置国密根 CA
红莲花浏览器 ✅ TLCP + RFC 8998 Chromium + Tongsuo 改造
Chrome / Edge ❌ 不支持 无计划支持
Firefox ❌ 不支持
Safari ❌ 不支持国际主流浏览器不支持国密 TLS 是国密 Web 部署的最大障碍。面向公众的网站必须采用双算法部署策略:
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ 国密浏览器 │─── 国密 ──→│ │ │ │
│ (360/奇安信) │ TLS │ Nginx/Tongsuo │───────→ │ 源站服务器 │
└─────────────┘ │ (双证书配置) │ │ │ │ │ │ │
┌─────────────┐ │ │ │ │
│ Chrome/Safari│─── 标准 ──→│ │ │ │
│ │ TLS └──────────────────┘ └─────────────┘
└─────────────┘Wireshark 抓包解析
国密 TLS 的抓包解析面临特殊挑战——标准 Wireshark 不识别 TLS_SM4_GCM_SM3 密码套件。需要:
- 导出 SSLKEYLOGFILE:客户端或服务端导出对称密钥日志
- 使用 Tongsuo 补丁版 Wireshark:Tongsuo 项目维护了支持国密解密的 Wireshark 分支
- 手动解析:通过
signature_algorithms扩展为0x0708(sm2sig_sm3)和 cipher_suite 为0x00C6来识别国密 TLS 握手
中间设备兼容性
设备类型 国密 TLS 支持 解决方案
────────────────────────────────────────────────────
阿里云 CDN ✅ 支持 通过 Tongsuo 实现
腾讯云 CLB ⚠️ 部分支持 部分区域支持国密 SSL
华为云 ELB ✅ 支持 国密双证书配置
传统 WAF ❌ 不支持 可能误判为异常流量
F5 BIG-IP ❌ 不支持 需自研 TLS 中间件对于不支持国密 TLS 的中间设备,常见的做法是在边缘节点做国密卸载(Edge Termination):
客户端 ←─ 国密 TLS ──→ CDN/WAF ←─ 标准 TLS ──→ 源站
(边缘节点解密后重新用标准 TLS 加密)安全考量
Nonce 重用风险
SM4-GCM 与 AES-GCM 一样,对 nonce 重用极其敏感。如果同一个 (key, nonce) 对下加密了两条不同的消息,攻击者可以:
- 通过异或两条密文得到两条明文的异或值
- 如果已知其中一条明文,可以直接恢复另一条明文
- 可以伪造有效的 GHASH 认证标签
侧信道攻击
SM2 的椭圆曲线标量乘法实现需要特别注意侧信道防护:
攻击类型 SM2 风险 防护措施
────────────────────────────────────────────────────────────────────
计时攻击 标准 double-and-add 泄露密钥 bit Montgomery ladder
或固定窗口方法
功耗分析 标量乘法中分支依赖密钥 bit 常量时间实现、
导致功耗差异 盲化标量
缓存攻击 查表操作(如预计算表)导致 缓存无关实现、
访问模式泄露密钥 避免基于密钥的
内存访问模式X25519 天然抵抗计时攻击(Montgomery ladder 的每一步操作不依赖密钥 bit),而 SM2 的实现需要额外注意这一点。
国密算法安全强度
算法 安全强度 等效 RSA 密钥长度 状态
────────────────────────────────────────────────────
SM2 128 bit 3072 bit 安全(当前)
SM3 256 bit 输出 - 128 bit 抗碰撞
SM4 128 bit - 安全(当前)
SM9 128 bit 3072 bit 安全(当前)国密算法在当前经典计算模型下均无已知有效攻击。量子计算威胁下,SM2/SM3/SM4 与 RSA/ECC/SHA-256 一样面临风险——Grover 算法将 SM4 和 SM3 的有效安全强度减半(分别降至 64 bit 和 128 bit 抗碰撞),Shor 算法可破解 SM2 的离散对数问题。
总结
国密 TLS 的三条技术路线——TLCP、GM/T 0024、RFC 8998——反映了中国密码标准从"独立发展"到"融入国际"的战略转变。TLCP 是完全独立的协议体系,适合高安全隔离的内网场景;RFC 8998 是与国际 TLS 1.3 完全兼容的算法扩展,代表了未来的主要方向。
双证书体系是国密 TLS 最本质的架构差异。理解签名密钥"自主生成、不可恢复"和加密密钥"中心生成、可托管"的职责分离设计,是正确部署国密 TLS 的基础。
对于新项目的选型建议:优先采用 RFC 8998(TLS 1.3 + SM4-GCM-SM3),配合 Tongsuo 等成熟开源实现。对于政务金融场景需要 TLCP 兼容的,应明确 TLCP 与国际 TLS 不互通的限制,并规划好客户端适配方案。
参考来源
- RFC 8998: ShangMi (SM) Cipher Suites for TLS 1.3
- GM/T 0024-2014: SSL VPN 技术规范
- GB/T 38636-2020: 信息安全技术 传输层密码协议(TLCP)
- GM/T 0024-2023: SSL VPN 技术规范(修订版)
- Tongsuo(铜锁)项目 - 国密 TLS 实现
- 国密 TLS 握手逐字节对比
- GmSSL 项目
相关实践
- 如需了解国密 TLS 在 Nginx 中的完整部署流程,请参阅《SM2 国密算法实战:从密钥生成到 TLS 完整部署》
- 如需了解国密 HTTPS 部署过程中的常见问题,请参阅《国密 HTTPS 踩坑实录:从开发到上线的 12 个坑》
- 如需了解国密 TLS 的架构转型思考,请参阅《国密 HTTPS 的"最后一公里":从证书管理到加密服务的架构转型》