3. 密码学基础(下):公钥基础设施(PKI)概念,数字证书与CA中心的作用
上一讲我们聊了对称与非对称加密、哈希和签名这些基础工具。但有个问题一直悬着:你怎么确定你拿到的公钥,真的是对方的?
我在项目里见过最典型的场景——设备A要给设备B发固件升级包,B拿到了一个公钥,结果这个公钥是攻击者伪造的。签名验签做得再漂亮,根上就错了。这就是我们今天要讲的核心:公钥基础设施(PKI),说白了就是一套解决“公钥归属问题”的信任体系。
3.1 为什么需要PKI?
先想一个简单问题。你收到一封邮件,声称来自你的银行,附带了银行的公钥。你怎么确认这个公钥真的是银行的?
直接比对?你没见过银行公钥长什么样。打电话问?电话那头也可能是骗子。这就是公钥分发问题——在开放网络里,没人能保证你拿到的公钥没被调包。
PKI的解决思路很朴素:找一个大家都信任的第三方,由它来担保“这个公钥属于谁”。这个第三方就是CA(Certificate Authority,证书颁发机构)。它颁发的担保书,就是数字证书。
核心一句话:PKI = 公钥 + 身份信息 + CA的数字签名。它把“谁的钥匙”这个问题,变成了“谁签了这张证书”。
3.2 数字证书长什么样?
数字证书本质上是一个结构化的数据文件。最通用的标准是X.509 v3,我在嵌入式设备里打交道最多的就是它。
一张典型的X.509证书包含以下字段:
| 字段 | 说明 | 我常关注的点 |
|---|---|---|
| 版本号 | 通常是v3(值为2) | v3才支持扩展项,老设备可能只认v1 |
| 序列号 | CA分配的唯一编号 | 吊销证书时靠它定位 |
| 签名算法 | 如SHA256-RSA、ECDSA-SHA256 | 嵌入式里ECDSA更省资源 |
| 颁发者 | 签发该证书的CA名称 | 链式验证时逐级比对 |
| 有效期 | notBefore ~ notAfter | 设备时间不准会导致验证失败,踩过坑 |
| 主体 | 证书持有者的身份信息 | 设备ID、域名、组织名 |
| 公钥 | 持有者的公钥(含算法参数) | RSA 2048位或ECC P-256最常见 |
| 扩展项 | 密钥用途、基本约束、CRL分发点等 | 嵌入式里常用来限制证书用途 |
| CA签名 | CA用私钥对整个证书的签名 | 验证这个签名,就是验证证书真伪 |
一个小技巧:我在做设备证书解析时,习惯先检查“基本约束”扩展里的CA标志。如果一张终端设备证书的CA标志被设为TRUE,那说明证书链设计有问题——终端设备不应该有签发下级证书的权限。
3.3 CA中心:信任的锚点
CA是整个PKI体系的信任起点。它做三件事:签发、管理、吊销。
我画了一张图,帮你理解CA在证书链里的位置:
实际部署时,根CA通常离线保存,只在签发二级CA时开机。二级CA在线运行,负责签发终端设备证书。这样做的好处是:就算二级CA被攻破,根CA还在,可以吊销二级CA证书并重新签发。
我曾经踩过的坑:有个项目把根CA私钥直接放在生产线的工控机上,方便批量签发设备证书。结果工控机中了勒索病毒,根CA私钥被加密。虽然最后通过备份恢复了,但那次之后我坚持:根CA私钥必须离线存储,最好用硬件安全模块(HSM)保护。生产线上只放二级CA的私钥,大不了吊销重签。
3.4 证书链验证:信任是怎么传递的
嵌入式设备验证签名时,不会只验证设备证书本身。它会沿着证书链一路验证到根CA。这个过程叫证书链验证。
具体步骤是这样的:
- 解析证书:从签名数据里提取出设备证书和中间CA证书(如果有)。
- 验证签名:用上一级证书的公钥,验证当前证书的签名。从设备证书开始,逐级向上。
- 检查有效期:每张证书的当前时间必须在notBefore和notAfter之间。
- 检查吊销状态:通过CRL(证书吊销列表)或OCSP(在线证书状态协议)确认证书未被吊销。
- 检查密钥用途:证书的扩展项里规定了这把公钥能干什么——签名、加密、还是两者都可。
- 到达信任锚:最后一级证书的颁发者,必须是设备里预置的根CA证书。
这里有个细节:信任锚是预置的,不是验证出来的。设备出厂时烧录的根CA证书,就是整个信任链的起点。它自签名——自己给自己签名,因为没人能给它担保。
嵌入式里的特殊处理:很多MCU资源有限,没法完整验证整条证书链。我常用的做法是——在产线预置时,直接把设备证书和中间CA证书打包成一条链,设备只验证设备证书的签名,然后检查中间CA证书是否与预置的根CA匹配。这样省掉了逐级解析的开销。
3.5 证书吊销:被信任的“不信任”
证书不是永久的。私钥泄露、设备退役、员工离职——这些情况都需要让一张证书失效。这就是证书吊销。
两种主流方式:
| 方式 | 原理 | 嵌入式适用性 |
|---|---|---|
| CRL(证书吊销列表) | CA定期发布一个列表,包含所有被吊销证书的序列号 | 适合离线设备,但列表会越来越大,存储开销高 |
| OCSP(在线证书状态协议) | 实时向CA查询某张证书的状态 | 需要网络连接,延迟低,但设备必须在线 |
我个人的建议是:物联网设备优先用CRL的增量更新方式。设备只下载自上次更新以来新增的吊销条目,而不是全量列表。这样既控制了存储,又能保持离线验证能力。
一个实用经验:我在智能门锁项目里,把CRL的更新频率设为每24小时一次。设备在夜间低峰期联网下载增量CRL。如果连续3天没更新,设备会进入“降级模式”——允许本地开锁,但禁止远程升级。这样既保证了安全,又没影响用户体验。
3.6 嵌入式里的PKI部署要点
最后总结几个我在实际项目中反复踩过的坑:
- 证书格式:嵌入式里最常用的是DER格式(二进制),而不是PEM(Base64文本)。DER解析快,省空间。我习惯在产线阶段就把PEM转成DER再烧录。
- 密钥存储:私钥绝对不能明文存在Flash里。用芯片自带的eFuse、OTP或安全元件(SE)来存。如果芯片没有硬件安全单元,至少用芯片唯一ID对私钥做加密存储。
- 时间问题:证书有效期验证依赖准确时间。很多物联网设备没有RTC电池,每次联网后先做NTP时间同步,再验证证书。如果时间不对,证书验证会误判。
- 证书大小:一张RSA 2048位的证书大约1~2KB。如果证书链有三四级,总大小可能超过5KB。对于Flash只有几十KB的MCU,这个开销不能忽视。我一般把证书链控制在两级(根CA + 设备证书),中间CA证书预置在固件里。