2. 度量架构设计:PCR寄存器详解、度量事件日志格式、度量代理架构
度量架构,说白了就是固件信任链的“记账本”和“审计员”。
我刚开始接触TPM时,总觉得PCR就是个计数器。后来踩了坑才明白——PCR的设计直接决定了度量结果能不能被信任。这一章,咱们就把PCR寄存器、事件日志和度量代理这三个核心组件拆开揉碎了讲。
2.1 PCR寄存器:信任链的“指纹锁”
PCR(Platform Configuration Register)是TPM内部的一组寄存器。它的特殊之处在于:只能扩展,不能直接写。
核心公式:
PCR新值 = SHA256( PCR旧值 || 新度量值 )
这意味着:你永远无法从PCR当前值反推出历史度量数据。这就是“单向哈希链”的威力。
TPM 2.0规范定义了至少24个PCR,每个都有特定用途。我整理了一张常用PCR分配表:
| PCR索引 | 用途 | 度量内容 |
|---|---|---|
| 0 | BIOS/固件代码 | BIOS ROM、微码补丁 |
| 1 | 主机平台配置 | 主板型号、芯片组配置 |
| 2 | Option ROM代码 | 显卡、网卡等扩展ROM |
| 3 | Option ROM配置 | 扩展卡的配置数据 |
| 4 | MBR/VBR代码 | 主引导记录、卷引导记录 |
| 5 | MBR/VBR配置 | 引导分区表、启动配置 |
| 6 | 状态转换 | 平台休眠/唤醒状态 |
| 7 | 安全策略 | Secure Boot策略、DBX |
| 8-15 | 操作系统使用 | OS Loader、内核、驱动 |
我的经验:实际排查时,PCR 0和PCR 7是最常出问题的。有一次客户说系统启动总报度量失败,我一看PCR 0的值跟预期对不上——结果是BIOS升级后微码变了,但白名单没更新。这种坑,你排查时一定要先确认固件版本。
2.2 度量事件日志:PCR的“解释器”
PCR本身只存哈希值,不存度量过程。那你怎么知道某个PCR值是怎么算出来的?
答案就是:度量事件日志(Event Log)。
事件日志记录了每一次度量操作的详细信息。TPM 2.0的事件日志格式遵循TCG EFI平台规范,每个事件条目包含:
- PCR索引:这次度量扩展到了哪个PCR
- 事件类型:比如EV_EFI_BOOT_SERVICES_APPLICATION
- 度量值:实际扩展的哈希值
- 事件数据:被度量对象的原始信息(比如文件的GUID、路径)
- 数字签名:可选,用于验证日志完整性
我习惯把事件日志比作“审计底稿”。PCR是最终结论,事件日志就是得出这个结论的每一步计算过程。没有日志,你根本没法排查度量问题。
注意:事件日志存储在内存中,系统重启就没了。如果你需要事后分析,必须在启动阶段就把日志抓出来保存。我曾经因为没及时保存日志,排查一个启动漏洞时只能靠猜——那感觉,别提多难受了。
下面是一个简化的事件日志条目示例:
PCR Index: 4
Event Type: EV_EFI_BOOT_SERVICES_APPLICATION
Digest: 0xA1B2C3D4E5F6...
Event Data:
- Image GUID: 12345678-1234-1234-1234-123456789ABC
- Image Path: \EFI\Microsoft\Boot\bootmgfw.efi
- Image Size: 0x123456
- Load Address: 0x7C00000
2.3 度量代理架构:谁来做度量?
PCR和事件日志是“数据”,那“谁”来执行度量操作?
答案是:度量代理(Measurement Agent)。
在UEFI固件中,度量代理通常是一个DXE驱动或SMM模块。它的工作流程是这样的:
- 拦截加载事件:当UEFI引导管理器要加载某个镜像时,度量代理先截获
- 计算哈希:对镜像内容做SHA256/SHA384
- 扩展PCR:把哈希值扩展到对应的PCR
- 记录日志:把这次度量事件写入Event Log
- 放行执行:允许镜像继续加载
度量代理的架构设计,直接决定了整个信任链的安全性。我画了一张架构图,帮你理解各组件的关系:
2.4 度量代理的三种实现模式
在实际项目中,度量代理的实现方式主要有三种。我根据经验做了个对比:
| 模式 | 实现位置 | 优点 | 缺点 |
|---|---|---|---|
| DXE驱动模式 | UEFI DXE阶段 | 开发简单,调试方便 | 容易被绕过(SMM更安全) |
| SMM模式 | 系统管理模式 | 权限高,难以绕过 | 性能开销大,开发复杂 |
| 混合模式 | DXE + SMM | 兼顾性能和安全性 | 架构复杂,调试困难 |
我建议:如果你的产品对安全等级要求高(比如服务器、金融终端),优先考虑SMM模式。虽然开发周期会长一些,但安全收益是值得的。我之前做过一个项目,客户坚持用DXE模式,结果被攻击者用SMM漏洞绕过了度量——嗯,后来他们还是改成了混合模式。
2.5 度量代理的常见漏洞
度量代理本身也可能有漏洞。我总结了几类常见问题:
- TOCTOU漏洞:度量时和加载时的镜像内容不一致。攻击者可以在度量完成后、加载前篡改镜像
- 日志伪造:事件日志没有签名保护,攻击者可以篡改日志内容
- PCR扩展遗漏:某些加载事件没有被度量代理拦截,导致PCR值不完整
- 哈希算法降级:攻击者诱导度量代理使用弱哈希算法(比如SHA1)
避坑指南:我曾经排查过一个案例,度量代理在计算哈希时只读了镜像的前4KB。攻击者把恶意代码藏在镜像后面,度量结果看起来是合法的,但实际执行的是恶意代码。所以,度量一定要覆盖整个镜像,别偷懒。
2.6 实战:如何验证度量代理是否正常工作
排查度量问题时,我一般按这个步骤来:
- 抓取事件日志:在启动阶段用工具(比如Linux的tpm2_eventlog)导出日志
- 解析日志条目:检查每个事件的PCR索引、度量值是否合理
- 重放度量过程:用同样的镜像和算法重新计算哈希,对比PCR值
- 验证日志完整性:如果日志有签名,验证签名是否有效
- 检查覆盖范围:确认所有关键组件(Bootloader、OS Loader、内核)都被度量
举个例子,如果你发现PCR 4的值跟预期不符,可以这样排查:
# 导出事件日志
tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements > eventlog.txt
# 查找PCR 4相关事件
grep "PCR: 4" eventlog.txt
# 重算哈希
sha256sum /EFI/Microsoft/Boot/bootmgfw.efi
# 对比PCR值
tpm2_pcrread sha256:4
如果重算的哈希跟日志里记录的不一致,那问题就出在度量代理本身——它可能没读到正确的镜像内容。
度量架构设计,说白了就是三个问题:度量什么?怎么度量?谁来度量?PCR解决了“度量什么”,事件日志解决了“怎么度量”,度量代理解决了“谁来度量”。这三者缺一不可,任何一个环节出问题,整个信任链就断了。