统一可扩展固件接口/安全启动

来自 ArchWiki

安全启动UEFI 标准中发现的一种安全功能,旨在为预启动过程增加一层保护:通过维护一份经过加密签名的二进制文件列表,这些文件被授权或禁止在启动时运行,它有助于提高对机器核心启动组件(启动管理器、内核、initramfs)未被篡改的信心。

因此,它可以被视为对保护您的计算环境所做努力的延续或补充,减少了其他软件安全解决方案(如系统加密)不易覆盖的攻击面,同时它完全独立,不依赖于它们。安全启动作为当前安全实践的一个组成部分独立存在,它有自己的一系列优点和缺点

注意: 有关 Linux 中安全启动的更深入概述,请参阅 Rodsbooks 的安全启动 文章和其他在线资源。本文重点介绍如何在 Arch Linux 中设置安全启动。

检查安全启动状态

在操作系统启动之前

此时,必须查看固件设置。如果机器已启动并在运行,在大多数情况下必须重新启动。

您可以通过在启动过程中按下一个特殊键来访问固件配置。要使用的键取决于固件。通常是 EscF2Del 或可能是另一个 Fn 键。有时,正确的键会在启动过程开始时短暂显示。主板手册通常会记录它。您可能需要在机器开机后立即按下该键,并持续按住,甚至在屏幕实际显示任何内容之前。

进入固件设置后,请小心不要在没有事先意图的情况下更改任何设置。通常在每个设置屏幕的底部都有导航说明和设置的简短帮助。设置本身可能由多个页面组成。您将必须导航到正确的位置。感兴趣的设置可能只是简单地用安全启动表示,可以设置为开启或关闭。

在操作系统启动之后

在使用 systemd 的系统上检查安全启动状态的简单方法是使用 systemd-boot

注意: 此命令的工作不需要使用 systemd-boot 作为您的启动管理器,它更类似于其他的 *ctl systemd 实用程序(localectl、timedatectl...),并且不会触及您的配置。
$ bootctl
System:
      Firmware: UEFI 2.80 (American Megatrends 5.26)
 Firmware Arch: x64
   Secure Boot: enabled (user)
  TPM2 Support: yes
  Measured UKI: yes
  Boot into FW: supported
...

在这里我们看到安全启动已启用并强制执行(在用户模式下);其他值包括“Setup Mode”的 disabled (setup)、安全启动已禁用的 disabled (disabled) 以及固件不具备安全启动功能的 disabled (unsupported)

检查机器是否在安全启动状态下启动的另一种方法是使用此命令

$ od --address-radix=n --format=u1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c

如果安全启动已启用,则此命令返回 1 作为五个整数列表中的最后一个,例如

6  0  0  0  1

但是请注意,如果使用了功能不足的启动加载器,即使内核在固件中启用了安全启动,内核也可能意识不到。这可以通过检查系统启动后不久的内核消息来验证

# dmesg | grep -i secure
[    0.013442] Secure boot disabled
[    0.013442] Secure boot could not be determined

否则,内核消息将显示 Secure boot enabled

启动安装介质

官方安装镜像不支持安全启动 (FS#53864)。安全启动支持最初在 archlinux-2013.07.01-dual.iso 中添加,后来在 archlinux-2016.06.01-dual.iso 中移除。当时 prebootloader 被替换为 efitools,即使后者使用未签名的 EFI 二进制文件。从那时起,官方安装介质中就再也没有对安全启动的支持。

为了在安全启动系统中启动安装介质,您需要禁用安全启动或修改镜像以添加已签名的启动加载器。

Archboot 镜像提供了一种在安装介质上使用安全启动的方法。

禁用安全启动

可以通过 UEFI 固件界面禁用安全启动功能。如何访问固件配置在 #在操作系统启动之前 中进行了描述。

如果使用热键不起作用并且您可以启动 Windows,您可以按以下方式强制重启进入固件配置(对于 Windows 10):设置 > 更新和安全 > 恢复 > 高级启动(立即重启) > 疑难解答 > 高级选项 > UEFI 固件设置 > 重启

请注意,某些主板(例如 Packard Bell 笔记本电脑和最近的小米笔记本电脑)仅允许在您设置了管理员密码(之后可以删除)的情况下禁用安全启动。另请参阅 Rod Smith 的禁用安全启动

重新打包安装镜像

请参阅 #ISO 重新打包

编辑安装介质

如果您正在使用 USB 闪存安装介质,则可以手动编辑介质上的 EFI 系统分区,以添加对安全启动的支持。

插入 USB 驱动器,然后挂载该分区

# mount /dev/disk/by-label/ARCHISO_EFI /mnt

然后按照 #使用已签名的启动加载器 中的说明安装任何已签名的启动加载器。例如,安装 #PreLoader

# mv /mnt/EFI/BOOT/BOOTx64.EFI /mnt/EFI/BOOT/loader.efi
# cp /usr/share/preloader-signed/PreLoader.efi /mnt/EFI/BOOT/BOOTx64.EFI
# cp /usr/share/preloader-signed/HashTool.efi /mnt/EFI/BOOT/HashTool.efi

实施安全启动

以下是一些使安全启动设置理想化的条件

  1. UEFI 被认为基本上是可信的(尽管有一些众所周知的批评和漏洞[1]),并且必须受到强密码保护
  2. 不使用默认制造商/第三方密钥,因为它们已被证明在很大程度上削弱了安全启动的安全模型[2]
  3. UEFI 直接加载用户签名的EFI 启动存根兼容统一内核镜像(无启动管理器),包括微代码(如果适用)和 initramfs,以便在整个启动过程中保持安全启动建立的信任链,并减少攻击面
  4. 使用全盘加密,以便参与内核镜像创建和签名过程的工具和文件不会被拥有机器物理访问权限的人访问和篡改。
  5. 使用 TPM 可以获得一些进一步的改进。

#使用您自己的密钥 中描述了一个简单且完全自力更生的设置,而 #使用已签名的启动加载器 则使用了由第三方签名的中间工具。

使用 GRUB 启动引导程序需要在启用安全启动之前执行额外的步骤,有关详细信息,请参阅 GRUB#安全启动支持

使用您自己的密钥

警告: 将平台密钥替换为您自己的密钥可能会导致某些机器(包括笔记本电脑)变砖,从而无法进入固件设置来纠正这种情况。这是因为某些设备(例如 GPU)固件 (OpROM) 在启动期间执行,使用 Microsoft 第三方 UEFI CA 证书或供应商证书进行签名。许多联想 Thinkpad X、P 和 T 系列笔记本电脑就是这种情况,它们使用联想 CA 证书对 UEFI 应用程序和固件进行签名。

安全启动实现使用以下密钥

平台密钥 (PK)
顶级密钥。
密钥交换密钥 (KEK)
用于签名签名数据库和禁止签名数据库更新的密钥。
签名数据库 (db)
包含允许的 EFI 二进制文件的密钥和/或哈希值。
禁止签名数据库 (dbx)
包含拒绝列入白名单的 EFI 二进制文件的密钥和/或哈希值。

有关更详细的说明,请参阅 所有 UEFI 密钥的含义

要使用安全启动,您至少需要 PKKEKdb 密钥。虽然您可以添加多个 KEK、db 和 dbx 证书,但只允许一个平台密钥。

一旦安全启动处于“用户模式”,密钥只能通过使用更高级别的密钥对更新进行签名(使用 sign-efi-sig-list)来更新。平台密钥可以由自身签名。

备份当前变量

在创建新密钥和修改 EFI 变量之前,建议备份当前变量,以便在发生错误时可以恢复它们。

安装 efitools 软件包,然后运行以下命令来备份所有四个主要的 Secure Boot 变量

$ for var in PK KEK db dbx ; do efi-readvar -v $var -o old_${var}.esl ; done

如果您在新计算机或主板上执行此命令,则您提取的变量很可能将是由 Microsoft 提供的变量。

将固件置于“设置模式”

当平台密钥被移除时,安全启动处于设置模式。要将固件置于设置模式,请进入固件设置实用程序并找到删除或清除证书的选项。如何进入设置实用程序在 #在操作系统启动之前 中进行了描述。

使用 systemd 的辅助过程

从 v257 开始,您可以使用 systemdsystemd-boot 轻松设置安全启动。安装 systemd-ukifysbsigntools

首先,使用例如以下命令生成您的签名密钥

# ukify genkey \
--secureboot-private-key /etc/kernel/secure-boot-private-key.pem \
--secureboot-certificate /etc/kernel/secure-boot-certificate.pem
提示: 或者,在 /etc/kernel/uki.conf 中设置您想要的配置(或使用 /usr/lib/kernel/uki.conf 中的模板),并使用 ukify 的 --config 选项。这对于稍后使用 kernel-install 自动重用密钥来签名 UKI 非常有用。

接下来,配置 ESP 以进行自动注册

# bootctl install --secure-boot-auto-enroll yes \
--certificate /etc/kernel/secure-boot-certificate.pem \
--private-key /etc/kernel/secure-boot-private-key.pem

这将在 /boot/loader/keys/auto/ 中创建三个文件 PK.authKEK.authdb.auth。请注意,此命令还会将 systemd-boot 启动加载器安装(或更新)到 ESP

最后,在 /boot/loader.conf 中设置 secure-boot-enroll=force。请参阅 loader.conf(5)

使用 sbctl 的辅助过程

sbctl 是一种用户友好的设置安全启动和签名文件的方式。

注意: sbctl 并非适用于所有硬件。它的工作效果如何取决于制造商。

要使用它,安装 sbctl。另请参阅 上游 READMEsbctl(8)

创建和注册密钥

在开始之前,进入您的固件设置并将安全启动模式设置为 设置模式。这对于每个设备都不同:请参阅 sbctl(8) § USAGE

重新登录后,检查安全启动状态

$ sbctl status

您应该看到 sbctl 未安装且安全启动已禁用。

然后创建您的自定义安全启动密钥

# sbctl create-keys

将您的密钥与 Microsoft 的密钥一起注册到 UEFI

# sbctl enroll-keys -m
警告: 启用安全启动后,某些固件会使用 Microsoft 的密钥进行签名和验证。不验证设备可能会导致它们变砖。要注册您的密钥而不注册 Microsoft 的密钥,请运行:sbctl enroll-keys。仅当您知道自己在做什么时才执行此操作。

再次检查安全启动状态

$ sbctl status

sbctl 现在应该已安装,但在使用您刚刚创建的密钥对启动文件进行签名之前,安全启动将无法工作。

签名

检查哪些文件需要签名才能使安全启动工作

# sbctl verify

现在对所有未签名的文件进行签名。通常需要对 内核启动加载器 进行签名。例如

# sbctl sign -s /boot/vmlinuz-linux
# sbctl sign -s /boot/EFI/BOOT/BOOTX64.EFI

需要签名的文件将取决于您系统的布局、内核和启动加载器。

提示: 尤其是在与 Windows 双启动的情况下,可能有很多文件需要签名。使用 sbctl 签名所有需要文件的过程可以使用 sed 完成
# sbctl verify | sed 's/✗ /sbctl sign -s /e'

此示例假定输出的文件路径相对于 /boot。或者,您可以使用

# sbctl verify | sed -E 's|^.* (/.+) is not signed$|sbctl sign -s "\1"|e'

这与文件路径无关,并且不需要 '✗' 字符。

现在您完成了!重新启动您的系统并在固件设置中重新开启安全启动。如果启动加载器和操作系统加载,则安全启动应该正在工作。使用以下命令检查

$ sbctl status
使用 pacman hook 自动签名

sbctl 附带一个 pacman hook,每当 Linux 内核systemd启动加载器 更新时,它都会自动签名所有新文件。

提示: 如果您使用 Systemd-bootsystemd-boot-update.service,则 启动加载器 仅在重新启动后更新,因此 sbctl pacman hook 将不会对新文件进行签名。作为一种解决方法,直接在 /usr/lib/ 中签名 启动加载器 可能很有用,因为 bootctl installupdate 将自动识别并复制 .efi.signed 文件到 ESP(如果存在),而不是正常的 .efi 文件。请参阅 bootctl(1)
# sbctl sign -s -o /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed /usr/lib/systemd/boot/efi/systemd-bootx64.efi

手动过程

安装 efitools

以下几乎所有部分都要求您安装 efitools 软件包。

创建密钥

要生成密钥,请执行以下步骤。

您将需要多种格式的私钥和证书

.key
用于 EFI 二进制文件和 EFI 签名列表签名的 PEM 格式私钥
.crt
用于 sbsign(1)sbvarsign(1)sign-efi-sig-list(1) 的 PEM 格式证书。
.cer
用于固件的 DER 格式证书。
.esl
用于 sbvarsign(1)efi-updatevar(1)KeyTool 和固件的 EFI 签名列表中的证书。
.auth
用于 efi-updatevar(1)sbkeysyncKeyTool 和固件的带有身份验证标头(即已签名的证书更新文件)的 EFI 签名列表中的证书。

为所有者标识创建一个 GUID

$ uuidgen --random > GUID.txt

平台密钥

$ openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Platform Key/" -out PK.crt
$ openssl x509 -outform DER -in PK.crt -out PK.cer
$ cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth

签名一个空文件,以便在“用户模式”下移除平台密钥

$ sign-efi-sig-list -g "$(< GUID.txt)" -c PK.crt -k PK.key PK /dev/null noPK.auth

密钥交换密钥

$ openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Key Exchange Key/" -out KEK.crt
$ openssl x509 -outform DER -in KEK.crt -out KEK.cer
$ cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth

签名数据库密钥

$ openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=my Signature Database key/" -out db.crt
$ openssl x509 -outform DER -in db.crt -out db.cer
$ cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth
辅助脚本

本主题参考页面的作者[3]提供了一个辅助/便捷脚本(需要 python)。一个经过轻微编辑的版本也打包为 sbkeysAUR

为了使用它,只需在安全位置创建一个文件夹(例如 /etc/efi-keys/,如果计划稍后使用 sbupdate-gitAUR 来自动化统一内核镜像的创建和签名)并运行它

# mkdir /etc/efi-keys
# cd !$
# curl -L -O https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
# chmod +x mkkeys.sh
# ./mkkeys.sh
Enter a Common Name to embed in the keys, e.g. "Secure Boot"

这将生成不同格式的所需文件。

在固件中注册密钥

使用以下方法之一注册 dbKEKPK 证书。

提示: 由于 dbx(禁止签名数据库)为空,因此可以在以下说明中安全地省略它。
警告: 注册平台密钥会将安全启动设置为“用户模式”,退出“设置模式”,因此应在序列中最后注册。
使用 sbkeysync

安装 sbsigntools。创建一个目录 /etc/secureboot/keys,目录结构如下 -

/etc/secureboot/keys
├── db
├── dbx
├── KEK
└── PK

例如使用

# mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK}

然后将之前生成的每个 .auth 文件复制到它们各自的位置(例如,PK.auth 复制到 /etc/secureboot/keys/PK,依此类推)。

如果您想验证 sbkeysync 将对系统的 UEFI 密钥库所做的更改,请使用

# sbkeysync --keystore /etc/secureboot/keys --pk --dry-run --verbose

最后,使用 sbkeysync 注册您的密钥。

# sbkeysync --keystore /etc/secureboot/keys --verbose
# sbkeysync --keystore /etc/secureboot/keys --verbose --pk
提示
  • 如果 sbkeysync 返回写入错误,请首先运行 chattr -i /sys/firmware/efi/efivars/{PK,KEK,db}*,然后再使用 sbkeysync 发出命令,以临时更改文件属性,从而启用 efivars 目录中 EFI 密钥的写入。请参阅 chattr(1)
  • 如果您收到 PK.authpermission denied 错误,您可以使用命令 efi-updatevar -f /etc/secureboot/keys/PK/PK.auth PK 注册它。
  • 如果这失败,可能是由于固件锁定 BIOS 设置。在 Dell 和联想系统上,您可能需要重置 BIOS 密码:Sysfs 固件身份验证文档

在联想系统上

# cat > /sys/class/firmware-attributes/thinklmi/authentication/Admin/current_password 
my-super-secret-password
^D

在 Dell 系统上

# cat > /sys/class/firmware-attributes/dell-wmi-sysman/authentication/Admin/current_password 
my-super-secret-password
^D
然后重试。

下次启动时,UEFI 应该会回到用户模式并强制执行安全启动策略。

使用固件设置实用程序

将所有 *.cer*.esl*.auth 文件(除了 noPK.auth 文件!)复制到 FAT 格式化的文件系统(您可以使用 EFI 系统分区)。

警告: 不要noPK.auth 文件复制到您 PC 的 EFI 系统分区 (ESP)!如果您这样做,并且有人例如偷了您的 PC,此人可以再次删除 UEFI 安全启动固件中的个人平台密钥,再次在您的 PC 上启用“设置模式”,并用他们自己的平台密钥替换您的安全启动密钥 (PK, KEK, db, dbx),从而破坏 UEFI 安全启动的整个目的。只有您应该能够替换平台密钥,因此只有您应该有权访问 noPK.auth 文件。因此,将 noPK.auth 文件保存在只有您才能访问的秘密、安全的地方。noPK.auth 文件的安全位置包括

根据 UEFI 规范,您的电脑的 EFI 系统分区 不得加密,并且可以在另一台电脑上挂载和读取(如果您的电脑被盗,并且硬盘驱动器被取出并连接到另一台电脑)。将 noPK.auth 文件复制到您电脑的 ESP 并随后删除也是不可取的,因为 FAT32 EFI 系统分区 上已删除的文件 可以使用 PhotoRec 等工具恢复

启动固件设置实用程序并注册 dbKEKPK 证书。固件具有各种不同的界面,例如,请参阅 使用固件设置实用程序替换密钥,了解如何注册密钥。

如果使用的工具支持,则首选使用 .auth.esl 而不是 .cer

使用 KeyTool

KeyTool.efi 位于 efitools 软件包中,将其复制到 ESP。要在注册密钥后使用它,请使用 sbsign 对其进行签名。

# sbsign --key db.key --cert db.crt --output esp/KeyTool-signed.efi /usr/share/efitools/efi/KeyTool.efi

使用固件设置实用程序、启动加载程序或 UEFI Shell 启动 KeyTool-signed.efi 并注册密钥。

请参阅 使用 KeyTool 替换密钥,了解 KeyTool 菜单选项的说明。

使用 systemd-boot

自 systemd 版本 252 起,可以使用 systemd-boot 来注册密钥。要注册密钥,请将 db.authKEK.authPK.auth 复制到 ESP 上的特殊文件夹

# cp db.auth KEK.auth PK.auth esp/loader/keys/NAME/

其中 NAME 可以是您分配的任何唯一名称,例如 MYKEYS

复制密钥并启用安全启动设置模式后,启动菜单中将出现一个新条目,内容为 Enroll Secure Boot keys: MYKEYS。激活此条目将注册安全启动密钥。

签名 EFI 二进制文件

安全启动 处于活动状态(即处于“用户模式”)时,只能启动已签名的 EFI 二进制文件(例如,应用程序、驱动程序统一内核镜像)。

使用 sbsigntools

安装 sbsigntools 以使用 sbsign(1) 签名 EFI 二进制文件。

提示
  • 要检查二进制文件是否已签名并列出其签名,请使用 sbverify --list /path/to/binary
  • rEFInd 启动管理器 的 refind-install 脚本可以签名 rEFInd EFI 二进制文件,并将它们与 db 证书一起复制到 ESP。请参阅 rEFInd#使用您自己的密钥 获取说明。
注意: 如果在没有 --output 的情况下运行 sbsign,则生成的文件将为 filename.signed。请参阅 sbsign(1) 获取更多信息。

要签名您的内核和启动管理器,请使用 sbsign,例如

# sbsign --key db.key --cert db.crt --output /boot/vmlinuz-linux /boot/vmlinuz-linux
# sbsign --key db.key --cert db.crt --output esp/EFI/BOOT/BOOTx64.EFI esp/EFI/BOOT/BOOTx64.EFI
警告: 仅签名内核将无法保护 initramfs 免受篡改。请参阅 统一内核镜像,了解如何生成组合镜像,然后您可以手动使用 sbsign 对其进行签名。
使用 mkinitcpio 后期挂钩签名内核

您还可以使用 mkinitcpio 后期挂钩 在生成 initramfs 时签名内核。

创建 以下文件并使其 可执行

/etc/initcpio/post/kernel-sbsign
#!/usr/bin/env bash

kernel="$1"
[[ -n "$kernel" ]] || exit 0

# use already installed kernel if it exists
[[ ! -f "$KERNELDESTINATION" ]] || kernel="$KERNELDESTINATION"

keypairs=(/path/to/db.key /path/to/db.crt)

for (( i=0; i<${#keypairs[@]}; i+=2 )); do
    key="${keypairs[$i]}" cert="${keypairs[(( i + 1 ))]}"
    if ! sbverify --cert "$cert" "$kernel" &>/dev/null; then
        sbsign --key "$key" --cert "$cert" --output "$kernel" "$kernel"
    fi
done

/path/to/db.key/path/to/db.crt 替换为您要用于签名内核的密钥对的路径。

如果您正在使用 systemd-boot,则有一个 专用的 pacman 挂钩 半自动地执行此任务。

使用 mkinitcpio 后期挂钩签名统一内核镜像

请参阅 统一内核镜像#为安全启动签名 UKI

使用 sbupdate 完全自动化统一内核生成和签名

本文或章节已过时。

原因: sbupdate 上游存储库[死链接 2024-07-30 ⓘ] 已于 2023 年 8 月存档。此外,它是在 mkinitcpio 和其他 initramfs 生成器获得生成 统一内核镜像 的能力之前很久创建的,这为以前繁琐的过程提供了极大的便利。如今,请考虑改用 #使用 sbctl 的辅助过程。(在 Talk:Unified Extensible Firmware Interface/Secure Boot 中讨论)

sbupdate 是一款专门用于自动化 Arch Linux 上统一内核镜像生成和签名的工具。它通过 pacman 挂钩 处理内核的安装、删除和更新。

安装 sbupdate-gitAUR 并按照项目主页上给出的说明配置它。[4]

提示: 如果使用 systemd-boot,请设置 OUT_DIR="EFI/Linux" 以使您的签名内核镜像直接被识别,而无需配置。请参阅 systemd-boot(7) § 文件systemd-boot#添加加载程序

配置完成后,只需以 root 身份运行 sbupdate 即可进行首次镜像生成。

注意: sbupdate 输出通常包含诸如 warning: data remaining[26413568 vs 26423180]: gaps between PE/COFF sections? 之类的错误。这些是无害的,可以安全地忽略。[5]

更新密钥

一旦安全启动处于“用户模式”,对 KEK、db 和 dbx 的任何更改都需要使用更高级别的密钥进行签名。

例如,如果您想用新密钥替换您的 db 密钥

  1. 创建新密钥,
  2. 将其转换为 EFI 签名列表,
  3. 签名 EFI 签名列表,
  4. 注册已签名的证书更新文件。
$ cert-to-efi-sig-list -g "$(< GUID.txt)" new_db.crt new_db.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db new_db.esl new_db.auth

如果不是替换您的 db 密钥,而是要向签名数据库添加另一个密钥,则需要使用选项 -a(请参阅 sign-efi-sig-list(1)

$ sign-efi-sig-list -a -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db new_db.esl new_db.auth

new_db.auth 创建后,注册它

与其他操作系统双启动

Microsoft Windows

本文或章节需要扩充。

原因: 是否可以通过使用 自定义密钥 签名 Windows 启动加载程序来启动 Windows?(在 Talk:Unified Extensible Firmware Interface/Secure Boot#使用自定义启动加载程序签名启动 Windows 中讨论)

通常不可能通过使用 自定义的个人密钥 签名 Windows 启动加载程序 (EFI/Microsoft/Boot/bootmgfw.efi) 并在启用安全启动模式的情况下启动 Windows,而无需在 UEFI 安全启动变量中注册“Microsoft Windows Production PCA 2011”密钥

  • 如果 bootmgfw.efi 包含来自“Microsoft Windows Production PCA 2011”来自您自己的安全启动 db 密钥的签名(因此是两个签名),则像 INSYDE Corp. 4096.01 (UEFI Version 2.31, Version F.70, Release Date: 07/18/2016, BIOS Revision 15.112, Firmware Revision: 29.66) 这样的 UEFI 固件实现将不会启动 bootmgfw.efi,并且会抛出安全违规错误(Selected boot image did not authenticate. Press ENTER to continue.):像这样的 UEFI 固件实现可能只能读取第一个签名,而不能读取第二个签名。只有第二个签名的证书注册在 UEFI 安全启动变量中,因此安全启动验证失败。
  • 如果 bootmgfw.efi 文件中的“Microsoft Windows Production PCA 2011”签名被剥离/删除,并且仅将来自您自己的安全启动 db 密钥的签名添加到文件中,则 UEFI 将启动该文件,但 Windows 将启动恢复/修复环境:Windows 抱怨 Windows 安装已损坏(因为 bootmgfw.efi 文件上缺少“Microsoft Windows Production PCA 2011”签名)。

因此,要与 Windows 双启动

使用 Microsoft 的 GUID (77fa9abd-0359-4d32-bd60-28f4e78f784b) 从 Microsoft 的 DER 格式 db 证书创建 EFI 签名列表,并将它们组合在一个文件中以简化操作

$ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_Win_db_2011.esl MicWinProPCA2011_2011-10-19.crt
$ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_Win_db_2023.esl 'windows uefi ca 2023.crt'
$ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_UEFI_db_2011.esl MicCorUEFCA2011_2011-06-27.crt
$ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_UEFI_db_2023.esl 'microsoft uefi ca 2023.crt'
$ cat MS_Win_db_2011.esl MS_Win_db_2023.esl MS_UEFI_db_2011.esl MS_UEFI_db_2023.esl > MS_db.esl

可选(为了严格符合 Microsoft UEFI 安全启动要求):使用 Microsoft 的 GUID (77fa9abd-0359-4d32-bd60-28f4e78f784b) 从 Microsoft 的 DER 格式 KEK 证书创建 EFI 签名列表

$ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_Win_KEK_2011.esl MicCorKEKCA2011_2011-06-24.crt
$ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_Win_KEK_2023.esl 'microsoft corporation kek 2k ca 2023.crt'
$ cat MS_Win_KEK_2011.esl MS_Win_KEK_2023.esl > MS_Win_KEK.esl

使用您的 KEK 签名 db 变量更新。使用带有选项 -asign-efi-sig-list添加而不是替换 db 证书

$ sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b -k KEK.key -c KEK.crt db MS_db.esl add_MS_db.auth

可选(为了严格符合 Microsoft UEFI 安全启动要求):使用您的 PK 签名 KEK 变量更新。使用带有选项 -asign-efi-sig-list添加而不是替换 KEK 证书

$ sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b -k PK.key -c PK.crt KEK MS_Win_KEK.esl add_MS_Win_KEK.auth

按照 #在固件中注册密钥 注册 add_MS_db.auth,为了严格符合 Microsoft UEFI 安全启动要求,注册 add_MS_Win_KEK.auth 到 UEFI 安全启动数据库变量中。

使用已签名的启动加载程序

使用已签名的启动加载程序意味着使用使用 Microsoft 密钥签名的启动加载程序。有两个已知的已签名启动加载程序:PreLoader 和 shim。它们的目的是链式加载其他 EFI 二进制文件(通常是 启动加载程序)。由于 Microsoft 永远不会签名自动启动任何未签名二进制文件的启动加载程序,因此 PreLoader 和 shim 使用一个名为 Machine Owner Key list(缩写为 MokList)的允许列表。如果二进制文件(Preloader 和 shim)的 SHA256 哈希值或二进制文件签名的密钥(shim)在 MokList 中,它们将执行它,否则它们将启动密钥管理实用程序,该实用程序允许注册哈希值或密钥。

警告: Microsoft 所谓的“安全核心 PC”出厂时未注册 Microsoft 第三方 UEFI CA 证书(Microsoft Corporation UEFI CA 2011 或 Microsoft UEFI CA 2023)。[6]。唯一注册的 DB 证书是 Microsoft Windows Production PCA 2011 证书,该证书专门用于签名 Windows 启动加载程序。

需要在固件设置中启用 Microsoft 第三方 UEFI CA 证书的注册,以启动使用此证书签名的 EFI 二进制文件和 OpROM。

PreLoader

运行时,PreLoader 尝试启动 loader.efi。如果 loader.efi 的哈希值不在 MokList 中,PreLoader 将启动 HashTool.efi。在 HashTool 中,您必须注册您想要启动的 EFI 二进制文件的哈希值,这意味着您的 启动加载程序 (loader.efi) 和内核。

注意: 每次您更新任何二进制文件(例如,启动加载程序或内核)时,您都需要注册它们的新哈希值。
提示: rEFInd 启动管理器 的 refind-install 脚本可以将 rEFInd 和 PreLoader EFI 二进制文件复制到 ESP。请参阅 rEFInd#使用 PreLoader 获取说明。
设置 PreLoader
注意: efitools 软件包中的 PreLoader.efiHashTool.efi 未签名,因此它们的用途有限。您可以从 preloader-signedAUR手动下载 获取已签名的 PreLoader.efiHashTool.efi

安装 preloader-signedAUR 并将 PreLoader.efiHashTool.efi 复制到 启动加载程序 目录;对于 systemd-boot,请使用

# cp /usr/share/preloader-signed/{PreLoader,HashTool}.efi esp/EFI/systemd

现在复制启动加载程序二进制文件并将其重命名为 loader.efi;对于 systemd-boot,请使用

# cp esp/EFI/systemd/systemd-bootx64.efi esp/EFI/systemd/loader.efi

最后,创建一个新的 NVRAM 条目以启动 PreLoader.efi

# efibootmgr --unicode --disk /dev/sdX --part Y --create --label "PreLoader" --loader /EFI/systemd/PreLoader.efi

X 替换为驱动器盘符,并将 Y 替换为 EFI 系统分区 的分区号。

此条目应添加到列表中作为第一个启动项;使用 efibootmgr 命令检查并在必要时调整启动顺序。

回退

如果启动自定义 NVRAM 条目时出现问题,请将 HashTool.efiloader.efi 复制到 UEFI 系统自动启动的默认加载程序位置

# cp /usr/share/preloader-signed/HashTool.efi esp/EFI/BOOT/
# cp esp/EFI/systemd/systemd-bootx64.efi esp/EFI/BOOT/loader.efi

复制 PreLoader.efi 并重命名它

# cp /usr/share/preloader-signed/PreLoader.efi esp/EFI/BOOT/BOOTx64.EFI

对于特别顽固的 UEFI 实现,请将 PreLoader.efi 复制到 Windows 系统使用的默认加载程序位置

# mkdir -p esp/EFI/Microsoft/Boot
# cp /usr/share/preloader-signed/PreLoader.efi esp/EFI/Microsoft/Boot/bootmgfw.efi
注意: 如果与 Windows 双启动,请首先备份原始 bootmgfw.efi,因为替换它可能会导致 Windows 更新出现问题。

与之前一样,将 HashTool.efiloader.efi 复制到 esp/EFI/Microsoft/Boot/

当系统在启用安全启动的情况下启动时,按照上述步骤注册 loader.efi/vmlinuz-linux(或正在使用的任何内核镜像)。

如何在启动时使用?

将显示一条消息,内容为 Failed to Start loader... I will now execute HashTool. 要使用 HashTool 注册 loader.efivmlinuz.efi 的哈希值,请按照以下步骤操作。这些步骤假设标题用于重新制作的 archiso 安装介质。您将获得的确切标题取决于您的启动加载程序设置。

  • 选择 OK
  • 在 HashTool 主菜单中,选择 Enroll Hash,选择 \loader.efi 并使用 Yes 确认。再次选择 Enroll Hasharchiso 以进入 archiso 目录,然后选择 vmlinuz.efi 并使用 Yes 确认。然后选择 Exit 返回到启动设备选择菜单。
  • 在启动设备选择菜单中,选择 Arch Linux archiso x86_64 UEFI CD
删除已注册的哈希值

在 MOK 数据库中注册的每个哈希值条目都会占用一小部分 NVRAM 空间。您可能想要删除无用的哈希值以释放空间并防止过时的程序启动。

安装 efitools 并复制 KeyTool.efi

# cp /usr/share/efitools/efi/KeyTool.efi esp/EFI/systemd/KeyTool.efi

设法启动到 Preloader,您将看到 KeyTool 条目。然后,您可以编辑 MOK 数据库中的哈希值。

删除 PreLoader
注意: 由于您要删除内容,因此最好备份它。

卸载 preloader-signedAUR 并简单地删除复制的文件并恢复配置;对于 systemd-boot,请使用

# rm esp/EFI/systemd/{PreLoader,HashTool}.efi
# rm esp/EFI/systemd/loader.efi
# efibootmgr --unicode --bootnum N --delete-bootnum
# bootctl update

其中 N 是为启动 PreLoader.efi 创建的 NVRAM 启动条目。使用 efibootmgr 命令检查并在必要时调整启动顺序。

注意: 上述命令涵盖了最简单的情况;如果您创建、复制、重命名或编辑了更多文件,您可能也需要处理它们。如果 PreLoader 是您的操作启动条目,那么您显然还需要 #禁用安全启动

shim

本文或章节需要扩充。

原因: 需要测试。(在 Talk:Unified Extensible Firmware Interface/Secure Boot#shim 中讨论)

运行时,shim 尝试启动 grubx64.efi。如果 MokList 不包含 grubx64.efi 的哈希值或它签名的密钥,shim 将启动 MokManager (mmx64.efi)。在 MokManager 中,您必须注册您想要启动的 EFI 二进制文件(您的 启动加载程序 (grubx64.efi) 和内核)的哈希值,或者注册它们签名的密钥。

注意
  • 如果您使用 #使用哈希值的 shim,则每次更新任何二进制文件(例如,启动加载程序或内核)时,您都需要注册它们的新哈希值。
  • 自 15.3 版本起,shim 将不会启动没有有效 .sbat 部分的 EFI 二进制文件。运行 objdump -j .sbat -s /path/to/binary.efi 以验证 EFI 二进制文件是否具有它。请参阅 SBAT 文档 获取详细信息。
  • 如果您实际上对安全启动带来的安全性不感兴趣,而只是为了满足 Windows 11 提出的要求而启用它,您可能需要考虑使用 mokutil --disable-validation 禁用 shim 中的验证过程。在这种情况下,您将不需要签名 grub(可能仍然需要 sbat)或内核镜像,并且同时能够使用 grub 中的 chainloader 启动 Windows。
设置 shim
提示: rEFInd 启动管理器 的 refind-install 脚本可以签名 rEFInd EFI 二进制文件,并将它们与 shim 和 MOK 证书一起复制到 ESP。请参阅 rEFInd#使用 shim 获取说明。

安装 shim-signedAUR

将您当前的 启动加载程序 重命名为 grubx64.efi,因为默认情况下,Shim 将尝试加载并运行名为 grubx64.efi 的文件。虽然可以通过将文件路径作为命令行参数传递给 shim 来覆盖此默认值,但由于某些固件在具有命令行参数的 UEFI 启动条目方面存在问题,因此依赖默认值更万无一失。

# mv esp/EFI/BOOT/BOOTx64.EFI esp/EFI/BOOT/grubx64.efi

shimMokManager 复制到 ESP 上的启动加载程序目录;使用您的启动加载程序之前的文件名作为 shimx64.efi 的文件名

注意: 确保您不要复制 fbx64.efi(它在同一目录下),除非您实际上有一个有效的 bootx64.csv 要使用。否则,shim 将不会执行 grubx64.efi,而是会显示为无法工作并只是重置机器。
# cp /usr/share/shim-signed/shimx64.efi esp/EFI/BOOT/BOOTx64.EFI
# cp /usr/share/shim-signed/mmx64.efi esp/EFI/BOOT/

最后,创建一个新的 NVRAM 条目以启动 BOOTx64.EFI

# efibootmgr --unicode --disk /dev/sdX --part Y --create --label "Shim" --loader /EFI/BOOT/BOOTx64.EFI

shim 可以通过 Machine Owner Key 或存储在 MokList 中的哈希值来验证二进制文件。

Machine Owner Key (MOK)
用户生成并用于签名 EFI 二进制文件的密钥。
哈希值
EFI 二进制文件的 SHA256 哈希值。

使用哈希值更简单,但每次更新启动加载程序或内核时,您都需要在 MokManager 中添加它们的哈希值。使用 MOK,您只需要添加一次密钥,但您每次更新启动加载程序和内核时都必须对其进行签名。

使用哈希值的 shim

如果 shim 在 MokList 中找不到 grubx64.efi 的 SHA256 哈希值,它将启动 MokManager (mmx64.efi)。

MokManager 中,选择 Enroll hash from disk,找到 grubx64.efi 并将其添加到 MokList。重复这些步骤并添加您的内核 vmlinuz-linux。完成后,选择 Continue boot,您的启动加载程序将启动,并且它将能够启动内核。

使用密钥的 shim

安装 sbsigntools

您将需要

.key
PEM 格式的 私钥,用于 EFI 二进制文件签名。
.crt
PEM 格式的证书,用于 sbsign
.cer
DER 格式的证书,用于 MokManager

创建 Machine Owner Key

$ openssl req -newkey rsa:2048 -nodes -keyout MOK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Machine Owner Key/" -out MOK.crt
$ openssl x509 -outform DER -in MOK.crt -out MOK.cer
注意: 似乎 shim 不支持将 4096 RSA 密钥添加到 MokList(在加载和验证 grubx64.efi 二进制文件时可能会冻结),因此请确保您现在使用 2048 密钥。请参阅 Debian:SecureBoot#生成新密钥

签名您的启动加载程序(名为 grubx64.efi)和内核

# sbsign --key MOK.key --cert MOK.crt --output /boot/vmlinuz-linux /boot/vmlinuz-linux
# sbsign --key MOK.key --cert MOK.crt --output esp/EFI/BOOT/grubx64.efi esp/EFI/BOOT/grubx64.efi

每次更新它们时,您都需要执行此操作。您可以使用 mkinitcpio 后期挂钩 自动化内核签名。创建 以下文件并使其 可执行

/etc/initcpio/post/kernel-sbsign
#!/usr/bin/env bash

kernel="$1"
[[ -n "$kernel" ]] || exit 0

# use already installed kernel if it exists
[[ ! -f "$KERNELDESTINATION" ]] || kernel="$KERNELDESTINATION"

keypairs=(/path/to/MOK.key /path/to/MOK.crt)

for (( i=0; i<${#keypairs[@]}; i+=2 )); do
    key="${keypairs[$i]}" cert="${keypairs[(( i + 1 ))]}"
    if ! sbverify --cert "$cert" "$kernel" &>/dev/null; then
        sbsign --key "$key" --cert "$cert" --output "$kernel" "$kernel"
    fi
done

MOK.cer 复制到 FAT 格式的文件系统(您可以使用 EFI 系统分区)。

重启并启用安全启动。如果 shim 在 MokList 中找不到 grubx64.efi 签名的证书,它将启动 MokManager (mmx64.efi)。

MokManager 中,选择 Enroll key from disk,找到 MOK.cer 并将其添加到 MokList。完成后,选择 Continue boot,您的启动加载程序将启动,并且它将能够启动任何使用您的 Machine Owner Key 签名的二进制文件。

使用密钥和 GRUB 的 shim

请参阅 GRUB#Shim-lock 获取说明。

删除已注册的哈希值/密钥

在 MOK 数据库中注册的每个哈希值/密钥条目都会占用一小部分 NVRAM 空间。您可能想要删除无用的哈希值/密钥以释放空间并防止过时的程序启动。

MOK 数据库可以使用 mokutil 进行管理

列出已注册的密钥和哈希值

# mokutil --list-enrolled

从数据库中删除哈希值。此处输入的密码将在 MOK 管理器中请求确认以删除。

# mokutil --delete-hash <hash to remove from above command>
Input password:

从数据库中删除密钥

# mokutil --delete MOK.cer

列出将在下次重启时删除的哈希值/密钥

# mokutil --list-delete

在下次重启时,将启动 MOK 管理器,其中包含注册/删除哈希值/密钥的选项。更多详细信息请参阅 mokutil(1)

删除 shim

卸载 shim-signedAUR,删除复制的 shimMokManager 文件,并将您的启动加载程序重命名回来。

保护安全启动

防止任何具有物理访问权限的人禁用安全启动的唯一方法是使用密码保护固件设置。大多数 UEFI 固件都提供此功能,通常在固件设置中的“安全”部分下列出。

考虑启用 内核锁定模式。请参阅 [7]

技巧和窍门

ISO 重打包

可以使用 libisoburnmtools 解包和重新打包官方安装镜像。这样,您可以创建一个支持安全启动的镜像,可以使用自定义密钥或已签名的启动加载程序。

本文或章节需要扩充。

原因: 添加用于重新打包 ISO 以包含 shim 的说明。(在 Talk:Unified Extensible Firmware Interface/Secure Boot 中讨论)

使用自定义密钥签名官方 ISO

只需提取启动加载程序 (BOOTx64.EFIBOOTIA32.EFI)、内核、UEFI shell,签名它们,然后使用已签名的文件重新打包 ISO,即可将使用自定义密钥的安全启动支持添加到官方 ISO。

首先提取相关文件和 El Torito 启动镜像

$ osirrox -indev archlinux-YYYY.MM.DD-x86_64.iso \
	-extract_boot_images ./ \
	-cpx /arch/boot/x86_64/vmlinuz-linux \
	/EFI/BOOT/BOOTx64.EFI \
	/EFI/BOOT/BOOTIA32.EFI \
	/shellx64.efi \
	/shellia32.efi ./

xorrisofs(1) 选项 -rational-rockmkarchiso 使用)使 ISO 9660 上的文件变为只读,这在提取它们后仍然存在。使文件可写,以便可以修改它们

$ chmod +w BOOTx64.EFI BOOTIA32.EFI shellx64.efi shellia32.efi vmlinuz-linux

签名文件。例如,要使用 sbsigntools 执行此操作

$ sbsign --key db.key --cert db.crt --output BOOTx64.EFI BOOTx64.EFI
$ sbsign --key db.key --cert db.crt --output BOOTIA32.EFI BOOTIA32.EFI
$ sbsign --key db.key --cert db.crt --output shellx64.efi shellx64.efi
$ sbsign --key db.key --cert db.crt --output shellia32.efi shellia32.efi
$ sbsign --key db.key --cert db.crt --output vmlinuz-linux vmlinuz-linux

将已签名的 EFI 二进制文件复制到 eltorito_img2_uefi.img。它将用作 EFI 系统分区,并将列为 El Torito UEFI 启动镜像。eltorito_img2_uefi.img 的大小是固定的,但 mkarchiso 添加了 8 MiB 的可用空间(用于舍入/对齐目的,以考虑保留扇区等),因此签名导致的大小增加应该不是问题。

$ mcopy -D oO -i eltorito_img2_uefi.img vmlinuz-linux ::/arch/boot/x86_64/vmlinuz-linux
$ mcopy -D oO -i eltorito_img2_uefi.img BOOTx64.EFI BOOTIA32.EFI ::/EFI/BOOT/
$ mcopy -D oO -i eltorito_img2_uefi.img shellx64.efi shellia32.efi ::/

使用修改后的 El Torito UEFI 启动镜像重新打包 ISO,并将已签名的 EFI 二进制文件添加到 ISO 9660

$ xorriso -indev archlinux-YYYY.MM.DD-x86_64.iso \
	-outdev archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso \
	-map vmlinuz-linux /arch/boot/x86_64/vmlinuz-linux \
	-map_l ./ /EFI/BOOT/ BOOTx64.EFI BOOTIA32.EFI -- \
	-map_l ./ / shellx64.efi shellia32.efi -- \
	-boot_image any replay \
	-append_partition 2 0xef eltorito_img2_uefi.img

启动生成的 archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso

使用 PreLoader 替换启动加载程序

将安全启动支持添加到官方 ISO 的另一种方法是提取启动加载程序并将其替换为 #PreLoader

首先,提取启动加载程序和 El Torito 启动镜像

$ osirrox -indev archlinux-YYYY.MM.DD-x86_64.iso \
	-extract_boot_images ./ \
	-extract /EFI/BOOT/BOOTx64.EFI loader.efi

BOOTx64.efi 文件替换为 PreLoader

$ cp /usr/share/preloader-signed/PreLoader.efi BOOTx64.EFI
$ cp /usr/share/preloader-signed/HashTool.efi HashTool.efi

将新文件添加到启动镜像

$ mcopy -D oO -i eltorito_img2_uefi.img BOOTx64.EFI loader.efi HashTool.efi ::/EFI/BOOT/

最后,使用修改后的启动镜像和新的启动加载程序文件重新打包 ISO

$ xorriso -indev archlinux-YYYY.MM.DD-x86_64.iso \
	-outdev archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso \
	-map_l ./ /EFI/BOOT/ BOOTx64.EFI loader.efi HashTool.efi -- \
	-boot_image any replay \
	-append_partition 2 0xef eltorito_img2_uefi.img

使用 Machine Owner Key 为 shim 签名官方 ISO

可以通过提取启动加载程序、内核和 UEFI shell,签名它们,然后使用已签名的文件和 shim 重新打包 ISO,将使用带有 Machine Owner Key (MOK) 的 shim 的安全启动支持添加到官方 ISO。

首先提取相关文件和 El Torito 启动镜像。启动加载程序文件名需要为 grubx64.efi,以便 shim 可以找到它。

$ osirrox -indev archlinux-YYYY.MM.DD-x86_64.iso \
	-extract_boot_images ./ \
	-extract /EFI/BOOT/BOOTx64.EFI grubx64.efi \
	-extract /shellx64.efi shellx64.efi \
	-extract /arch/boot/x86_64/vmlinuz-linux vmlinuz-linux

xorrisofs(1) 选项 -rational-rockmkarchiso 使用)使 ISO 9660 上的文件变为只读,这在提取它们后仍然存在。使文件可写,以便可以修改它们

$ chmod +w grubx64.efi shellx64.efi vmlinuz-linux

使用您的 MOK 签名文件

$ sbsign --key MOK.key --cert MOK.crt --output grubx64.efi grubx64.efi
$ sbsign --key MOK.key --cert MOK.crt --output shellx64.efi shellx64.efi
$ sbsign --key MOK.key --cert MOK.crt --output vmlinuz-linux vmlinuz-linux

获取预签名的 shim EFI 二进制文件,例如,通过安装 shim-signedAUR。将 shim 和 MokManager 放置在当前目录中,并将 shim EFI 二进制文件的文件名更改为 BOOTx64.EFI

$ cp /usr/share/shim-signed/shimx64.efi BOOTx64.EFI
$ cp /usr/share/shim-signed/mmx64.efi ./

将 shim、MokManager、已签名的 EFI 二进制文件和 DER 格式的 MOK 复制到 eltorito_img2_uefi.img。它将用作 EFI 系统分区,并将列为 El Torito UEFI 启动镜像。eltorito_img2_uefi.img 的大小是固定的,但 mkarchiso 添加了 8 MiB 的可用空间(用于舍入/对齐目的,以考虑保留扇区等),因此添加文件导致的大小增加应该不是问题。

$ mcopy -D oO -i eltorito_img2_uefi.img vmlinuz-linux ::/arch/boot/x86_64/vmlinuz-linux
$ mcopy -D oO -i eltorito_img2_uefi.img MOK.cer shellx64.efi ::/
$ mcopy -D oO -i eltorito_img2_uefi.img BOOTx64.EFI grubx64.efi mmx64.efi ::/EFI/BOOT/

使用修改后的 El Torito UEFI 启动镜像重新打包 ISO,并将 shim、MokManager、已签名的 EFI 二进制文件和 DER 格式的 MOK 添加到 ISO 9660

$ xorriso -indev archlinux-YYYY.MM.DD-x86_64.iso \
	-outdev archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso \
	-map vmlinuz-linux /arch/boot/x86_64/vmlinuz-linux \
	-map_l ./ / shellx64.efi MOK.cer -- \
	-map_l ./ /EFI/BOOT/ BOOTx64.EFI grubx64.efi mmx64.efi -- \
	-boot_image any replay \
	-append_partition 2 0xef eltorito_img2_uefi.img

启动生成的 archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso。当 MokManager 启动时,选择 Enroll key from disk > ARCHISO_EFI > MOK.cer。注册密钥后,重启,在下次启动时,实时环境将成功启动。

注册 Option ROM 摘要

Option ROM (OpROM),即在启动期间执行的设备固件,必须为安全启动签名,否则设备将不会初始化。通常,OpROM 使用 Microsoft 第三方 UEFI CA 证书签名,这可能会阻止仅使用您自己的密钥实现安全启动。为了解决这个问题,可以改为注册 OpROM 的 SHA256 摘要。

警告: 通过删除 Microsoft 第三方 UEFI CA 证书来阻止必要设备初始化可能会导致某些机器(包括笔记本电脑)上的硬件变砖,从而无法进入固件设置来纠正这种情况。

在配备 TPM 的系统上,可以从 TPM 事件日志中获取 Option ROM SHA256 摘要。

安装 tpm2-toolsdigest-to-efi-sig-listAUR

使用 tpm2_eventlog(1) 读取 /sys/kernel/security/tpm0/binary_bios_measurements 并查找 BOOT_SERVICES_DRIVER 的摘要。[8]

例如

# tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements
...
- EventNum: 9
  PCRIndex: 2
  EventType: EV_EFI_BOOT_SERVICES_DRIVER
  DigestCount: 1
  Digests:
  - AlgorithmId: sha256
    Digest: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
...
- EventNum: 10
  PCRIndex: 2
  EventType: EV_EFI_BOOT_SERVICES_DRIVER
  DigestCount: 1
  Digests:
  - AlgorithmId: sha256
    Digest: "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
...

这将打印一个易于解析的摘要列表

# tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements | grep -o 'Digest: "[a-f0-9]\{64\}"' | sed 's/Digest: "//;s/"$//'

使用 digest-to-efi-sig-listAUR 为您找到的每个 OpROM 摘要创建 EFI 签名列表

$ digest-to-efi-sig-list 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef OpROM1.esl
$ digest-to-efi-sig-list fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 OpROM2.esl

如果您有多个 OpROM,请将它们的 EFI 签名列表合并为一个,以便可以将其作为一个文件签名。

$ cat OpROM1.esl OpROM2.esl > OpROM.esl

如果您有很多摘要,可以使用像这样的 bash 脚本

签署 EFI 签名列表以便附加到签名数据库。

$ sign-efi-sig-list -a -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db OpROM.esl OpROM.auth

注册它.

最终也是最危险的步骤是从签名数据库中删除 Microsoft 第三方 UEFI CA 证书,并查看系统是否仍然启动以及所有设备是否仍然工作。

另请参阅