3、测试环境搭建:构建双签名验证环境、模拟新旧CA共存、配置安全启动链
好,咱们进入第三章。这一章要解决一个很实际的问题——怎么搭出一个能同时验证新旧签名的测试环境。
我在好几个项目里都遇到过这种情况:CA 要换,但旧固件不能停,新固件又要上线。两边签名都得认,安全启动链还不能断。说白了,就是让设备在过渡期里「脚踏两只船」。
3.1 双签名验证环境的核心思路
双签名验证,不是让设备同时验两个签名。而是让 BootROM 或 bootloader 在验证固件时,能识别两种不同的公钥——一个来自旧 CA,一个来自新 CA。
我习惯把这种模式叫做「OR 验证」:
- 旧 CA 签的固件 → 用旧公钥验 → 通过就启动
- 新 CA 签的固件 → 用新公钥验 → 通过就启动
- 两个都不通过 → 拒绝启动
你想想看,这个逻辑其实很简单。但真正落地的时候,坑都在细节里。
关键点:双签名验证不是「同时验两个签名」,而是「两个签名只要有一个通过就算通过」。
3.2 模拟新旧CA共存
要模拟新旧 CA 共存,你得先有两套 CA 证书和密钥。我一般会在测试环境里这样搭:
- 生成旧 CA 根证书——有效期设短一点,比如 1 年,模拟即将过期的场景
- 生成新 CA 根证书——有效期设长一点,比如 10 年,模拟新 CA 长期使用
- 分别签发中间 CA 证书——如果实际生产环境有中间 CA,测试环境也要有
- 生成两套固件签名密钥——旧 CA 签一套,新 CA 签一套
我曾经在一个项目里犯过傻——新旧 CA 的密钥长度不一样。旧的是 2048 位 RSA,新的是 4096 位。结果 BootROM 的签名验证模块只支持 2048 位,新固件死活起不来。嗯,这个坑你们别踩。
| 组件 | 旧 CA | 新 CA | 说明 |
|---|---|---|---|
| 根证书 | ca_old.pem | ca_new.pem | 有效期错开,模拟过渡期 |
| 签名密钥 | signing_key_old.pem | signing_key_new.pem | 密钥长度保持一致 |
| 固件镜像 | firmware_old.signed | firmware_new.signed | 分别用新旧密钥签名 |
| 验证公钥 | pubkey_old.bin | pubkey_new.bin | 烧录到设备的不同存储位置 |
3.3 配置安全启动链
安全启动链,说白了就是一条信任链。从 BootROM 开始,一级验一级。
在双签名场景下,这条链会变成这样:
BootROM (固定公钥)
└─ 验证 bootloader (旧CA 或 新CA 签名)
└─ 验证 OS kernel (旧CA 或 新CA 签名)
└─ 验证应用固件 (旧CA 或 新CA 签名)
每个环节都要能识别两套公钥。我建议的做法是:
- BootROM 里烧录两个公钥哈希——一个对应旧 CA,一个对应新 CA
- bootloader 里存储两个公钥——用于验证下一级镜像
- OS kernel 里也保留两个公钥——用于验证应用固件
小技巧:我习惯在 bootloader 里加一个「公钥选择器」。根据固件头部的 CA ID 字段,自动选择用哪套公钥来验。这样就不用每次都遍历两套公钥了,效率高不少。
3.4 测试环境的实际搭建步骤
好,咱们动手搭一个。以下是我在实验室里常用的步骤:
- 准备硬件——一块开发板,最好是支持安全启动的 SoC
- 烧录 BootROM——把两套公钥哈希烧进 OTP 或 eFuse
- 编译 bootloader——加入双签名验证逻辑,分别用新旧密钥签名
- 编译 OS kernel——同样加入双签名验证逻辑,分别签名
- 准备测试固件——旧 CA 签一个版本,新 CA 签一个版本
- 执行测试——分别烧录旧签名固件和新签名固件,验证能否正常启动
注意:千万不要在生产环境的 OTP 里做双公钥实验。一旦烧进去,想改就难了。我见过有人把开发板的 eFuse 烧错了,整块板子直接报废。测试环境一定要用可重烧的模拟 OTP,或者直接用软件模拟。
3.5 双签名验证的流程图
下面这张图是我自己画的,把整个流程串起来了。你一看就明白。
3.6 避坑指南
最后,我把自己踩过的坑列一下。你们搭建环境的时候,多留个心眼。
- 公钥存储位置要分开——旧公钥和新公钥不要放在同一个存储区域。万一旧公钥损坏,新公钥还能用。
- 签名算法要一致——新旧 CA 的签名算法、密钥长度、哈希算法必须一样。否则 BootROM 可能只支持其中一种。
- 测试覆盖所有组合——旧签旧固件、新签新固件、旧签新固件(应该失败)、新签旧固件(应该失败),四种情况都要测。
- 别忘了回滚场景——设备从新固件回滚到旧固件,签名验证也要能通过。
我的习惯:每次改完签名逻辑,我都会先拿一个空固件(没签名的)去测。如果空固件也能启动,说明签名验证根本没生效。这个「空固件测试」是我每次必做的 sanity check。