申请 EA 签名证书

需要如实填写公司信息, 签名证书并不便宜, 比如 DigiCert 的三年 $499.

参考: 获取代码签名证书

编译

这一步我们来编译带有签名的 shim 文件, 在 Ubuntu 16.04 64 位系统里操作.

获取源码

sudo apt install git
git clone --branch 14 https://github.com/rhboot/shim

使用最新的版本, 14

配置编译环境

安装以下依赖包:

  • gcc
  • gnu-efi
  • libelf-dev
  • make
sudo apt install gnu-efi:i386 libelf-dev gcc make

生成自己的私䄴

使用 make-certs 脚本生成密钥.

然后将公䄴复制到 shim/pub.cer:

cp -v deepin-uefi-ca.der shim/pub.cer

修改 Makefile

14 版里面的 Makefile 对 Ubuntu 系统的支持有点儿小问题, 需要先修正一下:

sed -ie '/^EFI_PATH/s|/gnuefi||' -e 's/ --no-undefined$//' Makefile

编译生成 32 位 shim 文件

mkdir -v inst32
setarch linux32 make ARCH=ia32 VENDOR_CERT_FILE=pub.cer -j4 | tee inst32/build.log
setarch linux32 make ARCH=ia32 DESTDIR=inst32 EFIDIR=deepin install | tee inst32/install.log

编译生成 64 位 shim 文件

编译之前清空一下之前的环境:

make clean

再编译 64 位的:

mkdir -v inst64
make VENDOR_CERT_FILE=pub.cer -j4 | tee inst64/build.log
make DESTDIR=inst64 EFIDIR=deepin install | tee inst64/install.log

将生成的 shim 文件从 ELF 格式转为 cab 格式

首先安装工具:

sudo apt install lcab

现在依次转换32位的和64位的 shim ELF 文件

lcab shimx64.efi shimx64-unsigned.cab
lcab shimia32.efi shimia32-unsigned.cab

对生成的 shim cab 文件 做签名

先安装 DigiCert 的签名工具

安装 SafeNetAuthenticationClient-x32-x64.exe, 然后插入 USB Key, 打开 SafeNet Authentication Client 应该就可以看到这个 Key 的授权用户了.

更新 winqual.exe 时间标签

使用 key/ 目录里的工具, 具体用法可以参数 key/readme.pdf.

signtool timestamp /t http://timestamp.verisign.com/scripts/timestamp.dll winqual.exe

正常情况下, 会提示:

Successfully timestamped: winqual.exe

签名

signtool sign /a shimia32-unsigned.cab
rename shimia32-unsigned.cab shimia32-signed.cab
signtool sign /a shimx64-unsigned.cab
rename shimx64-unsigned.cab shimx64-signed.cab

测试生成的 shim 文件

参考: UEFI 提交申请的预提交测试

提交 shim 文件

将之前使用EA证书签了名的 shim cab 文件上传到 microsoft sysdev dashboard

review shim

参考: Reviews of shim

给 grub2 签名

首先安装签名工具:

sudo apt install sbsigntool

然后生成 grub2 efi 文件:

grub2/grub-mkimage -o grubx64-unsigned.efi -O x86_64-efi \
  -p /EFI/deepin ntfs hfs appleldr \
  boot cat efi_gop efi_uga elf fat hfsplus iso9660 linux keylayouts memdisk \
  minicmd part_apple ext2 extcmd xfs xnu part_bsd part_gpt search \
  search_fs_file chain btrfs loadbios loadenv lvm minix minix2 reiserfs \
  memrw mmap msdospart scsi loopback normal configfile gzio all_video efi_gop \
  efi_uga gfxterm gettext echo boot chain eval ls test sleep png gfxmenu \
  linuxefi

上面只是包含了一部分 grub mod, 可以根据需要删减或者追加模块, 要注意的是, linuxefi 这个模块是 必须要包含的.

要注意的是 debian sid 里面包含的 grub2.02+dfsg1-3 这个版本, debian/patches/no_insmod_on_sb.patch 里面加入的以下部分代码是多余的:

 
+#ifdef GRUB_MACHINE_EFI
+  if (grub_efi_secure_boot ())
+    {
+      grub_error (GRUB_ERR_ACCESS_DENIED,
+		  "Secure Boot forbids loading module from %s", filename);
+      return 0;
+    }
+#endif
+

最后, 给 grub2 efi 签名:

sbsign --key deepin-uefi-ca.key --cert deepin-uefi-ca.crt --output grubx64.efi grubx64-unsigned.efi

给 kernel 签名

以 vmlinuz-4.15.0-1-amd64 为例:

sbsign --key deepin-uefi-ca.key --cert deepin-uefi-ca.crt --output vmlinuz-4.15.0-1-amd64-signed vmlinuz-4.15.0-1-amd64

用 grub2 引导签了名的内核时, 会打印一条消息:

EFI stub: UEFI Secure Boot is enabled.