很多设备安全讨论里会出现一句话:“固件已经签名了,所以安全。”
这句话只说对了一部分。固件签名能证明固件由可信私钥授权,且内容没有被篡改。但它不自动解决固件是否加密、旧版本能不能回滚、启动链每一级是否都验证下一极、签名密钥怎样保护、更新失败后设备能不能恢复。
Secure Boot 和 OTA 验签要解决的是两条链:
启动链:ROM -> Bootloader -> Kernel -> rootfs / app
升级链:update package -> staging slot -> verified boot target
核心问题不是“有没有签名文件”,而是设备是否只运行被授权、未篡改、版本策略允许的代码。
签名保护完整性和来源
固件签名通常是:
firmware image
-> hash
-> sign hash with vendor private key
-> firmware + signature + metadata
设备端验证:
firmware image
-> hash
-> verify signature with trusted public key
-> boot or reject
这里保护的是:
- 固件内容没有被改
- 固件确实由持有厂商私钥的一方授权
- 攻击者不能只靠重新打包生成合法签名
哈希本身只提供指纹。签名把这个指纹和可信私钥绑定起来。
签名不等于加密
签名保护完整性和来源,不保护机密性。
如果固件是明文签名包,攻击者仍然可以读取固件内容:
- 反编译业务逻辑
- 提取字符串和接口
- 分析协议实现
- 找漏洞
- 复制非秘密资源
签名能阻止攻击者修改后让设备接受,但不能阻止攻击者看。
如果固件内容本身需要保密,必须额外做固件加密或密钥包裹。但固件加密也不能替代签名。设备解密之前或之后仍要确认这个镜像是被授权的。
更稳的关系是:
签名:能不能运行
加密:能不能被别人看懂
两者解决的问题不同。
Secure Boot 是逐级验证
Secure Boot 的关键是启动链中每一级验证下一级。
典型路径:
ROM verifies first-stage bootloader
bootloader verifies second-stage bootloader or kernel
kernel verifies initramfs / rootfs / modules / app policy
system verifies OTA target before switching
第一段信任通常来自芯片 ROM、OTP/eFuse 里的公钥 hash、不可改写 boot ROM 逻辑或安全启动配置。
如果 ROM 验证了 bootloader,但 bootloader 不验证 kernel,攻击者仍然可以替换 kernel。如果 kernel 验证了 rootfs,但内核模块能随便加载,攻击者也可能绕过。
所以 Secure Boot 不是单点开关,而是一条信任链。
信任锚必须不可被普通固件改写
设备要有一个初始信任锚,例如:
- ROM 内置厂商公钥
- eFuse/OTP 中的公钥 hash
- 安全芯片里的验证公钥
- SoC 安全启动配置
- Bootloader 只读区域里的受保护公钥
这个信任锚必须不能被普通应用、普通固件升级或攻击者轻易改写。
如果公钥能被未授权固件替换,攻击者可以把自己的公钥写进去,再签自己的固件,整条信任链就失效。
OTA 验签保护升级入口
OTA 验签关注的是设备收到更新包以后,是否只接受可信发布方授权的包。
一个可靠 OTA 流程通常包括:
download update
-> verify package signature and metadata
-> verify target hardware / product / version
-> write inactive slot or staging area
-> verify written image
-> switch boot target
-> boot and mark success
更新包的 metadata 很重要。它通常包含:
- 产品型号
- 硬件版本
- 软件版本
- 镜像 hash
- 分区布局
- 最低可接受版本
- 签名算法和 key id
- 包格式版本
只签镜像内容而不签 metadata,可能让攻击者替换版本号、目标设备、分区信息或降级策略。
回滚保护是单独问题
签名不能自动阻止旧版本。
如果攻击者拿到一个旧的、合法签名的固件包,设备只验证签名,就可能接受这个旧版本。旧版本里可能有已知漏洞。
所以需要回滚保护:
firmware version / security counter
-> compare with monotonic counter
-> reject lower version
计数器可以放在:
- eFuse/OTP
- RPMB
- 安全存储
- Bootloader 受保护区域
- 服务器端策略配合设备状态
难点是计数器必须防回滚。普通 flash 里的版本文件如果能被旧镜像一起恢复,就不能单独承担安全回滚保护。
A/B 更新解决失败恢复,不等于安全
A/B 分区常见于可靠 OTA:
current slot: A
write update to slot B
verify B
boot B
mark B successful
fallback to A if boot fails
A/B 解决的是更新失败后的可恢复性。它不自动保证安全。
仍然需要:
- 写入前验签
- 写入后校验 hash
- 启动时验证目标 slot
- 防止回滚到有漏洞的旧 slot
- 成功启动后更新安全计数器
- 失败回退时遵守版本策略
不要把“有 A/B”理解成“有 Secure Boot”。
签名密钥泄露会影响整套发布体系
Secure Boot 和 OTA 的核心秘密是签名私钥。
设备里通常只放公钥或公钥 hash。发布系统或 HSM 里保存私钥。
需要重点防护:
- 私钥是否在 HSM 或离线环境里
- CI/CD 是否能直接接触生产签名私钥
- 测试 key 和生产 key 是否隔离
- key id 和签名算法是否支持轮换
- 泄露后设备是否能信任新 key
- 旧 key 是否能被禁用
- 产线镜像是否混入测试公钥
测试私钥如果被量产设备信任,攻击者拿到测试 key 就能签可运行固件。
验签失败必须停止信任路径
验签失败后继续启动,是 Secure Boot 的典型破口。
危险做法包括:
- 验签失败只打印 warning
- debug 模式在量产设备未关闭
- 失败后自动进入可写 shell
- fallback 到未验证分区
- 网络更新失败后运行未验证缓存包
- 对某些分区只校验 hash,不校验签名来源
量产设备的失败策略要明确:拒绝启动、进入受限恢复模式、等待可信恢复包,或者回退到版本策略允许且已验证的 slot。
排查顺序
遇到固件能被替换、OTA 包被拒绝、回滚异常、A/B 反复切换或 Secure Boot 打开后无法启动时,可以按这条链检查:
信任锚是否不可被普通固件改写
-> ROM 是否验证第一阶段 bootloader
-> bootloader 是否验证 kernel / next stage
-> kernel 是否限制 rootfs、模块和关键应用加载
-> OTA metadata 是否被签名覆盖
-> 写入后 image hash 是否和签名 metadata 一致
-> 回滚计数器是否防回滚
-> A/B fallback 是否仍遵守版本策略
-> 测试 key 是否没有进入量产信任链
-> 验签失败是否停止启动或进入受限恢复
Secure Boot 和 OTA 验签保护的是“设备只运行被授权、未篡改、版本策略允许的代码”。签名不是加密,也不是自动回滚保护;它必须和信任锚、逐级验证、metadata、计数器、A/B 恢复和签名密钥管理一起设计。