4、TPM 2.0 实战:PCR、EK 与 AIK 详解
好,咱们进入 TPM 2.0 的实战环节。前几章讲了远程证明的逻辑,现在得落地到硬件上了。TPM 芯片里最核心的三个东西——PCR 寄存器、EK(背书密钥)和 AIK(认证身份密钥),我一个个拆开讲。
说实话,我刚接触 TPM 时也被这些缩写搞晕过。后来亲手配过几台服务器,踩过坑,才算真正理解它们各自扮演的角色。你想想看,没有 PCR,你拿什么证明固件没被改过?没有 EK,平台身份怎么确立?没有 AIK,隐私又怎么保护?
4.1 PCR 寄存器:固件完整性的“黑匣子”
PCR 的全称是 Platform Configuration Register,平台配置寄存器。说白了,它就是 TPM 内部一组只能扩展(extend)不能直接写入的寄存器。
核心特性:
- 只可扩展,不可重置(特定情况下除外):每次写入新值,TPM 会把旧值与新值做哈希运算,结果再存回去。公式是:
PCR[n] = SHA256(PCR[n] || new_measurement)。 - 启动时清零:系统冷启动后,大部分 PCR 会复位到初始值(全 0 或全 1,取决于实现)。
- 不同 PCR 索引有不同用途:TPM 2.0 规范定义了 PCR 的用途,比如 PCR 0 存 BIOS 代码,PCR 1 存主板配置,PCR 7 存安全启动策略。
关键理解:PCR 的值是一个哈希链。你无法从最终值反推出中间测量了哪些组件,但你可以通过重放测量序列来验证当前值是否正确。这就是远程证明中“预期值”的来源。
我在项目中遇到过一个问题:某款服务器在更新 BIOS 后,远程证明总是失败。排查了半天,发现是 PCR 0 的预期值没更新。你看,PCR 就是这么敏感——任何固件改动都会反映在它的值里。
4.1.1 PCR 扩展流程示例
假设我们要测量 BIOS 代码和 Boot Loader:
// 伪代码:PCR 扩展过程
// 初始状态:PCR[0] = 0x0000...0000
// 步骤1:测量 BIOS 代码
bios_hash = SHA256(BIOS_ROM_CONTENT)
TPM_PCR_Extend(0, bios_hash)
// 此时 PCR[0] = SHA256(0x0000...0000 || bios_hash)
// 步骤2:测量 Boot Loader
bootloader_hash = SHA256(BOOT_LOADER_BINARY)
TPM_PCR_Extend(0, bootloader_hash)
// 此时 PCR[0] = SHA256(previous_pcr_value || bootloader_hash)
// 最终 PCR[0] 的值唯一确定了 BIOS + Boot Loader 的完整组合
嗯,这里要注意:扩展顺序至关重要。同样的组件,顺序不同,最终 PCR 值也不同。所以验证方必须知道确切的启动顺序。
4.2 EK(背书密钥):TPM 的“身份证”
EK 是 Endorsement Key 的缩写。它是 TPM 芯片出厂时烧录的一对非对称密钥(通常是 RSA-2048 或 ECC),私钥永远不出 TPM,公钥由芯片制造商签发证书。
EK 的特点:
- 唯一性:每个 TPM 芯片有唯一的 EK,就像人的身份证号。
- 不可变:EK 在 TPM 生命周期内不会改变,除非芯片被销毁。
- 隐私风险:正因为唯一且不变,如果直接使用 EK 做身份认证,所有操作都可被追踪。这就是为什么需要 AIK。
| 属性 | EK | AIK |
|---|---|---|
| 生成方式 | 出厂预置,不可更改 | 运行时生成,可随时创建 |
| 私钥存储 | TPM 内部,不可导出 | TPM 内部,不可导出 |
| 用途 | 证明 TPM 身份,签发 AIK 证书 | 签名 PCR 值,用于远程证明 |
| 隐私保护 | 差(唯一标识设备) | 好(可频繁更换) |
| 证书签发者 | TPM 制造商(如 Infineon、Nuvoton) | 隐私 CA(Privacy CA) |
重要提醒:EK 私钥绝对不能离开 TPM。我曾经见过一个方案,试图把 EK 私钥导出到文件系统做备份——这是严重的安全设计错误。一旦 EK 私钥泄露,整个 TPM 的身份就不可信了。
4.3 AIK(认证身份密钥):隐私保护的“马甲”
AIK 是 Attestation Identity Key 的缩写。它的作用是用 EK 做“担保”,生成一批临时身份密钥,专门用于签名 PCR 值。
流程是这样的:
- TPM 内部生成一对 AIK(公私钥)。
- TPM 用 EK 私钥对 AIK 公钥签名,生成 AIK 证书请求。
- Privacy CA(隐私证书颁发机构)验证 EK 证书有效后,签发 AIK 证书。
- 远程证明时,平台用 AIK 私钥签名 PCR 值,验证方用 AIK 公钥验证签名。
说白了,EK 是“户口本”,AIK 是“临时身份证”。你拿户口本去办身份证,之后出门办事都用身份证,没人知道你的户口本号码。这样既证明了你是合法公民,又保护了隐私。
4.3.1 AIK 生成与使用示例
// 步骤1:在 TPM 内部生成 AIK 密钥对
TPM2_Create(
parentHandle = TPM_RH_ENDORSEMENT, // 以 EK 为父密钥
inPublic = AIK_TEMPLATE, // 指定 AIK 属性
outPrivate = &aik_private,
outPublic = &aik_public
);
// 步骤2:用 EK 证明 AIK 的合法性
TPM2_Certify(
objectHandle = aik_handle,
signHandle = ek_handle, // 用 EK 签名
qualifyingData = nonce,
certifiedInfo = &aik_cert_info,
signature = &aik_signature
);
// 步骤3:远程证明时,用 AIK 签名 PCR 值
TPM2_Quote(
signHandle = aik_handle,
pcrSelect = {0, 1, 2, 3, 7}, // 选择要签名的 PCR
qualifyingData = challenge_nonce,
quoted = &pcr_quote,
signature = "e_signature
);
实战建议:我个人习惯为每个证明会话生成新的 AIK。虽然 TPM 可以保存多个 AIK,但每次用新的 AIK 可以避免长期关联。Privacy CA 的部署是关键——如果企业内部没有 Privacy CA,可以考虑用 DAA(Direct Anonymous Attestation)方案替代。
4.4 三者的协作关系
现在我们把 PCR、EK、AIK 串起来,看看远程证明的完整流程:
你看这个流程,每个组件各司其职。PCR 负责记录“发生了什么”,EK 负责证明“我是谁”,AIK 负责“我代表谁说话”。三者缺一不可。
4.5 实战中的常见问题
我整理了几个实际部署中容易踩的坑:
- PCR 选择不当:有些方案只选了 PCR 0-3,忽略了 PCR 7(安全启动策略)。结果攻击者改了安全启动策略,PCR 值却没变——证明形同虚设。
- EK 证书验证缺失:AIK 证书链必须追溯到受信任的根 CA。我见过一个系统直接信任了自签名的 AIK 证书——那跟没验证一样。
- Nonce 重用:远程证明的挑战随机数(nonce)必须每次不同。如果 nonce 可预测,攻击者可以重放旧的签名响应。
- PCR 预期值管理:固件更新后,PCR 预期值必须同步更新。我建议用自动化工具链管理预期值数据库,避免手动维护出错。
核心原则:远程证明不是一次性的。每次证明都应该使用新的 nonce、新的 AIK(或至少是新的签名会话),并且验证方必须维护最新的 PCR 预期值数据库。只有这样,才能构建真正可信的证明体系。