概述
Secure Boot 作为 UEFI 的一个选项,它可以被设置为开启或关闭 ( 有少数的计算机里面, Secure Boot 被设置为开启,却不存在关闭它的选项,但系统主板内置有 Windows 系统的公钥证书签名,使其只能加载 Windows ,其他系统一律不以加载,用户没有选项,不能关闭,还没法换系统,无法适用本博客介绍内容)。 Secure Boot 所需要的公钥证书被保存在计算机的主板的 FLASH 里面(注意不是磁盘里面哦),在主板的一小块 FLASH 里面保存着 PK , KEK, db, dbx 的证书链,所以, 在操作开始前请确保你的计算机 UEFI-BIOS 的 Secure Boot 能够被关闭,否则,发生操作失误,将导致证书不能匹配任何程序代码文件,而使主板拒绝加载任何程序代码文件,就会导致主板变砖 (虽然它不是 BIOS ,但是许多人都这么称呼它为 UEFI-BIOS ,所以,这里也这么称呼其为 UEFI-BIOS) 。
这里说一下 Fedora 是如何做到在 Secure Boot 开启时加载的,它实际上是 Fedora 开源项目向微软公司购买签名达到的, Fedora 被系统的主板识别为和 Windows 一样的系统,这种购买行为在开源社区是不鼓励的,好处是 Fedora 几乎可以在任何可以加载 Windows 系统上被识别加载,即使该计算机硬件不能关闭 Secure Boot。
本人只在 ThinkPad 测试成功,其他机器未曾实验过,不过仅从理论来看,应该也会成功。
工具
以下工具是必不可少的:
- openssl
- efitools
- sbsigntools
如果你是第三方编译好的软件包来安装的,可以忽略此步:
在用源代码编译 efitools 时,需要 Perl 的一个模块,名字为 File Slurp
,在 cpan 可以找到。
预先准备
开机进入系统的 UEFI-BIOS 页面,在安全页面里找到 Secure Boot 选项,先关掉 Secure Boot (如果没有关的话),再删除或清空所有证书文件,使机器从 User Mode
转到 Setup Mode
即为正常,如果这两步不能做到,可能影响到下面的步骤。
步骤
概念介绍
这里简要介绍 PK,KEK,db,dbx 和 MOK 的概念。
Platform Key (PK) - PK 是用于在硬件平台层和硬件平台拥有者建立起的信任关系 ,规定一个硬件平台只能被一个拥有者所拥有,即 PK 只能存在一个 ,与拥有者相关的公钥被存储在 FLASH 里面的 PK 变量里面,同时,拥有者的私钥可以来对 PK, KEK, db, dbx 进行签名和管理。
Key Exchange Key (KEK) - KEK 是用于在硬件平台和操作系统之间建立信任关系 ,KEK 的公钥可以在主板的 FLASH 存在多个不同项,即 KEK 可以存在多个 ,每一项对应一种可以被启动的操作系统,同样,KEK 的私钥可以来对 db, dbx 进行签名和管理。
Database (db) - db 是用于对 被许可的 EFI 文件予以加载的数据签名库 ,和 KEK 一样, db 的公钥可以存在很多项 。(在 UEFI 平台里面,操作系统加载文件就是一个 EFI 文件)
Database Excluded (dbx) - dbx 是一个 黑名单数据签名库 ,只要谁的 EFI 签名在这,谁就被屏蔽掉, dbx 的公钥也可以存在很多项 。
Machine Owner Key (MOK) - MOK 的作用是等价于 db 的,但是它不是标准 Secure Boot 的内容,
PreLoader
和Shim
使用了 MOK 。
建立 PK,KEK,db 密钥对
这里需要 Linux 系统中存在 uuidgen
:
1 | echo $(uuidgen) >guid |
如果你不打算启动 Windows 系统,请忽略文中所有提及有关 Windows 系统的内容
如果系统不存在 uuidgen
,就随便写个 GUID 到那个 guid 文件里,然后把微软的 Owner GUID 写到另外一个文件里:
1 | echo 77fa9abd-0359-4d32-bd60-28f4e78f784b >ms-guid |
建立密钥对:
1 | openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Platform Key/" -keyout PK.key -out PK.crt -days 3650 -nodes -sha256 |
上面的 -subj
的参数可以自己设置,参数 -days
是密钥的有效期,这里设置为 10 年,也可以设置为其他,生成私钥 PK.key
,公钥 PK.crt
。
同理,KEK 和 db 亦是如此:
1 | openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Key Exchange Key/" -keyout KEK.key -out KEK.crt -days 3650 -nodes -sha256 |
这里没有建立 dbx 的黑名单,因为暂时用不到这个,也没有黑名单签名文件,MOK 不通用,亦不讨论
建立 EFI List 文件
EFI List 文件其实就是公钥配以平台拥有者的 GUID 的文件:
1 | cert-to-efi-sig-list -g $(cat guid) PK.crt PK.esl |
这样三个公钥就全变成 List 文件了。
为了能够也启动磁盘里的 Windows 系统,下载三个微软的公钥,一个 KEK,两个 db:
1 | curl -L http://go.microsoft.com/fwlink/?LinkID=321185 -o MSKEK.der |
微软的这三个公钥与这里使用的公钥格式不同,需要重新转换:
1 | openssl x509 -in MSKEK.der -inform DER -out MSKEK.crt |
同样需要转换成 List 文件,不过这里的 GUID 最好用微软 Owner GUID:
1 | cert-to-efi-sig-list -g $(cat ms-guid) MSKEK.crt MSKEK.esl |
在这里需要注意一下,在 ThinkPad 里面,第二次添加 KEK 时(加参数 -a
),会出现失败,我的解决方法是把那些 List 合并成一个 List 文件,即:
1 | cat KEK.esl MSKEK.esl >realKEK.esl |
根据 efitools 的文档,这种 cat 操作是可以完成合并的。
给 List 文件签名
1 | sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.esl.signed |
上述中,平台拥有着的 Key 权限最高,可以对 PK 本身,和 KEK 签名,KEK 是建立操作系统和硬件平台之间的信任关系,它只用于对于 db 进行签名。
给二进制的 EFI 文件签名
这是密钥管理和签名的最后一步,我使用的 grub ,其他的比如 elilo 等等,同理。给 grub 的 EFI 文件签名:
1 | sbsign --key db.key --cert db.crt --output grubx64.efi.signed /boot/efi/EFI/slackware64/grub64.efi |
可以不用给内核 vmlinuz
签名,毕竟 vmlinuz
不是硬件平台的启动 EFI 文件,不过给内核签名也没什么影响,如果想给内核签名类似于给 grub 签名,用 私钥 db.key
及对应的公钥 db.crt
对其签名,这里用的 db 是那个自己创建的 db ,即没有合并微软 db 的那个,合并了微软 db 的是 realDB 。
写入 efivars
到这里是整个过程的最后一步,首先必须保证系统的 efivarfs 被正确挂载,ls
一下 /sys/firmware/efi/efivars/
是否存在文件,有的系统默认挂载 efivarfs ,有的则不是(后续步骤需要切换至 root 用户):
1 | mount -t efivarfs efivarfs /sys/firmware/efi/efivars/ |
再把那三个签过名的 List 文件写入主板:
1 | efi-updatevar -f PK.esl.signed PK |
参考 LinuxQuestions 上的解决方案,使用了在
efi-updatevar
添加-a
参数来表示添加,但是在 ThinkPad 上多次实验第二次皆以Operation not permitted
的错误而中断,所以,合并 EFI List 文件即只需添加一次,就全部都被加上,无需再用-a
来添加。上述的问题很难判断是密钥链的逻辑问题,还是硬件的保护机制,不过用合并这种方法,在 Secure Boot 下,Windows 和 Linux 都可以正常启动,看来没问题。
所有操作都完成后,可以运行 efi-readvar
来查看添加结果。只要 efivarfs 仍然被挂载,即使在非 root 用户也可以查看。
相关链接
from http://hchen90.top/2017/09/02/enablesbonlinux/
No comments:
Post a Comment