关于Secret的沉思(特辑):桌面启动链
23 min read
桌面启动链的真实
作为码区似乎没有什么可说的——真的吗?
本文旨在从底部开始——尽管底部是我们无法改变的——出发点。
固件(firmware)
当我们尝试从底部时,我们会想到BIOS,UEFI,我们将其称为 Host Boot Firmware——是的,这一层很关键,它是初始化系统并为其他所有内容奠定基础代码的基础代码。但问题是:现代平台中嵌入的固件比大多数人意识到的要多得多。固件不限于主 SPI flash 芯片。散布在您的系统中的是分立和集成设备,每个设备都有自己的固件,通常驻留在自己单独的闪存芯片中。
这一点有一些超出预料,倒也不值得惊讶,What is Intel® Management Engine? 其实很广为人知了,有一些不可控的方法对其进行操弄——我没试过——但是一直如幽灵。
固件主要两部分:
-
Host Boot Firmware:主要的 SPI flash 代码,包括 BIOS(以及其他一些内容)。
-
设备固件:在网卡、GPU、SSD 和嵌入式控制器等单个组件上运行的经常被忽视的固件。
主机处理器启动固件
包括:
-
Boot firmware: 主要是BIOS/UEFI。
-
Management Engine (ME) Firmware: 嗯,比如说刚才提及的
Intel ME
,嵌入在芯片组中的子系统。 -
集成设备的固件: 例如主板上集成的网卡的固件。
-
Platform Configuration Data: 初始化和运行时期间硬件行为的持久设置。
设备固件
-
OEM 嵌入式控制器 (EC): 集成到大多数笔记本电脑中的专用微控制器,旨在管理基本的平台功能。EC源于早期电脑中的键盘控制器(KBC),控制最初的硬件起点:开机/关机,休眠,唤醒(就电源状态意义上),电池管理;对集成的键盘扫描,触摸板,功能键,状态指示灯;风扇控制,笔记本电脑屏幕的开合检测。尽管 EC 由于缺乏总线主控功能而无法直接访问主机的内存,但它在键盘作中的特权角色会带来安全问题——对笔记本的按键记录:这是EC最经典、最直接的威胁。
-
网络接口控制器 (Network Interface Controller, NIC) :网卡。其安全威胁不言而喻。
-
图形处理单元 (GPU): 我相信随着变形金刚的盛行,在CPU外处理器上将能发起更强大的攻击,成为持久和隐蔽访问的攻击者的高价值目标。
-
存储设备 (HDD/SSD): 依靠嵌入的固件来控制读取写入,这对数据安全是一个值得考究的问题。
-
可信平台模块 (TPM): 一个专门的安全模块,旨在提供安全的加密和密钥储存,测量启动链。这也是对启动后的我们能看到的固件的信任根部。
-
电源: 是的,电池当然也有自己的微控制器和固件,用于控制充电和放电周期、监控电池健康状况并防止过热。
Intel Boot Guard
Boot Guard 在以下两种模式之一下运行:measured boot
或verified boot
,第三个选项将两者组合在一起。在制造过程中,ORM 通过熔断处理器上的保险丝来确定模式。
在measured boot
中,CRTM
(Core Root of Trust of Measurement)将接下来执行的代码的哈希记录到TPM的PCRs中;而在verified boot
中,CRTM
根据OEM融合到处理器中的密钥检查下一阶段代码的签名。Boot Guard BootROM 将控制权传递给 Intel 签名的 Authenticated Code Module (ACM),这里存在一些资源:
-
Boot Policy Manifest (BPM): 由PK签名的策略文件,记录需要验证的固件有哪些,和映像一起存储在固件中。
-
Firmware Descriptor (FD): 定义固件的存储区域。
启动的最初阶段是:硬件信任根验证BPM和FD,然后是根据BPM的记录验证其中的固件卷,并且确保执行的正确性——这里存在多个阶段的实现——到达启动设备选择,到这里Boot Guard结束。从这里开始,执行安全启动策略(如果你记得启动它)以验证引导加载程序和 UEFI 应用程序。
安全启动
我知道,在我们的层面,这只能是一个UEFI功能而已。当然,这一概念在不同平台上有几种实现:
-
UEFI
-
机器所有者密钥 (MOK)
-
Android 验证启动
对与本文谈论的UEFI,基点是:
UEFI 安全启动假定原始设备制造商 (OEM) 提供的系统固件是受信任的,因此本身不一定需要任何验证。
因此,其验证的对象包括操作系统的引导加载程序或其他第三方的UEFI 应用程序。
在实现中的早期阶段在不提,我们观察验证的起点。
映像加载过程中。DXE 验证加载到 UEFI 环境中的所有可执行映像:
-
UEFI 应用程序:引导加载程序,比如对窗口的
bootmgfw.efi
-
DXE 驱动程序:特定于设备的驱动程序,用于在 DXE 阶段配置和初始化硬件。
-
UEFI 选项 ROM:由附加设备(如 PCIe 卡)提供的固件模块。
-
UEFI Shell 工具:从外部存储加载或预安装在固件中的应用程序或实用程序。
然而上述一切都是可变的,因此在其下需要硬件级别的信任根。这就是上文所谓 Intel Boot Guard 。
参考文章:5
安全启动密钥
围绕平台密钥 (PK) 和密钥交换密钥 (KEK) 系统构建的,具有受信任签名和吊销签名的数据库:
来自微软的图片:
PK (Platform Key)
-
PK 是 UEFI 安全启动层次结构中的顶级密钥。
-
默认情况下,OEM 在系统制造时控制 PK。
-
你应该替换掉它(如果你竟然看到这里)
-
它的主要功能是授权对密钥交换密钥 (KEK) 数据库的更改。(进一步KEK 数据库用于授权对签名数据库 (
db
) 的更新。 -
Platform Key 是平台的密钥,存储在 PK 变量中。 它的工作是控制对 PK 变量和 KEK 变量的访问。 在大多数实现中,一次只能存储一个密钥在 PK 中,并且 PK 只能是一个 X509 密钥。
-
通过设置模式进行更新
KEK (Key Exchange Key)
-
KEK 充当管理信任数据库更新的中间机构
-
用于允许平台密钥 (PK) 所有者将控制权委托给作系统供应商或管理员
-
支持多个密钥,使第三方作系统或驱动程序供应商能够提供已签名的二进制文件。
-
用于更新签名数据库,并存储在 KEK 变量中。 它可用于更新当前签名数据库或对二进制文件进行签名以实现有效执行。 在大多数当前实现中,KEK 变量可能包含多个密钥,这些密钥可能是 X509 类型或RSA2048。
-
使用PK更新
Signature Databases
-
db:保存受信任的签名、证书和哈希的列表。
db 变量可以包含一组混合的密钥、签名或哈希。 在安全引导模式下,存储在 efi 二进制文件中的签名(如果没有签名,则为 SHA-256 哈希值)与数据库中的条目进行比较。 如果出现以下任一情况,则将执行该镜像:
- 未签名,但是映像的 SHA-256 哈希值位于数据库中,或者
- 映像已签名,并且签名本身位于数据库中,或
- 映像已签名,签名密钥在数据库中(并且签名有效)
-
dbx:保存已吊销或列入黑名单的签名、证书和哈希的列表。
dbx 变量可以包含密钥、签名或哈希。在安全引导模式下,将存储在 efi 二进制文件中的签名(如果二进制文件未签名,则使用 SHA-256 计算)与数据库中的条目进行比较。 如果出现以下任一情况,则拒绝执行:
- 二进制文件未签名,并且二进制文件的 SHA-256 哈希值位于 dbx 或
- 映像已签名,但是签名在 dbx 中
- 映像已签名,但是用于创建签名的密钥与 dbx 中的条目匹配
使用KEK更新 db 和 dbx。
对代码的签名
操作系统签名的公钥或证书被放入db
,进一步用于验证操作系统的映像。
那么实际上,安全启动到底能运行什么样的代码(efi二进制文件)呢?
- 未签名,但具有 SHA-256 哈希值,该哈希值位于
db
中,且不在dbx
中,或者 - 已签名,并且在
db
中具有签名,且签名不在dbx
中,或者 - 由 KEK 中的密钥或
db
中的密钥签名,并且密钥和签名都不在dbx
中。
现实
说了这么多,实际上我们能做什么呢?答案是很凄凉的。
首先的首先,请谨慎对待此文(应该是是这整个系列,因为是关乎安全的问题),对启动和固件级的修改可能导致变砖,请审慎行事。
首先,替换固件是困难的,对此勇于前进的朋友可以参考Libreboot——如果你有适合的机器。
我们手上有的只是UEFI之后的故事。
UEFI 之后
首先看窗口系统6:
你的KEK中应该有Microsoft Corporation KEK CA 2011
,不过:
The Microsoft Corporation KEK CA 2011 is set to expire in 2026, and all OEMs must create, sign, and submit updates for the new Microsoft Corporation KEK CA 2023 to Microsoft. This will allow Microsoft to update in-market devices with the new Microsoft KEK CA, allowing systems to continue receiving DB and DBX updates after 2026. For instructions and test collateral, please visit KEKUpdatePackage
之后将被换为Microsoft Corporation KEK 2K CA 2023
。
如果你来得够早,你的windows启动管理器应该还是Microsoft Windows Production PCA 2011
签名的,不过它很快它将被Windows UEFI CA 2023
取代。
此外db
中应该还有Microsoft Corporation UEFI CA 2011
——以后是新的Microsoft UEFI CA 2023
,就是shim所用到的签名——及Microsoft Option ROM UEFI CA 2023
。
这些就是唉资本微软藏在你电脑中的东西了,实际上即使你宣称摆脱了窗口系统,也没人敢肯定能摆脱它们——一些第三方固件也需要他们签名,这里关于Option ROM
有一些尝试(通过tpm日志以寻找并替换签名)。
我们可以做的事情——由上文可以想见:
-
如果主板正确实行安全启动,应该可以安全地替换
PK
。OEM的固件更新应该使用不同于PK的密钥(但这又是另一个安全问题了):在所有电脑上,建议不要将 PK 用作安全固件更新密钥。 如果 PKpriv 泄露,安全固件更新密钥也会泄露(因为它们是相同的)。 在这种情况下,可能无法进行更新以注册新的 PKpub,因为更新过程也会泄密。
-
需要以下 Microsoft KEK 证书以启用对不良映像的吊销,通过更新 dbx,并且可能更新数据库以准备较新的 Windows 签名映像:
- Microsoft Corporation KEK 2K CA 2023
-
若要允许 Windows OS 加载程序加载,必须将以下证书包含在 db 中:
- Windows UEFI CA 2023
-
除了锁定为仅启动 Windows 的系统,OEM 应考虑包括 Microsoft 第三方 UEFI CA 和 Microsoft Option ROM CA,以允许来自第三方的 UEFI 驱动程序和应用程序在电脑上运行,而无需用户执行其他步骤。
-
Microsoft Corporation UEFI CA 2011
-
Microsoft UEFI CA 2023
-
Microsoft Option ROM UEFI CA 2023
这就是你面对的东西了。
对KEK的更新实际上十几年未曾有过——直到最近——计划在今年这些证书将需要全部更新(毕竟明年2011的证书就过期了)。
-
PK
用于接受对KEK的更新,实际上几乎不需要,因此只要固件允许,可以替换之。
KEK
如果你需要使用窗口来帮你更新dbx,那么微软的KEK也是需要的——不过微软对dbx的更新是公开的secureboot_objects/PreSignedObjects/DBX/dbx_info_msft_06_10_25.json at main · microsoft/secureboot_objects · GitHub
也许你可以用自己的KEK签署之。
至于对db的更新?那是很少见的,如果你使用林纳斯系统,那就更无所谓了,至多你也可以手动加入Windows UEFI CA
。
DB
如果你需要直接启动Windows Boot Manager
,那么你必须使用Windows UEFI CA
,如果自己签名似乎会导致校验不通过。
为什么说是直接呢?
因为事实上我们使用链式启动,而据我现知:各种启动引导器似乎都没有在安全启动下验证链式启动:
The GRUB, except the chainloader command, works with the UEFI secure boot and the shim.
据说安全启动下grub应该无法insmod,然而我并未察觉到。
因此你可以链式启动Windows Boot Manager
,这样就不需要签名——但是我们需要其他验证机制——下文再议。
直接启动的efi文件必须有db中签名(或哈希记录),对我们来说无外乎两者:UKI和bootloader。
DBX
对DBX的更新上文说过了,可以来自windows update,此外Linux下如果没有去除微软的KEK,那么也许fwupd-uefi-dbx会更新dbx——但是无论如何它不可能在去除了微软KEK下运行。
启动项
启动链总算来到第一个可以设置的地方了。UEFI下你可以启动的程序,即PE32+ executable (DLL) (EFI application) x86-64
。
如果是窗口,你应该看到了bootmgfw.efi
,对很多林纳斯来说,大概是grubx64.efi
之类。
因此,第一步答案比较明显了:我们要签署我们的bootloader。
当当当然,你可以手动执行生成和上述密钥管理的全部——有人说过,密码学只有一个(还是两个问题),即密钥管理。
下面我要讨论不是怎么签署或者密钥管理,而是启动链本身。上文已经介绍了到bootloader前的安全问题,下面的问题就是之后了。
首先,我们还是致力于林纳斯,窗口的问题少说:
Linux,启动!
首先,这里有几种启动方式(我不提到shim等方式):
-
最传统的,bootloader加载内核和initramfs
我们必须在签名bootloader中实现对内核和initramfs的验证,这方面grub好像有使用PGP实现的功能(且支持加密的分区存放内核和initramfs,这的确是特别的),Limine则支持用配置文件中的b2sum校验完整性,结合嵌入配置文件的b2sum到Limine可执行文件,再使用安全启动签名从而形成完整的验证链(据称shim在一些情况中可以配合bootloader验证内核,未测试,且对于内核的cmdline和initramfs的完整性可疑)。
-
内核可以作为EFI stub启动
未尝试过,由于这种方法似乎不可能支持加密根分区。
-
进一步的,Unified Kernel Image
在此启动的将是一整个打包了systemd-stub,内核,内核命令行参数,ininramfs。微码的EFI文件,利用了安全启动的签名直接验证了全部完整性。7
在确保UKI完整性的情况下,也可以链式启动UKI——此处需要的安全策略和对windows启动管理器一样。
再参考7中,可以看到这一套体系中还需要结合TPM测量以实现完全的启动链控制。
调用的 UKI 中所有上述列出的 PE 部分都会被测量到 TPM PCR 11 中。在 UKI 初始化之前,此 TPM PCR 预计全为零。因此,如果已知 PE 映像中包含的资源,则预计算非常简单。
而根据systemd-stub
8:
Table 2. OS Resource PCR Summary
OS Resource Measurement | PCR |
---|---|
systemd-stub code (the entry point of the unified PE binary) | 4 |
Core kernel code (embedded in unified PE binary) | 4 + 11 |
OS release information (embedded in the unified PE binary) | 4 + 11 |
Main initrd (embedded in unified PE binary) | 4 + 9 + 11 |
Microcode initrd (embedded in unified PE binary) | 4 + 9 + 11 |
Default kernel command line (embedded in unified PE binary) | 4 + 11 |
Overridden kernel command line | 12 |
Boot splash (embedded in the unified PE binary) | 4 + 11 |
TPM2 PCR signature JSON (embedded in unified PE binary, synthesized into initrd) | 4 + 9 |
TPM2 PCR PEM public key (embedded in unified PE binary, synthesized into initrd) | 4 + 9 + 11 |
Credentials (synthesized initrd from companion files) | 9 + 12 |
System Extensions (synthesized initrd from companion files) | 9 + 13 |
Configuration Extensions (synthesized initrd from companion files) | 9 + 12 |
Selected profile unless zero | 12 |
啊,看了头大。但是,总而言之,主要是4和9和11代表了UKI的测量
关键的一个实施:安全启动下UKI将优先使用嵌入的.cmdline
按照设想,本来:
根文件系统加密密钥应该绑定到 TPM PCR 11,这样只有在启动一组特定的 UKI 后才能解锁
为此,现在你需要一个脚本,在更新UKI后,更新LUKS的tpm测量的密钥的slot(设计上,PCR 11是可以提前计算出来的,然后通过在UKI中附带其签名来不用更改LUKS的密钥slot——然而我还在考虑中:systemd-measure——因此先不绑定到11)。
至此,下面是根文件系统的挂载,参考是systemd-cryptsetup和systemd-cryptenroll,绑定到上述测量的PCR以解锁根文件系统,然后 switch-root。
至此,启动完成,进入到Linux系统内。
未细举的参考
TCG Trusted Boot Chain in EDK II
Unified Extensible Firmware Interface/Secure Boot - ArchWiki