中间证书弱私钥事件暴露密钥生成缺陷
文章复盘 eMudhra 八张中间 CA 证书的弱私钥问题:据公开报道,部分 P-384 私钥取值低于 256,可被枚举恢复。事件说明证书链验证通过并不能证明密钥生成安全,最终根因分析仍未完成。
AI 深度解读
8 张看起来正常、能串到受信任根证书的 eMudhra 中间 CA 证书,据原文披露,背后的 P-384 私钥竟小于 256,其中一个值是 4。攻击者不必破解椭圆曲线算法,逐个尝试小整数,就可能在一秒内找回私钥。
这起事件值得程序员读的地方,是错误怎样穿过了脚本、密钥选择、审计和故障处理。原文的核心判断是:强算法救不了失控的密钥流程,而一次被「修好」的签名报错,原本就能让事故提前结束。
私钥等于 4,为什么会危及整条信任链
中间 CA 不是普通网站证书。根 CA 是浏览器、操作系统信任库中的信任起点,通常由它签发中间 CA,再由中间 CA 签发日常使用的证书。中间 CA 私钥一旦泄露,攻击者可能在证书约束允许的范围内,签出客户端认为合法的证书。
风险因此不只落在某一个网站上,而是落在签发能力上。
理解这次问题,只需要看椭圆曲线公钥的计算关系:
Q = d × G
要看的是 d:它是私钥,G 是公开的固定基点,Q 是放进证书里的公钥。正常 P-384 私钥应是具有约 384 位熵的随机值,从公钥倒推私钥在计算上不可行。
但原文称,这批私钥的值小于 256。攻击者只需计算有限个候选公钥:
1 × G
2 × G
3 × G
4 × G
...
255 × G
关键在最后一行:搜索到 255 就覆盖了文中所述的小整数范围,再与证书公钥比较即可。原文称恢复私钥用时不到一秒,但没有给出完整测试环境。
这里失守的是密钥生成与验证流程,不能据此判断 P-384 算法被攻破。
正确密钥明明在 HSM 里,为什么发布出去的却是另一套
据原文整理的公开说明,2025 年 4 月 30 日的密钥生成仪式原计划生成 RSA-4096 和 P-384 密钥对。过程中加入了硬件安全模块(HSM)的密钥包装与解包测试,即 wrap-and-unwrap,用于检查密钥处理流程。
问题由此叠加:仪式脚本额外生成了一套弱 EC 密钥,两套密钥的标签相似,创建证书签名请求(CSR)时又选错了对象。最终,弱公钥被签进中间 CA 证书,并通过交叉签名增加了兼容路径;正确的强密钥虽然留在 HSM 中,却不对应已经发布的证书。
这里至少有两道本可阻止发布的关口:生成后核对全部密钥对象,以及签名前核对 CSR 公钥与批准使用的 HSM 对象。
原文明确说最终根因分析仍在进行,因此「脚本究竟错在哪一行」「内部审核如何放行」还不能下定论。能看清的是,生成缺陷制造了错误对象,选择与验证失误又把它变成了公开信任对象。
更难接受的是后续告警。约在 2025 年 5 月,证书吊销列表(CRL)的签名开始验证失败。CRL 是 CA 签发的吊销清单,签名必须能由对应 CA 证书里的公钥验证。失败说明签名私钥与证书公钥对不上,至少需要查清这种不一致从哪里来。
公开报道所述的处理方式,却是把 CRL 签名程序改为使用弱密钥,使验证重新通过。
功能恢复了,密钥为何多出一套、证书为何对应错对象,却没有得到充分解释。原文认为,只要继续追问并核对公钥指纹,这时就有机会发现问题。
两轮审计和证书吊销,为什么都没有兜住
原文称,弱中间 CA 获得公开信任约 18 个月,期间经过两个审计周期。研究者于 2026 年 10 月 17 日向 Chrome Root Program 报告后,Chrome 和 Firefox 很快进行了阻止,eMudhra 也吊销了相关中间证书,随后宣布提供客户迁移支持。
审计没有发现,不等于所有审计都无用。原文指出的边界是:检查流程、审批记录和仪式见证,不一定包含重新验证每一把密钥的安全属性。材料齐全,仍可能对应错误的实际产物。
作者建议补上的检查很具体:每个计划中的 CA 身份应只有一套批准密钥;用 SHA-256 公钥指纹选择和核对对象;由独立工具确认 CSR 与 HSM 对象一致;对 EC 公钥做小标量检查,对 RSA 密钥检查弱因子或共享因子。小标量检查就是排查私钥是否落在容易枚举的小整数范围,它能抓住这种离谱错误,但不能证明所有密钥都生成得足够随机。
吊销则有另一层限制:客户端未必获取吊销信息,也未必严格执行,部分客户端遇到网络错误还会放行。浏览器可以额外推送紧急不信任信息,但保护未必同步覆盖命令行工具、内部服务、Java 运行时和嵌入式设备。
此外,同一批弱中间密钥还存在 Sectigo 的 AAA Certificate Services 交叉签名路径。交叉签名让旧设备也能建立信任,同时增加了事故处置范围:只封堵 eMudhra 路径,客户端仍可能沿另一条路径完成验证。
处置对象必须覆盖同一把弱密钥的全部信任路径。
我的判断
这篇最有价值的判断,是把「系统恢复运行」和「故障原因得到解释」分开。签名验证失败属于明确的不一致信号,如果只是换个密钥让它通过,修复动作可能把证据一起掩盖。
独立验证也值得保留。负责生成密钥的脚本若同时负责证明输出正确,同一处错误就可能影响两边。让另一套工具检查最终产物,比再补一份流程记录更直接。
不过,这些建议仍有边界。原文没有给出增加这些检查前后的对照数据,也没有展示完整仪式代码或最终独立调查结论。它提出的是有技术依据的控制措施,不能据此认定某一个检查就能杜绝全部密钥事故,更不能把尚未完成的根因分析写成定案。
影响范围同样要收住。原文称,目前没有公开证据表明披露前发生过利用;Chrome 还表示,在阻止前没有记录到来自 6 个受影响 TLS 中间 CA 的 TLS 证书。这缩小了已知影响,却无法证明所有非浏览器客户端都未受影响。不要把「能够伪造」写成「已经伪造」,也不要把「没有已知利用」写成安全保证。
对普通前端和全栈团队,我更倾向于先落实信任依赖盘点与轮换能力。CA 级别的密钥仪式有其特殊性,日常工程最容易照搬的错误,则是为解决连接失败而关闭校验。
能拿来做什么
- Node 服务或构建脚本遇到证书链迁移导致的 HTTPS 失败时,应检查服务端证书链、客户端信任库和依赖配置,修正对应环节,避免用
verify false一类思路绕过证书验证。原文中的这个写法是泛指关闭校验,并未提供某个 Node API 的配置示例。 - 给团队的出站 HTTPS 客户端做一次盘点,记录哪些使用自定义 CA、固定证书、旧 Java 信任库或特殊代理。事故发生时,需要知道每个客户端实际信任什么,以及更新由谁负责。
- 对生成凭据、证书或签名密钥的自动化,增加独立的产物核对。至少确认最终发布对象与批准对象一致,别只凭名称相似或脚本返回成功就继续。
- 把证书与密钥轮换当作可执行的运维能力,提前明确替换、发布和验证步骤。遇到无法解释的签名失败时,保留证据并查清对象关系,再决定是否关闭事件。