可信平台模块 (TPM)
可信平台模块 (TPM) 是一项国际标准,用于安全加密处理器,它是一个专用的微处理器,通过将加密密钥集成到设备中来保护硬件。
实际上,TPM 可用于各种不同的安全应用,例如 安全启动、密钥存储和 随机数生成。
TPM 自然只能在支持 TPM 硬件的设备上运行。如果您的硬件支持 TPM 但未显示出来,可能需要在 BIOS 设置中启用它。
检查 TPM 支持
大多数现代计算机都支持 TPM 2.0,因为它自 2016 年以来已被 要求用于 Windows 10 认证。要检查您系统上的支持情况,请使用以下任何方法:
- 检查日志,例如,通过以 root 身份运行
journalctl -k --grep=tpm。 - 读取
/sys/class/tpm/tpm0/device/description[1]、/sys/class/tpm/tpm0/device/firmware_node/description或/sys/class/tpm/tpm0/tpm_version_major的值。
$ cat /sys/class/tpm/tpm0/device/description TPM 2.0 Device
- 使用 systemd-analyze(1) 检查 TPM 2.0 和所需的软件依赖项。
$ systemd-analyze has-tpm2
TPM 2.0 允许直接通过 /dev/tpm0 (一次一个客户端) 访问,通过 /dev/tpmrm0 进行内核管理访问,或者通过 tpm2-abrmd 资源管理器守护进程进行管理访问。 根据 systemd 项目成员的说法,已不再推荐使用 tpm2-abrmd。用户空间工具方面有两种选择,Intel 的 tpm2-tools 和 IBM 的 ibm-tssAUR。
TPM 2.0 需要 UEFI 启动;BIOS 或传统启动系统只能使用 TPM 1.2。
一些 TPM 芯片可以通过固件升级在 2.0 和 1.2 之间切换 (此操作只能进行有限次数)。
用法
可以在 tpm2-software 社区中找到许多信息资源,以了解如何在日常应用程序中配置和使用 TPM 2.0 服务。
LUKS 加密
可以使用安全存储在 TPM 中的密钥来加密卷。这种方法可确保您的驱动器在 TPM 不存在且特定条件(例如固件的完整性或 安全启动状态)不满足时保持锁定状态(请参阅 #访问 PCR 寄存器)。
此机制可用于在启动过程中自动解密根卷,类似于 Windows 上的 BitLocker 或 macOS 上的 FileVault。虽然这为将驱动器从带 TPM 的计算机上移除提供了强大的保护,但如果整个 PC 被盗,数据保护将仅依赖于基本措施,如用户密码和系统设置。为了缓解这种情况,您可以:
- 考虑使用其他机制加密用户数据,例如单个主目录,例如 fscrypt 或 systemd-homed。
- 使用 TPM PIN 来利用 TPM 的安全属性,同时避免完全无人值守解锁。
systemd-cryptenroll 和 Clevis 允许使用存储在 TPM 中的密钥来锁定 LUKS 卷。此外,systemd-cryptenroll 支持将加密绑定到签名策略,而不是静态 PCR 值(请参阅 systemd-cryptenroll(1))。
SSH
对于 TPM 密封的 SSH 密钥,有两种选择:
- ssh-tpm-agent — 兼容 ssh-agent 的代理,使用 TPM 后备密钥。
- https://github.com/Foxboron/ssh-tpm-agent || ssh-tpm-agent
- 请参阅 Store ssh keys inside the TPM: ssh-tpm-agent。
- tpm2-pkcs11 — 用于可信平台模块 2.0 硬件的 PKCS#11 接口。
- https://github.com/tpm2-software/tpm2-pkcs11 || tpm2-pkcs11
- 请参阅 SSH configuration 和 Using a TPM for SSH authentication (2020-01)。
systemd-creds
systemd-creds 使用 TPM 安全地存储和检索 systemd 单元使用的凭据。
GnuPG
GnuPG 从 2.3 版本开始支持将兼容的密钥移至 TPM。有关说明,请参阅 Using a TPM with GnuPG 2.3。
OpenSSL
有实现将密钥存储在 TPM 中的 OpenSSL provider 和 OpenSSL 引擎。
- tpm2-openssl — TPM2 集成的 OpenSSL Provider。
- tpm2-tss-engine — TPM2 设备的 OpenSSL 引擎。
- https://github.com/tpm2-software/tpm2-tss-engine || tpm2-tss-engine
- 请参阅 Using the TPM - It's Not Rocket Science (Anymore) - Johannes Holland & Peter Huewe (2020-11, Youtube)
TPM 2.0 使用的其他优秀示例
- Configuring Secure Boot + TPM 2 (2018-06, Debian)
访问 PCR 寄存器
平台配置寄存器 (PCR) 允许通过哈希值将密钥的加密绑定到特定的软件版本和系统状态,这样,只有在使用特定的受信任软件和/或配置时,才能访问(可能“解封”)已注册的密钥。
PCR 用于平台硬件和软件在启动之间的完整性验证(例如,防止 “邪恶女仆攻击”)。
《TCG PC Client Specific Platform Firmware Profile Specification》定义了使用的寄存器,而《The Linux TPM PCR Registry》则分配了使用它们的 Linux 系统组件。
寄存器是:
| PCR | 描述 | 由...扩展 |
|---|---|---|
| PCR0 | 核心系统固件可执行代码(又称固件)。如果升级 UEFI,它可能会改变。 | 固件 |
| PCR1 | 核心系统固件数据(又称 UEFI 设置;例如,已配置的启动顺序) | 固件 |
| PCR2 | 扩展或可插入的可执行代码(又称 OpROMs) | 固件 |
| PCR3 | 扩展或可插入的固件数据。在启动设备选择 UEFI 启动阶段设置。 | 固件 |
| PCR4 | 启动管理器代码和启动尝试。测量启动管理器和固件尝试启动的设备。 | 固件 |
| PCR5 | 启动管理器配置和数据。可以测量引导加载程序的配置;包括 GPT 分区表。 | 固件 |
| PCR6 | 从 S4 和 S5 电源状态事件恢复 | 固件 |
| PCR7 | 安全启动状态。包含 PK/KEK/db 的全部内容,以及用于验证每个启动应用程序的特定证书[2] | 固件,shim (添加 MokList, MokListX 和 MokSBState) |
| PCR81 | 内核命令行哈希 | GRUB |
| PCR91 | initramfs 和 EFI 加载选项的哈希 | Linux (测量 initramfs 和 EFI 加载选项,本质上是内核命令行选项) |
| PCR101 | 预留给未来使用 | |
| PCR111 | 统一内核镜像的哈希 | systemd-stub(7) |
| PCR121 | 已覆盖的内核命令行、凭据 | systemd-stub(7) |
| PCR131 | 系统扩展 | systemd-stub(7) |
| PCR141 | shim 的 MokList, MokListX 和 MokSBState。[3] | shim |
| PCR151 | LUKS 卷密钥的哈希 | systemd-cryptsetup |
| PCR161 | 调试。可以随时使用和重置。可能未包含在官方固件版本中。 | |
| PCR23 | 应用程序支持。操作系统可以设置和重置此 PCR。 |
- 由操作系统定义的用例,可能因不同的 Linux 发行版和 Windows 设备而异。
在 Windows 上,BitLocker 使用 PCR8-11(传统)或 PCR11-14(UEFI)来实现其自身目的。来自 tianocore 的文档[4]。
tpm2-totp 可帮助用户和专用可信设备进行此检查。
当前 PCR 值可以使用 systemd-analyze(1) 列出。
$ systemd-analyze pcrs
或者,也可以使用 tpm2_pcrread(1) (来自 tpm2-tools)。
# tpm2_pcrread
PCR 策略
使用 TPM2,可以将密钥(例如 LUKS 根解密密钥)绑定到签名策略,而不是原始 PCR 值。这些策略通过允许 PCR 值变化来增加灵活性,前提是这些值有一个有效的 PCR 签名,该签名与已注册密钥的公钥匹配。例如,与其简单地将加密密钥绑定到 PCR7 值(仅检查安全启动未被禁用或篡改),不如将其绑定到 PCR 策略,该策略验证启动一个已知的 统一内核镜像 (UKI),并在启动过程中测量其所有组件。请参阅 systemd-cryptenroll(1) § TPM2_PCRs_and_policies。
下面的示例允许在启动过程中(即在 initramfs 阶段)解密根分区,而加密密钥在系统完全启动后不可访问。有关不同启动阶段的多个信任策略的示例,请参阅 ukify(1)。
首先生成必要的签名密钥
# ukify genkey \
--pcr-private-key=/etc/systemd/tpm2-pcr-private-key.pem \
--pcr-public-key=/etc/systemd/tpm2-pcr-public-key.pem
/etc/systemd/tpm2-pcr-public-key.pem 是默认路径,如果存在,systemd-cryptenroll 会自动识别该文件。创建 /etc/kernel/uki.conf 或从 /usr/lib/kernel/uki.conf 复制模板。虽然 PCR 策略可以在没有安全启动的情况下使用,但最好也签名您的 UKI,因此请根据需要使用您的密钥更新以下内容:
/etc/kernel/uki.conf/
[UKI] SecureBootSigningTool=systemd-sbsign SignKernel=true SecureBootPrivateKey=/etc/kernel/secure-boot-private-key.pem SecureBootCertificate=/etc/kernel/secure-boot-certificate.pem Splash=/usr/share/systemd/bootctl/splash-arch.bmp [PCRSignature:initrd] Phases=enter-initrd PCRPrivateKey=/etc/systemd/tpm2-pcr-private-key.pem PCRPublicKey=/etc/systemd/tpm2-pcr-public-key.pem
要生成 UKI,请使用一个默认读取 /etc/kernel/uki.conf 的工具,例如 kernel-install 或 mkinitcpio。
最后,将 TPM2 策略注册到您的 LUKS 卷中。
# systemd-cryptenroll --wipe-slot tpm2 --tpm2-device auto /dev/disk/by-label/root
使用 # ukify inspect /path/to/uki 检查 UKI,确保它包含 .pcrsig 部分。
还要检查 LUKs 卷是否已注册公钥。
# cryptsetup luksDump /dev/disk/by-label/root | grep pubkey
tpm2-pubkey:
.....
tpm2-pubkey-pcrs: 11
故障排除
TPM2 LUKS2 解锁仍要求输入密码
如果您按照上述 说明 使用 TPM2 硬件模块中注册的密钥自动解锁 luks2 设备,但仍在 initramfs 启动阶段收到输入密码的提示。您可能需要 提前加载 负责处理您的特定 TPM2 模块的内核模块(您可以使用 systemd-cryptenroll --tpm2-device=list 获取其名称)。
尝试创建 NULL primary 时发生 TPM 错误 (714)
从 Linux Kernel 6.10 开始,CONFIG_TCG_TPM2_HMAC 默认启用,现在 TPM 必须支持 AES-128-CFB 进行会话加密。不支持此模式的 TPM,例如较旧的 Intel PTT,将无法初始化驱动程序,从而导致 A TPM error (714) occurred attempting to create NULL primary。更换硬件是唯一的完整解决方案。 systemd-cryptenroll 也需要 AES-128-CFB 支持,因此禁用内核选项是不够的,它会失败并产生此错误:TPM device not usable as it does not support the required functionality (AES-128-CFB missing?).
参见
- Gentoo:Trusted Platform Module
- TPM-JS 测试工具:源代码 - 在线版本。