3、测试环境搭建:构建双签名验证环境、模拟新旧CA共存、配置安全启动链

好,咱们进入第三章。这一章要解决一个很实际的问题——怎么搭出一个能同时验证新旧签名的测试环境。

我在好几个项目里都遇到过这种情况:CA 要换,但旧固件不能停,新固件又要上线。两边签名都得认,安全启动链还不能断。说白了,就是让设备在过渡期里「脚踏两只船」。

3.1 双签名验证环境的核心思路

双签名验证,不是让设备同时验两个签名。而是让 BootROM 或 bootloader 在验证固件时,能识别两种不同的公钥——一个来自旧 CA,一个来自新 CA。

我习惯把这种模式叫做「OR 验证」:

  • 旧 CA 签的固件 → 用旧公钥验 → 通过就启动
  • 新 CA 签的固件 → 用新公钥验 → 通过就启动
  • 两个都不通过 → 拒绝启动

你想想看,这个逻辑其实很简单。但真正落地的时候,坑都在细节里。

关键点:双签名验证不是「同时验两个签名」,而是「两个签名只要有一个通过就算通过」。

3.2 模拟新旧CA共存

要模拟新旧 CA 共存,你得先有两套 CA 证书和密钥。我一般会在测试环境里这样搭:

  1. 生成旧 CA 根证书——有效期设短一点,比如 1 年,模拟即将过期的场景
  2. 生成新 CA 根证书——有效期设长一点,比如 10 年,模拟新 CA 长期使用
  3. 分别签发中间 CA 证书——如果实际生产环境有中间 CA,测试环境也要有
  4. 生成两套固件签名密钥——旧 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 测试环境的实际搭建步骤

好,咱们动手搭一个。以下是我在实验室里常用的步骤:

  1. 准备硬件——一块开发板,最好是支持安全启动的 SoC
  2. 烧录 BootROM——把两套公钥哈希烧进 OTP 或 eFuse
  3. 编译 bootloader——加入双签名验证逻辑,分别用新旧密钥签名
  4. 编译 OS kernel——同样加入双签名验证逻辑,分别签名
  5. 准备测试固件——旧 CA 签一个版本,新 CA 签一个版本
  6. 执行测试——分别烧录旧签名固件和新签名固件,验证能否正常启动

注意:千万不要在生产环境的 OTP 里做双公钥实验。一旦烧进去,想改就难了。我见过有人把开发板的 eFuse 烧错了,整块板子直接报废。测试环境一定要用可重烧的模拟 OTP,或者直接用软件模拟。

3.5 双签名验证的流程图

下面这张图是我自己画的,把整个流程串起来了。你一看就明白。

双签名验证流程图 双签名验证流程图 BootROM 启动 读取固件 CA ID 旧 CA 公钥验证 新 CA 公钥验证 验证通过 → 启动 验证通过 → 启动 验证失败 → 拒绝启动 验证失败 → 拒绝启动 说明:两个验证路径是「OR」关系,只要有一个通过就启动。两个都失败才拒绝。 虚线表示验证失败后的流程。

3.6 避坑指南

最后,我把自己踩过的坑列一下。你们搭建环境的时候,多留个心眼。

  • 公钥存储位置要分开——旧公钥和新公钥不要放在同一个存储区域。万一旧公钥损坏,新公钥还能用。
  • 签名算法要一致——新旧 CA 的签名算法、密钥长度、哈希算法必须一样。否则 BootROM 可能只支持其中一种。
  • 测试覆盖所有组合——旧签旧固件、新签新固件、旧签新固件(应该失败)、新签旧固件(应该失败),四种情况都要测。
  • 别忘了回滚场景——设备从新固件回滚到旧固件,签名验证也要能通过。

我的习惯:每次改完签名逻辑,我都会先拿一个空固件(没签名的)去测。如果空固件也能启动,说明签名验证根本没生效。这个「空固件测试」是我每次必做的 sanity check。