BIOS开发笔记 18 – 解析 TPM 在固件启动过程中的作用
1. 概述
本文将深入剖析 EDK2 代码,结合从 PEI 到 DXE 的流程,详细探究 TPM 是如何介入启动过程的。
2. 核心概念
在深入代码之前,简要回顾几个关键术语:
- Measurement: 度量就是对一段代码、配置数据或关键状态进行加密哈希运算(通常使用 SHA-256 算法)。 如果待加载的可执行文件、驱动程序、BIOS 镜像或系统配置文件作为输入,输出则是一个固定长度的哈希值。这个哈希值就像是该组件的“数字指纹”,只要原始文件被修改哪怕一个字节,生成的度量值就会完全不同。
- PCR (Platform Configuration Registers): TPM 内部的寄存器,存储度量值。
- Extend: 将数据“添加”到 PCR 的操作。并不是简单的“写入”,而是通过一种特殊的 Extend 操作进行存储。这种方式确保了度量值是累积且不可逆的。它记录了系统从启动到当前时刻所有加载过的组件序列。一旦链条中某个环节被篡改,后续的所有 PCR 值都会发生偏移,且无法被伪造回原始状态。 计算公式: New_PCR_Value = Hash(Old_PCR_Value || New_Measurement)
- CRTM (Core Root of Trust for Measurement): 它是一段在 CPU 复位后首先执行的代码。它是可信链条的第一环,必须是不可篡改的。它的唯一任务是度量引导过程中的下一个组件。
- SRTM (Static Root of Trust for Measurement): 指从计算机上电复位(Reset)开始,直到操作系统启动为止的整个静态信任链构建过程。运作方式:首先 CRTM 度量 BIOS 部分;接着 BIOS 度量引导加载程序(Bootloader);最后 Bootloader 度量操作系统内核(OS Kernel)。
- Event Log: 存储在系统内存中的日志,记录了每次 Extend 操作的详细信息(什么被度量了,哈希是多少)。OS 读取该日志来验证 PCR 的内容。
3. 深度代码剖析
3.1 PEI 阶段
在 PEI 阶段,主要的驱动是:
SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
它的主要职责是:
- 检测 TPM 硬件。
- 发送 TPM2_Startup 命令:这是 TPM 复位后必须接收的第一个命令。
- 度量固件卷 (FV):保证 BIOS代码本身的完整性。
关键代码逻辑:测量 FV
在 SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c 中,如下函数负责度量 Firmware Volume:
// 伪代码摘要 (基于 Tcg2Pei.c) EFI_STATUS MeasureFvImage (EFI_PHYSICAL_ADDRESS FvBase, UINT64 FvLength) { // 1. 检查该 FV 是否已经被排除 (不需要度量) // 2. 检查该 FV 是否已经度量过 (避免重复) // 3. 准备 Event Header TcgEventHdr.PCRIndex = 0; // PCR 0 通常用于存放 BIOS 代码 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; // 4. 计算 Hash 并 Extend 到 TPM,同时记录日志 // 该函数是核心,它封装了底层的 Tpm2PcrExtend 和 Log 记录 Status = HashLogExtendEvent ( &mEdkiiTcgPpi, 0, // Flags (UINT8 *)(UINTN)FvDataBase, // 代码内容 (UINTN)FvLength, // 代码长度 &TcgEventHdr, EventData ); return Status; }
数据传递:HOB 机制
PEI 运行在 Cache-as-RAM 或有限内存中,它产生的 Event Log 如何传给 DXE?答案是 HOB (Hand-Off Block)。
Tcg2Pei 会创建 GUID HOB (gTcgEventEntryHobGuid 等),将 PEI 阶段产生的所有 Event Log 记录在内存中。
3.2 DXE 阶段
进入 DXE 阶段,SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c 接管工作。它会:
- 消费 HOB:读取 PEI 阶段的 HOB,重建 Event Log。
- 安装协议:安装 EFI_TCG2_PROTOCOL,供后续的 Boot Manager 和 OS Loader 使用。
- 继续度量:度量 Secure Boot 策略、GPT 分区表、加载的 Image 等。
核心函数:HashLogExtendEvent
无论是 PEI 还是 DXE,最核心的操作都是“哈希+扩展+记录”。在 DXE 中,这通常通过 EFI_TCG2_PROTOCOL.HashLogExtendEvent 完成。
// 简化的 HashLogExtendEvent 流程 EFI_STATUS HashLogExtendEvent (...) { // 1. 计算数据 Hash (SHA256, SHA384 等) // 根据系统支持的算法位图 (ActivePcrBanks) 可能会计算多个 Hash // 2. 调用 TPM 硬件命令:TPM2_PCR_Extend Tpm2PcrExtend(PcrIndex, Digests); // 3. 将事件记录到内存中的 Event Log 区域 // 这里的 Log 格式必须严格符合 TCG 规范 (Crypto Agile Log) LogHashEvent(DigestList, NewEventHdr, NewEventData); return EFI_SUCCESS; }
3.3 Image 度量 (PCR 4)
当 UEFI 加载一个 Application 或 Driver (如 OS Loader bootmgfw.efi) 时,DxeCore 会调用 LoadImage,进而触发 MeasurePeImageAndExtend。
这通常将数据度量到 PCR 4 (Boot Manager Code)。
// SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c EFI_STATUS MeasurePeImageAndExtend (...) { // 解析 PE/COFF 头,计算 Image 的 Hash // 注意:这里只 Hash 代码段和数据段,跳过签名字段等 // 扩展到 PCR 4 TcgEvent.PCRIndex = 4; TcgEvent.EventType = EV_EFI_BOOT_SERVICES_APPLICATION; Tcg2Protocol->HashLogExtendEvent(..., &TcgEvent); }
4. 关键 PCR 分配
|
|
|
|
|---|---|---|
| PCR 0 | SRTM, L0 BIOS Code |
|
| PCR 1 | Host Platform Config |
|
| PCR 2 | UEFI Drivers / ROMs |
|
| PCR 3 | Software / Config |
|
| PCR 4 | Boot Manager Code |
|
| PCR 5 | Boot Partition Data |
|
| PCR 7 | Secure Boot Policy |
|
5. 验证机制:如何确信数据是真实的?
如果只是把数据哈希后放入 TPM,而从不进行验证,那么 Measured Boot 毫无意义。
5.1 本地验证 (Sealing / Unsealing)
最典型的应用是 BitLocker。
- 封印 (Seal): 敏感数据(如磁盘解密密钥 )被加密,并与当前的 PCR 状态绑定。例如,绑定到 PCR[7] (Secure Boot state) 和 PCR[11] (BitLocker Control)。
- 解封 (Unseal): 只有当前的 PCR 值与封印时完全一致,TPM 才会释放密钥。
- 原理: 如果有人篡改了 BootLoader,其 Hash 会变化,Extend 后的 PCR 值也会变化,导致 Unseal 失败,系统进入恢复模式。
为什么需要 Event Log?
TPM 中的 PCR 只是一个最终的哈希值(例如 0x3A...2F)。光看这个哈希值,你无法知道究竟是加载了哪个驱动导致 PCR 变了。
Event Log 的作用是“记账”:
- 重放 (Replay): 验证者读取 Event Log,按顺序模拟执行 Extend 操作:CalculatedPCR = Hash(InitValue || Event1 || Event2 ...)。
- 比对: 将 CalculatedPCR 与 TPM 签名的 QuotedPCR 比对。
- 如果一致: 说明 Event Log 没有被篡改,验证者可以信任 Log 中的每一条记录(例如“加载了驱动 A,版本 1.0”)。
- 如果不一致: 说明 Log 是伪造的,或者 TPM 状态异常,拒绝信任。
这也是为什么在 EDK2 中,Tcg2Dxe 花了很大力气维护 EFI_TCG2_PROTOCOL.GetEventLog 的原因。
6. 总结
TPM 在固件启动中不仅仅是一个被动的安全芯片,它是一个贯穿始终的“审计员”。
- 一致性:从 Reset 向量开始,每一行执行的代码都被“记录在案”。
- 链式信任:PEI 信任 SEC,DXE 信任 PEI,OS 信任 UEFI。这个信任链通过 PCR 的连续 Extend 操作得以把守。
- 验证闭环:通过封印(本地)或引用(远程),将 PCR 的哈希值转化为对系统状态的实质性保护。
版权声明:
作者:bin
链接:https://ay123.net/mystudy/bios/1917/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论