统一可扩展固件接口/安全启动
安全启动 (Secure Boot) 是 UEFI 标准中的一项安全功能,旨在为 预启动过程 增加一层保护:通过维护一份经过加密签名的允许或禁止在启动时运行的二进制文件列表,它有助于提高对机器核心启动组件(引导管理器、内核、initramfs)未被篡改的信任度。
因此,它可以被视为对加固计算环境努力的延续或补充,减少了其他软件安全解决方案(如全系统加密)无法轻易覆盖的攻击面,同时它又与这些方案完全不同且互不依赖。安全启动作为当前安全实践的一个组成部分独立存在,有其自身的优点和缺点。
检查安全启动状态
启动操作系统之前
此时必须查看固件设置。如果机器已经启动并正在运行,大多数情况下必须重新启动。
您可以在启动过程中按特殊键进入固件配置界面。使用的按键取决于固件,通常是 Esc、F2、Del 或可能是另一个 Fn 键。有时,正确的按键会在启动过程开始时短暂显示。主板手册通常也会记录该按键。您可能需要在开启机器电源后立即按下并持续按下该键,甚至在屏幕实际显示任何内容之前。
进入固件设置后,请小心不要在没有预先意图的情况下更改任何设置。通常在每个设置屏幕的底部都有导航说明和设置的简短说明。设置本身可能由多个页面组成,您需要导航到正确的位置。相关的设置可能被简单地标注为“Secure Boot”,可以设置为开启(On)或关闭(Off)。
启动操作系统之后
在使用 systemd 的系统上,检查安全启动状态的一种简单方法是使用 bootctl(1)
$ 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 中被移除。当时 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
实施安全启动
要实现理想的安全启动设置,需要满足某些条件:
- UEFI 被认为基本可信(尽管存在一些众所周知的批评和漏洞[1]),并且必须由强密码保护
- 不使用默认的制造商/第三方密钥,因为这些密钥已被证明会大幅削弱安全启动的安全模型[2]
- UEFI 直接加载用户签名的且兼容 EFI 引导存根 的 统一内核镜像(无引导管理器),包含微代码(如果适用)和 initramfs,以便在整个启动过程中维持由安全启动建立的信任链并减少攻击面
- 使用 全盘加密,使得具有物理访问权限的人无法访问或篡改内核镜像创建和签名过程涉及的工具和文件。
- 通过使用 TPM 还可以获得进一步的改进。
#使用自定义密钥 介绍了一种简单且完全自力更生的设置,而 #使用已签名的引导加载程序 则利用了第三方签名的中间工具。
使用 GRUB 引导加载程序在启用安全启动之前需要额外的步骤,详情请参阅 GRUB#安全启动支持。
使用自定义密钥
安全启动实施使用以下密钥:
- 平台密钥 (PK)
- 顶级密钥。
- 密钥交换密钥 (KEK)
- 用于对签名数据库和禁用签名数据库更新进行签名的密钥。
- 签名数据库 (db)
- 包含允许的 EFI 二进制文件的密钥和/或哈希。
- 禁用签名数据库 (dbx)
- 包含黑名单中的 EFI 二进制文件的密钥和/或哈希。
详见 所有 UEFI 密钥的含义。
要使用安全启动,您至少需要 PK、KEK 和 db 密钥。虽然您可以添加多个 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
备份当前变量
在创建新密钥和修改 EFI 变量之前,建议备份当前变量,以便在发生错误时可以恢复。
安装 efitools 软件包,然后运行以下命令备份所有四个主要的安全启动变量
$ for var in PK KEK db dbx ; do efi-readvar -v $var -o old_${var}.esl ; done
如果您在新电脑或主板上执行此命令,提取出的变量很可能是微软提供的那些。
将固件置于“设置模式”
当平台密钥被移除时,安全启动处于“设置模式”。要将固件置于设置模式,请进入固件设置实用程序并寻找删除或清除证书的选项。如何进入设置实用程序在#启动操作系统之前中有描述。
使用 systemd 的辅助流程
从 v257 版本开始,您可以使用 systemd 和 systemd-boot 轻松设置安全启动。请安装 systemd-ukify。
首先按照 统一内核镜像#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
使用新创建的密钥为引导加载程序签名(有关自动化签名请参阅 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.auth、KEK.auth 和 db.auth 三个文件。不会生成单独的平台或密钥交换密钥,而是将签名密钥注册到所有三个级别。
最后,在 /boot/loader/loader.conf 中设置 secure-boot-enroll force,然后重启以在固件中注册密钥。参见 loader.conf(5)。
使用 sbctl 的辅助流程
sbctl 是一种设置安全启动和为文件签名的用户友好方式。
要使用它,请 安装 sbctl。另请参阅 上游 README 和 sbctl(8)。
搭配 GRUB 使用 sbctl
请参阅 GRUB#安全启动支持 获取说明。
创建并注册密钥
在开始之前,进入固件设置并将安全启动模式设置为设置模式 (Setup mode)。不同设备的操作不同:参见 sbctl(8) § 用法。
重新登录后,检查安全启动状态
$ sbctl status
您应该会看到 sbctl 尚未安装且安全启动已禁用。
然后创建您的自定义安全启动密钥
# sbctl create-keys
将您的密钥连同微软的密钥一起注册到 UEFI
# sbctl enroll-keys -m
sbctl enroll-keys。仅在您清楚自己在做什么时才执行此操作。sbctl enroll-keys -m -f再次检查安全启动状态
$ sbctl status
现在应该已安装 sbctl,但安全启动在引导文件使用刚才创建的密钥签名之前不会生效。
签名
检查哪些文件需要签名才能使安全启动工作
# sbctl verify
现在为所有未签名的文件签名。通常 内核 和 引导加载程序 需要签名。例如
# sbctl sign -s /boot/vmlinuz-linux # sbctl sign -s /boot/EFI/BOOT/BOOTX64.EFI
需要签名的文件取决于您的系统布局、内核和引导加载程序。
# 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-boot-update.service,引导加载程序仅在重启后才会更新,因此 sbctl 的 pacman hook 不会为新文件签名。作为变通方法,直接在 /usr/lib/ 中为引导加载程序签名很有用,因为 bootctl install 和 update 会自动识别并将 .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)、sbkeysync、KeyTool 和固件。
创建一个 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"
这将生成不同格式的所需文件。
在固件中注册密钥
使用以下方法之一注册 db、KEK 和 PK 证书。
使用 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 文件的安全位置包括:- 使用
KeyTool时,带有 EFI 系统分区 的外部 USB 闪存盘。不幸的是,KeyTool只能从非加密存储中读取文件。 - 使用
sbkeysync时,您 PC 上的加密存储。
根据 UEFI 规范,您 PC 的 EFI 系统分区 必须是不加密的,且可以在另一台 PC 上挂载并读取(如果您的 PC 被盗且硬盘被取出连接到另一台 PC)。将 noPK.auth 文件拷贝到您 PC 的 ESP 并在之后删除它也是不可取的,因为 FAT32 EFI 系统分区 上已删除的文件可以使用 PhotoRec 等工具恢复。
启动固件设置实用程序并注册 db、KEK 和 PK 证书。固件有各种不同的界面,有关如何注册密钥的示例,请参阅使用固件设置实用程序替换密钥。
如果所使用的工具支持,优先使用 .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.auth、KEK.auth 和 PK.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,例如:
# 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
通过 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 为统一内核镜像签名
使用 sbupdate 全自动生成并签名统一内核
sbupdate 是专门为 Arch Linux 自动化生成并签名统一内核镜像的工具。它通过 pacman hooks 处理内核的安装、移除和更新。
安装 sbupdate-gitAUR 并按照项目主页上的说明进行配置。[4]
OUT_DIR="EFI/Linux" 以便让您的已签名内核镜像被直接识别而无需配置。参见 systemd-boot(7) § 文件 和 systemd-boot#添加加载器。配置完成后,只需以 root 身份运行 sbupdate 即可进行首次镜像生成。
warning: data remaining[26413568 vs 26423180]: gaps between PE/COFF sections? 之类的错误。这些是无害的,可以放心忽略。[5]更新密钥
一旦安全启动处于“用户模式”,对 KEK、db 和 dbx 的任何更改都需要使用更高级别的密钥进行签名。
例如,如果您想用新密钥替换 db 密钥:
- 创建新密钥,
- 将其转换为 EFI 签名列表,
- 对 EFI 签名列表签名,
- 注册已签名的证书更新文件。
$ 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
通常情况下,在启用安全启动模式且未在 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 双启动:
- 您要么必须将
bootmgfw.efi的哈希添加到db变量中的允许哈希列表中;且每次 Windows 更新更改bootmgfw.efi时都必须更新db变量。这非常繁琐且容易出错,且不受微软支持;例如 BitLocker 在这种设置下将无法正常工作(BitLocker 每次都会要求您提供恢复密码来解密 Windows 分区)。 - 要么您必须将微软的证书添加到 UEFI 安全启动变量中。微软有四个 db 证书和两个 KEK 证书:
db变量中必须包含 Microsoft Windows Production PCA 2011 证书 和 Windows UEFI CA 2023,以允许 Windows 操作系统加载。db变量中应包含 Microsoft Corporation UEFI CA 2011 证书 和 Microsoft UEFI CA 2023(即微软第三方 UEFI CA 证书),以便使用第三方二进制文件,如 UEFI 驱动程序、option ROM、shim 等。KEK变量中应包含 Microsoft Corporation KEK CA 2011 证书 和 Microsoft Corporation KEK 2K CA 2023,以便“通过更新dbx来启用对不良镜像的吊销,并可能用于更新db以应对更新的 Windows 签名镜像”。不过,没有它们 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
使用您的 KEK 对 db 变量更新进行签名。使用带 -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 安全启动要求):使用您的 PK 对 KEK 变量更新进行签名。使用带 -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 中,它们就会执行该文件;否则,它们会启动一个密钥管理实用程序,允许用户注册该哈希或密钥。
需要在固件设置中启用微软第三方 UEFI CA 证书的注册,才能运行使用该证书签名的 EFI 二进制文件和 OpROM。
PreLoader
运行时,PreLoader 会尝试启动 loader.efi。如果 loader.efi 的哈希不在 MokList 中,PreLoader 将启动 HashTool.efi。在 HashTool 中,您必须注册您想要运行的 EFI 二进制文件的哈希,这意味着包括您的引导加载程序 (loader.efi) 和内核。
refind-install 脚本可以将 rEFInd 和 PreLoader 的 EFI 二进制文件拷贝到 ESP。参见 rEFInd#使用 PreLoader 获取说明。设置 PreLoader
PreLoader.efi 和 HashTool.efi 未经签名,因此其实用性有限。您可以从 preloader-signedAUR 获取已签名的 PreLoader.efi 和 HashTool.efi,或者手动下载它们。安装 preloader-signedAUR 并将 PreLoader.efi 和 HashTool.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.efi 和 loader.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
bootmgfw.efi,因为替换它可能会导致 Windows 更新出现问题。如前所述,将 HashTool.efi 和 loader.efi 拷贝到 esp/EFI/Microsoft/Boot/。
当系统在启用安全启动的情况下启动时,请按照上述步骤注册 loader.efi 和 /vmlinuz-linux(或正在使用的任何内核镜像)。
启动时如何使用?
系统将显示一条消息:Failed to Start loader... I will now execute HashTool.。按照以下步骤使用 HashTool 注册 loader.efi 和 vmlinuz.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 空间。您可能希望删除无用的哈希以释放空间并防止过时的程序启动。
# 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 命令检查,并在必要时调整启动顺序。
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-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
将 shim 和 MokManager 拷贝到 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
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,删除复制的 shim 和 MokManager 文件,然后将引导加载程序重命名回原样。
保护安全启动
防止具有物理访问权限的任何人禁用安全启动的唯一方法是使用密码保护固件设置。大多数 UEFI 固件都提供此功能,通常在固件设置的“安全”部分下列出。
技巧与提示
重新打包 ISO
可以使用 libisoburn 和 mtools 来解包和重新打包官方安装镜像。这样,您就可以创建一个支持安全启动的镜像,可以使用自定义密钥或签名引导加载程序。
使用自定义密钥签名官方 ISO
可以通过简单地提取引导加载程序 (BOOTx64.EFI 和 BOOTIA32.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。
在具有 TPM 的系统上,可以从 TPM 事件日志 获取 Option ROM SHA256 digests。
安装 tpm2-tools 和 digest-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 证书,然后查看系统是否仍然能够启动并且所有设备是否仍然正常工作。
参见
- tianocore 的 UEFI 安全启动链解析
- Wikipedia:Unified Extensible Firmware Interface#Secure Boot
- Rod Smith 的 处理安全启动
- Rod Smith 的 控制安全启动
- Matthew Garrett 的 UEFI 安全启动 (第二部分)
- James Bottomley 的 UEFI 安全启动
- efitools README
- 自由软件基金会的 您的电脑的“安全启动”会变成“受限启动”吗?
- 自由软件基金会关于考虑安全启动的自由操作系统发行版的建议
- Intel 的 UEFI 安全启动教程
- 安全启动、签名模块和签名 ELF 二进制文件
- 美国国家安全局文档:UEFI 防御实践指南 和非保密的 UEFI 安全启动定制
- Jeremy Kerr 的 sbkeysync & 维护 UEFI 密钥数据库
- 保护您的启动过程:UEFI + Secureboot + EFISTUB + Luks2 + lvm + ArchLinux (2020-07)
- Security StackExchange 上的 如何在带有 UEFI 安全启动的机器上支持休眠?
- Lennart Poettering 的 Linux 上的认证启动和磁盘加密 (2021-09-23)
- 工具 cryptbootAUR 简化了整个过程并且易于使用