密码学基础(下):公钥基础设施(PKI)、证书链、信任根

上一讲我们聊了对称与非对称加密、哈希和数字签名。这些工具单独用,其实挺脆弱的。你想想看——你拿到一个公钥,怎么确定它真的是设备厂商的?中间人完全可以伪造一对密钥,把自己的公钥塞给你。

这就是 PKI 要解决的问题。说白了,PKI 就是一套「谁说了算」的信任机制。我在做固件安全审计时,见过太多设备因为 PKI 部署不当,签名形同虚设。嗯,今天我们就把它彻底讲透。

PKI 的核心角色

PKI 不是单个技术,而是一套体系。它包含三个核心角色:

  • 证书颁发机构(CA)——负责签发和吊销证书。它是信任的源头。
  • 注册机构(RA)——负责验证申请者的身份。CA 通常不直接对接用户,RA 做初审。
  • 终端实体——持有证书的设备或人。比如你的 IoT 设备、固件签名服务器。

我习惯把 CA 比作「身份证办理中心」,RA 是「派出所户籍窗口」,终端实体就是「你手里的身份证」。没有这套体系,你没法证明「你就是你」。

X.509 证书结构

固件签名中最常用的证书格式是 X.509 v3。一个证书长什么样?我拆开给你看:

字段 含义 我的备注
版本号 通常是 v3 v3 才支持扩展项
序列号 CA 分配的唯一编号 吊销时靠它定位
签名算法 如 SHA256-RSA 别用 SHA1,已经废了
颁发者 CA 的 DN(专有名称) 链式验证的关键
有效期 notBefore / notAfter 过期证书直接拒掉
主体 证书持有者的 DN 设备 ID 通常放这里
公钥 持有者的公钥 RSA 2048+ 或 ECC P-256
扩展项 Key Usage、Basic Constraints 等 我吃过亏,后面细说
签名值 CA 对上述字段的签名 防篡改的最后一道锁
我的习惯:拿到一个证书,先看 Basic Constraints 扩展。如果 CA 证书没标记 CA:TRUE,那它签发的子证书全是废纸。我曾经在一个客户项目里排查了三天,最后发现根证书的 CA 标志位没设——嗯,低级错误,但后果很严重。

证书链与信任根

你不可能让每个设备都内置所有 CA 的公钥。现实做法是——设备只内置几个「信任根」,然后通过证书链逐级验证。

举个例子。你的 IoT 设备里烧录了 Root CA 的公钥。固件签名用的是 Intermediate CA 签发的代码签名证书。验证流程是这样的:

  1. 设备收到固件包,附带签名值和签名证书。
  2. 设备用内置的 Root CA 公钥,验证 Intermediate CA 证书的签名。
  3. 验证通过后,用 Intermediate CA 的公钥,验证代码签名证书的签名。
  4. 最后用代码签名证书的公钥,验证固件哈希的签名值。

每一步都环环相扣。只要有一环断了,信任就崩塌。

关键点:信任根(Root of Trust)是物理上不可篡改的。在嵌入式设备里,它通常烧录在一次性可编程存储器(OTP)或安全元件(SE)中。软件层面的信任根,说白了就是「信任一个你没法改的东西」。

证书链的 SVG 结构图

下面这张图展示了典型的固件签名证书链。我建议你仔细看箭头方向——验证是从下往上,签名是从上往下。

固件签名证书链结构 Root CA(信任根) 自签名 · 烧录在设备 OTP 签发 Intermediate CA 由 Root CA 签发 · 有效期 5 年 签发 代码签名证书 由 Intermediate CA 签发 · 有效期 2 年 签名 固件镜像 携带签名值 + 证书链 验证方向:固件 → 代码签名证书 → Intermediate CA → Root CA(信任根) 签名方向:Root CA → Intermediate CA → 代码签名证书 → 固件

证书吊销:被遗忘的防线

证书会过期,也会被泄露。一旦私钥泄露,你必须能及时吊销证书。常用的吊销机制有两种:

  • CRL(证书吊销列表)——CA 定期发布一个黑名单。设备下载后比对。缺点是实时性差,列表会越来越大。
  • OCSP(在线证书状态协议)——设备实时向 OCSP 服务器查询证书状态。实时性好,但需要网络连接。
我曾经踩过的坑:在一个车联网项目里,设备只实现了 CRL 检查,但 CRL 更新周期设成了 30 天。结果中间 CA 私钥泄露后,整整一个月内所有新签发的固件都能在已泄露的链上通过验证。后来我强制要求:关键设备必须同时支持 OCSP Stapling,把 OCSP 响应嵌在证书链里一起下发。

固件签名中的 PKI 最佳实践

做了这么多年嵌入式安全,我总结了几条铁律:

  1. 根 CA 离线保存——根 CA 私钥永远不要联网。签中间 CA 证书时,用一台断网的专用机器操作。我见过有人把根 CA 私钥放在构建服务器上——嗯,那跟没锁门一样。
  2. 分层管理密钥——根 CA、中间 CA、代码签名证书,三级分离。即使代码签名证书泄露,你只需要吊销它,根和中间 CA 不受影响。
  3. 证书有效期要短——代码签名证书建议 1-2 年。中间 CA 不超过 5 年。根 CA 可以 10-20 年,但私钥保护级别要最高。
  4. 设备端做完整链验证——不要只验证叶子证书。我见过不少设备只检查固件签名证书的有效期,却不验证它是否由受信任的 CA 签发——这等于没验。
  5. 硬编码信任根要谨慎——信任根的公钥哈希要烧死在芯片的 eFuse 或安全存储里。别放在文件系统里,那太容易被替换了。
一个小技巧:在固件更新包里,把完整的证书链(从代码签名证书到根 CA 证书,但不包含根 CA 私钥)一起打包。设备端只需要内置根 CA 公钥,就能逐级验证。这样即使中间 CA 证书更换,旧设备也能无缝升级。

实际部署中的常见误区

我整理了几个高频翻车点,你对照看看自己的项目有没有中招:

误区 后果 正确做法
根 CA 私钥存储在构建机 一次入侵,整个信任体系崩塌 离线 HSM 或专用安全机器
证书链验证跳过中间 CA 中间人可以用自签名证书冒充 逐级验证到信任根
CRL 更新周期过长 吊销滞后,泄露的证书仍可用 CRL 更新 ≤ 24 小时,配合 OCSP
信任根可软件更新 攻击者替换信任根,签名形同虚设 信任根写死在一次性存储中
证书扩展项未检查 代码签名证书被用于 TLS 服务器 检查 Key Usage 和 Extended Key Usage

PKI 这东西,搭建起来不难,但想搭得牢靠,细节特别多。你想想看——整个固件安全体系都建立在信任根不被篡改这个假设上。一旦这个假设破了,后面所有加密、签名、校验都是白搭。

我个人习惯在项目初期就画好证书链拓扑图,明确每个角色的职责和存储位置。别等到量产了才发现信任根烧录流程有漏洞——那时候改起来,成本就高了。