跳转至内容

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

来自 ArchWiki

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

因此,它可以被视为对加固计算环境努力的延续或补充,减少了其他软件安全解决方案(如全系统加密)无法轻易覆盖的攻击面,同时它又与这些方案完全不同且互不依赖。安全启动作为当前安全实践的一个组成部分独立存在,有其自身的优点和缺点

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

检查安全启动状态

启动操作系统之前

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

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

进入固件设置后,请小心不要在没有预先意图的情况下更改任何设置。通常在每个设置屏幕的底部都有导航说明和设置的简短说明。设置本身可能由多个页面组成,您需要导航到正确的位置。相关的设置可能被简单地标注为“Secure Boot”,可以设置为开启(On)或关闭(Off)。

启动操作系统之后

在使用 systemd 的系统上,检查安全启动状态的一种简单方法是使用 bootctl(1)

注意: 运行此命令不需要使用 systemd-boot 作为引导管理器,它更类似于其他 systemd 的 *ctl 实用程序(如 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
...

在这里我们可以看到安全启动已启用并强制执行(处于用户模式);其他可能的值包括: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

但请注意,如果使用的引导加载程序功能不足,即使固件中启用了安全启动,内核也可能无法感知到它。这可以通过在系统启动后不久检查内核消息来验证

# journalctl -kg 'secure boot'
kernel: Secure boot disabled
kernel: Secure boot could not be determined

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

启动安装介质

官方安装镜像不支持安全启动(archlinux/archiso#69)。安全启动支持最初在 archlinux-2013.07.01-dual.iso 中添加,后来在 archlinux-2016.06.01-dual.iso 中被移除。当时 prebootloaderefitools 取代,尽管后者使用的是未签名的 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)来更新密钥。平台密钥可以对其自身进行签名。

确定 OpROM 签名

按照以下步骤检查您是否有任何已签名的 OpROM。

列出所有带有 OpROM 的设备

$ find /sys/devices/ -name rom
/sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom
 ...

这显示了一个带有已签名 EFI ROM 的 Intel 数据中心 SSD 示例。对每个设备重复以下步骤。

$ lspci -s 81:00.0
81:00.0 Non-Volatile memory controller: Intel Corporation PCIe Data Center SSD (rev 01)

转储 ROM

# echo 1 > /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom
# cat /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom > ~/intel_ssd.rom
# echo 0 > /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom

获取并编译 TianoCore 的 EDK II 工具

$ make -C BaseTools

解析 ROM 文件

$ ./BaseTools/Source/C/bin/EfiRom -d ~/intel_ssd.rom
Image 1 -- Offset 0x0
  ROM header contents
    Signature              0xAA55
    PCIR offset            0x001C
    Signature               PCIR
    Vendor ID               0x8086
    Device ID               0x0953
    Length                  0x001C
    Revision                0x0003
    DeviceListOffset        0x00
    Class Code              0x000000
    Image size              0x6A00
    Code revision:          0x0000
    MaxRuntimeImageLength   0x00
    ConfigUtilityCodeHeaderOffset 0x00
    DMTFCLPEntryPointOffset 0x00
    Indicator               0x80   (last image)
    Code type               0x03   (EFI image)
  EFI ROM header contents
    EFI Signature          0x0EF1
    Compression Type       0x0001 (compressed)
    Machine type           0x8664 (X64)
    Subsystem              0x000B (EFI boot service driver)
    EFI image offset       0x0038 (@0x38)

这表明 OpROM 在 Offset 0x0 的 Image 1 的偏移量 0x0038 处有一个压缩的 EFI 镜像。

提取 EFI 部分

$ dd if=intel_ssd.rom ibs=1 skip=$(( 0x00 + 0x38 )) of=intel_ssd.rom.efi.compressed

解压镜像

$ ./BaseTools/Source/C/bin/TianoCompress -d --uefi -v ~/intel_ssd.rom.efi.compressed -o ~/intel_ssd.rom.efi
$ file ../intel_ssd.rom.efi
../intel_ssd.rom.efi: PE32+ executable for EFI (boot service driver), x86-64, 6 sections

使用 sbsigntools 检查签名,您可以看到它是用微软的 DB 证书签名的

$ sbverify --list ~/intel_ssd.rom.efi
signature 1
image signature issuers:
 - /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation UEFI CA 2011
image signature certificates:
 - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=MOPR/CN=Microsoft Windows UEFI Driver Publisher
   issuer:  /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation UEFI CA 2011
 - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation UEFI CA 2011
   issuer:  /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation Third Party Marketplace Root
警告: 为了避免设备软变砖,如果您发现显卡带有已签名的 ROM,请确保在注册您自己的密钥后,您的安全启动 DB 仍保留必要的发行者。

备份当前变量

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

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

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

如果您在新电脑或主板上执行此命令,提取出的变量很可能是微软提供的那些。

将固件置于“设置模式”

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

使用 systemd 的辅助流程

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

注意: 此方法不包含微软的证书。参见 #注册 Option ROM 摘要#与其他操作系统双启动

首先按照 统一内核镜像#ukify 设置所需的配置(可以使用 /usr/lib/kernel/uki.conf 中的模板),然后生成您的签名密钥

# ukify genkey --config /etc/kernel/uki.conf
Using config file: /etc/kernel/uki.conf
Writing SecureBoot private key to /etc/kernel/secure-boot-private-key.pem
Writing SecureBoot certificate to /etc/kernel/secure-boot-certificate.pem
提示: kernel-install 将自动使用此配置为 UKI 签名。

使用新创建的密钥为引导加载程序签名(有关自动化签名请参阅 systemd-boot#为安全启动签名

# /usr/lib/systemd/systemd-sbsign sign \
--private-key /etc/kernel/secure-boot-private-key.pem \
--certificate /etc/kernel/secure-boot-certificate.pem \
--output /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed \
/usr/lib/systemd/boot/efi/systemd-bootx64.efi

接下来,为自动注册配置 ESP

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

这会将已签名的 systemd-boot 引导加载程序安装(或更新)到 ESP,并在 /boot/loader/keys/auto/ 中创建 PK.authKEK.authdb.auth 三个文件。不会生成单独的平台或密钥交换密钥,而是将签名密钥注册到所有三个级别。

最后,在 /boot/loader/loader.conf 中设置 secure-boot-enroll force,然后重启以在固件中注册密钥。参见 loader.conf(5)

使用 sbctl 的辅助流程

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

注意: sbctl 并不适用于所有硬件,其效果取决于制造商。

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

搭配 GRUB 使用 sbctl

请参阅 GRUB#安全启动支持 获取说明。

创建并注册密钥

在开始之前,进入固件设置并将安全启动模式设置为设置模式 (Setup mode)。不同设备的操作不同:参见 sbctl(8) § 用法

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

$ sbctl status

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

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

# sbctl create-keys

将您的密钥连同微软的密钥一起注册到 UEFI

# sbctl enroll-keys -m
警告: 启用安全启动时,某些固件使用微软密钥进行签名和验证。未验证设备可能会导致其变砖。要在不注册微软密钥的情况下注册您的密钥,请运行:sbctl enroll-keys。仅在您清楚自己在做什么时才执行此操作。
注意: 对于某些 PC(例如 Framework 笔记本电脑),如果您想保留升级固件和运行 OEM 提供的其他引导应用程序的能力,建议也包含 OEM 固件内置的证书。在这种情况下,请改为运行:sbctl enroll-keys -m -f

再次检查安全启动状态

$ 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 软件包。

创建密钥

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

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

创建一个 GUID 用于所有者识别

$ uuidgen --random > GUID.txt

平台密钥 (PK)

$ openssl req -newkey rsa:4096 -noenc -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

密钥交换密钥 (KEK)

$ openssl req -newkey rsa:4096 -noenc -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

签名数据库密钥 (db)

$ openssl req -newkey rsa:4096 -noenc -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

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

# 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 返回写入错误,请在发出 sbkeysync 命令之前先运行 chattr -i /sys/firmware/efi/efivars/{PK,KEK,db}*,以临时更改文件属性,从而实现在 efivars 目录内写入 EFI 密钥。参见 chattr(1)
  • 如果 PK.auth 出现 permission denied 错误,您可以使用命令 efi-updatevar -f /etc/secureboot/keys/PK/PK.auth PK 来注册它。
  • 如果失败,可能是由于固件锁定了 BIOS 设置。在戴尔或联想系统上,您可能需要重置 BIOS 密码。参见 sysfs 固件属性身份验证文档

在联想系统上

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

在戴尔系统上

# 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 规范,您 PC 的 EFI 系统分区 必须是不加密的,且可以在另一台 PC 上挂载并读取(如果您的 PC 被盗且硬盘被取出连接到另一台 PC)。将 noPK.auth 文件拷贝到您 PC 的 ESP 并在之后删除它也是不可取的,因为 FAT32 EFI 系统分区 上已删除的文件可以使用 PhotoRec 等工具恢复

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

如果所使用的工具支持,优先使用 .auth.esl 而非 .cer

使用 KeyTool

本文或本章节已过时。

原因: efitools 1.9.2-6 不再附带 EFI 二进制文件。已在 archlinux/packaging/packages/efitools#3 中向维护者反映。(在 Talk:Unified Extensible Firmware Interface/Secure Boot 中讨论)

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#使用自定义密钥 获取说明。
注意: 如果运行 sbsign 时不带 --output,生成的文件将为 文件名.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 post hook 为内核签名

您还可以使用 mkinitcpio post hook 在生成 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 hook 半自动地执行此任务。

通过 mkinitcpio post hook 为统一内核镜像签名

参见 统一内核镜像#为安全启动签署 UKI

使用 sbupdate 全自动生成并签名统一内核

本文或本章节已过时。

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

sbupdate 是专门为 Arch Linux 自动化生成并签名统一内核镜像的工具。它通过 pacman hooks 处理内核的安装、移除和更新。

安装 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 引导加载程序来启动它?(在 Talk:Unified Extensible Firmware Interface/Secure Boot#使用自定义引导加载程序签名启动 Windows 中讨论)

通常情况下,在启用安全启动模式且未在 UEFI 安全启动变量中注册“Microsoft Windows Production PCA 2011”密钥时,无法通过使用自定义个人密钥签署 Windows 引导加载程序 (EFI/Microsoft/Boot/bootmgfw.efi) 来启动它:

  • 如果 bootmgfw.efi 同时包含来自“Microsoft Windows Production PCA 2011”和您自己的安全启动 db 密钥的签名(即两个签名),则某些 UEFI 固件实施(如 INSYDE Corp. 4096.01)将不会运行 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 双启动

使用微软的 GUID (77fa9abd-0359-4d32-bd60-28f4e78f784b) 从微软的 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

可选(为了严格符合微软 UEFI 安全启动要求):使用微软的 GUID (77fa9abd-0359-4d32-bd60-28f4e78f784b) 从微软的 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

使用您的 KEKdb 变量更新进行签名。使用带 -a 选项的 sign-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

可选(为了严格符合微软 UEFI 安全启动要求):使用您的 PKKEK 变量更新进行签名。使用带 -a 选项的 sign-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 以及(为了严格符合要求)add_MS_Win_KEK.auth 注册到 UEFI 安全启动数据库变量中。

使用已签名的引导加载程序

使用已签名的引导加载程序意味着使用由微软密钥签名的引导加载程序。目前有两种已知的已签名引导加载程序:PreLoader 和 shim。它们的目的是链式加载其他 EFI 二进制文件(通常是引导加载程序)。由于微软绝不会签名一个会自动运行任何未签名二进制文件的引导加载程序,因此 PreLoader 和 shim 使用名为机器所有者密钥列表(Machine Owner Key list,简称 MokList)的允许列表。如果二进制文件的 SHA256 哈希(Preloader 和 shim)或签名该文件的密钥(shim)在 MokList 中,它们就会执行该文件;否则,它们会启动一个密钥管理实用程序,允许用户注册该哈希或密钥。

警告: 微软所谓的“受保护内核电脑 (Secured-core PCs)”在出厂时未注册微软第三方 UEFI CA 证书(Microsoft Corporation UEFI CA 2011 或 Microsoft UEFI CA 2023)[6]。唯一注册的 DB 证书是 Microsoft Windows Production PCA 2011 证书,它专门用于签署 Windows 引导加载程序。

需要在固件设置中启用微软第三方 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 Hash 并选择 archiso 进入 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

运行时,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 的文件。虽然可以通过将指向不同 EFI 二进制文件的文件路径作为命令行参数传递给 shim 来覆盖此默认设置,但由于某些固件对带有命令行参数的 UEFI 启动项支持存在问题,因此依赖默认设置更为保险。

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

shimMokManager 拷贝到 ESP 上的引导加载程序目录;将 shimx64.efi 重命名为您引导加载程序之前的名称

注意: 除非您确实有一个有效的 bootx64.csv 可供使用,否则请确保不要拷贝 fbx64.efi(位于同一目录下)。否则 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 可以通过存储在 MokList 中的机器所有者密钥或哈希来验证二进制文件。

机器所有者密钥 (MOK)
用户生成并用于签署 EFI 二进制文件的密钥。
哈希 (hash)
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

创建机器所有者密钥 (MOK)

$ 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 似乎不支持在 MokList 中添加 4096 位的 RSA 密钥(在加载和验证 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 post hook 自动化内核签名。创建以下文件并使其可执行

/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,引导加载程序将启动,并能够启动任何使用您的机器所有者密钥签名的二进制文件。

shim 配合密钥和 GRUB

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

删除已注册的哈希/密钥

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

可以使用 mokutil 来管理 MOK 数据库。

列出已注册的密钥和哈希

# 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 添加对自定义密钥的安全启动支持。按照下面的步骤进行,或使用 gsai-gitAUR 进行自动化替代。

首先提取相关文件和 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-rock(由 mkarchiso 使用)使 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

用 PreLoader 替换 BOOTx64.efi 文件

$ 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 对官方 ISO 进行签名以用于 shim

通过提取引导加载程序、内核和 UEFI Shell,对它们进行签名,然后用签名文件和 shim 重新打包 ISO,可以为官方 ISO 添加对带 Machine Owner Key (MOK) 的 shim 的安全启动支持。

首先提取相关文件和 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-rock(由 mkarchiso 使用)使 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 启动时,选择 从磁盘注册密钥 > ARCHISO_EFI > MOK.cer。注册密钥后,重启,下次启动时,Live 环境将成功启动。

注册 Option ROM digests

Option ROMs (OpROMs),即在启动期间执行的设备固件,必须进行安全启动签名,否则设备将无法初始化。通常 OpROMs 使用 Microsoft 3rd Party UEFI CA 证书签名,这可能会阻止仅使用您自己的密钥实现安全启动。为了解决这个问题,可以改而注册 OpROMs 的 SHA256 digests。

警告 移除 Microsoft 3rd Party UEFI CA 证书会导致重要设备无法初始化,从而可能导致某些机器(包括笔记本电脑)变砖,无法进入固件设置进行修复。

在具有 TPM 的系统上,可以从 TPM 事件日志 获取 Option ROM SHA256 digests。

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

使用 tpm2_eventlog(1) 读取 /sys/kernel/security/tpm0/binary_bios_measurements 并查找 BOOT_SERVICES_DRIVER 的 digests。[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"
...

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

# 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 digest 创建一个 EFI 签名列表

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

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

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

如果您有很多 digests,可以使用 类似这样的 bash 脚本

签名 EFI 签名列表以追加到签名数据库

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

注册它.

最后一步也是最危险的一步是:从签名数据库中删除 Microsoft 3rd Party UEFI CA 证书,然后查看系统是否仍然能够启动并且所有设备是否仍然正常工作。

参见