安全攻防 - 03 TLCP 握手:双证书、密码套件与常见术语
文章目录
- 1. TLCP 为什么经常说“双证书”
- 2. 一次简化版 TLCP 握手
- 3. 本工程默认密码套件怎么理解
- 3.1 `TLCP_ECC_SM4_GCM_SM3`
- 3.2 `TLCP_ECC_SM4_CBC_SM3`
- 3.3 为什么默认不启用 ECDHE
- 4. `sm2sig_sm3` 为什么重要
- 5. TrustManager、KeyManager 在握手里分别做什么
- 5.1 TrustManager:验证对方
- 5.2 KeyManager:证明自己
- 6. Hostname 校验在 TLCP 里还要不要
- 7. TLCP 握手问题如何分层
- 7.1 TCP 层
- 7.2 协议层
- 7.3 密码套件层
- 7.4 签名算法层
- 7.5 证书链层
- 7.6 Hostname 层
- 8. 本工程怎么记录握手
- 8.1 `socketPreparations`
- 8.2 `handshakes`
- 8.3 `hostnameChecks`
- 9. 新手最该记住的 5 句话
普通 TLS 新手最容易卡在“证书链”;TLCP 新手更容易卡在“为什么服务端有两张证书”“为什么有 ECC 和 ECDHE 两类套件”“为什么客户端有时也要双证书”。
这一篇专门讲 TLCP 的握手和双证书。
1. TLCP 为什么经常说“双证书”
TLCP/国密 SSL 的典型服务端会使用两套 SM2 证书/私钥:
| 证书 | 用途 | 类比 |
|---|---|---|
| 签名证书 | 证明服务端身份,对握手关键参数签名 | “我是谁” |
| 加密证书 | 用于密钥交换中加密预主密钥等 | “给我发秘密时用这把公钥加密” |
普通 TLS 里,服务端通常一张证书就能承担认证用途;密钥交换可以走 RSA/ECDHE 等不同机制。TLCP 的国密双证书体系把签名和加密用途分开了。
Tongsuo 文档也把 NTLS/TLCP 的特点描述为加密证书/私钥和签名证书/私钥相分离。
2. 一次简化版 TLCP 握手
用本工程默认单向认证场景举例:客户端只验证服务端,客户端自己不发证书。
1. ClientHello - 客户端说:我支持 TLCPv1.1 - 我支持这些密码套件:TLCP_ECC_SM4_GCM_SM3 / TLCP_ECC_SM4_CBC_SM3 - 我支持签名算法:sm2sig_sm3 2. ServerHello - 服务端选择 TLCPv1.1 - 服务端选择一个双方都支持的密码套件 3. Certificate - 服务端发送签名证书和加密证书 - 证书链可能包含中间 CA 4. ServerKeyExchange - 服务端用签名证书对应私钥对关键参数签名 5. 客户端验证 - 验证证书链是否能链到本地 TrustStore - 验证证书签名算法、公钥算法是否支持 - 验证 ServerKeyExchange 签名 6. ClientKeyExchange - 客户端生成预主密钥 - 用服务端加密证书公钥加密后发给服务端 7. 双方派生会话密钥 - 后续 HTTP 数据用 SM4 保护 8. Finished - 双方确认握手没有被篡改真正协议细节比这个多,但新手先抓住三点:
- 服务端身份靠签名证书证明;
- 关键秘密用加密证书保护;
- CA 链验证失败、签名算法不支持、密码套件不匹配都会导致握手失败。
3. 本工程默认密码套件怎么理解
application.yml默认:
enabled-cipher-suites:-TLCP_ECC_SM4_GCM_SM3-TLCP_ECC_SM4_CBC_SM33.1TLCP_ECC_SM4_GCM_SM3
可以粗略拆成:
| 片段 | 含义 |
|---|---|
| TLCP | 协议族 |
| ECC | 静态 ECC-SM2 相关密钥交换/认证模式 |
| SM4 | 对称加密算法 |
| GCM | AEAD 工作模式 |
| SM3 | 杂凑/完整性相关算法 |
3.2TLCP_ECC_SM4_CBC_SM3
和上面类似,只是 SM4 的工作模式从 GCM 换成 CBC。
3.3 为什么默认不启用 ECDHE
README 里已经提示:当前默认没有客户端证书,所以先启用常见 ECC 套件。如果服务端只接受TLCP_ECDHE_*,通常要同时配置客户端证书 KeyStore,再把 ECDHE 套件加入列表。
示例:
enabled-cipher-suites:-TLCP_ECDHE_SM4_GCM_SM3-TLCP_ECDHE_SM4_CBC_SM3-TLCP_ECC_SM4_GCM_SM3-TLCP_ECC_SM4_CBC_SM3client-key-store:path:file:/secure/client.p12type:PKCS12password:changeitkey-password:changeit是否必须客户端证书,要以服务端配置为准。你不能只看客户端代码猜。
4.sm2sig_sm3为什么重要
本工程默认:
client-signature-schemes:-sm2sig_sm3启动时KonaProviderInitializer会把它写到:
com.tencent.kona.ssl.client.signatureSchemes这个系统属性会影响 ClientHello 里的signature_algorithms扩展。
如果服务端是 SM2 证书,而客户端没有告诉服务端“我支持 SM2 with SM3 签名”,服务端可能无法选择合适签名算法,常见错误是:
no suitable signature algorithm所以联调时第一批要确认的字段包括:
{"tlcp":{"konaClientSignatureSchemes":"sm2sig_sm3"}}如果这里是空的,先别怀疑业务接口,先修客户端签名算法配置。
5. TrustManager、KeyManager 在握手里分别做什么
5.1 TrustManager:验证对方
客户端的 TrustManager 用于验证服务端证书链。
本工程构造 TrustManager 的核心路径:
trust-certificates 配置 ↓ ResourceLoader 读取 classpath:/file:/绝对路径/相对路径 ↓ CertificateFactory("X.509", "KonaPKIX") 解析证书 ↓ KeyStore("JKS", "KonaPKIX") 临时装入 CA ↓ TrustManagerFactory("PKIX", "KonaSSL") 生成 TrustManager重点:对 SM2 证书链,不要随手换成默认 JDK Provider。否则可能证书解析或签名验证阶段失败。
5.2 KeyManager:证明自己
客户端 KeyManager 用于客户端证书认证。
只有配置了:
client-key-store.path本工程才会加载 KeyStore 并创建 KeyManager。
路径:
client-key-store.path ↓ KeyStore(type, "KonaPKIX") 加载 PKCS12/JKS ↓ KeyManagerFactory("NewSunX509", "KonaSSL") ↓ SSLContext.init(keyManagers, trustManagers, random)6. Hostname 校验在 TLCP 里还要不要
要。TLCP 解决的是传输安全协议和国密算法问题,不代表你可以忽略证书主体匹配。
证书链校验回答:
这张证书是不是可信 CA 签出来的?Hostname 校验回答:
这张证书是不是发给我正在访问的这个 host/IP 的?本工程为了兼容内网 IP 联调默认关闭:
hostname-verification-enabled:false生产建议开启。正确做法是让服务端证书 SAN 包含访问域名或 IP,而不是长期关闭校验。
7. TLCP 握手问题如何分层
看到握手失败时,不要马上乱改密码套件。先按层看:
7.1 TCP 层
现象:
Connection refused No route to host Connection timed out说明还没进 TLCP。检查 IP、端口、防火墙、服务是否监听。
7.2 协议层
现象:
wrong version number unsupported protocol可能客户端说 TLCP,服务端端口不是 TLCP;或者服务端说普通 TLS,客户端只启用 TLCP。
7.3 密码套件层
现象:
handshake_failure no cipher suites in common检查enabled-cipher-suites与服务端支持列表是否有交集。
7.4 签名算法层
现象:
no suitable signature algorithm优先检查sm2sig_sm3是否生效。
7.5 证书链层
现象:
PKIX path building failed CertPathValidatorException certificate verify failed检查 CA 链是否完整、证书是否过期、是否把服务端证书误当 CA、Provider 是否是 Kona。
7.6 Hostname 层
现象:
Hostname ... not verified No subject alternative names matching IP address ...检查 SAN/CN 和访问地址是否匹配。
8. 本工程怎么记录握手
TlcpHandshakeRecorder会记录三类信息:
{"tlcpTrace":{"socketPreparations":[],"handshakes":[],"hostnameChecks":[]}}8.1socketPreparations
能看到 socket 上实际启用的协议和密码套件:
{"enabledProtocols":["TLCPv1.1"],"enabledCipherSuites":["TLCP_ECC_SM4_GCM_SM3","TLCP_ECC_SM4_CBC_SM3"]}如果这里没有记录,可能失败发生在 socket 创建前,比如 OkHttp ConnectionSpec 校验、URL 构造、证书文件读取。
8.2handshakes
握手完成后才会有。可以看到:
- 协议;
- 密码套件;
- peer certificates;
- session id;
- principal。
如果handshakes为空但socketPreparations有记录,说明 socket 已经准备好,但握手没有完成。
8.3hostnameChecks
能看到 Hostname Verification 是否启用、校验目标是什么、结果是什么。
9. 新手最该记住的 5 句话
- TLCP 常见服务端有签名证书和加密证书,不要只按普通 TLS 单证书理解。
- 客户端 TrustStore 放 CA,客户端 KeyStore 放自己的证书和私钥。
sm2sig_sm3缺失会导致 SM2 证书服务端签名算法协商失败。- 密码套件必须和服务端有交集,ECC/ECDHE 是否需要客户端证书要问服务端。
- 联调可以临时关闭 hostname verification,但生产应让 SAN 匹配并开启。
下一篇开始读本工程代码地图,把这些概念对应到具体类和配置。
