工控固件安全实战:从裸奔到硬件信任根的完整链路
一步步实现在 NXP i.MX RT 平台上的硬件信任根安全启动与签名 OTA 升级,教训与方案适用于所有 Cortex-M 设备。
1. 为什么要搞安全启动?
在工控领域,固件被篡改不只是数据泄露的问题——它是物理安全威胁。被篡改的固件可能禁用看门狗、改写热关断阈值,或悄无声息地窃取核心运动控制参数。
然而现实是,大多数工业物联网设备出厂时 JTAG 全开,固件完整性校验仅靠 CRC32。CRC32 能抓比特翻转,但对有动机的攻击者毫无作用。
2025 年中,我们对泰诺固件供应链做了安全审计,发现多处缺口:OTA 载荷未签名、无版本回滚防护、生产设备调试接口未关闭。这篇文章记录完整修复方案。
2. 信任链设计
我们的安全启动实现了三级信任链:
$$ROM Boot Code(不可变,掩膜 ROM 固化)
↓ 验证 ECDSA 签名
第一级:Bootloader(公钥哈希烧录在 OTP eFuse 中)
↓ 验证 ECDSA 签名
第二级:应用固件
↓ 验证 ECDSA 签名
第三级:FPGA 比特流 + 标定数据$$
每一级的公钥内嵌于上一级,信任根锚定于 i.MX RT1064 的一次性可编程(OTP)eFuse。公钥哈希一旦烧入 OTP,除非物理更换芯片,否则无法修改。
所有签名使用 ECDSA with NIST P-256。选择 ECDSA 而非 RSA 基于两个考量:签名体积更小(64 字节 vs. 同等安全强度的 256+ 字节),以及在 Cortex-M 核上的验证速度更快(无需硬件加密加速器即可获得可接受的性能)。
3. OTA 防回滚
仅有签名是不够的。攻击者可以截获一个有效但过时的 OTA 包,将其重放以将设备降级到存在已知漏洞的旧版本。
我们的防回滚机制简单且硬件支持:
- 每个固件镜像在其签名元数据中携带一个单调递增的安全版本号。
- 当前安全版本号存储在 eFuse 实现的单调计数器中(只能烧 1,不能清 0)。
- Bootloader 拒绝任何安全版本号小于 eFuse 计数值的镜像。
- 提升安全版本的 OTA 更新会烧录新的 eFuse 比特——这是一个物理上不可逆的操作,即使全片擦除也无法撤销。
4. CI/CD 中的密钥管理
密钥管理是大多数安全启动方案在实际落地中最薄弱的环节。密钥存在开发者的笔记本上,就意味着迟早会泄露。
我们的方案:
- 离线根 CA:一台物理断网的机器持有根签名密钥,每年仅使用一次来签发中间证书。
- HSM 支持的 CI 签名:日常固件签名密钥驻留在接入 CI 服务器的 YubiHSM 2 中。私钥永不离开 HSM;CI 流水线将固件哈希发送给 HSM 签名,HSM 返回签名结果。
- 开发者签名使用由 CI 中间 CA 签发的临时密钥,有效期 8 小时——开发者工作站上不保留任何持久化私钥。
5. 实践教训
- 先测"变砖"路径:在启用安全启动推生产之前,我们故意刷入未签名的镜像来验证设备是否正确拒绝启动。故障模式必须是安全且可恢复的。
- OTP 比特不可逆:烧录前反复核对每个 eFuse 值。我们维护一份"熔丝位映射表",任何 OTP 编程操作前必须由两名工程师交叉审核。
- 密钥生成仪式是必要的:根密钥生成过程全程录像,两人在场见证。根私钥仅以纸质形式存在(QR 码编码的助记词),存放于物理保险柜中。
自 i.MX RT 全系设备部署安全启动以来,固件完整性校验使启动时间增加了约 120ms。但用这点代价换取"绝无未授权代码运行在泰诺控制器上"的保证,非常值得。