UEFI/安全啟動 - Arch Linux 中文维基

跳至內容

# UEFI/安全啟動

出自 Arch Linux 中文维基
< UEFI
翻譯狀態：

- 本文（或部分內容）譯自 Unified Extensible Firmware Interface/Secure Boot，最近一次同步於 2023-02-03，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- Arch 的啟動流程
- 安全

安全啟動（Secure Boot）是UEFI標準中的一項安全功能，旨在為pre-boot process添加一層保護；通過維護被授權或禁止的在啟動時運行的經過加密簽署的二進制文件列表，它有助於使得核心引導組件（引導管理器、內核、initramfs）不被篡改。

因此，它可以被視為對個人使用環境的securing所做努力的延續或補充，減少其他軟體安全解決方案（如系統加密）無法輕易覆蓋的攻擊面，同時完全不同且不依賴於它們。安全啟動只是作為當前安全實踐的一個組成部分獨立存在，具有自己的一套優缺點。

注意：為了更深入地了解Linux中的安全啟動。見Rodsbooks' Secure Boot與other online resources。文章重點介紹了如何在 Arch Linux 中設置安全啟動。

## 檢查安全啟動狀態

### 在啟動作業系統之前

此時，必須查看固件設置。如果機器已啟動並正在運行，則在大多數情況下必須重新啟動。

您可以在引導過程中通過按特殊鍵來訪問固件配置。使用的特殊鍵取決於固件。它通常是`Esc`、`F2`、`Del`或者`Fn`鍵中的一個。有時在啟動過程中特殊鍵的名稱會顯示一小段時間。主板說明書往往有關於此的記載。如果你想要按下特殊鍵，請在啟動機器後立即按下該鍵，甚至是在屏幕實際顯示任何內容之前。 進入固件設置後，請注意不要擅自更改任何設置。 通常在每個設置的底部都會有導航說明和設置的簡短幫助。設置本身可能由幾個頁面組成，您必須導航到正確的位置。有一些安全啟動設置可能簡單地表示為安全啟動選項，可以將其設置為打開或關閉 .

### 在啟動作業系統之後

使用systemd檢查系統上的安全啟動狀態的一種簡單方法是使用bootctl(1)：

注意：以下命令，並非要求你強制使用systemd-boot,作為你的引導啟動管理器，才能正確讓你得到你需要的內容（安全啟動是否開啟），它更類似於其他*ctl systemd實用程序（localectl、timedatectl……），此處即為有關啟動事項的綜合管理工具，並且不會影響你的配置。

    $ bootctl

    System:
          Firmware: UEFI 2.80 (American Megatrends 5.26)
     Firmware Arch: x64
       Secure Boot: enabled (user)
      TPM2 Support: yes
      Measured UKI: yes
      Boot into FW: supported
    ...

在這裡，我們看到安全啟動已啟用並強制執行用戶模式（user mode）。Secure Boot的其他值包括`disabled`，Setup Mode的其他值包括`setup`[1]。

檢查機器是否使用安全啟動的另一種方法是使用以下命令：

$ od --address-radix=n --format=u1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c

如果啟用了安全啟動，此命令將返回`1`作為五個列表中的最後一個整數，例如：

    6  0  0  0  1

但是請注意，如果使用了功能缺失的引導加載程序，內核可能不知道安全引導（即使它在固件中啟用）。 這可以通過在系統啟動後不久檢查內核消息來驗證：

    # journalctl -kg 'secure boot'

    kernel: Secure boot disabled
    kernel: Secure boot could not be determined

能啟用的內核會列印`Secure boot enabled`。

## 引導安裝介質

官方安裝鏡像不支持安全啟動（archlinux/archiso#69）。對於安全啟動的支持最早在 `archlinux-2013.07.01-dual.iso` 中引入，但隨後在 `archlinux-2016.06.01-dual.iso` 中被移除。當時，prebootloader 被替換為了 efitools包，儘管後者使用的是未簽名的 EFI 二進制文件。自那之後，官方安全介質就再未支持過安全啟動。

為了在開啟安全啟動的系統上引導安裝介質，你需要禁用安全啟動，或者修改鏡像以添加已簽名的引導加載程序（Bootloader）。

Archboot 鏡像提供了一種在安裝介質中使用安全啟動的方式。

### 禁用安全啟動

可以通過 UEFI 固件接口禁用安全啟動功能。如何訪問固件配置請訪問#在啟動作業系統之前.

如果使用熱鍵不起作用並且您可以啟動 Windows，您可以通過以下方式強制重新啟動到固件配置（對於 Windows 10）：設置 > 更新和安全 > 恢復 > 高級啟動（立即重新啟動）> 故障排除 > 高級選項 > UEFI 固件設置 > 重啟。

請注意，某些主板（Packard Bell 筆記本電腦就是這種情況）只有在您設置了管理員密碼（之後可以刪除）時才允許禁用安全啟動。 另請參閱 Rod Smith 的禁用安全啟動。

### 重新打包安裝鏡像

參見#ISO 重新打包。

### 編輯安裝介質

如果使用的是 U 盤安裝介質，則可以通過手動編輯介質上的 EFI 系統分區來添加對安全啟動的支持。

插入 U 盤，然後掛載該分區：

    # mount /dev/disk/by-label/ARCHISO_EFI /mnt

接著按照使用自己的密鑰中的說明安裝任意已簽名的 Bootloader。例如，若要安裝 #PreLoader：

    # mv /mnt/EFI/BOOT/BOOTx64.EFI /mnt/EFI/BOOT/loader.efi
    # cp /usr/share/preloader-signed/PreLoader.efi /mnt/EFI/BOOT/BOOTx64.EFI
    # cp /usr/share/preloader-signed/HashTool.efi /mnt/EFI/BOOT/HashTool.efi

## 實施安全啟動

為了確保理想的安全啟動設置，有以下幾個特定條件：

1. UEFI基本被認為是可信的（儘管有一些眾所周知的批評和漏洞[2]），且必須被強密碼保護。
2. 不使用默認的製造商或第三方密鑰，因為它們被證明會大大削弱安全啟動的安全模型[3]。
3. UEFI直接加載用戶簽名的、兼容EFI boot stub（英語：EFI boot stub）的統一內核鏡像（無需引導加載程序），包含微碼（如果適用）以及 initramfs。以便在整個啟動過程維持安全啟動建立的信任鏈並減少攻擊面。
4. 使用完整驅動器加密，這樣在創建內核鏡像和簽署的過程中所涉及的工具與文件就無法被具有機器物理訪問權限的人訪問並篡改。
5. 可以使用TPM（可信平台模塊）獲得進一步的提升。

#使用自己的密鑰中描述了一個簡單且完全自力更生的設置，而#使用已簽署的引導加載程序使用了第三方簽署的中間工具。

使用 GRUB 引導加載程序在啟用安全啟動前需要額外的步驟，參見GRUB#啟用安全啟動。

### 使用自己的密鑰

警告：使用自定義密鑰替換平台密鑰（PK）會癱瘓某些機器（比如筆記本）上的硬體，甚至無法進入UEFI/BIOS設置恢復。這是因為某些硬體（例如顯卡）的固件（OpROMs）在啟動時微軟使用微軟第三方 CA 證書進行簽署。許多聯想 Thinkpad X、P 和 T 系列筆記本電腦以及華碩 TUF Gaming 筆記本電腦均屬於這種情況。

實現安全啟動需要下列密鑰：

平台密鑰 Platform Key （PK）：最高級的密鑰。
密鑰交換密鑰 Key Exchange Key （KEK）：用於簽署簽名資料庫和禁止的簽名資料庫更新的密鑰。
簽名資料庫 Signature Database （db）：包含密鑰和/或被允許的EFI二進制文件的散列值。
禁止的簽名資料庫 Forbidden Signatures Database （dbx）：包含密鑰和/或被禁止的EFI二進制文件的散列值。

詳細解釋請閱讀所有UEFI密鑰的含義。

為了使用安全啟動，你至少需要PK，KEK和db密鑰。 雖然你可以添加多個KEK，db和dbx證書，但只允許一個平台密鑰（PK）。

一旦安全啟動處於「用戶模式」，密鑰只能通過用更高級別的密鑰簽署（使用sign-efi-sig-list）來更新。平台密鑰可以自己簽署。

#### 確定 OpROM 簽名

按以下步驟檢查是否擁有任何已簽名的 OpROM。

列出所有帶 OpROM 的設備：

    $ find /sys/devices/ -name rom

    /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom
    ...

以上展示了一個帶有已簽名 EFI ROM 的 Intel DC SSD 示例。對每個設備重複以下步驟。

    $ lspci -s 81:00.0

    81:00.0 Non-Volatile memory controller: Intel Corporation PCIe Data Center SSD (rev 01)

轉儲（Dump）ROM 內容：

    # echo 1 > /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom
    # cat /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom > ~/intel_ssd.rom
    # echo 0 > /sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0/rom

獲取並編譯 TianoCore 的 EDK II 工具：

    $ make -C BaseTools

解析 ROM 文件：

    $ ./BaseTools/Source/C/bin/EfiRom -d ~/intel_ssd.rom

    Image 1 -- Offset 0x0
      ROM header contents
        Signature              0xAA55
        PCIR offset            0x001C
        Signature               PCIR
        Vendor ID               0x8086
        Device ID               0x0953
        Length                  0x001C
        Revision                0x0003
        DeviceListOffset        0x00
        Class Code              0x000000
        Image size              0x6A00
        Code revision:          0x0000
        MaxRuntimeImageLength   0x00
        ConfigUtilityCodeHeaderOffset 0x00
        DMTFCLPEntryPointOffset 0x00
        Indicator               0x80   (last image)
        Code type               0x03   (EFI image)
      EFI ROM header contents
        EFI Signature          0x0EF1
        Compression Type       0x0001 (compressed)
        Machine type           0x8664 (X64)
        Subsystem              0x000B (EFI boot service driver)
        EFI image offset       0x0038 (@0x38)

結果顯示，該 OpROM 在偏移量（Offset）0x0 處的 Image 1 偏移量 0x0038 位置包含一個壓縮的 EFI 鏡像。提取該 EFI 區域：

    $ dd if=intel_ssd.rom ibs=1 skip=$(( 0x00 + 0x38 )) of=intel_ssd.rom.efi.compressed

解壓縮該鏡像：

    $ ./BaseTools/Source/C/bin/TianoCompress -d --uefi -v ~/intel_ssd.rom.efi.compressed -o ~/intel_ssd.rom.efi

    $ file ../intel_ssd.rom.efi

    ../intel_ssd.rom.efi: PE32+ executable for EFI (boot service driver), x86-64, 6 sections

使用 sbsigntools包 檢查簽名，可以看到它是使用微軟的 DB 證書籤名的：

    $ sbverify --list ~/intel_ssd.rom.efi

    signature 1
    image signature issuers:
     - /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation UEFI CA 2011
    image signature certificates:
     - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=MOPR/CN=Microsoft Windows UEFI Driver Publisher
       issuer:  /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation UEFI CA 2011
     - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation UEFI CA 2011
       issuer:  /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Corporation Third Party Marketplace Root

警告：為了防止設備軟變磚（Soft brick），如果發現顯卡帶有已簽名的 ROM，請確保在錄入自定義密鑰後，你的 Secure Boot DB（允許資料庫）中依然保留了必要簽發者（Issuers）證書。

#### 備份當前變量

在創建新的密鑰和修改EFI變量之前，建議備份當前的變量，以便在發生錯誤時可以恢復。

安裝 efitools包 軟體包後，運行以下命令來備份所有四個主要的安全啟動變量。

    $ for var in PK KEK db dbx ; do efi-readvar -v $var -o old_${var}.esl ; done

如果你在新電腦或主板上執行這條命令，你提取的變量很可能是微軟提供的。

#### 創建密鑰

##### 手動流程

要生成密鑰，請執行以下步驟。

你將需要多種格式的私鑰和證書。

.key
  PEM格式的私鑰，用於簽署EFI二進制和EFI簽名列表。
.crt
  PEM格式的證書，用於sbsign(1)、sbvarsign(1)與sign-efi-sig-list(1)。
.cer
  DER格式的證書，用於固件。
.esl
  EFI簽名列表的證書，用於sbvarsign(1)、efi-updatevar(1)、KeyTool與固件。
.auth
  EFI簽名列表中的證書，帶有認證頭（即簽名的證書更新文件），用於efi-updatevar(1)、sbkeysync、KeyTool與固件。

創建一個GUID用於自我識別：

    $ uuidgen --random > GUID.txt

平台密鑰：

    $ 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 no_PK.auth

密鑰交換密鑰：（生成KEK.auth的指令沒有加-a，所以文件只能用來update KEK實現替換。如果要生成用於add添加的KEK.auth，則需要在指令裡添加-a，同理db等。PK只能有一個所以直接替換就好，刪除的話用本頁面介紹的指令生成的rm_PK.auth。）

    $ 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

簽名資料庫密鑰：

    $ 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

##### 輔助腳本

關於這個主題的參考頁[4]的作者提供了一個輔助/快捷腳本（需要python)。一個輕度修改的版本也被打包為sbkeysAUR。

為了使用它，請在安全位置創建一個文件夾（比如`/etc/efi-keys/`，如果你接下來計劃統一內核鏡像的創建與簽署自動化過程）並且運行：

    # mkdir /etc/efi-keys
    # cd !$
    # curl -L -O https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
    # chmod +x mkkeys.sh
    # ./mkkeys.sh
    <輸入一個通用名，以嵌入至密鑰中，比如 "Secure Boot">

這將產生所需的不同格式的文件。

##### 更新密鑰

一旦安全啟動進入「用戶模式」，任何對KEK、db以及dbx的改變都需要更高級的密鑰簽署。

比如，如果你想要更新你的db密鑰：

1. 創建新的密鑰，
2. 轉換其為EFI簽名列表，
3. 簽署EFI簽名列表，
4. 登記已簽署的證書更新文件。

    $ cert-to-efi-sig-list -g "$(< GUID.txt)" new_db.crt new_db.esl
    $ sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db new_db.esl new_db.auth

如果你想添加另一個密鑰至簽名資料庫中且不替換你的db密鑰，你需要使用選項`-a`（請看sign-efi-sig-list(1)）：

    $ sign-efi-sig-list -a -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db new_db.esl new_db.auth

當`new_db.auth`被創建，登記它。

#### 簽署EFI二進制文件

當安全啟動激活時（比如在「用戶模式」中），只有已被簽署的EFI二進制文件（比如應用程式、驅動、統一內核鏡像）可以被啟動。

##### 使用sbsigntools手動操作

安裝sbsigntools包來使用sbsign(1)簽署EFI二進制文件。

提示：

- 為了檢查一個二進制文件是否被簽署並列出它的簽名，使用`sbverify --list /path/to/binary`。
- rEFInd啟動管理器的`refind-install`腳本可以簽署rEFInd的EFI二進制文件並把它們與db證書一起拷貝到ESP中。 請參考rEFInd#使用你自己的密鑰。

注意：如果不帶`--output`使用sbsign的話，生成文件將會是`filename.signed`。詳情請看sbsign(1)。

使用sbsign來簽署你的內核與啟動管理器，比如：

    # 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

警告：只對內核進行簽署並不能保護initramfs不被篡改。查看統一內核鏡像以了解如何生成一個組合鏡像並通過sbsign手動簽署。

##### 使用pacman鉤子簽署內核

你也可使用mkinitcpio的pacman鉤子在安裝與更新時簽署一個內核。

複製`/usr/share/libalpm/hooks/90-mkinitcpio-install.hook`到`/etc/pacman.d/hooks/90-mkinitcpio-install.hook`以及複製 `/usr/share/libalpm/scripts/mkinitcpio-install`到`/usr/local/share/libalpm/scripts/mkinitcpio-install`。

在`/etc/pacman.d/hooks/90-mkinitcpio-install.hook`裡，將：

    Exec = /usr/share/libalpm/scripts/mkinitcpio-install

替換為：

    Exec = /usr/local/share/libalpm/scripts/mkinitcpio-install

在`/usr/local/share/libalpm/scripts/mkinitcpio-install`裡，將：

    install -Dm644 "${line}" "/boot/vmlinuz-${pkgbase}"

替換為：

    sbsign --key /path/to/db.key --cert /path/to/db.crt --output "/boot/vmlinuz-${pkgbase}" "${line}"

如果你正在使用systemd-boot，有一個專用的pacman鉤子會半自動的做這個任務。

##### 用sbupdate全自動生成和簽署統一內核

sbupdate是一個專門為在Arch Linux上自動生成和簽署統一內核鏡像而製作的工具。它通過Pacman#鉤子處理內核的安裝、移除和更新。

安裝sbupdate-gitAUR並按照項目主頁上的說明進行配置。[5]

提示：如果正在使用systemd-boot，設置`OUT_DIR="EFI/Linux"`可以讓你的已簽署的內核鏡像直接被識別而不需要必須的配置。請看systemd-boot(7) § FILES與Systemd-boot#增加啟動選項。

一旦完成配置，只需要以root運行`sbupdate`以完成首次鏡像生成。

注意：sbupdate的輸出經常包含錯誤比如`warning: data remaining[26413568 vs 26423180]: gaps between PE/COFF sections?`。那些是無害的且可以被安全的無視掉。[6]

#### 將固件置於 "設置模式 "下

當平台密鑰被刪除時，安全啟動處於設置模式。要將固件置於設置模式，請進入固件設置工具，並找到刪除或清除證書的選項。#在啟動作業系統之前中介紹了如何進入設置工具。

#### 在固件中登記密鑰

使用下列某種方式登記'db、KEK和PK證書。

提示：如果dbx（禁止的簽名資料庫）是空白的，在下面的說明中，它可以被安全地排除在外。
警告：登記平台密鑰會使安全啟動進入「用戶模式」，也就意味著會離開「設置模式」，所以登記應該完成在所有流程的最後。

##### 使用sbkeysync

安裝sbsigntools包。按照以下目錄結構創建文件夾`/etc/secureboot/keys` -

    /etc/secureboot/keys
    ├── db
    ├── dbx
    ├── KEK
    └── PK

比如，這樣用：

    # mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK}

接下來複製之前生成的每一個.auth文件到它們所對應的位置（比如，把`PK.auth`放進`/etc/secureboot/keys/PK`，以此類推）。

檢查`sbkeysync`會對你系統的UEFI密鑰庫做什麼改變。

    # sbkeysync --pk --dry-run --verbose

最後，使用`sbkeysync`來登記你的密鑰。

    # sbkeysync --verbose
    # sbkeysync --verbose --pk

提示：

- 如果`sbkeysync`返回了寫錯誤，那麼在執行`sbkeysync`前先運行`chattr -i /sys/firmware/efi/efivars/{PK,KEK,db}*`來暫時改變文件屬性，使EFI密鑰可以寫入`efivars`目錄中。詳情見chattr(1)。
- 如果為`PK.auth`得到了一個`permission denied`錯誤，你可以使用命令`efi-updatevar -f /etc/secureboot/keys/PK/PK.auth PK`登記密鑰。
- 如果都失敗了，這可能是因為固件對BIOS設置上鎖了。對於戴爾和聯想的系統，你或許需要重置你的BIOS密碼：Sysfs固件認證文檔

對於聯想系統：

    # cat > /sys/class/firmware-attributes/thinklmi/authentication/Admin/current_password
    my-super-secret-password
    ^D

對於戴爾系統：

    # cat > /sys/class/firmware-attributes/dell-wmi-sysman/authentication/Admin/current_password
    my-super-secret-password
    ^D

然後再次嘗試。

下一次啟動時，UEFI應該會切回用戶模式並且執行安全啟動策略。

##### 使用固件設置工具

複製所有的`*.cer`、`*.esl`、`*.auth`文件（除了`noPK.auth`）到一個FAT格式的文件系統（你可以使用EFI 系統分區）。

警告：不要把`noPK.auth`文件複製到你個人電腦的EFI 系統分區（ESP）！如果你這樣做了，假如有人偷了你的電腦，這個人可以刪除UEFI安全啟動固件中的個人平台密鑰，再一次打開你電腦上的「設置模式」，然後用他們自己的平台密鑰替換你的安全啟動密鑰（PK、KEK、db、dbx），這將完全違背UEFI安全啟動的目的。 應當只有你自己可以替換平台密鑰，只有你自己可以訪問`noPK.auth`文件。因此把`noPK.auth`文件保存在一個只有你自己能訪問的安全的地方。這些地方對於`noPK.auth`文件來說都可以是安全的：

- 當你使用`KeyTool`時，可以使用帶有EFI 系統分區的外部U盤。要注意，`KeyTool`只能讀取未加密存儲中的文件。
- 當你使用`sbkeysync`時，運用靜態數據加密。

個人電腦的EFI 系統分區一定要按照UEFI的規範進行加密，否則就可以在另一台電腦上被掛載且被讀取（如果你的電腦被偷了，硬碟可以被取出來掛載到另一台電腦上）。複製`noPK.auth`到你電腦的ESP後再刪除也是不可取的，因為在FAT32格式的EFI 系統分區上被刪除的文件可以通過像是PhotoRec這樣的工具被還原。

啟動固件設置工具，登記db、KEK與PK證書。 固件會有各種不同的界面，請看使用固件的設置工具更換密鑰，以了解如何登記密鑰。

如果使用的工具支持，最好使用.auth和.esl而不是.cer。

##### 使用KeyTool

`KeyTool.efi`包含在efitools包包中，複製它到ESP。為了能在登記密鑰後使用它，請用`sbsign`對它簽署。

    # sbsign --key db.key --cert db.crt --output esp/KeyTool-signed.efi /usr/share/efitools/efi/KeyTool.efi

使用固件設置工具，引導加載程序或者UEFI Shell啟動`KeyTool-signed.efi`，然後登記密鑰。

參見使用KeyTool更換密鑰了解KeyTool的菜單選項。

#### 與其他作業系統進行雙重啟動

##### 微軟 Windows

這篇文章的某些內容需要擴充。

原因：是否有可能通過用自定義密鑰簽署其啟動程序來啟動Windows？ (在 Talk:UEFI/安全啟動#使用自定義密鑰啟動Windows 中討論)

通常情況下，啟用安全引導下，僅使用私人自定義密鑰簽署微軟引導程序（`EFI/Microsoft/Boot/bootmgfw.efi`）而沒有在UEFI安全啟動變量中登記「Microsoft Windows Production PCA 2011」不可能啟動Windows：

- 如果`bootmgfw.efi`同時包含來自「Microsoft Windows Production PCA 2011」和你自己的安全啟動資料庫密鑰（也就是說有兩個簽名），那麼UEFI固件實現（比如INSYDE Corp. 4096.01 (UEFI Version 2.31, Version F.70, Release Date: 07/18/2016, BIOS Revision 15.112, Firmware Revision: 29.66)）將不會啟動`bootmgfw.efi`，並且會拋出一個安全違規錯誤（`Selected boot image did not authenticate. Press ENTER to continue.`）。像是這樣的UEFI固件實現可能只能讀取第一個簽名而忽略第二個。只有第二個簽名的證書被註冊到UEFI安全啟動變量中，所以安全啟動驗證失敗。

- 如果從`bootmgfw.efi`中剝離/移除「Microsoft Windows Production PCA 2011」證書，而只在文件中添加了你自己的安全啟動資料庫密鑰的簽名，雖然UEFI會啟動該文件但Windows將啟動一個恢復/修復環境。Windows會抱怨說：Windows的安裝被破壞了（因為`bootmgfw.efi`中缺失了「Microsoft Windows Production PCA 2011」證書）。

所以為了實現雙系統：

- 你必須把`bootmgfw.efi`的散列值添加到`DB`變量中允許的散列值列表中，而且每次Windows更新改變`bootmgfw.efi`時，你都必須更新DB變量。這非常繁瑣，容易出錯，而且不被微軟支持，例如，Bitlocker在這種設置下將無法正常工作（Bitlocker每次解密Windows分區時都會要求你提供恢復密碼）。
- 或者你必須將微軟的證書添加到UEFI安全啟動的變量中，微軟有兩個`DB`證書和一個`KEK`證書：

- - 為了使Windows作業系統可以被引導，Microsoft Windows Production PCA 2011 證書必須被包含進`DB`變量。
  - 為了使用第三方二進制，比如UEFI驅動、其他ROM、shim包等，Microsoft Corporation UEFI CA 2011 證書（又叫作微軟第三方UEFI CA證書）必須被包含進`DB`變量。
  - 為了「通過更新`DBX`和潛在更新`DB`來撤銷不良鏡像對新的Windows簽名鏡像做準備」，Microsoft Corporation KEK CA 2011 證書應當被包含進`KEK`變量。然而沒有「Microsoft Corporation KEK CA 2011」證書，Windows也可以啟動。

使用微軟的GUID（`77fa9abd-0359-4d32-bd60-28f4e78f784b`），根據微軟的多個DER格式的`DB`證書創建多個EFI簽名列表。然後為了方便，把它們合併進一個文件中：

    $ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_Win_db.esl MicWinProPCA2011_2011-10-19.crt
    $ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_UEFI_db.esl MicCorUEFCA2011_2011-06-27.crt
    $ cat MS_Win_db.esl MS_UEFI_db.esl > MS_db.esl

可選操作（為了嚴格符合的微軟UEFI安全啟動要求）：使用微軟的GUID（`77fa9abd-0359-4d32-bd60-28f4e78f784b`），根據微軟的KEK格式的`DB`證書創建EFI簽名列表：

     $ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output MS_Win_KEK.esl MicCorKEKCA2011_2011-06-24.crt

使用你自己的`KEK`簽署一個`DB`變量更新。使用帶有`-a`選項的`sign-efi-sig-list`來添加而不是替換一個`DB`證書：

    $ sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b -k KEK.key -c KEK.crt db MS_db.esl add_MS_db.auth

可選操作（為了嚴格符合微軟的UEFI安全啟動要求）：使用你自己的`PK`簽署一個`KEK`變量更新。使用帶有`-a`選項的`sign-efi-sig-list`來添加而不是替換一個`KEK`證書：

    $ sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b -k PK.key -c PK.crt KEK MS_Win_KEK.esl add_MS_Win_KEK.auth

按照#在固件中登記密鑰的內容來登記`add_MS_db.auth`，為了嚴格符合微軟的UEFI安全啟動要求，將`add_MS_Win_KEK.auth`放入UEFI安全啟動資料庫的變量中。

### 使用已簽署的引導加載程序

使用已簽署的引導加載程序意味著使用由微軟的密鑰簽署的引導加載程序。有兩個已知的簽署的引導加載程序：PreLoader和shim。它們的目的是連鎖加載其他EFI二進制文件（通常是引導加載程序）。由於微軟不會簽署一個自動啟動任何未簽署的二進制文件的引導加載程序，PreLoader和shim使用一個叫做機器所有者密鑰列表的白名單，縮寫為MokList。如果二進制文件的SHA256散列值（Preloader和shim）或簽署二進制文件的密鑰（shim）在MokList中，它們就執行它，如果沒有，他們就啟動一個密鑰管理工具，允許註冊散列值或密鑰。

警告：微軟所謂的「Secured-core PCs」在出廠時並沒有登記微軟第三方UEFI CA證書（Microsoft Corporation UEFI CA 2011） [7]。唯一登記的DB證書是Microsoft Windows Production PCA 2011證書，該證書專門用於簽署Windows的引導加載程序。

微軟第三方UEFI CA證書的登記需要在固件設置中啟用，以啟動用該證書籤署的EFI二進制文件和OpROM。

#### PreLoader

運行時，PreLoader嘗試啟動`loader.efi`。如果`loader.efi`的散列值不在MokList中，PreLoader將會啟動`HashTool.efi`。在HashTool中，你必須登記你想要啟動的EFI二進制的散列值，也就是你的引導加載程序（`loader.efi`）以及內核的散列值。

注意：每次你更新任何二進制文件（如引導加載程序或內核）時，你都需要登記它們的新散列值。
提示：rEFInd加載管理程序的`refind-install`腳本可以複製rEFInd與PreLoader的EFI二進制文件到ESP。請看REFInd#使用_PreLoader。

##### 設置PreLoader

注意：efitools包包中的`PreLoader.efi`與`HashTool.efi`沒有被簽署，所以它們的作用是有限的。你可以從preloader-signedAUR獲取被簽署的`PreLoader.efi`與`HashTool.efi`，或者手動下載它們。

安裝preloader-signedAUR和`HashTool.efi`然後複製`PreLoader.efi`和`HashTool.efi`到引導加載程序目錄中。對於systemd-boot，使用：

    # cp /usr/share/preloader-signed/{PreLoader,HashTool}.efi esp/EFI/systemd

現在複製一份引導加載程序的二進制文件並重命名為`loader.efi`。對於systemd-boot，使用：

    # cp esp/EFI/systemd/systemd-bootx64.efi esp/EFI/systemd/loader.efi

最終，創建一個新的NVRAM引導項來啟動`PreLoader.efi`：

    # efibootmgr --unicode --disk /dev/sdX --part Y --create --label "PreLoader" --loader /EFI/systemd/PreLoader.efi

把`X`替換為驅動器字符並把`Y`替換為EFI 系統分區的分區號。

這個啟動項應當添加進啟動列表中並作為第一項啟動，用`efibootmgr`命令檢查，必要時調整啟動順序。

###### 回撤

如果啟動這個自定義NVRAM啟動項時出現問題，複製`HashTool.efi`和`loader.efi`到UEFI系統自動啟動的默認加載程序位置：

    # cp /usr/share/preloader-signed/HashTool.efi esp/EFI/BOOT/
    # cp esp/EFI/systemd/systemd-bootx64.efi esp/EFI/BOOT/loader.efi

複製一份`PreLoader.efi`並重命名：

    # cp /usr/share/preloader-signed/PreLoader.efi esp/EFI/BOOT/BOOTx64.EFI

對於特別頑固的UEFI實現，可以將`PreLoader.efi`複製到Windows系統使用的默認加載程序位置：

    # mkdir -p esp/EFI/Microsoft/Boot
    # cp /usr/share/preloader-signed/PreLoader.efi esp/EFI/Microsoft/Boot/bootmgfw.efi

注意：如果與Windows雙啟動，請先備份原始的`bootmgfw.efi`，因為替換它可能會導致Windows更新的問題。

如前所述，將`HashTool.efi`和`loader.efi`複製到`'esp/EFI/Microsoft/Boot/`。

當系統在啟用安全啟動下啟動時，按照上述步驟登記`loader.efi`和`/vmlinuz-linux`（或任何使用的內核鏡像）。

##### 如何在啟動時使用？

當出現一條消息說：`Failed to Start loader... I will now execute HashTool.`。要使用HashTool來登記`loader.efi`和`vmlinuz.efi`的散列值，請遵循以下步驟。這些步驟假定了一個重製的archiso安裝介質的項目。你得到的確切的項目取決於你的引導加載程序的設置。

- 選擇 OK
- 在HashTool的主菜單，選擇Enroll Hash，選擇`\loader.efi`然後選Yes確認。同樣，再選擇Enroll Hash和`archiso`來進入archiso的目錄，然後選擇`vmlinuz.efi`，用Yes確認。接下來選擇Exit返回至啟動設備選單。
- 在啟動設備選單中選擇Arch Linux archiso x86_64 UEFI CD

##### 移除PreLoader

注意：既然你要刪除東西，那麼最好先備份。

卸載preloader-signedAUR然後

並簡單地刪除複製的文件並恢復配置。 對於systemd-boot使用：

    # rm esp/EFI/systemd/{PreLoader,HashTool}.efi
    # rm esp/EFI/systemd/loader.efi
    # efibootmgr --unicode --bootnum N --delete-bootnum
    # bootctl update

這裡`N`指的是用來啟動`PreLoader.efi`所創建的NVRAM啟動項。 如有必要，用efibootmgr命令檢查並調整啟動順序。

注意：上述命令涵蓋了最簡單的情況；如果你創建、複製、重命名或編輯了更多的文件，那麼你也必須處理它們。如果PreLoader是你的操作引導項，你還需要#禁用安全啟動。

##### 刪除已登記的散列值

在MOK資料庫中登記的每一條散列值都會吃掉NVRAM的一小塊空間。你可能想刪除無用的散列值，以釋放空間並防止過時的程序啟動。

安裝efitools包然後複製`KeyTool.efi`：

    # cp /usr/share/efitools/efi/KeyTool.efi esp/EFI/systemd/KeyTool.efi

引導啟動至Preloader，你會看到KeyTool引導項。然後你就可以在MOK資料庫中編輯散列值。

#### shim

這篇文章的某些內容需要擴充。

原因：需要進一步測試。 (在 Talk:UEFI/安全啟動#shim 中討論)

在運行時，shim會嘗試啟動`grubx64.efi`。如果MokList沒有包含`grubx64.efi`的散列值或它所簽署的密鑰，shim將會啟動MokManager（`mmx64.efi`）。你必須在MokManager裡登記你想要啟動的EFI二進制文件（你的引導加載程序`grubx64.efi`與內核）的散列值，或者登記你想要簽署的密鑰。

注意：

- 如果你使用#shim與散列值，每次你升級任何二進制文件（比如引導加載程序或內核）後都需要重新登記它們的散列值。
- 在版本15.3之後，shim不再啟動沒有合法`.sbat`部分的EFI二進制文件。想要驗證一個EFI二進制文件是否具有這個部分，運行`objdump -j .sbat -s /path/to/binary.efi`。詳情看：SBAT文檔。
- 或許值得注意的是，說實話，如果你對安全啟動帶來的安全性並不感興趣，之所以想要開啟它僅僅是為了滿足Windows 11的要求，你或許可以考慮關閉shim的驗證過程：`mokutil --disable-validation`。這種情況下你不必簽署grub（或許sbat仍然需要）以及內核鏡像，且還可以通過`chainloader`從grub啟動Windows。

##### 設置shim

提示：rEFInd引導程序中的`refind-install`腳本可以簽署rEFInd的EFI二進制文件並與shim和MOK證書一併複製到ESP中。詳情見rEFInd#使用 shim。

安裝shim-signedAUR.

重命名當前的引導加載程序為`grubx64.efi`

    # mv esp/EFI/BOOT/BOOTx64.EFI esp/EFI/BOOT/grubx64.efi

複製shim與MokManager到ESP中的啟動引導文件夾，然後將`shimx64.efi`重命名為引導加載程序之前的文件名：

注意：

- 確保你不要複製同一目錄下的fbx64.efi，除非你真的有一個有效的bootx64.csv可以使用。否則shim不會執行grubx64.efi，這將無法正常工作，只會重置機器。

    # cp /usr/share/shim-signed/shimx64.efi esp/EFI/BOOT/BOOTx64.EFI
    # cp /usr/share/shim-signed/mmx64.efi esp/EFI/BOOT/

最終，創建一個新的NVRAM引導項來啟動`BOOTx64.EFI`：

    # efibootmgr --unicode --disk /dev/sdX --part Y --create --label "Shim" --loader /EFI/BOOT/BOOTx64.EFI

shim可以通過機器所有者密鑰或MokList所存儲的散列值驗證二進制文件。

機器所有者密鑰 - Machine Owner Key (MOK)
  一個由用戶生成並被用來簽署EFI二進制文件的密鑰。
散列值 - hash
  一個EFI二進制文件的SHA256散列值。

使用散列值更簡單但是每次升級你的引導加載器或內核後需要添加它們新的散列值進MokManager。而使用MOK你只需要添加密鑰一次，但是每次引導加載器或內核升級後都需要重新簽署。

###### shim與散列值

如果shim無法找到在MokList中找到`grubx64.efi`的SHA256散列值，它將會啟動MokManager（`mmx64.efi`）。

在MokManager中選擇Enroll hash from disk，找到`grubx64.efi`然後添加它到MokList。重複這一步驟添加你的內核`vmlinuz-linux`。完成之後，選擇Continue boot，你的引導加載程序便會啟動並成功加載內核。

###### shim與密鑰

安裝sbsigntools包。

你需要：

.key
  PEM格式的私有密鑰，用於簽署EFI二進制文件。
.crt
  PEM格式的證書，用於sbsign。
.cer
  DER格式的證書，用於MokManager。

創建一個機器所有者密鑰（MOK）：

    $ openssl req -newkey rsa:4096 -nodes -keyout MOK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Machine Owner Key/" -out MOK.crt
    $ openssl x509 -outform DER -in MOK.crt -out MOK.cer

簽署你的引導加載程序（名為`grubx64.efi`）以及內核：

    # sbsign --key MOK.key --cert MOK.crt --output /boot/vmlinuz-linux /boot/vmlinuz-linux
    # sbsign --key MOK.key --cert MOK.crt --output esp/EFI/BOOT/grubx64.efi esp/EFI/BOOT/grubx64.efi

每次它們更新後你都需要這麼做。你可以使用一個Pacman鉤子自動化簽署過程，比如：

    /etc/pacman.d/hooks/999-sign_kernel_for_secureboot.hook

    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = Package
    Target = linux
    Target = linux-lts
    Target = linux-hardened
    Target = linux-zen

    [Action]
    Description = Signing kernel with Machine Owner Key for Secure Boot
    When = PostTransaction
    Exec = /usr/bin/find /boot/ -maxdepth 1 -name 'vmlinuz-*' -exec /usr/bin/sh -c 'if ! /usr/bin/sbverify --list {} 2>/dev/null | /usr/bin/grep -q "signature certificates"; then /usr/bin/sbsign --key MOK.key --cert MOK.crt --output {} {}; fi' ;
    Depends = sbsigntools
    Depends = findutils
    Depends = grep

或者使用一個 mkinitcpio鉤子：

    /etc/initcpio/post/kernel-sbsign

    #!/usr/bin/env bash

    kernel="$1"
    [[ -n "$kernel" ]] || exit 0

    # use already installed kernel if it exists
    [[ ! -f "$KERNELDESTINATION" ]] || kernel="$KERNELDESTINATION"

    keypairs=(/path/to/db.key /path/to/db.crt)

    for (( i=0; i<${#keypairs[@]}; i+=2 )); do
        key="${keypairs[$i]}" cert="${keypairs[(( i + 1 ))]}"
        if ! sbverify --cert "$cert" "$kernel" &>/dev/null; then
            sbsign --key "$key" --cert "$cert" --output "$kernel" "$kernel"
        fi
    done

複製`MOK.cer`到一個FAT格式的文件系統（你可以使用EFI 系統分區）。

重新啟動並啟用「安全啟動」。如果shim未能找到在MokList中找到簽署的`grubx64.efi`證書，它將啟動MokManager（`mmx64.efi`）。

在MokManager中選擇Enroll key from disk，找到`MOK.cer`並把它添加到MokList。完成之後，選擇Continue boot，你的引導加載程序便會啟動並成功加載任何由你的機器所有者密鑰簽署的二進制文件。

###### shim與密鑰和GRUB

這篇文章的某些內容需要擴充。

原因：GRUB#UEFI 系統提到了一個叫做`grub-mkstandalone`的工具，但是這裡並沒有出現。 (在 Talk:UEFI/安全啟動 中討論)

本文或本章節可能需要合併到GRUB。

附註： 關於構建自己的EFI二進制文件並選擇模塊或許應該放進GRUB頁面。（在 Talk:UEFI/安全啟動 中討論）

只有GRUB的EFI二進制文件包含所有能夠讀取vmlinuz與initramfs鏡像所在文件系統的模塊，才能在安全啟動模式下成功啟動。

從GRUB版本`2.06.r261.g2f4430cc0`之後，通過`insmod`在安全啟動下讀取模塊不再被允許，因為這將違反不側載任意代碼的構想。如果GRUB模塊沒有被嵌入進EFI二進制文件，GRUB會嘗試通過`insmod`側載它們，這會在啟動時報出如下錯誤信息：

    error: prohibited by secure boot policy

根據Ubuntu的官方構建腳本，Ubuntu嵌入了下列GRUB模塊在它已簽署的GRUB EFI二進制文件`grubx64.efi`中。

- 「base」模塊，為了從CD或者單一分區硬碟中啟動所必需含有： `all_video`, `boot`, `btrfs`, `cat`, `chain`, `configfile`, `echo`, `efifwsetup`, `efinet`, `ext2`, `fat`, `font`, `gettext`, `gfxmenu`, `gfxterm`, `gfxterm_background`, `gzio`, `halt`, `help`, `hfsplus`, `iso9660`, `jpeg`, `keystatus`, `loadenv`, `loopback`, `linux`, `ls`, `lsefi`, `lsefimmap`, `lsefisystab`, `lssal`, `memdisk`, `minicmd`, `normal`, `ntfs`, `part_apple`, `part_msdos`, `part_gpt`, `password_pbkdf2`, `png`, `probe`, `reboot`, `regexp`, `search`, `search_fs_uuid`, `search_fs_file`, `search_label`, `sleep`, `smbios`, `squash4`, `test`, `true`, `video`, `xfs`, `zfs`, `zfscrypt`, `zfsinfo`
- 「platform-specific」模塊，為了x86_64-efi架構所必需含有，例如：
  - `play`：為了在啟動中播放聲音
  - `cpuid`：為了啟動中的CPU支持
  - `linuxefi`：為了支持UEFI啟動
  - `tpm`：為了支持度量啟動（Measured boot）與可信平台模塊
- 「advanced」模塊，包含下列模塊：
  - `cryptodisk`：為了從plain模式加密的硬碟啟動
  - `gcry_algorithm`：為了支持特定的散列和加密算法
  - `luks`：為了從LUKS加密的硬碟啟動
  - `lvm`：為了從LVM邏輯分卷硬碟啟動
  - `mdraid09`, `mdraid1x`, `raid5rec`, `raid6rec`：為了從RAID虛擬硬碟中啟動

你必須以一個shell變量的形式構建你的GRUB模塊列表，我們將它表示為`GRUB_MODULES`。你可以使用最新的Ubuntu腳本作為一個出發點，並修剪掉你系統中不需要的模塊。修剪模塊將使啟動過程相對更快，並在ESP分區上節省一些空間。

如果GRUB從UEFI shim加載器啟動，為了提高安全性，你還需要在EFI二進制文件中包含一個安全啟動高級目標（SBAT）文件/部分。這個SBAT文件/部分包含了關於GRUB二進制文件的元數據（版本、維護者、開發者、上游URL），並且使shim更容易阻止某些有安全漏洞的GRUB版本被加載[8][9]，正如UEFI shim引導加載程序的安全啟動生命流程的提升文檔中所解釋的那樣。

如果`grubx64.efi`中的SBAT部分丟失，UEFI shim引導加載程序的第一階段將無法啟動`grubx64.efi`。

如果安裝了GRUB，`/usr/share/grub/sbat.csv`中提供了一個SBAT的.csv文件樣本。

使用提供的`/usr/share/grub/sbat.csv`文件和所有需要的`GRUB_MODULES`重新安裝GRUB並簽署：

    # grub-install --target=x86_64-efi --efi-directory=esp --modules=${GRUB_MODULES} --sbat /usr/share/grub/sbat.csv
    # sbsign --key MOK.key --cert MOK.crt --output esp/EFI/GRUB/grubx64.efi esp/EFI/GRUB/grubx64.efi
    # cp esp/GRUB/grubx64.efi esp/boot/grubx64.efi

重新啟動，在MokManager中選擇密鑰，安全啟動就應該可以工作了。

##### 移除shim

卸載shim-signedAUR，移除被複製的shim與MokManager文件並重命名為你的引導加載程序默認名。

## 保護安全啟動

防止有物理訪問權限的人禁用安全啟動的唯一方法是用密碼保護固件設置。

大多數UEFI固件提供這樣的功能，通常列在固件設置中的「安全」部分。

## 提示與技巧

### sbctl

sbctl包是一種用戶友好的設置安全啟動和簽署文件方式。

注意：sbctl並不能在所有的硬體上工作。它的實際工作效果取決於製造商。

#### 創建並登記密鑰

在開始之前，進入你的固件設置將安全啟動模式設置為設置模式。每個設備都有所不同。

當你重新登錄後，檢查安全啟動的狀態：

    $ sbctl status

你應當看到sbctl並未安裝，並且「設置模式」（Setup Mode）已經開啟，以及安全啟動已關閉。

若顯示「設置模式」（Setup Mode）關閉，請進入BIOS手動重置進入Setup Mode。

接下來創建你的自定義安全啟動密鑰：

    # sbctl create-keys

（在sbctl 0.8以及更新版本之後，執行此命令默認會把密鑰創建在/var/lib/sbctl/keys/文件夾內）

將你的密鑰與微軟的密鑰登記入UEFI中：

    # sbctl enroll-keys -m

警告：啟用安全啟動時，一些固件會用微軟的密鑰進行簽署和驗證。不對設備進行驗證可能會使它們變磚。如果想僅登記你的密鑰而不登記微軟的，請運行：`# sbctl enroll-keys`。只有在你清楚了解自己在做什麼的情況下才可以這樣做。

再次檢查安全啟動狀態：

    $ sbctl status

sbctl現在應該已經安裝好了，但是在用你剛剛創建的密鑰對啟動文件進行簽署之前，安全啟動將無法工作。

#### 簽署

為了安全啟動工作，檢查需要被簽署的文件：

    # sbctl verify

現在簽署所有的未被簽署的文件。通常是內核與引導加載程序需要被簽署。比如：

    # sbctl sign -s /boot/vmlinuz-linux
    # sbctl sign -s /boot/EFI/BOOT/BOOTX64.EFI

需要被簽署的文件將取決與你系統的結構，內核以及引導加載程序。

現在萬事大吉！重新啟動你的系統，並在固件設置中重新打開安全啟動。如果引導加載程序與作業系統被加載，安全啟動應當開始工作了。用下列命令確認：

    $ sbctl status

#### 使用pacman鉤子自動簽署

sbctl帶有一個Pacman鉤子可以在內核、systemd或者引導加載程序更新後自動地簽署所有的新文件。

提示：如果你通過Systemd-boot啟用了`systemd-boot-update.service`，那麼引導加載程序只會在重啟後升級，導致sbctl的Pacman鉤子因此而不簽署新的文件。 變通的方法是直接在`/usr/lib/`中小心的簽署引導加載程序，這樣`bootctl install`與`update`將會自動識別並複製.efi.signed（如果有的話）到ESP，而不是普通的.efi文件。詳情見bootctl(1)。

    # sbctl sign -s -o /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed /usr/lib/systemd/boot/efi/systemd-bootx64.efi

### 用自定義密鑰簽署官方ISO

使用自定義密鑰的安全啟動支持可以添加到官方ISO中，只需提取出引導加載程序（`BOOTx64.EFI`與`BOOTIA32.EFI`）、內核與UEFI Shell，並對它們進行簽署，然後用被簽署的文件重新打包ISO。

安裝libisoburn包、mtools包與sbsigntools包。

首先解壓出相關的文件以及El-Torito啟動鏡像：

    $ osirrox -indev archlinux-YYYY.MM.DD-x86_64.iso \
    	-extract_boot_images ./ \
    	-extract /EFI/BOOT/BOOTx64.EFI BOOTx64.EFI \
    	-extract /EFI/BOOT/BOOTIA32.EFI BOOTIA32.EFI \
    	-extract /shellx64.efi shellx64.efi \
    	-extract /shellia32.efi shellia32.efi \
    	-extract /arch/boot/x86_64/vmlinuz-linux vmlinuz-linux

mkarchiso所使用的，xorrisofs(1)的`-rational-rock`選項，會使ISO 9660中的文件變為只讀，且在解壓後仍然如此。我們需要讓這些文件變為可寫，以便它們可以被修改：

    $ chmod +w BOOTx64.EFI BOOTIA32.EFI shellx64.efi shellia32.efi vmlinuz-linux

使用一個已登記的資料庫密鑰和證書籤署這些文件：

    $ sbsign --key db.key --cert db.crt --output BOOTx64.EFI BOOTx64.EFI
    $ sbsign --key db.key --cert db.crt --output BOOTIA32.EFI BOOTIA32.EFI
    $ sbsign --key db.key --cert db.crt --output shellx64.efi shellx64.efi
    $ sbsign --key db.key --cert db.crt --output shellia32.efi shellia32.efi
    $ sbsign --key db.key --cert db.crt --output vmlinuz-linux vmlinuz-linux

將引導加載程序與UEFI Shell複製到`eltorito_img2_uefi.img`中。它將被用作為EFI系統分區，並被列為一個El-Torito UEFI啟動鏡像。`eltorito_img2_uefi.img`的大小是固定的，但mkarchiso增加了1 MiB的空餘空間，用於對齊以及為後續的扇區保留，所以簽署所帶來的大小增加應該不是問題。

    $ mcopy -D oO -i eltorito_img2_uefi.img BOOTx64.EFI BOOTIA32.EFI ::/EFI/BOOT/
    $ mcopy -D oO -i eltorito_img2_uefi.img shellx64.efi shellia32.efi ::/

使用修改過的El-Torito UEFI引導映像，重新打包ISO，並在ISO 9660中加入簽署的引導加載程序文件、UEFI Shell和內核。

    $ xorriso -indev archlinux-YYYY.MM.DD-x86_64.iso \
    	-outdev archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso \
    	-boot_image any replay \
    	-append_partition 2 0xef eltorito_img2_uefi.img \
    	-map BOOTx64.EFI /EFI/BOOT/BOOTx64.EFI \
    	-map BOOTIA32.EFI /EFI/BOOT/BOOTIA32.EFI \
    	-map shellx64.efi /shellx64.efi \
    	-map shellia32.efi /shellia32.efi \
    	-map vmlinuz-linux /arch/boot/x86_64/vmlinuz-linux

啟動生成的`archlinux-YYYY.MM.DD-x86_64-Secure_Boot.iso`文件。

## 另見

- Understanding the UEFI Secure Boot Chain by tianocore
- Wikipedia:Unified Extensible Firmware Interface#Secure boot
- Dealing with Secure Boot by Rod Smith
- Controlling Secure Boot by Rod Smith
- UEFI secure booting (part 2) by Matthew Garrett
- UEFI Secure Boot by James Bottomley
- efitools README
- Will your computer's "Secure Boot" turn out to be "Restricted Boot"? — Free Software Foundation
- Free Software Foundation recommendations for free operating system distributions considering Secure Boot
- Intel's UEFI Secure Boot Tutorial
- Secure Boot, Signed Modules and Signed ELF Binaries
- National Security Agency docs: UEFI Defensive Practices Guidance and unclassified UEFI Secure Boot customization
- sbkeysync & maintaining uefi key databases by Jeremy Kerr
- Secure your boot process: UEFI + Secureboot + EFISTUB + Luks2 + lvm + Arch Linux (2020-07)
- How is hibernation supported, on machines with UEFI Secure Boot? (Security StackExchange)
- Authenticated Boot and Disk Encryption on Linux by Lennart Poettering (2021-09-23)

分類：​

- 啟動過程

隱藏分類：​

- 使用「模板:合併」標記的頁面或章節

UEFI/安全啟動
新增話題