4. 信任链(Chain of Trust):从BIOS到操作系统的度量启动
好,咱们来聊聊信任链。这个概念,说白了就是「谁信谁」的问题。
你想想看,TPM 本身是一个可信根,但它不能自己跳出来说「我是可信的」。它需要一套机制,把信任一级一级传递下去。从你按下电源键那一刻起,到操作系统完全加载,每一步都要确保「上一步是可信的,这一步才可信」。这就是信任链的核心思想。
4.1 信任链的建立过程
我习惯把信任链想象成一个接力赛。第一棒是 TPM 芯片里的可信根(RTM),它负责度量 BIOS 的代码。如果 BIOS 的哈希值跟预期一致,信任就传递给 BIOS。然后 BIOS 再去度量 Option ROM、引导加载程序(Boot Loader),最后到操作系统内核。
这个过程,在 TCG(Trusted Computing Group)的规范里叫「度量启动」(Measured Boot)。注意,它跟「安全启动」(Secure Boot)不是一回事。安全启动是「如果度量失败,就阻止启动」。度量启动是「不管度量结果如何,都记录在 PCR 里,供后续验证」。我见过不少工程师把这两个概念搞混,结果调试时走了不少弯路。
信任链的核心原则:
- 不可逆性:信任只能向前传递,不能回退。一旦某个环节被破坏,后续所有环节都不可信。
- 度量优先:每个环节在获得控制权之前,必须先被前一个环节度量。
- 记录不可篡改:度量结果存储在 TPM 的 PCR 中,只有复位才能清空。
下面这张图,是我在项目中经常用来跟团队解释信任链的。它把整个流程串起来了。
4.2 从BIOS到操作系统的度量启动
度量启动的具体流程,我拆成几个关键步骤来讲。每一步都涉及 TPM 的 PCR 扩展操作。
4.2.1 第一步:CRTM 度量 BIOS
CRTM(Core Root of Trust for Measurement)是信任链的起点。它通常固化在 BIOS 的不可更新区域。CPU 上电后,首先执行 CRTM 代码。CRTM 会计算 BIOS 主固件的哈希值,然后通过 TPM2_PCR_Extend 命令,把哈希值扩展到 PCR[0]。
我的经验:CRTM 代码必须足够小且简单,因为它没法被度量。一旦 CRTM 本身有漏洞,整个信任链就崩塌了。我曾经在一个项目中,发现某厂商的 CRTM 代码居然有 64KB,里面还包含了网络驱动。这明显违背了最小化原则。
4.2.2 第二步:BIOS 度量 Option ROM 和引导加载程序
BIOS 获得控制权后,会继续度量其他固件模块。比如网卡、显卡的 Option ROM,以及磁盘上的引导加载程序(如 GRUB)。这些度量结果会扩展到 PCR[1] 到 PCR[4]。
这里有个细节:BIOS 不仅要度量代码本身,还要度量配置信息。比如启动顺序、安全策略等。因为这些配置一旦被篡改,攻击者就能绕过信任链。我记得有一次,客户反馈说 PCR 值总是不对,查了半天发现是 BIOS 设置里的「快速启动」选项导致的。那个选项会跳过某些度量步骤。
4.2.3 第三步:引导加载程序度量操作系统内核
引导加载程序(如 GRUB)被度量并执行后,它会度量操作系统内核、initramfs 以及关键内核模块。这些结果扩展到 PCR[5] 到 PCR[8]。
GRUB 本身需要支持 TPM 2.0 的度量功能。我建议你在编译 GRUB 时,确认开启了 --with-tpm 选项。否则,它不会调用 TPM 的度量接口。
注意:如果引导加载程序被恶意软件替换,它可能跳过度量步骤,直接加载恶意内核。这就是为什么「安全启动」和「度量启动」需要配合使用。安全启动确保只有签名的引导加载程序才能运行,度量启动则记录所有运行过的组件。
4.2.4 第四步:操作系统度量服务和应用程序
操作系统内核启动后,会继续度量关键系统服务、安全策略以及用户态应用程序。这些度量结果扩展到 PCR[9] 及以上。
在 Linux 下,IMA(Integrity Measurement Architecture)就是干这个的。IMA 会在文件被访问或执行时,计算其哈希值并扩展到 TPM 的 PCR。你可以通过 /sys/kernel/security/ima/ 接口查看当前的度量策略。
下面是一个简单的 IMA 策略示例,它度量所有可执行文件和共享库:
# 启用 IMA 度量
echo "measure func=BPRM_CHECK" > /sys/kernel/security/ima/policy
echo "measure func=FILE_MMAP mask=MAY_EXEC" >> /sys/kernel/security/ima/policy
# 查看当前 PCR 值
cat /sys/class/tpm/tpm0/pcr-sha256/9
4.3 信任链的验证
信任链建立起来后,怎么验证它是否完整?这就需要远程证明(Remote Attestation)了。验证方(比如服务器)向设备发送一个随机数(Nonce),设备用 TPM 的 TPM2_Quote 命令,对指定的 PCR 值进行签名,然后把签名结果返回给验证方。
验证方通过比对 PCR 的预期值,就能判断设备是否被篡改过。这个过程,说白了就是「你报一下你的 PCR,我看看对不对」。
| PCR 索引 | 度量内容 | 典型用途 |
|---|---|---|
| PCR[0] | BIOS 固件代码 | 验证 BIOS 是否被篡改 |
| PCR[1] | BIOS 配置 | 验证 BIOS 设置是否被修改 |
| PCR[2] | Option ROM 代码 | 验证扩展固件是否可信 |
| PCR[3] | Option ROM 配置 | 验证扩展固件配置 |
| PCR[4] | 引导加载程序代码 | 验证 GRUB 等是否被篡改 |
| PCR[5] | 引导加载程序配置 | 验证 GRUB 配置 |
| PCR[6] | 操作系统内核 | 验证内核是否被篡改 |
| PCR[7] | 内核模块 | 验证驱动是否可信 |
| PCR[8] | initramfs | 验证初始文件系统 |
| PCR[9] | IMA 度量 | 验证系统服务和应用程序 |
避坑指南:我曾经遇到一个案例,远程证明总是失败,但本地 PCR 值看起来没问题。后来发现,是 TPM 的时钟不同步导致的。TPM 在签名时会把当前时钟值也包含进去,如果设备时钟跟服务器时钟偏差太大,签名验证就会失败。所以,记得在部署前校准 TPM 的时钟。
嗯,信任链的内容差不多就这些。记住,信任链不是一劳永逸的。每次系统更新、BIOS 升级、配置修改,都会导致 PCR 值变化。你需要重新计算预期值,并更新验证策略。这就是为什么 TPM 的 PCR 是「扩展」而不是「覆盖」——它保留了所有历史度量记录,让你能追溯每一次变化。