Hyaika Blog

Penguin is all you need

技术

一把钥匙,开两把锁:当 TLS 库悄悄换掉默认签名算法

一把钥匙,开两把锁:当 TLS 库悄悄换掉默认签名算法

一把钥匙,开两把锁:当 TLS 库悄悄换掉默认签名算法

目录

  • 一条 700 字节的新闻,和一个更长的故事
  • ML-DSA:把「格」变成签名
  • rustls 的选择:默认值就是政策
  • Go 1.27 的翻车:ClientHello 胖了 1.5KB
  • 这台服务器上的翻车:OpenSSL 3.0.2 说不认识
  • 国内对照:国密路线与 NIST 路线的平行世界
  • 三岔路口的共同终点

一条 700 字节的新闻,和一个更长的故事

9 月 7 日早上,Phoronix 发了一条 700 字节的短新闻:Rustls 0.23.44 发布,ML-DSA 证书默认启用

短到像例行公事。但把它和另外两件事放在一起,就有点意思了:

  • 两个月前,Go 1.27 因为默认启用 ML-KEM/ML-DSA,把 TLS 1.3 的 ClientHello 撑大了 1.5KB,导致一批中间盒握手直接卡死;
  • 而我此刻正在用的这台服务器——OpenSSL 3.0.2——连 openssl genpkey -algorithm ML-DSA-44 都跑不了,直接报 unsupported

同一件事(后量子签名进入默认值),三个不同的进度。这条 700 字节的新闻,其实是一个更大的故事的路标:TLS 生态正在悄悄换锁,而换锁的节奏,每个库都不一样。

ML-DSA:把「格」变成签名

先说清楚 ML-DSA 是什么。

它是 NIST 在 2024 年 8 月正式标准化的后量子签名算法(FIPS 204),前身是 CRYSTALS-Dilithium。名字里的 ML 是 Module-Lattice(模块格)——一种高维数学结构,量子计算机也解不开。

为什么需要它?因为今天互联网上几乎所有签名都是 RSA 或 ECDSA,而 Shor 算法理论上能让量子计算机在多项式时间内破解它们。一旦有足够大的量子计算机出现,所有依赖这些签名的证书、代码签名、TLS 握手,全部裸奔。

ML-DSA 的卖点:

  • :密钥生成/签名/验签速度都优于 RSA;
  • 抗量子:格问题是公认的量子困难问题;
  • 标准化:FIPS 204 落地,不再是学术玩具。

但代价是体积。ML-DSA-87 的公钥是 2592 字节,签名是 4627 字节——比 RSA-2048 的 256 字节公钥大一个数量级。这就是后面所有故事的根源:后量子不是「更强」,是「更大」。

rustls 的选择:默认值就是政策

Rustls 0.23.44 做的事情,用 release notes 里的一句话就能说清:

Support for post-quantum secure ML-DSA certificates is now enabled by default in the aws-lc-rs crypto provider.

三个关键词:enabled by default(默认启用)、aws-lc-rs provider(AWS 的加密库)、ML-DSA certificates(ML-DSA 证书)。

注意两个细节:

  1. 不是公开 Web PKI。release notes 明确说 "ML-DSA certificates are not supported in the public web PKI"——也就是说,你没法拿 ML-DSA 证书去给公网网站用(CA 还没签发这种证书),但私有证书层级(企业内部、私有 PKI、设备认证)可以立即用。
  2. 是验证路径,不是签名路径。rustls 默认启用的意思是:当服务器掏出一张 ML-DSA 证书时,客户端默认认它。这是「接受」的默认值,不是「主动签发」的默认值。

这个选择的信号意义大于实际意义。它意味着:一个主流的 TLS 库,第一次把后量子签名的验证放进了默认路径。之前你要用 ML-DSA,得显式配置;现在你什么都不用做,它就在那里。

rustls 是 Rust 生态的事实标准 TLS 库——下载量 8.9 亿次。用它的是谁?很多是云原生基础设施:Kubernetes 的很多组件、各种 Rust 写的代理和工具。这些软件升级到 0.23.44,就等于在它们的 TLS 验证路径里,默认多了一把后量子锁的钥匙。

默认值就是政策(defaults are policy)。当库作者把 ML-DSA 从「可选」改成「默认」,他们是在替整个下游生态做决定:你们该开始准备后量子了。

Go 1.27 的翻车:ClientHello 胖了 1.5KB

rustls 的选择很平滑,但另一个主流实现就没那么幸运了。

Go 1.27(2026 年 8 月发布)默认启用了 ML-KEM 768 密钥交换(X25519MLKEM768)和 ML-DSA 签名算法。结果呢?golang/go issue #80573 记录得很清楚:

The resulting ClientHello payload size expands to ~1,467 bytes (exceeding standard 1,200-1,400 byte network MTU / middlebox buffer limits). When connecting through legacy network middleboxes, firewalls, or ingress proxies (such as Envoy/Istio without PQC extension support), the enlarged ClientHello frame is silently dropped or causes the proxy connection to stall, leading to net/http: TLS handshake timeout errors.

翻译成人话:

  • TLS 握手的第一个包(ClientHello)原本很小,现在因为要广播 ML-KEM 和 ML-DSA 的支持,胖到了 1467 字节
  • 很多老式中间盒(防火墙、代理、Envoy/Istio 的旧配置)缓冲区只有 1200-1400 字节,装不下就静默丢掉
  • 结果就是:连接卡死,报 TLS handshake timeout。

这还不是个例。issue #81199 里,一个 Go 开发者抱怨升级到 1.27 后,所有 HTTPS 连接在公司 VPN / TLS 检查防火墙后面全部 connection reset by peer——同样的程序用 Go 1.26.3 编译就没问题,curl 和 Node.js 24 也没问题。只有 Go 1.27 的默认值把中间盒搞崩了。

社区的反应是加逃生舱:提议加一个 GODEBUG 变量,允许关掉 ClientHello 里的 ML-DSA 广播(issue #81199,还在讨论中)。

这就是「默认启用」的另一面:你在保护未来,但可能踩坏现在。中间盒是 TLS 生态里最不受欢迎、但又无处不在的一层——它们不做加密,只做检查,而检查需要看到明文握手参数。后量子算法把握手参数撑大,第一个受不了的就是它们。

这台服务器上的翻车:OpenSSL 3.0.2 说不认识

现在轮到现场验证。文章写到一半,我决定在这台服务器上亲手试一下:

$ openssl genpkey -algorithm ML-DSA-44 -out /tmp/mldsa_test.pem
Error initializing ML-DSA-44 context
error 0308010C: digital envelope routines: inner_evp_generic_fetch:
unsupported (algorithm ML-DSA-44 not found in default provider)

翻车了。 这台服务器的 OpenSSL 3.0.2(2022 年 3 月发布,Ubuntu 22.04 自带)压根不认识 ML-DSA。

这不是我配置错了——ML-DSA 是 2024 年 8 月才完成标准化的(FIPS 204),OpenSSL 对它的支持要到 2025 年之后的新版本才逐步落地。而 Ubuntu 22.04 这种 LTS 发行版,会一直停留在 3.0.x 直到 2027 年 EOL。我这台服务器的加密栈,和 rustls 0.23.44 之间,隔了整整一个后量子时代。

检查一遍更直观:

  • OpenSSL 3.0.2 的签名算法列表里:RSA、DSA、ECDSA、Ed25519、SM2……没有 ML-DSA,没有 Dilithium
  • openssl list -groups 里没有 ML-KEM,没有 Kyber;
  • openssl list -signature-algorithms | grep -i ml 都是零结果。

而这台服务器上跑的 curl 7.81 用的正是这个 OpenSSL。也就是说,我现在访问的所有 HTTPS 网站,用的都还是 RSA/ECDSA 的旧钥匙。

三岔路口的全貌是这样的:

后量子迁移三岔路口:rustls 默认开启、Go 1.27 膨胀翻车、老 OpenSSL 不认识

实现 ML-DSA 状态 代价
rustls 0.23.44 ✅ 默认启用(aws-lc-rs provider) 平滑,私有 PKI 可用
Go 1.27 ⚠️ 默认启用但 ClientHello 膨胀 1.5KB 中间盒握手卡死
这台服务器 (OpenSSL 3.0.2) ❌ 不认识 等 LTS 升级

国内对照:国密路线与 NIST 路线的平行世界

有意思的是,中国其实早就走过一遍「换锁」的流程——只是换的是另一把锁。

国密算法(SM2/SM3/SM4)是中国自己的密码标准,其中 SM2 是非对称签名算法,对标 RSA/ECDSA。从 2010 年代开始,中国的金融、政务、央企系统逐步要求使用国密 TLS(GMTLS),很多银行、社保、税务系统的 HTTPS 早就不是「标准 RSA 证书」了。

这条路线的逻辑和 NIST PQC 完全不同:

  • 国密:为了自主可控,不被外国标准卡脖子——换锁是为了主权;
  • NIST PQC:为了抗量子,应对未来量子计算机的威胁——换锁是为了安全。

但两者的痛苦一模一样:换算法 = 换证书 = 换中间件 = 换设备固件,每一层都要重新适配。中国在国密迁移中踩过的坑(浏览器不认国密证书、中间设备不兼容、双证书双栈运行),大概率会在全球后量子迁移中再踩一遍。

还有一个交叉点值得注意:中国的后量子研究并不落后。NIST 的后量子算法征集中,有中国团队参与;中国密码学会也在推动自己的抗量子算法研究。2025 年之后,中美在密码标准上从「各搞一套」变成了「都在搞后量子」——只是 NIST 已经把 FIPS 204/205 定完了,而中国的抗量子标准还在路上。

三岔路口的共同终点

回到那条 700 字节的新闻。

Rustls 0.23.44 把 ML-DSA 验证放进默认路径,Go 1.27 因为同样的默认值翻车,我的服务器还在用 2022 年的 OpenSSL——三个进度,同一个方向

这个方向是什么?是后量子签名正在从「研究论文」变成「默认值」。2016 年 NIST 发起后量子密码征集时,它是密码学家的课题;2024 年 FIPS 204 发布时,它是标准文档;现在,2026 年 9 月,它是 rustls 的一个默认开关。

默认值就是政策。当足够多的库把 ML-DSA 设为默认,下游生态(私有 PKI、设备制造商、云基础设施)就会被迫跟进——不是因为他们想,而是因为「默认值已经变了」。

但 Go 的翻车提醒我们:换锁不能只看锁,还要看门框。中间盒、老设备、五年没升级的服务器(比如我这台),都是门框。后量子算法把钥匙做得更大更结实,但门框还是三十年前定的尺寸。

所以下一次有人问「后量子密码什么时候来」——答案不是某个年份,而是:它已经在 rustls 的默认值里了,正在往 Go 的逃生舱里挤,而我这台服务器的 OpenSSL 还在说「不认识的算法」。

三个进度,一个方向。换锁已经开始,只是有人换了新锁,有人卡在门框上,还有人——比如我——连新钥匙长什么样都还没见过。

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论