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 的证书又是谁签的?
典型的证书链分三级:
- 根证书(Root CA):自签名,是整个信任体系的锚点
- 中间证书(Intermediate CA):由根证书签发,用于签发终端证书
- 终端证书(End-Entity):服务端或客户端实际使用的证书
为什么要搞中间证书?我个人的理解是:安全隔离。根证书一旦泄露,整个体系就完了。所以根证书通常离线保存,日常签发用中间 CA。即使中间 CA 出问题,吊销它就行,根证书不受影响。
注意:MQTT 双向认证时,服务端必须发送完整的证书链(终端证书 + 中间证书),不能只发终端证书。否则客户端无法验证信任路径。我曾经见过有人只配了终端证书,结果客户端报「unable to get local issuer certificate」。
下面这张图展示了证书链的信任传递关系:
4.4 CRL证书吊销列表:黑名单机制
证书还没到期,但私钥泄露了,或者设备报废了,怎么办?——吊销。
CRL,Certificate Revocation List,证书吊销列表。它就是 CA 发布的一份「黑名单」,里面列出了所有被吊销的证书序列号。
CRL 的工作流程:
- CA 定期生成 CRL 文件,并签名
- 客户端或服务端下载 CRL,缓存到本地
- 验证证书时,检查其序列号是否在 CRL 中
- 如果在,拒绝连接
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 双向认证时,会反复用到。尤其是证书链的配置和吊销状态的检查,是很多线上事故的根源。我建议你先把这张图刻在脑子里,后面实操时就不会迷路。