信任根(RoT)基础:硬件信任根、软件信任根、信任链的建立与传递

说到固件安全,信任根是个绕不开的话题。我刚开始接触这个领域时,总觉得“信任”是个很虚的概念——芯片上电后,凭什么相信第一行代码是安全的?后来踩过几次坑才明白,信任根就是整个安全体系的锚点。锚点不稳,后面全是白搭。

说白了,信任根(Root of Trust, RoT)是一个绝对可信的起点。它必须满足两个条件:一是自身不可篡改,二是能验证下一级组件的可信度。今天我们就从硬件和软件两个维度,把信任根这件事彻底讲透。

核心观点:没有信任根,就没有信任链。信任根是安全启动的“第一块积木”,它的安全性决定了整个系统的安全上限。

2.1 硬件信任根:物理世界的锚点

硬件信任根,我习惯叫它“物理锚点”。它通常是一个不可更改的硬件模块,比如芯片内部的ROM、一次性可编程熔丝(eFuse),或者专用的安全协处理器。为什么必须是硬件?因为软件可以被改写,而硬件一旦固化,物理上就改不动了。

我在项目中遇到过最典型的硬件信任根,就是Boot ROM。芯片上电后,CPU第一条指令从Boot ROM里取,这段代码是芯片出厂时写死的,谁都没法改。你想想看,如果连Boot ROM都能被篡改,那整个安全体系就崩塌了。

常见的硬件信任根载体包括:

  • Boot ROM:只读存储器,出厂固化,用于加载并验证下一级Bootloader。
  • eFuse / OTP:一次性可编程存储,用于存储公钥哈希、芯片唯一ID、安全配置位。
  • HSM / TPM:专用安全芯片,提供密钥生成、签名验证、随机数等硬件加速能力。
  • PUF(物理不可克隆函数):利用芯片制造差异生成唯一密钥,防物理破解。
载体类型 可篡改性 典型用途 我见过的坑
Boot ROM 不可改(物理只读) 第一级启动代码 ROM bug只能通过硬件改版修复
eFuse 一次性写入 存储公钥哈希、安全等级 熔丝烧断后无法恢复,测试要格外小心
HSM/TPM 硬件隔离 密钥管理、签名验证 通信接口容易被侧信道攻击
PUF 物理随机 芯片唯一密钥生成 环境温度变化可能导致密钥不稳定
避坑指南:我曾经在一个IoT项目中,团队为了省成本,把公钥直接硬编码在Flash里,没有用eFuse保护。结果攻击者通过JTAG读出Flash,替换了公钥,整个安全启动形同虚设。记住:硬件信任根必须物理不可改,放在Flash里那不叫信任根,那叫“信任建议”。

2.2 软件信任根:从硬件到软件的桥梁

硬件信任根再强,最终还是要跑软件。软件信任根,说白了就是被硬件信任根验证通过的那段代码。它本身不一定是硬件不可改的,但它的可信度由硬件信任根来保证。

我习惯把软件信任根理解为“信任接力棒的第一棒”。Boot ROM验证完Bootloader后,Bootloader就成了新的信任根,继续验证下一级。但这里有个关键点:软件信任根必须保持最小化。代码越少,攻击面越小,越容易做形式化验证。

软件信任根通常包含以下功能:

  • 度量自身完整性:计算自身哈希,与硬件存储的参考值比对。
  • 验证下一级镜像:使用公钥验证下一级固件的签名。
  • 建立安全环境:配置MMU、关闭调试接口、初始化安全区域。
  • 传递信任:将控制权交给已验证的下级组件。
个人经验:我在设计软件信任根时,会强制要求代码量不超过4KB。为什么?因为4KB以内的代码可以用形式化验证工具做全路径覆盖,超过这个量级,验证成本指数级上升。你想想看,信任根本身如果有bug,那整个信任链就是“信任崩塌链”。

2.3 信任链的建立与传递:逐级验证,环环相扣

信任链,就是一条从硬件信任根开始,逐级验证、逐级传递信任的链条。每一级都验证下一级的完整性和真实性,验证通过后才移交控制权。一旦某一级验证失败,系统必须进入安全状态——通常是死循环或复位。

典型的信任链流程如下:

  1. 上电复位:CPU从Boot ROM取指,执行固化代码。
  2. 度量Bootloader:Boot ROM读取Bootloader镜像,计算哈希,与eFuse中的参考值比对。
  3. 验证签名:使用eFuse中的公钥验证Bootloader的数字签名。
  4. 移交控制权:验证通过后,跳转到Bootloader执行。
  5. Bootloader度量OS Kernel:Bootloader重复上述过程,验证OS内核。
  6. OS度量应用:OS内核在加载应用时,继续验证应用签名。

这个过程,我称之为“洋葱式信任传递”——每一层都包裹着下一层,从最核心的硬件信任根向外层层展开。

信任链建立与传递流程图 Boot ROM(硬件RoT) Bootloader(软件RoT) OS Kernel 系统服务 / 应用 验证Bootloader签名 使用eFuse公钥 验证OS Kernel签名 使用Bootloader内置公钥 验证应用签名 使用OS内核公钥 验证失败 → 安全状态 死循环 / 复位 / 报警
关键原则:信任链的每一级都必须满足“度量-验证-执行”三个步骤。度量是计算哈希,验证是比对签名,执行是移交控制权。缺一步,信任链就断了。

2.4 信任链的常见攻击面与防御

信任链听起来很坚固,但实际落地时到处都是坑。我总结了几类最常见的攻击方式,以及对应的防御措施。

攻击类型 攻击手法 防御措施 我的亲身经历
回滚攻击 攻击者刷入旧版本固件,利用已知漏洞 eFuse中存储版本计数器,禁止降级 曾经有个客户没做版本防回滚,被攻击者刷回一年前的固件,直接绕过所有安全补丁
密钥泄露 私钥被提取,攻击者签名恶意固件 使用HSM保护私钥,定期轮换 见过某厂商把签名私钥放在CI服务器上,明文存储,被挖矿脚本扫到后全网公开
侧信道攻击 通过功耗、电磁辐射分析提取密钥 使用恒定时间比较、随机延时、掩码技术 我在做安全认证时,实验室用简单功耗分析(SPA)就破解了一款未防护的签名验证实现
JTAG/SWD调试接口 通过调试接口读取内存或篡改流程 量产时熔断调试接口,或使用密码保护 这个坑我踩过两次,后来强制要求所有产品在出厂前必须锁死调试接口
特别提醒:信任链的强度取决于最弱的一环。很多团队把精力花在Boot ROM和Bootloader上,却忽略了应用层的签名验证。我曾经审计过一个系统,Bootloader验证做得滴水不漏,但OS内核加载应用时直接跳过签名检查——因为“应用太多,验证太慢”。结果攻击者只需要替换一个普通应用,就能拿到系统权限。记住:信任链必须贯穿始终,不能有“信任断层”。

2.5 信任根的度量与报告

信任根不仅要“可信”,还要“可度量”。在可信计算领域,有一个概念叫度量启动(Measured Boot)。它和前面说的安全启动(Secure Boot)有什么区别?

  • Secure Boot:验证失败就停止启动,保证只运行可信代码。
  • Measured Boot:记录每一级组件的哈希值,即使启动继续,也能向远程验证方报告当前系统的信任状态。

我个人更倾向于两者结合:先用Secure Boot保证启动过程的安全性,再用Measured Boot记录信任链的度量值,用于远程证明(Remote Attestation)。

度量值通常存储在平台配置寄存器(PCR)中,由TPM或HSM管理。每一级启动组件都会扩展(Extend)PCR值:

// 伪代码:信任链度量过程
PCR[0] = HASH(Boot ROM)
PCR[1] = HASH(PCR[0] || Bootloader)
PCR[2] = HASH(PCR[1] || OS Kernel)
PCR[3] = HASH(PCR[2] || Application)

为什么要用“扩展”而不是“覆盖”?因为扩展操作是不可逆的,攻击者无法伪造一个特定的PCR值。你想想看,如果只是覆盖,攻击者完全可以在加载恶意代码后,把PCR改回正常值。扩展操作保证了度量值的完整性。

实用建议:在设计信任链时,我建议把度量日志(Event Log)也保存下来。PCR只存储最终的哈希值,但日志记录了“谁度量了谁、结果是什么”。远程验证时,验证方可以重放整个信任链,确认每一步都正确。这就像审计日志——光有结论不够,还得有过程。

2.6 小结:信任根设计的三个黄金法则

做了这么多年固件安全,我总结出信任根设计的三个黄金法则,分享给你:

  1. 最小化原则:信任根的代码越少越好。Boot ROM最好控制在4KB以内,软件信任根不超过16KB。代码越少,越容易验证,越难被攻击。
  2. 物理隔离原则:硬件信任根必须与主系统物理隔离。Boot ROM不能通过系统总线改写,eFuse不能通过软件接口读取。隔离是信任的物理基础。
  3. 全链覆盖原则:信任链不能有断层。从Boot ROM到应用层,每一级都必须验证下一级。哪怕有一个环节跳过验证,整个信任链就失去了意义。