4、PKI公钥基础设施:CA机构、数字证书格式(X.509)、证书链、CRL证书吊销列表、OCSP在线证书状态协议

好,咱们进入第四讲。这一章是基础中的基础,也是很多人在做双向认证时容易「翻车」的地方。

PKI,全称是公钥基础设施。说白了,它就是一套管理密钥和证书的体系。你想想看,MQTT 双向认证里,客户端和服务端都要出示证书。那这些证书谁签发的?怎么保证它没被篡改?过期了怎么办?被吊销了怎么查?——这些问题,都得靠 PKI 来回答。

4.1 CA机构:谁来当这个「公证人」?

CA,Certificate Authority,证书颁发机构。它就是 PKI 体系里的「信任锚点」。

我习惯把 CA 比作「身份证签发机关」。你拿着户口本去办身份证,公安局核实你的身份后,给你盖个章。这个章就是 CA 的签名。别人看到这个章,就知道你的身份证是真的。

在 MQTT 场景里,CA 的角色是这样的:

  • 签发证书:为服务端和客户端生成数字证书
  • 管理证书生命周期:从申请、审核、签发,到续期、吊销
  • 维护证书状态:通过 CRL 或 OCSP 提供证书有效性查询

关键点:在双向认证中,客户端和服务端必须信任同一个 CA(或者 CA 的上级根证书)。否则,证书校验会直接失败。

我在项目中遇到过一种情况:客户自己搭了私有 CA,但客户端只配了服务端证书,没配 CA 根证书。结果 TLS 握手一直报错,查了半天才发现是信任链断了。嗯,这种坑踩过一次就记住了。

4.2 数字证书格式(X.509):证书里到底写了啥?

现在通用的证书格式是 X.509 v3。你打开一个 PEM 文件,看到的「-----BEGIN CERTIFICATE-----」那一串,就是 X.509 证书的 Base64 编码。

一个标准的 X.509 证书包含以下字段:

字段 说明 我的备注
Version 版本号,目前主流是 v3 v3 才支持扩展字段
Serial Number 证书序列号,CA 唯一分配 吊销时靠它定位
Signature Algorithm 签名算法,如 SHA256-RSA 别用 SHA1,已不安全
Issuer 签发者(CA 的 DN) 就是「谁签的」
Validity 有效期(notBefore / notAfter) 过期证书直接拒掉
Subject 证书持有者(DN) 客户端证书里填设备 ID
Public Key 公钥信息(算法 + 密钥值) 核心数据
Extensions 扩展字段(v3 特性) 用途、约束都在这里

扩展字段里,有几个我特别关注:

  • Key Usage:指定密钥用途,比如 digitalSignature、keyEncipherment
  • Extended Key Usage:更细粒度,比如 serverAuth、clientAuth
  • Subject Alternative Name (SAN):主题备用名称,MQTT 里常用它填设备标识

我的习惯:签发客户端证书时,一定在 Extended Key Usage 里加上 clientAuth。否则某些 MQTT Broker 会拒绝连接。我踩过这个坑,当时 Mosquitto 日志里报「certificate用途不匹配」,查了半天才发现是 EKU 没配。

4.3 证书链:信任是怎么传递的?

证书链,也叫信任链。它解决一个问题:你的证书是 CA 签的,那 CA 的证书又是谁签的?

典型的证书链分三级:

  1. 根证书(Root CA):自签名,是整个信任体系的锚点
  2. 中间证书(Intermediate CA):由根证书签发,用于签发终端证书
  3. 终端证书(End-Entity):服务端或客户端实际使用的证书

为什么要搞中间证书?我个人的理解是:安全隔离。根证书一旦泄露,整个体系就完了。所以根证书通常离线保存,日常签发用中间 CA。即使中间 CA 出问题,吊销它就行,根证书不受影响。

注意:MQTT 双向认证时,服务端必须发送完整的证书链(终端证书 + 中间证书),不能只发终端证书。否则客户端无法验证信任路径。我曾经见过有人只配了终端证书,结果客户端报「unable to get local issuer certificate」。

下面这张图展示了证书链的信任传递关系:

证书链信任传递关系 根 CA(自签名) 信任锚点,离线保存 中间 CA 由根CA签发,日常使用 终端证书 服务端/客户端实际使用 验证过程:终端证书 → 中间CA → 根CA(信任锚点) 任何一环验证失败,整个信任链断裂,TLS握手拒绝

4.4 CRL证书吊销列表:黑名单机制

证书还没到期,但私钥泄露了,或者设备报废了,怎么办?——吊销。

CRL,Certificate Revocation List,证书吊销列表。它就是 CA 发布的一份「黑名单」,里面列出了所有被吊销的证书序列号。

CRL 的工作流程:

  1. CA 定期生成 CRL 文件,并签名
  2. 客户端或服务端下载 CRL,缓存到本地
  3. 验证证书时,检查其序列号是否在 CRL 中
  4. 如果在,拒绝连接

CRL 的缺点:实时性差。CRL 是定期发布的,比如每 24 小时更新一次。如果证书在刚发布后被吊销,那在下次更新前,它依然被认为是有效的。这就是所谓的「吊销延迟窗口」。

我曾经在一个物联网项目里吃过这个亏。设备私钥泄露了,我们紧急吊销了证书,但 CRL 还没更新。结果攻击者利用这个时间窗口继续连接服务器。嗯,从那以后,我对 CRL 的实时性就特别敏感。

4.5 OCSP在线证书状态协议:实时查询方案

OCSP,Online Certificate Status Protocol,在线证书状态协议。它解决了 CRL 的实时性问题。

OCSP 的工作方式:

  • 验证方(比如 MQTT Broker)向 OCSP 响应器发送查询请求
  • 请求内容:证书序列号 + 签发者信息
  • OCSP 响应器返回状态:good(有效)、revoked(已吊销)、unknown(未知)

OCSP 比 CRL 好在哪?

对比项 CRL OCSP
实时性 低(定期更新) 高(实时查询)
网络开销 下载整个列表 单条查询
隐私性 好(不暴露查询目标) 差(暴露了查谁的证书)
适用场景 离线环境、内网 在线环境、高安全要求

我的建议:在 MQTT 双向认证中,如果设备能联网,优先用 OCSP。如果设备离线或网络受限,用 CRL + 较短的更新周期。我一般设 CRL 更新间隔为 1 小时,平衡实时性和带宽。

不过 OCSP 也有个问题:OCSP 响应器如果挂了,查询会失败。这时候怎么办?——OCSP Stapling。服务端在 TLS 握手时,主动把 OCSP 响应「钉」在证书里发给客户端,客户端就不用自己去查了。这个技术我在后面的章节会细讲。

4.6 小结:PKI 在 MQTT 双向认证中的位置

这一章的内容,说白了就是回答一个问题:你怎么证明你手里的证书是可信的?

  • CA 机构负责签发和管理证书
  • X.509 证书是承载信任的载体
  • 证书链把信任从根传递到终端
  • CRL 和 OCSP 负责处理证书的「死后」问题

这些概念,在后续配置 MQTT 双向认证时,会反复用到。尤其是证书链的配置和吊销状态的检查,是很多线上事故的根源。我建议你先把这张图刻在脑子里,后面实操时就不会迷路。