一、UEFI 是什么?
UEFI 是一種規范,定義了平臺固件和操作系統之間的接口,從廠商實現的角度出發,我們可以把 UEFI 理解為比 BIOS 更安全、更具擴展性的新固件(固件就是固化在主板 EEPROM 中的子系統,用于處理計算機操作系統加載之前的所有事情),我們跟 UEFI 打交道的界面就是 UEFI 固件的 UI,大概長這個樣子(如下圖),我們都見過 BIOS UI,只有簡單的文本操作界面,為什么 UEFI 能夠做到圖形化呢?因為 UEFI 固件在啟動時可以加載 EFI 設備驅動,有了顯卡驅動, UEFI 的界面就可以實現豐富的圖形化。
- UEFI 支持從網絡啟動
- UEFI 能自動識別 USB 和 CD-ROM 中的啟動項
- UEFI 啟動項等配置可以在操作系統上通過定義的接口進行修改
- UEFI 啟動界面支持豐富的圖形化
- UEFI 支持安全啟動
- UEFI 支持擴展
二、 Secure Boot 和密鑰
Secure Boot 是 UEFI 標準的一部分,簡單地說,UEFI 通過公私鑰加密體系來確保 UEFI 啟動過程中加載的所有可執行文件(EFI 驅動程序、EFI 可執行程序、操作系統 bootloader 等)的有效性和合法性,即數字簽名存在且是有效的,這從根本上在在固件啟動過程中的可能遭受的攻擊問題,為了實現這個功能,UEFI 中定義了以下四個類型的安全變量存儲密鑰、簽名和哈希值。
盡管密鑰驗證看起來類似于 SSL 標準,但是還有些不同,密鑰鏈只驗證到密鑰數據庫中的密鑰本身,不會再往后追溯,但 SSL 會一直驗證到 CA 根。所有的密鑰都存儲在 UEFI 安全變量中,每個變量創建后,只有能證明(擁有對應的私鑰)自己是創建本安全變量的人才能更新此變量,其他人無法更新。
1. PK (Platform Key 平臺密鑰)
此處的平臺可以理解為某一個主板廠商的某一個型號的主板(所以一般計算機廠商都有 n 中不同的平臺),每個主板中改密鑰最多只能有一個,它的作用是用來驗證 KEK 變量中所有密鑰的合法性,大部分的廠商實現中,這個密鑰是 X509 數字證書格式(當然存儲在 NVRAM 中的密鑰是轉換后的二進制格式)。平臺密鑰的擁有者本質上就是平臺的擁有者,比如:聯想的某個主板中的 PK 擁有者就是聯想公司這個主體。如果平臺密鑰被清除,平臺一般會進入到安裝模式,同時平臺密鑰可以被替換成自己生成的密鑰。
2. KEK (Key Exchange Key 密鑰交換密鑰)
KEK 用于對 db 和 dbx 數據庫中內容進行存儲、更新、刪除時進行簽名驗證,只有有效簽名的密鑰、簽名和哈希值才能寫入、刪除或更新到數據庫中。KEK 可以包含多個,一般計算機出廠時包含兩個 KEK,一個是微軟的,一個是主板廠商的,這樣微軟和廠商都可以發布固件更新包對固件進行直接更新。
3. db (Signature Database 簽名數據庫)
用于在 Secure Boot 打開的情況下對 EFI 二進制文件進行簽名驗證,db 中可以包含密鑰、簽名和哈希,在 Secure Boot 模式下,EFI 二進制文件(EFI 驅動,bootloader 等)中的簽名信息會跟這個數據庫中的數據進行比較,如果滿足以下任何一個條件,則說明該二進制文件合法可執行。
- 文件沒有簽名,但 db 中包含該文件的 SHA-256 哈希值
- 文件已簽名并且 db 中包含這個簽名信息
- 文件已簽名并且 db 中包含給這個文件簽名的密鑰并且簽名是有效的
4. dbx (Forbidden Signatures Database 禁用簽名數據庫)
這是一個類似黑名單的數據庫,只要 EFI 可執行文件的簽名、哈希等信息存在于黑名單中,那么這個 EFI 二進制文件將不能被執行。
三、如何執行數字簽名和驗證數字簽名
首先會對該文件使用哈希算法(SHA-256,MD5等)進行消息摘要操作,生成一個固定長度的摘要信息,MD5后的消息摘要長度為 32 (128/8) 字節,SHA-256 哈希后的長度為 64 (256/8) 個字節,然后使用私鑰對生成的固定長度的摘要進行不對稱加密(只有對應的公鑰才能解密),加密后的密文就是數字簽名,數字簽名可以追加到原始文件的后面,也可以單獨用另一個文件保存,隨原始文件一起發布。
問題: 為什么不對文件直接進行非對稱加密操作,而是對文件哈希后的摘要加密?
因為非對稱加密是個 CPU 密集型操作,需要消耗大量算力,當需要加密的文件很大時,這個操作帶來的性能問題是難以接受的,而哈希算法的不可逆性和生成的摘要長度短小且固定正好能夠用在這個場景中。
四、常見問題
PK 、KEK 能不能被清除或寫入?
大部分兼容機都可以被清除和寫入自己的 PK,但有些筆記本不行,比如:Surface 的 Secure Boot 無法被關閉,所有密鑰都不能被清除。
EFI 可執行文件包括哪些?
包括在 UEFI 啟動過程中加載的所有可執行文件、驅動、鏡像、操作系統 bootloader 等。
PK KEK 安全變量中存儲的密鑰格式?
密鑰大部分是 X509 數字證書格式,存儲到安全變量中的是轉換后的二進制格式。
幾種類型密鑰之間的關系?
UEFI 模式轉換關系
如何創建自己的密鑰?
在 Windows(安裝 git bash) 或 Linux 主機上可以使用以下腳本自己創建對應的密鑰。
#!/bin/bash
echo -n "請輸入一個通用名,比如公司名稱或個人名字: "
read NAME
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$NAME PK/" -keyout PK.key \
-out PK.crt -days 3650 -nodes -sha256
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$NAME KEK/" -keyout KEK.key \
-out KEK.crt -days 3650 -nodes -sha256
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$NAME DB/" -keyout DB.key \
-out DB.crt -days 3650 -nodes -sha256
openssl x509 -in PK.crt -out PK.cer -outform DER
openssl x509 -in KEK.crt -out KEK.cer -outform DER
openssl x509 -in DB.crt -out DB.cer -outform DER
GUID=`python -c 'import uuid; print(str(uuid.uuid1()))'`
echo $GUID > myGUID.txt
cert-to-efi-sig-list -g $GUID PK.crt PK.esl
cert-to-efi-sig-list -g $GUID KEK.crt KEK.esl
cert-to-efi-sig-list -g $GUID DB.crt DB.esl
rm -f noPK.esl
touch noPK.esl
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
-k PK.key -c PK.crt PK PK.esl PK.auth
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
-k PK.key -c PK.crt PK noPK.esl noPK.auth
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
-k PK.key -c PK.crt KEK KEK.esl KEK.auth
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \
-k KEK.key -c KEK.crt db DB.esl DB.auth
chmod 0600 *.key
echo ""
echo ""
echo "For use with KeyTool, copy the *.auth and *.esl files to a FAT USB"
echo "flash drive or to your EFI System Partition (ESP)."
echo "For use with most UEFIs' built-in key managers, copy the *.cer files."
echo ""
參考文章
UEFI SecureBoot on Debian
Protecting the pre-OS environment with UEFI