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

上一讲我们聊了对称与非对称加密、哈希和签名。这些算法单独拿出来,其实都挺完美的。但一放到真实世界里,问题就来了——你怎么确定你拿到的公钥,真的是对方的?

我在一个物联网项目里就踩过这个坑。设备A要给设备B发一条加密指令,B把公钥通过Wi-Fi传过来。看起来没问题对吧?但中间人完全可以把这个公钥换成自己的。A用假公钥加密,中间人解密后篡改数据,再用真公钥转发给B。整个过程,A和B都浑然不觉。

所以,光有密码学算法是不够的。我们需要一套机制,来回答那个灵魂拷问:“你怎么证明你是你?”

这就是公钥基础设施(PKI)要解决的问题。

3.1 什么是PKI?

PKI不是某个算法,也不是某个软件。它是一整套策略、流程、硬件、软件的组合。说白了,就是一套“发身份证、查身份证、吊销身份证”的管理体系。

一个典型的PKI系统包含以下几个核心角色:

角色 英文 职责
证书颁发机构 CA 签发、吊销证书,是整个PKI的信任锚点
注册机构 RA 负责验证申请者的身份,把审核结果告诉CA
证书库 Repository 存储已签发的证书和吊销列表(CRL)
终端实体 End Entity 持有证书的个人、设备或服务器

你想想看,如果没有RA,CA就得亲自去验证每一个申请者的身份。对于大型系统来说,这根本不现实。我经手的一个车联网项目,每天有上万台新设备上线。CA根本忙不过来,必须靠RA做第一道审核。

3.2 数字证书长什么样?

证书就是PKI里的“身份证”。最通用的标准是X.509 v3。一个证书里包含的信息,比你想象的多得多。

我习惯把证书结构拆成三块来看:

  1. 主体信息:谁持有这个证书(设备ID、域名、组织名)
  2. 公钥信息:持有者的公钥,以及使用的算法
  3. 签发信息:谁签发的、有效期、签名值

用OpenSSL看一下证书内容,最直观:

openssl x509 -in device.crt -text -noout

输出里你会看到类似这样的字段:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0x12345678
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, O=MyCA, CN=Root CA
        Validity
            Not Before: Jan  1 00:00:00 2024 GMT
            Not After : Dec 31 23:59:59 2025 GMT
        Subject: C=CN, O=MyDevice, CN=device-001
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
        X509v3 extensions:
            X509v3 Basic Constraints: CA:FALSE
            X509v3 Key Usage: Digital Signature, Key Encipherment
    Signature Algorithm: sha256WithRSAEncryption
         a1:b2:c3:... (签名值)

嗯,这里要注意Basic Constraints这个扩展。它标记了这个证书能不能继续签发下级证书。CA证书是CA:TRUE,终端设备证书是CA:FALSE。如果搞反了,安全体系就形同虚设。

我曾经见过一个厂商,把所有设备证书都设成了CA:TRUE。 结果一台设备被攻破后,攻击者直接用这台设备的证书签发了大量假证书,整个产品线的信任体系瞬间崩塌。这个坑,千万别踩。

3.3 证书链与信任传递

单靠一个CA签所有证书,风险太集中。CA的私钥一旦泄露,整个系统就完了。所以实际部署中,我们几乎都用多级证书链。

典型的证书链分三层:

  • 根CA(Root CA):离线保存,极少使用。自签名证书。
  • 中间CA(Intermediate CA):在线工作,由根CA签发。可以有多级。
  • 终端证书(Leaf Certificate):由中间CA签发,给设备或服务器用。

为什么要这么设计?我举个实际例子。在安全启动里,根CA的私钥通常放在硬件安全模块(HSM)里,平时不通电。只有每年更新中间CA时,才把HSM接上。这样即使生产线的服务器被黑,攻击者也拿不到根CA的私钥。

验证证书链时,是从叶子往根追溯:

  1. 用中间CA的公钥验证叶子证书的签名
  2. 用根CA的公钥验证中间CA的签名
  3. 根CA是自签名的,它的信任来自“预置在信任存储区”

这个过程,说白了就是“我信你,因为你是我信的人担保的”。

下面这张图展示了三级证书链的结构和验证流程:

三级证书链结构与验证流程 根CA(离线) 自签名 · 信任锚点 中间CA(在线) 由根CA签发 叶子证书(设备) 由中间CA签发 签发 签发 验证方向 ① 用中间CA公钥 验证叶子签名 ② 用根CA公钥 验证中间CA签名 ③ 根CA在信任存储区 天然可信 验证追溯

3.4 根证书的信任分发

根证书是整个信任链的起点。但问题是,根证书本身没有上级给它签名。那你怎么信任它?

答案是:预置。

在安全启动场景里,根证书的公钥(或者它的哈希)是直接烧录在芯片的一次性可编程(OTP)存储器里的。芯片出厂时就写死了,之后任何人都改不了。

我参与的一个TEE项目,根证书哈希就放在eFuse里。产线烧录时,会同时写入这个哈希。每次启动时,固件先读取eFuse里的值,然后校验根证书是否匹配。不匹配?直接拒绝启动。

核心原则: 信任的源头不是算法,而是物理。根证书的完整性,最终靠的是硬件防篡改能力,而不是数学证明。

3.5 证书吊销:信任的撤回

证书不是永久的。私钥泄露、设备报废、员工离职——这些情况都需要把证书“作废”。

常用的吊销机制有两种:

机制 原理 适用场景
CRL(证书吊销列表) CA定期发布一个黑名单,列出所有被吊销的证书序列号 离线设备、网络受限环境
OCSP(在线证书状态协议) 实时查询某个证书是否有效 在线服务、低延迟要求

我个人习惯在嵌入式设备上用CRL。原因很简单——OCSP需要联网,而很多IoT设备根本没有稳定的网络连接。但CRL有个问题:时效性。如果CA刚吊销了一个证书,但设备上次拉取CRL是一周前,那这一周内它就是“带病运行”。

我的建议: 对于安全等级要求高的设备,可以结合CRL和短有效期证书。把证书有效期缩短到24小时,配合每日一次的CRL更新。这样即使吊销有延迟,最多也就一天的空窗期。

3.6 安全启动中的PKI实践

好了,理论说完了。咱们看看PKI在安全启动里到底怎么落地。

一个典型的安全启动PKI架构是这样的:

  • 根CA:离线保存在HSM里,只用来签发中间CA。一年用一次。
  • 代码签名CA:一个专门的中间CA,只用来签名固件镜像。
  • 设备身份CA:另一个中间CA,用来签发每个设备的身份证书。

为什么要分开?我在一个项目里吃过亏。当时代码签名和设备身份共用一个CA。结果固件签名流程需要联网,而设备身份注册也需要联网。两个流程混在一起,权限边界模糊。后来一次误操作,签名CA的私钥被暴露了。虽然及时更换,但所有已出货的设备都得召回升级——成本惨痛。

从那以后,我坚持职责分离。代码签名CA的私钥只放在隔离的签名服务器上,不联网。设备身份CA可以放在线,但权限严格受限。

最后,给一张完整的PKI在安全启动中的流程图:

安全启动PKI架构 根CA(HSM离线) 信任锚点 代码签名CA 隔离签名服务器 设备身份CA 在线注册服务 固件镜像 带代码签名证书 设备终端 带设备身份证书

这张图里,根CA只做一件事:签发两个中间CA。代码签名CA只签固件,设备身份CA只签设备。两条链路互不干扰。即使设备身份CA被攻破,攻击者也拿不到代码签名权限,无法伪造固件更新。

这就是PKI的精髓——通过分层和隔离,把信任风险控制在可接受的范围内。