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 值。

流程是这样的:

  1. TPM 内部生成一对 AIK(公私钥)。
  2. TPM 用 EK 私钥对 AIK 公钥签名,生成 AIK 证书请求。
  3. Privacy CA(隐私证书颁发机构)验证 EK 证书有效后,签发 AIK 证书。
  4. 远程证明时,平台用 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 串起来,看看远程证明的完整流程:

TPM 远程证明核心组件协作图 TPM 远程证明核心组件协作流程 PCR 寄存器 存储固件测量值 EK(背书密钥) 平台唯一身份 AIK(认证身份密钥) 隐私保护签名 步骤1:系统启动,固件测量值依次扩展到 PCR 步骤2:TPM 生成 AIK,EK 为 AIK 签发证书 步骤3:验证方发送挑战随机数,平台用 AIK 签名 PCR 值 步骤4:验证方校验 AIK 证书、签名、PCR 预期值 关键点:EK 只用于证明 AIK 的合法性,不直接参与远程证明签名 PCR 值由 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 预期值数据库。只有这样,才能构建真正可信的证明体系。