国密安全启动:UEFI Secure Boot 中 SM2/SM3 签名验证的部署与实践
前言
2024 年,一篇题为《微软掌控的UEFI CA,正在卡国产供应链脖子》的文章引发了行业广泛讨论。问题的核心在于:UEFI Secure Boot 的证书体系由微软主导的 UEFI CA 控制,国产操作系统和固件的签名依赖外部 CA 签发,一旦供应链受阻,系统更新和部署就会陷入被动。
与此同时,随着 GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》的落地,以及密评(密码应用安全性评估)对固件安全启动的要求日趋明确,越来越多的企业需要在 UEFI Secure Boot 中构建基于国密算法(SM2/SM3)的自主可控信任链。
本文基于 openEuler 22.03 LTS 和 openAnolis 国密安全启动白皮书,给出完整的部署方案:
- 国密 PKI 证书链:建立根 CA → 中间 CA → 签名证书的三级体系
- 固件签名:用 sbsigntools 对 shim、grub2、内核进行 SM2-SM3 签名
- UEFI 安全启动:部署国密 PK/KEK/DB,实现固件级 SM2 签名验证
- 安全策略更新:国密签名的 DBX 黑名单更新机制
- 踩坑记录:实际部署中的典型问题与解决方案
⚠️ 安全警告:安全启动密钥(尤其是 PK)一旦烧录到固件中,通常不可更改。操作失误可能导致设备无法启动。请在测试环境中充分验证后再部署到生产环境。
一、UEFI Secure Boot 与国密算法
1.1 UEFI Secure Boot 信任链
┌──────────────────────────────────────────────────────────────────┐
│ UEFI Secure Boot 信任链 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │
│ │ PK │───▶│ KEK │───▶│ DB │───▶│ 固件/引导程序 │ │
│ │ 平台密钥 │ │ 密钥交换 │ │ 签名数据库│ │ 签名验证 │ │
│ └─────────┘ └─────────┘ └─────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ SM2 公钥 SM2 公钥 SM2 签名 │
│ (OTP 烧录) (固件更新) (白名单/黑名单) │
│ │
│ ┌─────────┐ │
│ │ DBX │───▶ 吊销的签名黑名单 │
│ └─────────┘ │
└──────────────────────────────────────────────────────────────────┘UEFI Secure Boot 的四个核心密钥数据库:
| 密钥/数据库 | 作用 | 更新方式 | 国密适配 |
|---|---|---|---|
| PK (Platform Key) | 平台根信任锚,控制 KEK 更新 | 固件 OTP 烧录,通常不可更改 | SM2-256 公钥 |
| KEK (Key Exchange Key) | 控制 DB/DBX 更新的签名密钥 | 通过 PK 签名的更新包 | SM2-256 公钥 |
| DB (Signature Database) | 允许执行的签名白名单 | 通过 KEK 签名的更新包 | SM2-SM3 签名列表 |
| DBX (Forbidden Database) | 吊销的签名黑名单 | 通过 KEK 签名的更新包 | SM2-SM3 签名列表 |
1.2 国密算法在 Secure Boot 中的映射
| 标准 UEFI 算法 | 国密替代 | 说明 |
|---|---|---|
| SHA-256 (Hash) | SM3 | 固件镜像摘要算法 |
| RSA-2048/3072 签名 | SM2-256 签名 | 证书和签名验证 |
| PKCS#7 Signed Data | GM/T 0010 SM2 签名消息语法 | 签名数据格式 |
| ECDSA (可选) | SM2 数字签名 | GM/T 0003.2 |
关键标准:GM/T 0010-2023《SM2密码算法加密签名消息语法规范》定义了国密 SM2 签名的消息格式,与 PKCS#7 兼容但使用 SM3 替代 SHA-256。
1.3 现有 UEFI Secure Boot 的国密局限性
根据 openAnolis 国密安全启动白皮书的分析,标准 UEFI Secure Boot 存在以下国密兼容性问题:
- Hash 算法限制:UEFI 规范仅支持 SHA-224/256/384/512,不原生支持 SM3
- 签名格式不兼容:仅支持 PKCS#7 Signed Data,不兼容 GM/T 0010 定义的 SM2 签名格式
- PKI 依赖外部 CA:UEFI CA 由微软主导,无法自主控制
- 缺乏国密优先级:白名单中所有证书处于相同等级,无法强制国密验证
二、环境准备
2.1 硬件与软件环境
| 组件 | 版本/型号 | 说明 |
|---|---|---|
| 服务器 | 华为 TaiShan 200 / 浪潮 K1 Power | 支持 UEFI Secure Boot |
| UEFI 固件 | edk2 (支持国密 SM2 编译选项) | 需编译启用国密支持的固件 |
| 操作系统 | openEuler 22.03 LTS / openAnolis 8 | 已集成国密安全启动组件 |
| sbsigntools | 0.9.3+ | 国密签名工具 |
| shim | 15.4+ (国密版) | 支持 SM2 验签的 shim |
| grub2 | 2.06+ (国密版) | 支持 SM2 验签的 grub2 |
| 国密 CA 工具 | 自研 / 三未信安 / 江南天安 | 签发国密证书 |
2.2 编译支持国密的 edk2 固件
# 克隆 edk2 源码
git clone https://github.com/tianocore/edk2.git
cd edk2
git submodule update --init --recursive
# 安装编译依赖
sudo dnf install gcc g++ make uuid-devel nasm acpica-tools python3
# 初始化编译环境
make -C BaseTools
source edksetup.sh
# 修改编译配置,启用国密算法
# 在 Conf/target.txt 中设置:
# ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
# TOOL_CHAIN_TAG = GCC5
# 编译 OVMF (虚拟机固件,物理机需适配具体平台)
build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc注意:物理服务器的固件编译需要参考具体硬件厂商的开发手册。华为 TaiShan 和浪潮等厂商通常提供已集成国密支持的固件版本,可直接联系厂商获取。
2.3 安装国密版 shim 和 grub2
# openEuler 22.03 已集成国密安全启动组件
sudo dnf install shim-signed grub2-efi-x64 sbsigntools
# 验证 shim 是否支持国密
pesign -S -i /boot/efi/EFI/centos/shimx64.efi | grep -i "digest"
# 应看到 SM3 相关的摘要信息
# 验证 sbsigntools 版本和支持的算法
sbsign --version
sbsign --list-algorithms
# 应包含 SM2 和 SM3 相关选项三、国密 PKI 证书链建立
3.1 证书链架构
┌─────────────────────────────────────────────────────┐
│ 国密 Secure Boot 证书链 │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 国密根 CA (Root CA) │ │
│ │ CN=GM Secure Boot Root CA │ │
│ │ 算法: SM2-256 + SM3 │ │
│ │ 有效期: 20年 │ │
│ │ 用途: 签发中间 CA │ │
│ └──────────────────┬──────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 国密中间 CA (Issuing CA) │ │
│ │ CN=GM Secure Boot Issuing CA │ │
│ │ 算法: SM2-256 + SM3 │ │
│ │ 有效期: 10年 │ │
│ │ 用途: 签发固件签名证书 │ │
│ └──────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────┼──────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ PK 证书 │ │ KEK 证书 │ │ DB 证书 │ │
│ │ 平台密钥 │ │ 密钥交换 │ │ 签名证书 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────┘3.2 生成国密根 CA
#!/bin/bash
# generate_gm_secure_boot_ca.sh
# 生成国密 Secure Boot 证书链
set -euo pipefail
CA_DIR="/root/gm-secure-boot-ca"
mkdir -p "${CA_DIR}"/{root-ca,issuing-ca,certs}
# 使用 gmssl 生成 SM2 密钥和证书
GMSSL="gmssl"
# ---- 1. 生成根 CA ----
echo "=== 生成国密根 CA ==="
# 生成 SM2 私钥
${GMSSL} ecparam -genkey -name sm2p256v1 -out "${CA_DIR}/root-ca/sm2-root-ca.key"
# 生成自签名根 CA 证书 (20年有效期)
${GMSSL} req -new -x509 -sm3 \
-key "${CA_DIR}/root-ca/sm2-root-ca.key" \
-out "${CA_DIR}/root-ca/sm2-root-ca.crt" \
-days 7300 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=GM Secure Boot Root CA" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,keyCertSign,cRLSign"
echo "根 CA 证书指纹:"
${GMSSL} x509 -in "${CA_DIR}/root-ca/sm2-root-ca.crt" -noout -sm3 -fingerprint
# ---- 2. 生成中间 CA ----
echo "=== 生成国密中间 CA ==="
${GMSSL} ecparam -genkey -name sm2p256v1 -out "${CA_DIR}/issuing-ca/sm2-issuing-ca.key"
# 生成 CSR
${GMSSL} req -new -sm3 \
-key "${CA_DIR}/issuing-ca/sm2-issuing-ca.key" \
-out "${CA_DIR}/issuing-ca/sm2-issuing-ca.csr" \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=GM Secure Boot Issuing CA"
# 根 CA 签发中间 CA 证书 (10年有效期)
${GMSSL} x509 -req -sm3 \
-in "${CA_DIR}/issuing-ca/sm2-issuing-ca.csr" \
-CA "${CA_DIR}/root-ca/sm2-root-ca.crt" \
-CAkey "${CA_DIR}/root-ca/sm2-root-ca.key" \
-CAcreateserial \
-out "${CA_DIR}/issuing-ca/sm2-issuing-ca.crt" \
-days 3650 \
-extfile <(printf "basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign")
echo "中间 CA 证书指纹:"
${GMSSL} x509 -in "${CA_DIR}/issuing-ca/sm2-issuing-ca.crt" -noout -sm3 -fingerprint
echo "=== 证书链验证 ==="
${GMSSL} verify -CAfile "${CA_DIR}/root-ca/sm2-root-ca.crt" \
"${CA_DIR}/issuing-ca/sm2-issuing-ca.crt"
echo "=== 证书链生成完成 ==="
echo "根 CA: ${CA_DIR}/root-ca/sm2-root-ca.crt"
echo "中间 CA: ${CA_DIR}/issuing-ca/sm2-issuing-ca.crt"3.3 生成 PK/KEK/DB 证书
#!/bin/bash
# generate_gm_sb_certs.sh
# 生成 Secure Boot 所需的 PK、KEK、DB 证书
set -euo pipefail
CA_DIR="/root/gm-secure-boot-ca"
CERTS_DIR="${CA_DIR}/certs"
mkdir -p "${CERTS_DIR}"
GMSSL="gmssl"
ISSUING_CA_KEY="${CA_DIR}/issuing-ca/sm2-issuing-ca.key"
ISSUING_CA_CRT="${CA_DIR}/issuing-ca/sm2-issuing-ca.crt"
# ---- 1. 生成 PK (Platform Key) ----
echo "=== 生成 PK 证书 ==="
${GMSSL} ecparam -genkey -name sm2p256v1 -out "${CERTS_DIR}/sm2-pk.key"
${GMSSL} req -new -sm3 \
-key "${CERTS_DIR}/sm2-pk.key" \
-out "${CERTS_DIR}/sm2-pk.csr" \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=GM Platform Key"
${GMSSL} x509 -req -sm3 \
-in "${CERTS_DIR}/sm2-pk.csr" \
-CA "${ISSUING_CA_CRT}" \
-CAkey "${ISSUING_CA_KEY}" \
-CAcreateserial \
-out "${CERTS_DIR}/sm2-pk.crt" \
-days 3650 \
-extfile <(printf "basicConstraints=CA:FALSE\nkeyUsage=critical,digitalSignature\nextendedKeyUsage=1.3.6.1.4.1.311.10.3.13")
# ---- 2. 生成 KEK (Key Exchange Key) ----
echo "=== 生成 KEK 证书 ==="
${GMSSL} ecparam -genkey -name sm2p256v1 -out "${CERTS_DIR}/sm2-kek.key"
${GMSSL} req -new -sm3 \
-key "${CERTS_DIR}/sm2-kek.key" \
-out "${CERTS_DIR}/sm2-kek.csr" \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=GM Key Exchange Key"
${GMSSL} x509 -req -sm3 \
-in "${CERTS_DIR}/sm2-kek.csr" \
-CA "${ISSUING_CA_CRT}" \
-CAkey "${ISSUING_CA_KEY}" \
-CAcreateserial \
-out "${CERTS_DIR}/sm2-kek.crt" \
-days 3650 \
-extfile <(printf "basicConstraints=CA:FALSE\nkeyUsage=critical,digitalSignature\nextendedKeyUsage=1.3.6.1.4.1.311.10.3.9")
# ---- 3. 生成 DB 签名证书 ----
echo "=== 生成 DB 签名证书 ==="
${GMSSL} ecparam -genkey -name sm2p256v1 -out "${CERTS_DIR}/sm2-db.key"
${GMSSL} req -new -sm3 \
-key "${CERTS_DIR}/sm2-db.key" \
-out "${CERTS_DIR}/sm2-db.csr" \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=GM Signature Database Key"
${GMSSL} x509 -req -sm3 \
-in "${CERTS_DIR}/sm2-db.csr" \
-CA "${ISSUING_CA_CRT}" \
-CAkey "${ISSUING_CA_KEY}" \
-CAcreateserial \
-out "${CERTS_DIR}/sm2-db.crt" \
-days 1825 \
-extfile <(printf "basicConstraints=CA:FALSE\nkeyUsage=critical,digitalSignature\nextendedKeyUsage=1.3.6.1.4.1.311.10.3.32")
echo "=== 所有 Secure Boot 证书生成完成 ==="
ls -la "${CERTS_DIR}"/*.crt四、固件镜像签名
4.1 签名工具链
国密固件签名使用 sbsigntools 的 SM2 支持版本。签名流程:
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 内核镜像 │───▶│ SM3 摘要 │───▶│ SM2 签名 │───▶│ 签名镜像 │
│ vmlinuz │ │ (Hash) │ │ (Sign) │ │ .signed │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
│
▼
┌────────────┐
│ DB 私钥 │
│ sm2-db.key │
└────────────┘4.2 签名脚本
#!/bin/bash
# sign_gm_firmware.sh
# 对引导组件进行国密 SM2-SM3 签名
set -euo pipefail
CA_DIR="/root/gm-secure-boot-ca"
DB_KEY="${CA_DIR}/certs/sm2-db.key"
DB_CERT="${CA_DIR}/certs/sm2-db.crt"
KERNEL_DIR="/boot"
SIGN_DIR="/root/signed-firmware"
mkdir -p "${SIGN_DIR}"
# 签名内核镜像
echo "=== 签名内核镜像 ==="
for kernel in "${KERNEL_DIR}"/vmlinuz-*; do
kernel_name=$(basename "${kernel}")
echo "签名: ${kernel_name}"
sbsign --key "${DB_KEY}" --cert "${DB_CERT}" \
--output "${SIGN_DIR}/${kernel_name}.signed" \
"${kernel}"
# 验证签名
sbverify --cert "${DB_CERT}" "${SIGN_DIR}/${kernel_name}.signed"
echo "✓ ${kernel_name} 签名验证通过"
done
# 签名 shim 引导程序
echo "=== 签名 shim ==="
sbsign --key "${DB_KEY}" --cert "${DB_CERT}" \
--output "${SIGN_DIR}/shimx64.efi.signed" \
/boot/efi/EFI/centos/shimx64.efi
sbverify --cert "${DB_CERT}" "${SIGN_DIR}/shimx64.efi.signed"
echo "✓ shim 签名验证通过"
# 签名 grub2
echo "=== 签名 grub2 ==="
sbsign --key "${DB_KEY}" --cert "${DB_CERT}" \
--output "${SIGN_DIR}/grubx64.efi.signed" \
/boot/efi/EFI/centos/grubx64.efi
sbverify --cert "${DB_CERT}" "${SIGN_DIR}/grubx64.efi.signed"
echo "✓ grub2 签名验证通过"
echo "=== 所有固件签名完成 ==="
ls -la "${SIGN_DIR}"/*.signed4.3 部署签名后的固件
#!/bin/bash
# deploy_signed_firmware.sh
# 部署签名后的固件到 EFI 系统分区
set -euo pipefail
SIGN_DIR="/root/signed-firmware"
EFI_DIR="/boot/efi/EFI/centos"
# 备份原始固件
echo "=== 备份原始固件 ==="
cp "${EFI_DIR}/shimx64.efi" "${EFI_DIR}/shimx64.efi.bak"
cp "${EFI_DIR}/grubx64.efi" "${EFI_DIR}/grubx64.efi.bak"
# 部署签名固件
echo "=== 部署签名固件 ==="
cp "${SIGN_DIR}/shimx64.efi.signed" "${EFI_DIR}/shimx64.efi"
cp "${SIGN_DIR}/grubx64.efi.signed" "${EFI_DIR}/grubx64.efi"
# 部署签名内核
echo "=== 部署签名内核 ==="
cp "${SIGN_DIR}"/vmlinuz-*.signed /boot/
# 更新 fstab 中的内核引用(如果需要)
echo "=== 固件部署完成 ==="
echo "请重启系统验证安全启动"五、UEFI 安全启动部署
5.1 准备密钥数据库
#!/bin/bash
# prepare_sb_databases.sh
# 准备国密 Secure Boot 的 PK/KEK/DB 数据库
set -euo pipefail
CA_DIR="/root/gm-secure-boot-ca"
CERTS_DIR="${CA_DIR}/certs"
SB_DIR="/root/secure-boot-db"
mkdir -p "${SB_DIR}"
# 将证书转换为 ESL (EFI Signature List) 格式
# 使用 cert-to-efi-sig-list 工具
# ---- 1. 创建 DB 签名数据库 ----
echo "=== 创建 DB 数据库 ==="
cert-to-efi-sig-list \
-g "$(uuidgen)" \
"${CERTS_DIR}/sm2-db.crt" \
"${SB_DIR}/db.esl"
# ---- 2. 创建 KEK 数据库 ----
echo "=== 创建 KEK 数据库 ==="
cert-to-efi-sig-list \
-g "$(uuidgen)" \
"${CERTS_DIR}/sm2-kek.crt" \
"${SB_DIR}/kek.esl"
# ---- 3. 创建 PK 数据库 ----
echo "=== 创建 PK 数据库 ==="
cert-to-efi-sig-list \
-g "$(uuidgen)" \
"${CERTS_DIR}/sm2-pk.crt" \
"${SB_DIR}/pk.esl"
# ---- 4. 签名数据库更新包 ----
# KEK 更新包 (用 PK 签名)
echo "=== 签名 KEK 更新包 ==="
sign-efi-sig-list \
-g "$(uuidgen)" \
-k "${CERTS_DIR}/sm2-pk.key" \
-c "${CERTS_DIR}/sm2-pk.crt" \
kek \
"${SB_DIR}/kek.esl" \
"${SB_DIR}/kek.auth"
# DB 更新包 (用 KEK 签名)
echo "=== 签名 DB 更新包 ==="
sign-efi-sig-list \
-g "$(uuidgen)" \
-k "${CERTS_DIR}/sm2-kek.key" \
-c "${CERTS_DIR}/sm2-kek.crt" \
db \
"${SB_DIR}/db.esl" \
"${SB_DIR}/db.auth"
# PK 更新包 (用当前 PK 签名)
echo "=== 签名 PK 更新包 ==="
sign-efi-sig-list \
-g "$(uuidgen)" \
-k "${CERTS_DIR}/sm2-pk.key" \
-c "${CERTS_DIR}/sm2-pk.crt" \
pk \
"${SB_DIR}/pk.esl" \
"${SB_DIR}/pk.auth"
echo "=== Secure Boot 数据库准备完成 ==="
ls -la "${SB_DIR}"/*.auth5.2 通过 UEFI 固件界面部署
警告:以下操作涉及固件级修改,操作失误可能导致设备无法启动。请确保有物理访问能力或远程管理(IPMI/iLO)可用。部署步骤:
- 进入 UEFI 设置界面:开机按
Del或F2进入 - 进入 Secure Boot 配置:Security → Secure Boot Configuration
- 清除现有密钥:Reset to Setup Mode(清除所有现有密钥)
- 部署 PK:选择
PK选项,加载pk.auth文件 - 部署 KEK:选择
KEK选项,加载kek.auth文件 - 部署 DB:选择
DB选项,加载db.auth文件 - 启用 Secure Boot:将 Secure Boot Mode 设为
Enabled - 保存并退出
5.3 通过命令行部署(高级)
#!/bin/bash
# deploy_sb_via_efi_vars.sh
# 通过 EFI 变量接口部署(需要 efivarfs 挂载)
set -euo pipefail
SB_DIR="/root/secure-boot-db"
# 检查 efivarfs 是否挂载
if ! mount | grep -q efivarfs; then
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
fi
# 写入 PK
echo "=== 写入 PK ==="
efi-updatevar -e -f "${SB_DIR}/pk.esl" PK
# 写入 KEK
echo "=== 写入 KEK ==="
efi-updatevar -e -f "${SB_DIR}/kek.esl" KEK
# 写入 DB
echo "=== 写入 DB ==="
efi-updatevar -e -f "${SB_DIR}/db.esl" db
echo "=== EFI 变量写入完成 ==="
echo "请重启系统使配置生效"六、安全策略更新(DBX 黑名单)
6.1 创建 DBX 更新包
当发现某个固件的签名存在安全漏洞时,需要将其加入 DBX 黑名单:
#!/bin/bash
# create_dbx_update.sh
# 创建 DBX 黑名单更新包
set -euo pipefail
CA_DIR="/root/gm-secure-boot-ca"
CERTS_DIR="${CA_DIR}/certs"
DBX_DIR="/root/dbx-updates"
mkdir -p "${DBX_DIR}"
# 方法 1: 按签名者吊销
# 将需要吊销的签名者证书哈希加入 DBX
echo "=== 创建 DBX 更新包 ==="
# 计算要吊销证书的 SM3 哈希
CERT_TO_REVOKE="/path/to/compromised-cert.crt"
CERT_HASH=$(gmssl x509 -in "${CERT_TO_REVOKE}" -outform DER | gmssl sm3)
echo "吊销证书 SM3 哈希: ${CERT_HASH}"
# 创建 DBX ESL 文件
cert-to-efi-hash-list \
-g "$(uuidgen)" \
--hash "${CERT_HASH}" \
"${DBX_DIR}/dbx.esl"
# 用 KEK 签名 DBX 更新包
sign-efi-sig-list \
-g "$(uuidgen)" \
-k "${CERTS_DIR}/sm2-kek.key" \
-c "${CERTS_DIR}/sm2-kek.crt" \
dbx \
"${DBX_DIR}/dbx.esl" \
"${DBX_DIR}/dbx.auth"
echo "=== DBX 更新包创建完成 ==="
echo "部署命令: efi-updatevar -e -f ${DBX_DIR}/dbx.auth dbx"6.2 自动化安全策略更新
#!/bin/bash
# update_dbx_cron.sh
# 定期检查和更新 DBX 黑名单
set -euo pipefail
LOG_FILE="/var/log/gm-secure-boot-dbx.log"
DBX_DIR="/root/dbx-updates"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "${LOG_FILE}"
}
log "=== 开始 DBX 更新检查 ==="
# 检查是否有新的吊销列表
if [ -f "${DBX_DIR}/dbx.auth" ]; then
log "发现 DBX 更新包,开始部署..."
# 备份当前 DBX
if [ -f /sys/firmware/efi/efivars/dbx-d719b2cb-3d3a-4593-a300-11057988efb2 ]; then
cp /sys/firmware/efi/efivars/dbx-* "${DBX_DIR}/backup/" 2>/dev/null || true
fi
# 部署 DBX 更新
efi-updatevar -e -f "${DBX_DIR}/dbx.auth" dbx
log "✓ DBX 更新部署成功"
# 清理更新包
rm -f "${DBX_DIR}/dbx.auth" "${DBX_DIR}/dbx.esl"
else
log "无新的 DBX 更新"
fi
log "=== DBX 更新检查完成 ==="七、踩坑实录
坑 1:sbsigntools 版本不支持 SM2
现象:执行 sbsign 时报错 unrecognized algorithm 或 certificate verification failed。
原因:系统自带的 sbsigntools 版本较旧,不支持 SM2/SM3 算法。
解决:
# 检查版本
sbsign --version
# 需要 >= 0.9.3
# 从源码编译支持国密的版本
git clone https://github.com/openEuler/sbsigntools.git
cd sbsigntools
git checkout gm-support # 国密支持分支
autoreconf -fi
./configure --with-gmssl
make
sudo make install坑 2:shim 无法验证 SM2 签名
现象:shim 启动时提示 verification failed: Security Violation,拒绝加载 grub2。
原因:shim 版本不支持 GM/T 0010 定义的 SM2 签名消息格式。
解决:
# 确认 shim 版本
pesign -S -i /boot/efi/EFI/centos/shimx64.efi | head -5
# 需要国密版 shim(openEuler/openAnolis 已集成)
# 如果使用 CentOS,需要手动编译
git clone https://github.com/rhboot/shim.git
cd shim
# 应用国密补丁后编译
make ARCH=x86_64 CROSS_COMPILE= VENDOR_CERT_FILE=./ca.cer坑 3:UEFI 固件不识别 SM2 证书
现象:在 UEFI 设置界面加载证书时,提示 Invalid certificate format。
原因:部分 UEFI 固件的 SM2 支持需要特定的证书格式或 OID。
解决:
# 确保证书包含正确的 EKU (Extended Key Usage)
# PK 证书需要: 1.3.6.1.4.1.311.10.3.13 (Secure Boot Component)
# KEK 证书需要: 1.3.6.1.4.1.311.10.3.9 (PKCS#7 Signed Data)
# DB 证书需要: 1.3.6.1.4.1.311.10.3.32 (Secure Boot DB Signing)
# 重新生成包含正确 EKU 的证书
gmssl x509 -req -sm3 \
-in csr.pem \
-CA issuing-ca.crt \
-CAkey issuing-ca.key \
-CAcreateserial \
-out cert.pem \
-days 3650 \
-extfile <(printf "extendedKeyUsage=1.3.6.1.4.1.311.10.3.13")坑 4:内核更新后安全启动失败
现象:系统更新内核后,新内核无法通过安全启动验证。
原因:新内核未被 DB 证书签名。
解决:配置内核更新自动签名:
# /etc/kernel/postinst.d/99-sign-kernel.sh
#!/bin/bash
KERNEL_VERSION="$1"
KERNEL_IMAGE="/boot/vmlinuz-${KERNEL_VERSION}"
DB_KEY="/root/gm-secure-boot-ca/certs/sm2-db.key"
DB_CERT="/root/gm-secure-boot-ca/certs/sm2-db.crt"
if [ -f "${KERNEL_IMAGE}" ]; then
sbsign --key "${DB_KEY}" --cert "${DB_CERT}" \
--output "${KERNEL_IMAGE}" \
"${KERNEL_IMAGE}"
logger "GM Secure Boot: 已签名内核 ${KERNEL_VERSION}"
fi坑 5:DBX 更新后系统无法启动
现象:部署 DBX 黑名单后,系统提示 Access Denied 无法启动。
原因:DBX 中的哈希匹配到了正在使用的合法签名。
解决:
# 紧急恢复:进入 UEFI 设置,临时禁用 Secure Boot
# 然后移除错误的 DBX 条目
# 查看当前 DBX 内容
efivar -p -n dbx-d719b2cb-3d3a-4593-a300-11057988efb2 | xxd
# 清除 DBX(需要进入 Setup Mode)
efi-updatevar -d dbx八、验证与测试
8.1 验证安全启动状态
# 检查 Secure Boot 状态
mokutil --sb-state
# 输出: SecureBoot enabled
# 检查是否为国密签名
pesign -S -i /boot/efi/EFI/centos/shimx64.efi
# 应显示 SM2/SM3 相关信息
# 检查内核签名
pesign -S -i /boot/vmlinuz-$(uname -r)
# 应显示 SM2/SM3 相关信息
# 检查 EFI 变量
efivar -p -n PK-8be4df61-93ca-11d2-aa0d-00e098032b8c | head -58.2 安全启动抗攻击测试
# 测试 1: 替换内核镜像(应被拒绝)
cp /boot/vmlinuz-$(uname -r) /tmp/vmlinuz-modified
echo "malicious" >> /tmp/vmlinuz-modified
cp /tmp/vmlinuz-modified /boot/vmlinuz-$(uname -r)
# 重启后应无法启动,提示 "Secure Boot violation"
# 测试 2: 使用未签名驱动(应被拒绝)
insmod /tmp/unsigned-module.ko
# 应提示 "module verification failed: signature and/or required key missing"
# 测试 3: 篡改已签名文件(应被拒绝)
printf '\x00' | dd of=/boot/vmlinuz-$(uname -r) bs=1 count=1 conv=notrunc
# 重启后应无法启动九、总结
国密安全启动是构建自主可控系统安全基线的关键环节。通过 SM2/SM3 算法替代 RSA/SHA-256,可以从固件层面建立不受外部 CA 控制的信任链。
关键要点回顾:
- 证书链:根 CA → 中间 CA → PK/KEK/DB 证书,全部使用 SM2-256 + SM3
- 签名工具:sbsigntools 0.9.3+ 支持 SM2 签名,shim/grub2 需要国密版
- 部署顺序:先 PK → 再 KEK → 最后 DB,不可逆序
- 密钥安全:根 CA 私钥应离线存储在 HSM 中,DB 私钥用于日常签名
- 更新机制:内核更新需自动签名,DBX 黑名单需定期更新
- GM/T 0002-2012《SM2 椭圆曲线公钥密码算法》
- GM/T 0003.2-2012《SM2 第2部分:数字签名算法》
- GM/T 0004-2012《SM3 密码杂凑算法》
- GM/T 0010-2023《SM2密码算法加密签名消息语法规范》
- GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》
- GM/T 0028-2014《密码模块安全技术要求》