度量启动:从BIOS到可信链的建立

度量启动(Measured Boot)这个概念,我第一次认真研究是在一个金融客户的项目里。当时他们要求服务器启动时必须能证明「我没有被篡改过」。安全启动(Secure Boot)只能保证启动代码签名有效,但签名有效不代表代码没被改过——嗯,这里有个微妙的区别。

说白了,度量启动干的事就是:把启动过程中每个组件的哈希值记下来,存到日志里,再扩展到TPM的PCR寄存器。这样远程验证方就能拿到一份「启动过程的完整体检报告」。

核心思想:度量启动不阻止恶意代码运行,但它确保任何篡改都会被记录在案。你改得了代码,改不了PCR里的哈希值。

BIOS/UEFI启动度量流程

我习惯把度量启动分成三个阶段来看:

  1. 前BIOS阶段:CPU微码、启动ROM的度量
  2. BIOS/UEFI阶段:固件、驱动、Option ROM的度量
  3. OS Loader阶段:引导加载程序、内核的度量

每个阶段都会调用TPM的TPM2_PCR_Extend命令,把当前组件的哈希值「扩展」到PCR里。扩展操作不是简单的覆盖,而是:

PCR新值 = SHA256(PCR旧值 || 新组件的哈希值)

这个设计很巧妙。你没法回滚PCR值,也没法伪造一个合法的扩展链。我在调试一个国产服务器时遇到过一个问题——BIOS度量顺序和规范不一致,导致远程验证总是失败。查了两天才发现是固件厂商把某个Option ROM的度量顺序搞反了。

度量日志(Event Log)

PCR只存了最终的哈希链,但没存「谁度量了谁」的详细信息。度量日志就是补这个缺的。

日志格式遵循TCG规范,每个事件记录包含:

字段 说明 长度
PCRIndex 扩展到了哪个PCR寄存器 4字节
EventType 事件类型(如EV_EFI_BOOT_SERVICES_APPLICATION) 4字节
Digest 该组件的哈希值 20/32/48字节
EventData 组件名称、版本、签名信息等 可变

你想想看,远程验证时,验证方会做两件事:

  • 重放日志中的每个事件,计算PCR值是否匹配
  • 检查每个组件的哈希值是否在白名单中

如果日志被篡改,重放计算出的PCR值就和TPM报告的PCR值对不上。这就是度量启动的防篡改机制。

实战技巧:在Linux下可以用tpm2_eventlog命令查看度量日志。我建议你抓一份真实日志看看,比读十遍规范都管用。

与安全启动(Secure Boot)的区别

很多初学者会把这两个概念搞混。我做个对比表,你一看就明白:

维度 安全启动(Secure Boot) 度量启动(Measured Boot)
目标 阻止未签名代码运行 记录所有运行过的代码
机制 签名验证,拒绝未授权代码 哈希扩展,记录到PCR
阻断能力 能阻断启动 不阻断,只记录
依赖硬件 UEFI固件 TPM芯片
远程验证 无法直接远程验证 通过PCR引用进行远程验证
篡改后果 启动失败 PCR值与日志不匹配

我曾经在一个项目里看到有人只配了安全启动,没开度量启动。结果设备被攻破后,攻击者直接替换了合法的签名证书——安全启动照样通过,但系统已经被完全控制了。如果开了度量启动,PCR值的变化会立刻暴露问题。

重要提醒:安全启动和度量启动是互补关系,不是替代关系。最佳实践是两者都开。安全启动负责「防」,度量启动负责「记」。

度量启动的完整流程

下面这张图展示了从BIOS到OS Loader的完整度量链:

度量启动完整流程 度量启动(Measured Boot)完整流程 BIOS/UEFI固件 度量固件组件 PCR[0-7] Option ROM/驱动 度量Option ROM PCR[2-4] Boot Loader 度量Boot Loader PCR[4] OS Kernel 度量内核模块 PCR[5-7] 度量日志(Event Log):记录每个组件的名称、哈希值、扩展时间 验证方重放日志 → 计算预期PCR值 → 与TPM报告的PCR值比对 → 一致则可信 任何篡改都会导致PCR值不匹配,远程验证立刻发现

PCR寄存器的分配规则

TCG规范定义了PCR的用途。我挑几个关键的说说:

  • PCR[0]:BIOS/UEFI固件代码
  • PCR[1]:BIOS/UEFI配置数据
  • PCR[2]:Option ROM代码
  • PCR[3]:Option ROM配置数据
  • PCR[4]:MBR/引导加载程序
  • PCR[5]:GPT分区表
  • PCR[6]:状态转换和唤醒事件
  • PCR[7]:安全启动策略

我记得有一次排查问题,发现PCR[7]的值和预期不符。查了半天,原来是安全启动的DBX(吊销签名数据库)更新了,但度量日志里没体现。这提醒了我:度量日志和PCR必须一一对应,缺一个都不行。

调试技巧:用tpm2_pcrread可以实时查看PCR值。我习惯在设备启动前后各抓一次,对比变化。如果某个PCR值没变,说明对应的组件可能没被度量——这是个危险信号。

远程验证中的度量启动

在远程证明场景里,度量启动的价值就体现出来了。验证方拿到设备发来的度量日志和PCR引用后,会做三步检查:

  1. PCR值验证:重放日志,计算预期PCR值,比对TPM报告的PCR引用
  2. 组件白名单:检查每个组件的哈希值是否在已知的可信列表中
  3. 启动链完整性:确认度量顺序符合规范,没有跳过的步骤

这三步只要有一项不通过,设备就被判定为不可信。我在做金融项目时,客户要求每15分钟做一次远程验证。一开始觉得频率太高,后来发现确实有必要——攻击者可能在两次验证之间篡改系统。

避坑指南:我曾经遇到一个案例,设备度量日志完整,PCR值也匹配,但远程验证就是失败。最后发现是TPM固件版本太老,PCR引用算法和验证方不兼容。所以,TPM固件版本和验证方的算法套件必须对齐。

度量启动不是银弹,但它提供了启动过程的可信证据。配合安全启动和远程验证,就能构建一条从硬件到应用的完整可信链。嗯,这就是为什么我在所有涉及可信计算的方案里,都会把度量启动作为必选项。