方案分析
安全启动的实现有两种方法,使用自签名安全证书以及使用经认证的第三方 (微软)证书,下表简单对比了这两种方法的优劣。
方案 | 优势 | 劣势 |
---|---|---|
自建签名 | 可控 无感知 兼容 Windows 安全启动 | 需自建密钥 需修改 BIOS (的证书数据库) 不能复用 |
第三方签名 (PreLoader.efi & shim.efi ) | 方便 不修改 BIOS 设置 复用 | 安装简单,但操作对新手不友好 维护麻烦 GRUB 无法链式加载 EFI 二进制文件 |
第三方签名
这意味着需要使用微软的证书来给引导器签名,或者使用微软签名过的特殊引导器来引导 Bootloader 。
显然我们没法用微软的私钥签名,但是我们可以给我们的引导器套一个微软的壳。
Archwiki1 介绍了两个来自微软的小工具:Preloader
和 shim
。但是,不管用哪个工具都有很大的局限性。
更新系统时繁琐的重签名工作、无法链式启动其他 EFI 工具的致命缺陷让它的功能变得非常的鸡肋。
个人认为这种方法仅适用于需要多设备使用以及不会对 Kernel 和 Bootloader 更新的场景。比如什么电脑都会插的急救盘、自构建的安装盘等。
自建签名
这种方法通用性更强。首次配置较为复杂,但后续的更新维护完全可以实现自动化。只要保留自建签名的私钥,也可以实现在多台设备上复用。
创建自签名证书
安装
efitools
几乎所有的以下部分需要你安装的
efitools
包。生成所有者标识 UUID
uuidgen --random> GUID.txt
生成平台密钥 (PK)
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 rm_PK.auth
生成密钥交换密钥 (KEK)
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
生成签名数据库密钥 (db)
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
这部分也可以使用辅助脚本2。
以上步骤创建了三个自签证书并使用工具将其转化成 EFI 接受的格式。
如果可以自行签发证书或有自建 CA ,也可以使用自己的证书取代之。
操作完成后,一份安全启动需要的自签名证书就完成了。
在固件中注册证书
- 清除 BIOS 原有的密钥数据库,使其进入设置模式
这部分需要进入 BIOS 设置。
由于不同平台的操作方式不同,这步请各位自行探索。
注册密钥。这里有三种方法,各不相同,其中第三种方法最保险,可以通用
- 使用
sbkeysync
3 工具
可能会卡在最后一步注册 PK 文件的时候报错失败。
使用 BIOS 自带工具
不是所有 BIOS 都带有这个功能,没有就是没有。自行探索,不再赘述。
使用
KeyTool
使用自签证书签名
KeyTool
的执行程序,让它在设置模式下能够被引导使用 ROOT 权限执行
sbsign --key db.key --cert db.crt --output ${ESP}/KeyTool-signed.efi /usr/share/efitools/efi/KeyTool.efi
esp 处替换为自己的 BOOT 分区路径。
将之前制作好的 PK, KEK, db 文件复制到 BOOT 分区中
重启并引导签名后的
KeyTool
可以提前添加到启动项也可以使用 Bootloader 的命令行,这里示范使用 GRUB 命令行
search --no-floppy --set=root --file /EFI/KeyTool-signed.efi chainloader /EFI/KeyTool-signed.efi boot
根据图形化界面的指引导入各个数据库
- 使用
签名已有 EFI 引导器和内核
使用 sbsign
签名内核和启动管理器。
用 ROOT 权限执行:
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
也可以顺便签名一下 EFI 文件夹里所有的 EFI 文件。
部署全自动签名 hook
ArchWiki4 介绍了两种方法,手动配置 pacman hook 和使用自动化程序。
hook 和 sbupdate 二选一即可,GRUB 用户推荐使用 hook 。
合并微软签名
可以将微软的公钥并入自己的数据库中,让自签证书兼容 Windows 和 Windows 启动盘的安全启动。
此处参考 ArchWiki5 。
完成之后重启电脑。进入系统后可通过 bootctl status
查看安全启动是否设置成功。
至此,安全启动就设置完成了。
参考资料
https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface/Secure_Boot ↩
https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface/Secure_Boot#Helper_scripts ↩
https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface/Secure_Boot#Using_sbkeysync ↩
https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface/Secure_Boot#Signing_the_kernel_with_a_pacman_hook ↩
https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface/Secure_Boot#Microsoft_Windows ↩