4. 镜像格式与元数据
在安全Boot体系中,镜像格式不只是“把固件打包”的容器,而是承载信任链、版本策略与回滚防护的结构化载体。一个设计良好的镜像格式,应当让BootROM、一级引导、二级引导和操作系统加载器都能以统一方式解析、验签和决策。本章围绕镜像头、签名区、证书链、版本号与回滚索引五个关键字段展开,说明它们如何共同构成可验证、可升级、可回滚的镜像元数据体系。
一、核心原理:镜像元数据是信任链的“数据契约”
安全Boot的验签过程本质上是“读取元数据 → 计算摘要 → 验证签名 → 检查策略”的流水线。镜像头负责描述“这是什么、有多大、用什么算法”;签名区负责证明“内容未被篡改”;证书链负责回答“签名者是否被信任”;版本号与回滚索引负责回答“这个镜像是否允许被启动”。这五者缺一不可:缺少版本号,攻击者可降级到含漏洞的旧固件;缺少回滚索引,设备无法区分“合法回滚”与“恶意降级”。
设计原则:镜像头必须可被最小可信代码解析;签名区必须覆盖镜像头与镜像体;证书链必须可裁剪到设备信任根;版本号必须单调递增;回滚索引必须与安全存储中的计数器联动。
二、关键字段设计详解
1. 镜像头(Image Header):通常位于镜像起始偏移,包含魔数、头长度、镜像类型、镜像体长度、加载地址、入口地址、算法ID、签名区偏移、证书链偏移、版本号、回滚索引、头CRC等。魔数用于快速识别格式,头CRC用于在验签前做完整性初筛。头长度必须固定或可自描述,避免解析歧义。
2. 签名区(Signature Block):存放对镜像头与镜像体的数字签名。推荐采用“先哈希后签名”的两级结构:先对镜像体计算SHA-256/SHA-384摘要,再将摘要与镜像头关键字段一起签名。签名区应包含签名算法、签名长度、签名值以及被签名数据的范围描述,防止“签名覆盖不全”导致的部分篡改攻击。
3. 证书链(Certificate Chain):从设备信任根(如BootROM中烧录的根公钥哈希)到镜像签名证书的路径。典型链为“根CA → 中间CA → 固件签名证书”。每级证书需包含公钥、有效期、用途扩展、签名算法和上级签名。设备可只验证到信任根,无需联网。证书链应支持裁剪,避免镜像过大。
4. 版本号(Version):采用语义化版本或单调递增整数,如major.minor.patch.build。版本号必须被签名覆盖,防止被篡改。Bootloader在启动前比较镜像版本与安全存储中的当前版本,决定是否允许升级或回滚。
5. 回滚索引(Rollback Index):一个单调递增的计数器,通常与安全存储(OTP、TEE、RPMB)中的“最低允许版本”比较。若镜像回滚索引小于安全存储中的值,则拒绝启动。回滚索引与版本号可分离:版本号用于展示,回滚索引用于安全决策。
三、方法流程:从镜像生成到启动校验
镜像生成阶段,构建系统按固定顺序拼接:镜像头 → 证书链 → 签名区 → 镜像体。签名区中的签名值由私钥对“镜像头关键字段 + 镜像体摘要”计算得到。启动阶段,Bootloader按以下顺序执行:
- 读取镜像头,校验魔数与头CRC,确认格式合法。
- 根据头中偏移定位证书链,从信任根逐级验证证书签名与有效期。
- 用叶子证书公钥验证签名区,确认镜像头与镜像体未被篡改。
- 比较镜像版本号与安全存储中的当前版本,判断升级/回滚合法性。
- 比较回滚索引与安全存储中的最低允许值,拒绝降级攻击。
- 全部通过后,跳转到入口地址执行。
四、案例场景:OTA升级中的回滚索引联动
某设备当前运行版本为2.3.0,安全存储中回滚索引为23。服务器下发新镜像2.4.0,回滚索引24。Bootloader验签通过后,将回滚索引更新为24并写入OTP。若攻击者随后尝试刷入旧版2.2.0(回滚索引22),Bootloader读取到22 < 24,直接拒绝启动。这样即使旧镜像签名合法,也无法被用于降级攻击。
# 镜像头关键字段示例(伪代码)
struct image_header {
uint32_t magic; // 0x53454342 "SECB"
uint16_t header_size; // 固定 128 字节
uint16_t image_type; // 0=BL1, 1=BL2, 2=OS
uint32_t body_length;
uint32_t load_addr;
uint32_t entry_addr;
uint8_t algo_id; // 0=SHA256+RSA2048, 1=SHA384+ECDSA
uint32_t sig_offset;
uint32_t cert_offset;
uint32_t version; // 语义化版本编码
uint32_t rollback_index; // 单调递增
uint32_t header_crc;
};
五、误区与复盘
常见误区:只签名镜像体、不签名镜像头。攻击者可篡改版本号或回滚索引,使旧镜像“看起来”是新版本,或绕过降级检查。正确做法是将镜像头关键字段纳入签名范围,并在签名区中记录被签名数据的范围描述。
| 字段 | 作用 | 是否必须被签名 | 典型长度 |
|---|---|---|---|
| Magic | 格式识别 | 是 | 4 字节 |
| Header Size | 解析边界 | 是 | 2 字节 |
| Body Length | 镜像体范围 | 是 | 4 字节 |
| Algo ID | 算法选择 | 是 | 1 字节 |
| Version | 版本决策 | 是 | 4 字节 |
| Rollback Index | 防降级 | 是 | 4 字节 |
| Signature Value | 完整性证明 | — | 256/384 字节 |
| Cert Chain | 信任传递 | — | 可变 |
复盘建议:镜像格式设计完成后,应做三项检查:一是签名覆盖范围是否包含所有安全关键字段;二是回滚索引是否与安全存储形成闭环;三是证书链是否支持离线验证与裁剪。只有这三项都满足,镜像格式才能真正支撑安全Boot的信任链与升级策略。