4、度量与报告机制:PCR、度量启动与远程证明报告
好,咱们进入第四章。这一章讲的是整个远程证明的“地基”——度量与报告。说白了,就是你的设备怎么证明自己“没被改过”。
我见过不少团队,把精力全花在签名算法和证书链上,结果底层度量一塌糊涂。你想想看,上层做得再花哨,底层 PCR 值对不上,那证明就是废纸一张。
4.1 平台配置寄存器(PCR)——信任的“账本”
PCR 是什么?它是 TPM 芯片里的一组寄存器。你不能直接往里面写数据,只能“扩展”。
扩展操作是这样的:PCR[n] = SHA256( PCR[n]旧值 || 新度量值 )。
这个设计很巧妙。你没法回退,也没法预测最终值。只有严格按照顺序度量,才能得到预期的 PCR 值。
核心要点:PCR 的不可逆性,是信任链的根基。一旦某个环节被篡改,PCR 值就会“跑偏”,远程证明方一眼就能看出来。
4.1.1 PCR 的典型分配
TCG 规范定义了 PCR 的用途。我整理了一张表,这是最常用的几个:
| PCR 索引 | 度量内容 | 典型用途 |
|---|---|---|
| PCR 0 | BIOS/固件代码 | 验证 BIOS 是否被篡改 |
| PCR 1 | 主板配置 | 检测硬件配置变化 |
| PCR 2 | Option ROM 代码 | 验证扩展卡固件 |
| PCR 3 | Option ROM 配置 | 检测扩展卡配置 |
| PCR 4 | MBR / 引导加载程序 | 验证 Bootloader 完整性 |
| PCR 5 | MBR 配置 / GPT | 检测分区表篡改 |
| PCR 6 | 状态转换 / 唤醒 | 检测休眠恢复状态 |
| PCR 7 | 安全策略 | 验证 Secure Boot 策略 |
| PCR 8-15 | 操作系统组件 | 度量内核、驱动、关键文件 |
我的习惯:在项目中,我通常会把 PCR 0-7 作为“硬件信任根”的度量范围,PCR 8-15 留给操作系统。这样分层清晰,出了问题也好排查。
4.2 度量启动(Measured Boot)——信任链的传递
度量启动,不是 Secure Boot。Secure Boot 是“验签,过就启动,不过就停”。度量启动是“度量,记录到 PCR,然后继续启动”。
它不阻止你启动,它只负责记账。启动完了,PCR 里就记下了一笔完整的“启动流水账”。
我遇到过有人问:“那度量启动有什么用?又不能阻止恶意代码。” 嗯,这里要注意:度量启动的价值在于“事后审计”。你把 PCR 值发给远程证明服务器,服务器一比对,就知道你的启动链有没有被动过。
4.2.1 度量启动的流程
流程其实不复杂,我画了张图,你看一眼就明白了:
你看,从 BIOS 开始,一级度量一级,每一级都把度量值扩展到 PCR。最终 PCR 里就存了整条链的“指纹”。
4.2.2 代码示例:度量一个文件并扩展 PCR
在 Linux 下,你可以用 tpm2-tools 来模拟这个过程。我写个简单的例子:
# 1. 计算文件的哈希值
sha256_hash=$(sha256sum /boot/vmlinuz-* | awk '{print $1}')
# 2. 将哈希值转换为二进制格式
echo $sha256_hash | xxd -r -p > /tmp/kernel_hash.bin
# 3. 读取当前 PCR 8 的值
tpm2_pcrread sha256:8 > /tmp/pcr8_before.bin
# 4. 扩展 PCR 8(模拟度量启动的扩展操作)
tpm2_pcrextend 8:sha256=/tmp/kernel_hash.bin
# 5. 验证扩展后的 PCR 8 值
tpm2_pcrread sha256:8
我曾经踩过的坑:扩展 PCR 时,一定要确保输入的哈希值格式正确。有一次我忘了做 xxd -r -p 转换,直接把 ASCII 字符串扩展进去了,结果 PCR 值完全不对。排查了半天才发现是格式问题。
4.3 远程证明报告生成——把证据打包好
度量完了,PCR 值也有了,接下来就是生成报告。报告不是直接把 PCR 值扔过去,那样太容易被中间人篡改。
标准的做法是:TPM 用 Attestation Identity Key (AIK) 对 PCR 值签名,生成一个 TPMS_ATTEST 结构。这个结构包含了 PCR 值、时间戳、随机数(nonce)等信息。
4.3.1 报告生成流程
- 挑战:验证方生成一个随机数 nonce,发给设备。
- 引用:设备调用 TPM2_Quote 命令,传入 nonce 和要引用的 PCR 索引。
- 签名:TPM 用 AIK 私钥对 PCR 值 + nonce 签名,生成 TPMS_ATTEST。
- 打包:设备把 TPMS_ATTEST、AIK 证书、PCR 日志一起发给验证方。
我建议你在设计时,把 nonce 的生成和校验放在业务层。这样即使 TPM 固件有漏洞,nonce 还能提供一层保护。
4.3.2 代码示例:生成引用报告
# 1. 验证方生成 nonce(这里用随机数模拟)
nonce=$(openssl rand -hex 16)
# 2. 设备端:引用 PCR 8-15,并用 AIK 签名
tpm2_quote \
--key-context 0x81000000 \ # AIK 密钥句柄
--pcr-list sha256:8,9,10,11,12,13,14,15 \
--message /tmp/quote.msg \
--signature /tmp/quote.sig \
--qualification $nonce
# 3. 查看引用消息内容
tpm2_print -t TPMS_ATTEST /tmp/quote.msg
关键点:验证方收到报告后,会做三件事:
- 用 AIK 公钥验证签名
- 检查 nonce 是否匹配
- 比对 PCR 值是否与预期一致
三步缺一不可。我见过只验签名不验 nonce 的设计,结果被重放攻击打穿了。
4.4 实战中的常见问题
嗯,这里我总结几个实际项目中容易出问题的地方:
- PCR 值漂移:固件升级后,PCR 值会变。你需要同步更新验证方的“预期值”数据库。
- AIK 证书管理:AIK 证书过期了怎么办?我建议用短生命周期证书,配合自动续期。
- 日志完整性:PCR 日志(Event Log)要和 PCR 值一起验证。日志被篡改,PCR 值对不上,证明就失败。
我的经验:在量产阶段,我会把 PCR 预期值固化在验证方的配置中心。每次固件发布,同步更新配置。这样既保证了安全性,又避免了线上事故。
好了,这一章的内容就到这里。度量与报告是远程证明的“硬功夫”,PCR 是账本,度量启动是记账过程,报告生成是把账本拿出来给人看。三者环环相扣,缺一不可。