3、密码学基础(下):数字签名原理、公钥基础设施(PKI)、证书链
上一节我们聊了哈希和对称/非对称加密。这一节,我们把这些工具组合起来,解决一个核心问题:你怎么证明这个升级包是你发的,而且没人动过手脚?
答案就是数字签名。它不是什么神秘魔法,说白了就是「私钥加密,公钥验证」的经典应用。我当年刚接触OTA时,总觉得签名就是给文件加个密码,后来踩了坑才明白——签名不是为了保密,而是为了防篡改和防抵赖。
3.1 数字签名:升级包的「身份证+防拆封」
想象一下:你写了一份合同,签上自己的名字,再盖上骑缝章。别人拿到后,一看笔迹和章就知道是你签的,而且内容没被换过。数字签名干的就是同样的事,只不过用的是数学。
签名过程(发送方):
- 对升级包文件做哈希,得到摘要(比如SHA-256)。
- 用自己的私钥加密这个摘要,生成签名。
- 把「升级包 + 签名 + 你的公钥证书」一起发给设备。
验签过程(接收方/设备):
- 设备用你的公钥解密签名,得到摘要A。
- 设备自己对升级包做哈希,得到摘要B。
- 比较A和B。如果一致,说明包没被改,且确实是你签的。
核心要点:签名不是加密整个文件,而是加密文件的哈希值。这样效率高,而且哈希的不可逆性保证了安全性。我见过有人直接加密整个固件做签名,结果升级包大了几十倍,设备内存直接爆了——千万别这么干。
我的习惯:在实际项目中,我会把签名算法固定为RSA-2048 + SHA-256,或者ECDSA + SHA-256。ECDSA签名更短,适合资源受限的嵌入式设备。但要注意,有些老设备只支持RSA,升级时得兼容。
3.2 公钥基础设施(PKI):谁来证明这把公钥是真的?
好,现在设备拿到了你的公钥,用它验签通过了。但问题来了——设备怎么知道这把公钥真的是你的?如果攻击者伪造了一把公钥,用自己的私钥签名了一个恶意包,设备用假公钥验签,一样能通过。
这就是PKI要解决的问题。PKI是一套完整的信任体系,包含证书颁发机构(CA)、证书、证书吊销列表(CRL)等组件。它的核心思想是:引入一个大家都信任的第三方(CA),由CA来证明「这把公钥属于谁」。
PKI的核心角色:
| 角色 | 职责 | 类比 |
|---|---|---|
| CA(证书颁发机构) | 签发和管理数字证书 | 公安局,负责办身份证 |
| RA(注册机构) | 验证申请者身份的真实性 | 派出所,核实你的信息 |
| 证书持有者 | 拥有公私钥对,用证书证明身份 | 你本人,持有身份证 |
| 依赖方(设备) | 验证证书的有效性 | 银行柜员,检查你的身份证 |
| CRL/OCSP | 管理已吊销的证书 | 通缉令/实时查询系统 |
在OTA升级场景中,设备就是依赖方。它必须信任某个根CA,然后由这个根CA来签发你的代码签名证书。设备只认这个根CA签发的证书,其他的一概不认。
我曾经踩过的坑:早期做项目时,我把CA的根证书直接硬编码在设备固件里。后来根证书过期了,所有新签发的升级包设备都不认,只能召回设备刷固件。血的教训——一定要在设备中预置根证书的更新机制,或者使用足够长的有效期(比如20年)。
3.3 证书链:从根CA到你的签名证书
你可能会问:CA直接给我的证书签名不就行了?为什么还要搞什么证书链?
原因很简单:安全隔离和风险分散。如果根CA的私钥泄露了,整个信任体系就崩塌了。所以实际中,根CA通常离线保存,只在最安全的环境下使用。日常签发工作由中间CA完成。
典型的证书链结构:
- 根CA证书(自签名,信任锚点)—— 离线保存,极少使用。
- 中间CA证书(由根CA签发)—— 用于签发最终实体证书。
- 最终实体证书(由中间CA签发)—— 就是你的代码签名证书。
设备验证时,会从你的证书开始,逐级向上验证,直到找到它信任的根CA证书。这个过程就叫证书链验证。
你想想看,如果中间CA的私钥泄露了,只需要吊销中间CA证书,重新签发一个就行。根CA的私钥还是安全的,整个体系不会崩溃。这就是分层的好处。
3.4 证书验证的完整流程
设备收到升级包和签名证书后,会做以下几件事:
- 检查证书有效期:当前时间是否在证书的「有效期起止」范围内。过期或未生效的证书直接拒绝。
- 检查证书吊销状态:通过CRL或OCSP查询证书是否被吊销。这一步很多嵌入式设备会省略,但安全要求高的场景必须做。
- 验证证书链:从最终证书开始,逐级验证签名,直到信任的根证书。
- 验证代码签名:用最终证书中的公钥验签升级包。
避坑指南:我曾经遇到一个案例,设备只验证了证书链,没检查证书有效期。结果攻击者用一个已过期的证书签了恶意包,设备居然通过了验证。从那以后,我在代码里强制加了时间检查——证书有效期和签名验证,一个都不能少。
3.5 嵌入式环境下的PKI实践要点
嵌入式设备资源有限,不能像PC或服务器那样搞全套PKI。我总结了几条实战经验:
- 预置根证书:设备出厂时烧录根CA证书,作为信任锚点。建议使用2048位RSA或256位ECDSA的根证书。
- 证书链精简:不要带完整的证书链,只带必要的中间证书。我一般控制在3层以内,再多设备解析不过来。
- 证书存储安全:根证书放在只读区域,防止被篡改。如果芯片有安全元件(SE)或TEE,优先存在里面。
- 时间同步:证书验证需要准确时间。设备如果没有RTC或网络时间,可以考虑使用「有效期窗口」——比如证书签发后30天内有效,避免依赖绝对时间。
- 吊销处理:嵌入式设备很难实时查询CRL/OCSP。我的做法是:在升级包中附带最新的CRL列表,设备先更新CRL,再验证证书。
我的建议:如果你刚开始做OTA安全,不要一上来就搞复杂的PKI。先从最简单的「单根证书+代码签名」开始,跑通流程。等产品稳定了,再逐步引入证书链、吊销检查等机制。安全是逐步完善的,不是一步到位的。
3.6 小结:数字签名与PKI的关系
数字签名解决的是「包是谁发的、有没有被改」的问题。PKI解决的是「公钥是谁的、能不能信」的问题。两者缺一不可。
在OTA升级中,你最终要交付给设备的是:升级包 + 签名 + 证书链。设备拿到后,先验证书链,再用证书里的公钥验签名。全部通过,才允许刷写。
嗯,这一节的内容就到这里。记住一句话:没有PKI的数字签名,就像没有身份证的签名——谁都可以冒充你。