UEFI 驗證選項 ROM 指引

1.3 版

本文件可協助 OEM 和 ODM 驗證其韌體是否檢查其選項 ROM 的簽章,作為安全開機鏈信任鏈結的一部分。

本指南假設您瞭解 UEFI 的基本概念、安全開機的基本瞭解(UEFI 規格的第 1 章、2、13、20 和 27 章),以及 PKI 安全性模型。

簡介

選項 ROM (或 OpROM) 是由電腦 BIOS 在平臺初始化期間執行的韌體。 它們通常儲存在外掛程式卡片上,不過它們可以位於系統面板上。

通常需要選項 ROM 的裝置是 RAID 模組的視訊卡、網路適配器和儲存裝置驅動程式。 這些選項 ROM 通常也會提供韌體驅動程式給電腦。

它們包含各種不同的韌體驅動程序類型,包括舊版PC-AT、開放式韌體和EFI選項 ROM。 韌體驅動程式的範例包括視頻卡上的視訊 BIOS、乙太網路卡的 PXE 開機驅動程式,以及 RAID 控制器上的儲存裝置驅動程式。 這些裝置通常會有提供韌體驅動程序的選項 ROM。

整合可擴展韌體介面 (UEFI) 支援舊版模式選項 ROM。

根據最新的 UEFI 規格(目前為 2.3.1 Errata C – 第 2.5.1.2 節),ISA (舊版) 選項 ROM 不是 UEFI 規格的一部分。 基於此討論的目的,只會考慮PCI型UEFI相容選項 ROM。

當無法在計算機韌體中內嵌裝置的韌體時,可以使用選項 ROM。 當選項 ROM 攜帶驅動程式時,IHV 可以利用該驅動程式,並將驅動程式和裝置保留在一個地方。

本文件將討論您需要驗證選項 ROM 的原因,並示範一些執行動作的技術。

同時支援 UEFI BIOS 和舊版 BIOS

許多製造商會建立裝置,包括許多計算機類型的選項 ROM 和韌體。 常見的組合包括:

  • 僅限舊版 ROM
  • UEFI 原生 OpROM
  • 舊版 ROM + UEFI EBC OpROM
  • 舊版 ROM + UEFI x64 OpROM
  • 舊版 ROM + UEFI x64 + UEFI IA32
  • 舊版 ROM + UEFI x64 + UEFI IA32 + UEFI EBC OpROM

啟用相容性支援模組 (CSM) 時,UEFI BIOS 可以載入和執行舊版韌體驅動程式。 請注意,啟用安全開機時,禁止執行相容性支援模組和舊版 ROM,因為舊版韌體驅動程式不支持驗證。如果 BIOS 設定中的 Option ROM 格式設定為舊版 ROM,它一律會在裝置上使用舊版 ROM。

如果 Option ROM 格式設定為 UEFI 相容,則如果存在 EFI ROM,則會使用較新的 EFI ROM,如果不存在,則會使用舊版 ROM。

許多新的韌體層級安全性功能以及啟用 UEFI 開機順序,都需要 UEFI 驅動程式。 例如,當啟用安全開機時,無法從連接至非 UEFI 相容儲存控制器的光碟安裝 Windows。

1. UEFI 和選項 ROM

diagram of uefi driver considerations

圖 2:UEFI 驅動程式安全性考慮,來源:UEFI 2.3.1 Errata C

下列文字源自 UEFI 2.3.1 Errata C,但此後已使用 partnerf 的深入解析進行修改:

由於 UEFI 使用者配置檔詳述了許多安全性相關許可權,因此使用者身分識別管理員和使用者認證提供者及其執行環境必須受到信任。

這包括:

  • 保護儲存這些驅動程式的儲存區域。
  • 保護選取這些驅動程式的方法。
  • 保護這些驅動程式的執行環境,避免未驗證的驅動程式。
  • 這些驅動程式所使用的數據結構不應在未授權的驅動程式仍在使用時損毀。

使用者身分識別管理員、使用者認證驅動程式和面板驅動程式等元件可能位於安全的位置,例如由平台原則信任的受寫入保護的快閃磁碟驅動器。

其他一些驅動程式可能位於未受保護的儲存位置,例如選項 ROM 或硬碟磁碟分區,而且可能很容易被取代。 必須驗證這些驅動程式。

例如,預設平臺原則必須能夠成功驗證 Driver#### 載入選項中列出的驅動程式,否則必須先識別使用者,才能處理這些驅動程式。 否則,應該延後驅動程序執行。 如果使用者配置檔是透過後續呼叫識別 () 或透過動態驗證來變更,則 Driver#### 選項可能無法再次處理。

使用者配置檔資料庫會根據是否可以受到保護,使用不同的 UEFI 訊號事件來關閉。

UEFI 驅動程式和 UEFI 選項 ROM 只會針對開機路徑中的裝置執行。

PCI 規格允許相同裝置上的多個選項 ROM 映像。 這些選項 ROMS 可以是舊版 x86 和 UEFI。 UEFI 韌體會設定平台原則,以挑選選項 ROM。 這可讓選擇性適配卡的 ROM 以自己的控制裝置的形式執行。

韌體會在 BDS 和 DXE 階段期間驗證簽章。 事件的順序如下:

  1. 初始化PCI和衍生總線
  2. 探查PCI裝置的選項 ROM
  3. 找到的選項 ROM 會對應到記憶體中
  4. DXE 階段會在 ROM 中載入任何 UEFI 驅動程式

UEFI 選項 ROM 可以是記憶體中的任何位置。 預設值是讓卡片上的 ROM 管理裝置。 UEFI 可讓平臺控制哪些選項 ROM 控制使用EFI_PLATFORM_DRIVER_OVERRIDE裝置的原則。 UEFI 支援選項 ROM 來註冊組態介面。

在已啟用安全開機的計算機上,如果 ROM 驅動程式未簽署或未驗證,選項 ROM 驅動程式會構成安全性威脅。 選項 ROM 的簽章驗證是 WHCK 需求。 維護選項 ROM 時也是如此,以確保在安裝之前驗證更新。

從 Windows 硬體相容性計劃規格和原則版本 1809

  1. 已簽署的韌體程式代碼完整性檢查。 OEM 所安裝的韌體,而且是唯讀的,或受到上述安全韌體更新程式所保護的韌體,可能會被視為受保護。 系統應確認所有未受保護的韌體元件、UEFI 驅動程式和 UEFI 應用程式都已使用最低 RSA-2048 與 SHA-256 簽署(禁止 MD5 和 SHA-1),並確認未根據這些需求簽署的 UEFI 應用程式和驅動程式將無法執行(這是可接受的簽章演演算法的默認原則)。 如果在授權資料庫中找不到影像簽章,或在禁止資料庫中找到映射簽章,則不得啟動映像,而應將其相關信息放在映像執行資訊表中。

2. 問題語句

某些已啟用安全開機的 UEFI BIOS 組建,包括 Tiano Core,預設不會驗證 UEFI 選項 ROM,因為在安全開機開發期間無法使用已簽署的 UEFI 選項 ROM。 這會公開 UEFI 安全開機中的受攻擊面/弱點。

2.1. 弱點

截至 2013 年 8 月,EDK II 和 UDK2010 仍存在此弱點。 來源維護人員知道問題,並提出 Bug。 任何衍生自 EDK II 和 UDK2010 的韌體都應該驗證選項 ROM 驗證的管理方式。 選項 ROM 驗證行為是由 EDK II SecurityPkg 套件中的 PCD 值 PcdOptionRomImageVerificationPolicy 所控制。

TianoCore 弱點的原始程式碼為 SecurityPkg\SecurityPkg.dec 檔案:

## Pcd for OptionRom.
  #  Image verification policy settings:
  #  ALWAYS_EXECUTE                         0x00000000
  #  NEVER_EXECUTE                          0x00000001
  #  ALLOW_EXECUTE_ON_SECURITY_VIOLATION    0x00000002
  #  DEFER_EXECUTE_ON_SECURITY_VIOLATION    0x00000003
  #  DENY_EXECUTE_ON_SECURITY_VIOLATION     0x00000004
  #  QUERY_USER_ON_SECURITY_VIOLATION       0x00000005
gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x00|UINT32|0x00000001

默認值 (0x00) 是ALWAYS_EXECUTE,這無法正確執行載入宏周邊選項 ROM 中已簽署驅動程序的驗證。 對於任何實作 UEFI 安全開機功能的系統而言,這不是理想的值。

建議值 (最佳安全性): DENY_EXECUTE_ON_SECURITY_VIOLATION (0x04)

建議的值(最佳彈性): QUERY_USER_ON_SECURITY_VIOLATION (0x05)

在EDK II和 UDK2010中,適當的編碼作法會使用覆寫機制來修改平臺韌體的電腦D值。 因此,不應該在 中SecurityPkg\SecurityPkg.dec變更的值PcdOptionRomImageVerificationPolicy。 覆寫值應該在平臺的 DSC 檔案中設定。 以下是使用 Nt32Pkg\Nt32Pkg.dsc 的範例:

[PcdsFixedAtBuild]
gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x04

PCD 覆寫應該放在 DSC 檔案的 區段之下 [PcdsFixedAtBuild] 。 覆寫參數的確切機制可能會因 BIOS 廠商工具而異。

注意

此弱點可能存在於獨立 BIOS 廠商的 UEFI 安全開機 BIOS 早期實作中。 請連絡 BIOS 廠商,以判斷您的版本是否受到影響。

3. 神秘 受到影響?

實作安全開機的 UEFI 計算機,且具有未簽署的 UEFI 選項 ROM 驅動程式。 此外,用來取得現有卡片運作的韌體可能會有安全性弱點,但不會驗證選項 ROM。

膝上型計算機、網簿、Ultrabook 和平板電腦:大部分不會受到影響。 選項 ROM 通常存在於背板總線上,例如 PCI/e、ISA 及其衍生產品(ExpressCard、miniPCI、CardBus、PCCard、LPC、ThunderBolt 等)。 如果膝上型計算機沒有暴露這些,其受攻擊面會大幅減少。 此外,上線膝上型計算機元件的 UEFI 驅動程式可能會整合到核心 BIOS 韌體磁碟區中,而不是位於個別選項 ROM 上。 因此,大多數膝上型計算機沒有風險。 此外,當舊版選項 VM 停用時,UEFI 似乎只支援PCI選項 ROM。

不過,如果您有桌面、主機板或具有 UEFI BIOS 並實作安全開機的伺服器,可能會受到影響。 在伺服器的專用 RAID 控制器或 SATA、FC 等的載入宏儲存控制器上,或乙太網路 PCIe 網路卡可能會有選項 ROM。 支援伺服器上各種功能的載入宏控制器很常見,因此這特別適用於伺服器空間。

這可能會影響32位和64位電腦,類別2和類別3。

如果安全開機平臺支援來自未永久附加至平臺之裝置的選項 ROM,且支援驗證這些選項 ROM 的能力,則必須支援網路協定 - UDP 和 MTFTP 中所述的選項 ROM 驗證方法,以及 UEFI 規格 2.3.1 Errata C 第 7.2 節中所述的已驗證 EFI 變數。

4.如何測試?

如果您正在開發韌體,且其以 Tiano Core 為基礎,請檢查 2.1 節中所述的弱點。 如果您使用另一個 IBV 的韌體,請洽詢它們。 或者,您可以自行進行測試,如下所示。

您將需要下列項目:

  • 受 UEFI 韌體測試的電腦
  • 受測電腦上具有選項 ROM 的 PCI 裝置(例如視頻卡)
  • 確定已啟用安全開機

測試的步驟:

  1. 將具有 UEFI 選項 ROM 的 PCI 記憶卡上的 UEFI 新增至受測電腦。

    如果您使用PCI視訊卡進行測試,請連結外部監視器。

  2. 使用下列設定啟用安全開機:

    • PK:您的 PK 或自我簽署測試 PK
    • KEK:MS KEK、PK 簽署的 Fabrikam 測試 KEK 或其他 KEK
    • DB:NULL。 (這必須是 NULL。
    • DBX:NULL。
    • SecureBoot:UEFI 變數應設定為 true
  3. 重新啟動電腦

  4. 預期會有下列結果:

    • 如果正確實作 UEFI 韌體,UEFI 選項 ROM 驅動程式將不會載入,因為選項 ROM 的存在會使韌體檢查憑證的 「Db」。 由於「Db」 是 NULL,因此 UEFI 驅動程式將無法載入。 例如,如果您使用視訊卡進行測試,您會看到顯示時不會顯示任何內容。
    • 如果未正確實作韌體,UEFI 驅動程式會從選項 ROM 載入,因為韌體不會檢查 「Db」 中的簽章。 例如,如果您使用視頻卡進行測試,您會看到連結至選項 ROM 記憶卡的監視器將會顯示。

    ![注意]如果 UEFI 選項 ROM 驅動程式已簽署或未簽署,當 DB 為 Null 且啟用 SB 時,ROM 選項不會載入,這並不重要(已註冊 PK 和 KEK)。

請參閱 WHCK 中提供的範例腳本,以產生 PK 和 KEK。 附錄 B 有範例腳本和更多詳細數據。

您也可以參考附錄 A,以取得執行上述測試的另一種方法。 此方法不需要將 DB 設定為 Null,但需要來自 IHV 的未簽署 UEFI 選項 ROM 驅動程式。

5.如何修正此問題

如果上述測試失敗,請與您的 IBV 合作以取得必要的版本,並將其設定為驗證選項 ROM。 請確定韌體通過測試。 針對隨附的計算機,您必須進行安全的韌體更新。 請參閱 NIST 發行集 800-147 和/或參閱 Windows 8.1 安全開機密鑰建立和管理指引

您可以測試計算機,並利用 Windows HCK 作為測試工具(而非認證工具),以測試安全韌體更新。

5.1. 簽署驅動程式

如果您發現 UEFI 選項 ROM 上可能有未簽署的驅動程式,請閱讀下方如何修正此問題。

個別簽署每個選項 ROM 驅動程式。 這會中斷PCI選項 ROM 格式。 您只需要簽署 UEFI 驅動程式,才能建立合併的選項 ROM。

在 OpROM 中插入 UEFI 驅動程式之前,請先簽署 UEFI 映射,然後在 UEFI 殼層使用安全開機和關閉來測試它(載入/卸除驅動程式檔案)。 然後將已簽署的驅動程式放入合併的選項 ROM。

您可以將 IHV 導向 Microsoft SysDev 中心,以透過 SysDev 中心所提供的服務取得其 UEFI 選項 ROM。

5.2. 更新的驗證

執行上述測試,以確認弱點不存在。 使用 HCK 測試來確保沒有功能回歸。

6. 資源

附錄 A:使用未簽署選項 ROM 驅動程式進行測試的替代方法

此方法依賴從 IHV 取得工具,以確保 UEFI 選項 ROM 驅動程式已簽署。

您將需要下列項目:

  • 受 UEFI 韌體測試的電腦
  • 已連結至受測電腦之未簽署選項 ROM 驅動程式的 PCI 裝置(例如視訊卡)
  • 確定已啟用安全開機
  • 選項 IHV 工具,在選項 ROM 驅動程式上偵測簽章時,如果選項 ROM 驅動程式簽署或未簽署

如果韌體已正確實作,且 ROM 選項未簽署,卡片應該會因韌體檢查失敗,而不會在卡片上載入驅動程式。 計算機應該回報錯誤碼,例如 EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND。 如果您使用視訊卡,您可能會看到計算機只會顯示黑色螢幕,因為選項 ROM 驅動程式未載入。

如果韌體實作不正確,此測試將會運作。

附錄 B:使用 NULL db 啟用安全開機的腳本

您可以使用您目前的安全開機變數集(PK 和 KEK),或產生測試變數來測試。

以下是用來產生測試 PK、KEK 並將 Db 設定為 NULL 的步驟。 請確定未啟用安全開機;否則,這些步驟會要求已簽署的 UEFI bin 檔案。

注意

我們會以反向順序設定安全開機變數 – Db、KEK 和 PK,因此我們不需要簽署 UEFI bin 檔案。

在此步驟之前,計算機應該處於安裝模式。

  1. 建立 KEK 和 PK 憑證

    此步驟需要 Windows SDK可用的makecert.exe工具。

    MakeCert.exe -cy authority -len 2048 -m 60 -a sha256  -pe -ss my -n "CN=DO NOT SHIP - Fabrikam Test KEK CA" Fabrikam_Test_KEK_CA.cer
    MakeCert.exe -cy authority -len 2048 -m 60 -a sha256  -pe -ss my -n "CN=DO NOT SHIP - Fabrikam Test PK" TestPK.cer
    
  2. 產生測試 PK 的腳本

    以下提供範例。

    this scripts demonstrates how to format the Platform key
    NOTE The PK is actually set in the Enable_OEM_SecureBoot.ps1 script
    Import-Module secureboot
    $d = (pwd).Path
    
    ###############################################################################
    Complete the following parameters
    ###############################################################################
    
    $certname = "TestPK"
    TODO change this path to where you have the PK.cer file
    This is where you plugin the certificate generated by the HSM
    $certpath = $d + "\" + $certname + ".cer"
    
    Each signature has an owner SignatureOwner, which is a GUID identifying the agent which inserted the signature in the database.
    Agents might include the operating PC or an OEM-supplied driver or application.
    Agents may examine this field to understand whether they should manage the signature or not.
    TODO replace with OEM SignatureOwner GUID.
    You can use tools like Guidgen.exe tool in SDK or a similar tool to generate a GUID
    $sigowner = "55555555-5555-5555-5555-555555555555"
    
    $var = "PK"
    $efi_guid = "{8BE4DF61-93CA-11d2-AA0D-00E098032B8C}"
    $append = $false
    
    ###############################################################################
    Everything else is calculated
    ###############################################################################
    
    Workaround relative path bug
    TODO substitute OEM with your OEM name
    $siglist =  $certname + "_SigList.bin"
    $serialization = $certname + "_SigList_Serialization_for_" + $var + ".bin"
    $signature = $serialization + ".p7"
    
    $appendstring = "set_"
    $attribute = "0x27"
    $example = "Example_SetVariable_Data-" + $certname + "_" + $appendstring + $var + ".bin"
    
    Format-SecureBootUEFI -Name $var -SignatureOwner $sigowner -ContentFilePath $siglist -FormatWithCert -Certificate $certpath -SignableFilePath $serialization -Time 2011-05-21T13:30:00Z  -AppendWrite:$append
    
    OutputFilePath - Specifies the name of the file created that contains the contents of what is set.
    If this parameter is specified, then the content are not actually set, just stored into this file.
    Please note if -OutputFilePath is provided the PK is not set like in this case. The master script sets it at the end.
    
    Time - you can change the time below as long as it isn't in the future. Nothing wrong with keeping it as is.
    
    Set-SecureBootUEFI -Name $var -Time 2011-05-21T13:30:00Z -ContentFilePath $siglist  -OutputFilePath $example -AppendWrite:$append
    
  3. 產生測試 KEK 或使用您自己的 OEM KEK

    您可以利用 WHCK 中自己的 OEM KEK 或腳本來進行此工作。

    以下提供範例。

    script to add option OEM KEK
    Import-Module secureboot
    $d = (pwd).Path
    
    ###############################################################################
    Complete the following parameters
    ###############################################################################
    
    $certname = "Fabrikam_Test_KEK_CA"
    TODO change this path to where you have the PK.cer file
    This is where you plugin the certificate generated by the HSM
    $certpath = $d + "\" + $certname + ".cer"
    
    TODO change this path to where you have the OEM_KEK.cer file
    Each signature has an owner SignatureOwner, which is a GUID identifying the agent which inserted the signature in the database.
    Agents might include the operating system or an OEM-supplied driver or application.
    Agents may examine this field to understand whether they should manage the signature or not.
    TODO replace with OEM SignatureOwner GUID.
    You can use tools like Guidgen.exe tool in SDK or a similar tool to generate a GUID
    
    $sigowner = "00000000-0000-0000-0000-000000000000"
    
    $var = "KEK"
    $efi_guid = "{8BE4DF61-93CA-11d2-AA0D-00E098032B8C}"
    $append = $false
    
    ###############################################################################
    Everything else is calculated
    ###############################################################################
    
    $siglist = $certname + "_SigList.bin"
    $serialization = $certname + "_SigList_Serialization_for_" + $var + ".bin"
    $signature = $serialization + ".p7"
    if ($append -eq $false)
    {
    $appendstring = "set_"
    $attribute = "0x27"
    } else
    {
    $appendstring = "append_"
    $attribute = "0x67"
    }
    $example = "Example_SetVariable_Data-" + $certname + "_" + $appendstring + $var + ".bin"
    
    Format-SecureBootUEFI -Name $var -SignatureOwner $sigowner -ContentFilePath $siglist -FormatWithCert -CertificateFilePath $certpath -SignableFilePath $serialization -Time 2011-05-21T13:30:00Z -AppendWrite:$append
    
    -Time You can change the time below as long as it isn't in the future. Nothing wrong with keeping it as is.
    
    Set-SecureBootUEFI -Name $var -Time 2011-05-21T13:30:00Z -ContentFilePath $siglist -OutputFilePath $example -AppendWrite:$append
    
  4. 將 Db 設定為 Null,並將 KEK 和 PK 設定為

    此腳本所做的第一件事是將 Db 設定為 Null。

    注意

    請記住,如果 Fabrikam 測試 KEK CA 是唯一存在的 KEK CA(表示沒有 Windows KEK CA),計算機可能會開機進入 Windows RE。

    在腳本執行之前,請執行 “Set-ExecutionPolicy Bypass -Force”

    Import-Module secureboot
    try
    {
    Write-Host "Deleting db..."
    Set-SecureBootUEFI -Name db -Time "2011-06-06T13:30:00Z" -Content $null
    }
    catch
    {
    }
    Write-Host "Setting Fabrikam KEK..."
    Set-SecureBootUEFI -Time 2011-05-21T13:30:00Z  -ContentFilePath Fabrikam_Test_KEK_CA_SigList.bin  -Name KEK
    
    Write-Host "Setting self-signed Test PK..."
    Set-SecureBootUEFI -Time 2011-05-21T13:30:00Z -ContentFilePath TestPK_SigList.bin  -Name PK
    
    Write-Host "`n... operation complete.  `nSetupMode should now be 0 and SecureBoot should also be 0. Reboot and verify that Windows is correctly authenticated, and that SecureBoot changes to 1."
    
  5. 插入選項 ROM 記憶卡並測試

    測試應根據韌體正確性通過或失敗。 例如:

    如果韌體中的選項 ROM 已正確實作,而且您正使用視訊卡進行測試,則附加監視器應該不會顯示任何畫面。

    不過,如果您使用不正確的韌體,視訊卡在顯示器上應該有輸出。

Windows 安全開機密鑰建立和管理指引

安全開機概觀

驗證 Windows UEFI 韌體更新平臺功能