4、UEFI安全启动:UEFI Secure Boot原理、PK/KEK/db/dbx数据库、签名与验证流程

UEFI Secure Boot,说白了就是给电脑的启动过程加了一把锁。我刚开始接触这个功能时,觉得它就是个麻烦——动不动就把系统搞黑屏。后来在几个安全合规项目里被折腾过几次,才真正理解了它的价值。

它的核心逻辑其实很简单:只允许运行经过签名的、可信的代码。从固件到引导加载器,再到操作系统内核,每一环都要验明正身。任何一个环节出了问题,启动就会中断。

4.1 核心数据库:PK、KEK、db、dbx

这四个数据库是Secure Boot的命根子。它们存储在主板上的NVRAM里,跟BIOS设置是分开的。我见过不少运维同事误以为清BIOS就能重置Secure Boot,结果发现根本没用——因为这些数据是独立存储的。

数据库 全称 作用 数量
PK Platform Key 平台密钥,最高权限 通常1个
KEK Key Exchange Key 密钥交换密钥,管理db/dbx 可多个
db Signature Database 白名单,允许执行的签名 可多个
dbx Forbidden Signature Database 黑名单,禁止执行的签名 可多个

PK(平台密钥)是老大。它只用来签名KEK的更新。一旦PK被清空或设置为空,Secure Boot就自动进入"设置模式",这时候任何人都可以修改数据库。嗯,这里要注意——很多主板出厂时PK是空的,这就是为什么你买的新电脑默认能装各种系统。

KEK(密钥交换密钥)是管家。它负责签名db和dbx的更新。微软的KEK几乎在所有支持Windows的机器上都存在。我个人习惯在部署Linux时保留微软的KEK,这样万一要双系统启动,不会出问题。

db(签名数据库)是白名单。里面存的是允许执行的签名证书或文件的哈希值。比如微软的Windows引导加载器签名就在这里面。我在项目中遇到过有人误删了db里的微软证书,结果Windows直接启动不了——那叫一个尴尬。

dbx(禁止签名数据库)是黑名单。用来吊销有安全漏洞的引导加载器签名。比如2018年的BootHole漏洞,就是通过更新dbx来封堵的。你想想看,如果没有这个机制,一个被攻破的引导加载器可以一直用下去,那多可怕。

4.2 签名与验证流程

整个验证流程是一个链式结构。我画了一张图帮你理解:

UEFI Secure Boot 签名验证链 UEFI 固件 (BIOS) 验证签名 Boot Manager 验证签名 引导加载器 (shim/GRUB) 验证签名 操作系统内核 PK 验证 KEK 签名 KEK 验证 db/dbx 签名 db 白名单 / dbx 黑名单 内核签名验证

验证流程其实就三步:

  1. 固件启动:UEFI固件先检查Boot Manager的签名是否在db里,且不在dbx里。如果通过,就加载它。
  2. 链式传递:Boot Manager再去验证下一个要加载的程序(比如shim或GRUB)的签名。每一环都用自己的签名证书去验下一环。
  3. 内核加载:最后引导加载器验证操作系统内核的签名。全部通过,系统才能正常启动。

关键点:整个链条上任何一个环节的签名验证失败,启动就会停止。屏幕上通常会显示"Secure Boot Violation"之类的错误信息。

4.3 实际操作中的避坑指南

我在生产环境里踩过不少坑,挑几个典型的说说:

坑1:自己签名的内核启动不了

我曾经自己编译了一个内核,用自己的证书签了名,结果死活启动不了。查了半天才发现——我的证书虽然加到了db里,但签名算法用的是SHA-1,而固件只支持SHA-256。后来换了算法就OK了。

教训:签名前先查一下固件支持的哈希算法,别想当然。

技巧:查看当前Secure Boot状态

在Linux下可以用这个命令:

# 查看Secure Boot是否启用
mokutil --sb-state

# 查看当前db里的证书列表
mokutil --list-enrolled

# 查看dbx里的黑名单
mokutil --list-blacklist

坑2:更新固件后Secure Boot失效

有一次我给服务器更新了BIOS,重启后系统直接进了恢复模式。一查发现Secure Boot被重置成了"设置模式",所有自定义证书都没了。原来那个固件更新把NVRAM给清空了。

教训:更新固件前,先用efibootmgr导出当前的Secure Boot配置。更新完再导回去。

4.4 签名工具与操作示例

实际操作中,最常用的工具是sbsigntool和sign-efi-sig-list。我一般这么用:

# 1. 生成自己的签名证书
openssl req -new -x509 -newkey rsa:2048 -keyout my.key \
    -out my.crt -days 3650 -subj "/CN=My Secure Boot Key/"

# 2. 用证书签名EFI文件
sbsign --key my.key --cert my.crt --output /boot/efi/EFI/BOOT/grubx64.efi.signed \
    /boot/efi/EFI/BOOT/grubx64.efi

# 3. 将证书导入到db数据库
mokutil --import my.crt

# 4. 重启后按提示完成证书注册
reboot

这里有个细节——mokutil导入证书后,重启时会进入MOK管理界面,需要手动确认。我第一次用的时候不知道,重启后傻等了半天,以为系统卡死了。其实只要按几个键确认就行。

4.5 关于shim的补充说明

说到Linux下的Secure Boot,就绕不开shim。它是一个微小的引导加载器,由微软签名,然后用来加载GRUB。为什么要多这一层?因为GRUB的签名证书变更比较频繁,每次变更都要找微软签名太麻烦。shim的证书相对稳定,用它来验GRUB就灵活多了。

我在项目中遇到过shim版本不匹配的问题。比如系统里装的是shim 15.4,但GRUB是15.6编译的,结果shim验GRUB签名时失败。解决办法就是保持shim和GRUB版本一致,或者用sbverify先检查一下签名是否匹配:

# 检查GRUB的签名是否被shim的证书验证
sbverify --cert /usr/share/shim/shim.cer /boot/efi/EFI/centos/grubx64.efi

一句话总结:Secure Boot就是个信任链,从固件到内核,每一环都要验明正身。PK是根信任,KEK管更新,db/dbx管执行权限。配置时注意算法兼容性,更新固件前记得备份配置。

可可精品资料库