2、信任链基础:信任根、信任链传递机制、度量与验证模型

聊可信启动,绕不开一个核心问题:凭什么相信一个系统是“干净”的?

你想想看,从按下电源键到操作系统跑起来,中间经历了固件、引导程序、内核加载……任何一个环节被篡改,整个系统就沦陷了。所以,我们需要一条信任链,从最底层开始,一级一级往上验证。

2.1 信任根(Root of Trust)

信任根,说白了就是整个信任链的起点。它必须是一个绝对可信的实体,不能被篡改,也不能被绕过。

我个人习惯把信任根分成两类:

  • 硬件信任根(HRoT):比如 TPM 芯片、Intel PTT、ARM TrustZone 中的安全元件。这些硬件在出厂时就被植入了不可更改的密钥和固件。
  • 固件信任根(FRoT):比如 UEFI 安全启动中的平台密钥(PK)。它存储在 SPI Flash 中,理论上可以被物理改写,但通常有写保护机制。

核心原则:信任根必须满足三个条件——不可伪造、不可篡改、不可绕过。缺一个,信任链就断了。

我在项目中遇到过一件事:某厂商为了省成本,把信任根密钥直接硬编码在 BootROM 里,结果被逆向工程提取出来,整个产品线的安全防线瞬间崩塌。嗯,这就是典型的“信任根不信任”案例。

2.2 信任链传递机制

有了信任根,接下来就是怎么把信任传递下去。这个过程,我习惯叫它“接力赛”。

每一棒(下一级组件)在起跑前,必须先被上一棒验证。验证通过,才把控制权交出去。这就是信任链传递的核心逻辑。

典型的信任链传递流程如下:

  1. 第一棒:BootROM(固化在芯片内部,不可修改)
  2. 第二棒:Bootloader(如 U-Boot SPL)
  3. 第三棒:主引导程序(如 U-Boot proper 或 GRUB)
  4. 第四棒:操作系统内核(如 Linux Kernel)
  5. 第五棒:内核模块与关键服务

每一棒在启动下一棒之前,都会做两件事:

  • 度量:计算下一棒代码的哈希值
  • 验证:用上一棒的公钥验证这个哈希值的签名

避坑指南:我曾经遇到一个项目,BootROM 验证了 Bootloader 的签名,但 Bootloader 在加载内核时,竟然没有验证内核的签名。结果攻击者替换了内核,系统照样启动。记住:信任链不能断,每一棒都必须验证下一棒。

2.3 度量与验证模型

度量与验证,是信任链的“安检员”。它们负责检查每一棒是否被篡改过。

2.3.1 度量(Measurement)

度量就是计算组件的哈希值。常用的算法有 SHA-256、SHA-384 等。度量结果通常存储在 TPM 的 PCR(平台配置寄存器)中。

举个例子,度量一个内核镜像:

# 计算内核镜像的 SHA-256 哈希值
sha256sum vmlinuz-5.10.0

# 输出示例
# a1b2c3d4e5f6...  vmlinuz-5.10.0

这个哈希值会被记录到 PCR 中。注意,PCR 的值是累加的——每次度量新组件,都会和之前的 PCR 值一起做一次哈希扩展。这样,最终 PCR 值就代表了整个信任链的“指纹”。

2.3.2 验证(Verification)

验证就是拿度量结果和预期值做比较。预期值通常是一个签名过的哈希值,存储在安全区域(比如 TPM 的 NVRAM 或固件分区中)。

验证流程大致如下:

  1. 用公钥解密签名,得到预期的哈希值
  2. 比较实际度量的哈希值和预期值
  3. 如果一致,验证通过;否则,拒绝启动

注意:公钥本身也必须被保护。如果攻击者替换了公钥,那签名验证就形同虚设。所以,公钥通常存储在信任根中,或者由信任根来验证公钥的完整性。

2.3.3 两种验证模型

在实际部署中,我见过两种主流的验证模型:

模型 描述 优点 缺点
静态信任链 在启动时一次性完成所有度量与验证 实现简单,性能开销小 无法应对运行时攻击
动态信任链 在系统运行过程中持续度量与验证 能检测运行时篡改 实现复杂,性能开销大

我个人更倾向于动态信任链,尤其是对安全性要求高的场景。但要注意,动态验证会引入额外的性能开销。我曾经在一个嵌入式项目中,因为动态验证频率设置得太高,导致系统响应延迟增加了 30%。后来调整了验证策略,才平衡了安全与性能。

2.4 信任链的图形化理解

为了让你更直观地理解信任链的传递过程,我画了一张图:

信任根 BootROM / TPM 度量+验证 Bootloader U-Boot SPL 度量+验证 主引导程序 GRUB / U-Boot 度量+验证 操作系统内核 Linux Kernel 度量+验证 内核模块 驱动 / 服务 信任链传递机制 每一棒在启动下一棒之前,必须完成度量与验证 关键点: 1. 信任根是起点,必须绝对可信 2. 每一棒都要验证下一棒的签名 3. 度量结果存储在 PCR 中,形成完整的信任链指纹

2.5 避坑总结

最后,我把这些年踩过的坑总结一下:

  • 信任根不能“假”:别把信任根密钥放在可读写的存储介质里。我曾经见过有人把 PK 放在 SPI Flash 的未保护区域,结果被轻松改写。
  • 信任链不能“断”:每一棒都必须验证下一棒。别偷懒,别跳过任何一环。
  • 度量不能“少”:不仅要度量代码本身,还要度量配置数据、环境变量等。攻击者经常在这些“边角料”里动手脚。
  • 验证不能“慢”:动态验证的频率要合理。太频繁影响性能,太稀疏又失去意义。我一般建议在关键操作(如加载模块、执行脚本)时触发验证。

一句话总结:信任链的本质,就是用不可篡改的根,通过逐级验证,确保整个启动过程可度量、可验证、可追溯。

嗯,信任链基础就聊到这里。记住这些原则,后面讲具体部署时,你会少踩很多坑。