核心模組簽名工具

概述

核心模組簽名工具可以在安裝期間對模組進行加密簽名,然後在載入模組時檢查簽名。 這可以透過禁止載入未簽名的模組或使用無效金鑰簽名的模組來提高核心安全性。 模組簽名透過使其更難以將惡意模組載入到核心中來提高安全性。 模組簽名檢查由核心完成,因此無需具有受信任的使用者空間位。

該工具使用 X.509 ITU-T 標準證書來編碼所涉及的公鑰。 簽名本身未以任何工業標準型別編碼。 內建工具目前僅支援 RSA & NIST P-384 ECDSA 公鑰簽名標準(但它是可插拔的並允許使用其他標準)。 可以使用的雜湊演算法有 SHA-2 和 SHA-3,大小為 256、384 和 512(該演算法由簽名中的資料選擇)。

配置模組簽名

可以透過轉到核心配置的 Enable Loadable Module Support 部分並啟用

CONFIG_MODULE_SIG       "Module signature verification"

這有許多可用的選項

  1. 要求模組有效簽名 (CONFIG_MODULE_SIG_FORCE)

    這指定核心應如何處理具有未知金鑰的簽名或未簽名模組的模組。

    如果此選項關閉(即“允許”),則允許使用金鑰不可用的模組和未簽名的模組,但核心將被標記為已汙染,並且相關的模組將被標記為已汙染,並帶有字元“E”。

    如果此選項開啟(即“限制性”),則僅載入具有有效簽名且可以透過核心擁有的公鑰驗證的模組。 所有其他模組將生成錯誤。

    無論此處的設定如何,如果模組具有無法解析的簽名塊,它將被立即拒絕。

  2. 自動簽名所有模組 (CONFIG_MODULE_SIG_ALL)

    如果此選項開啟,則將在構建的 modules_install 階段自動簽名模組。 如果此選項關閉,則必須使用以下命令手動簽名模組

    scripts/sign-file
    
  3. 應該使用哪種雜湊演算法對模組進行簽名?

    這提供了一個選擇,安裝階段將使用哪種雜湊演算法對模組進行簽名

    CONFIG_MODULE_SIG_SHA256

    使用 SHA-256 簽名模組

    CONFIG_MODULE_SIG_SHA384

    使用 SHA-384 簽名模組

    CONFIG_MODULE_SIG_SHA512

    使用 SHA-512 簽名模組

    CONFIG_MODULE_SIG_SHA3_256

    使用 SHA3-256 簽名模組

    CONFIG_MODULE_SIG_SHA3_384

    使用 SHA3-384 簽名模組

    CONFIG_MODULE_SIG_SHA3_512

    使用 SHA3-512 簽名模組

    此處選擇的演算法也將內建到核心中(而不是作為模組),以便可以使用該演算法簽名的模組檢查其簽名,而不會導致依賴關係迴圈。

  4. 模組簽名金鑰的檔名或 PKCS#11 URI (CONFIG_MODULE_SIG_KEY)

    將此選項設定為除其預設值 certs/signing_key.pem 之外的值將停用簽名金鑰的自動生成,並允許使用您選擇的金鑰對核心模組進行簽名。 提供的字串應標識一個檔案,該檔案以 PEM 形式包含私鑰及其對應的 X.509 證書,或者在 OpenSSL ENGINE_pkcs11 功能正常的系統上,標識一個由 RFC7512 定義的 PKCS#11 URI。 在後一種情況下,PKCS#11 URI 應同時引用證書和私鑰。

    如果包含私鑰的 PEM 檔案已加密,或者如果 PKCS#11 令牌需要 PIN,則可以在構建時透過 KBUILD_SIGN_PIN 變數提供。

  5. 預設系統金鑰環的其他 X.509 金鑰 (CONFIG_SYSTEM_TRUSTED_KEYS)

    可以將此選項設定為 PEM 編碼檔案的檔名,該檔案包含將預設包含在系統金鑰環中的其他證書。

請注意,啟用模組簽名會將 OpenSSL devel 包的依賴項新增到核心構建過程中,用於執行簽名的工具。

生成簽名金鑰

需要加密金鑰對來生成和檢查簽名。 私鑰用於生成簽名,相應的公鑰用於檢查簽名。 僅在構建期間需要私鑰,之後可以刪除或安全儲存。 公鑰內建到核心中,以便可以在載入模組時使用它來檢查簽名。

在正常情況下,當 CONFIG_MODULE_SIG_KEY 與其預設值保持不變時,如果檔案中不存在新的金鑰對,核心構建將自動使用 openssl 生成一個新的金鑰對

certs/signing_key.pem

在構建 vmlinux 期間(金鑰的公共部分需要構建到 vmlinux 中),使用以下引數:

certs/x509.genkey

檔案中的引數(如果該檔案尚不存在,也會生成該檔案)。

可以選擇 RSA (MODULE_SIG_KEY_TYPE_RSA) 和 ECDSA (MODULE_SIG_KEY_TYPE_ECDSA) 來生成 RSA 4k 或 NIST P-384 金鑰對。

強烈建議您提供自己的 x509.genkey 檔案。

最值得注意的是,在 x509.genkey 檔案中,req_distinguished_name 部分應從預設值更改

[ req_distinguished_name ]
#O = Unspecified company
CN = Build time autogenerated kernel key
#emailAddress = unspecified.user@unspecified.company

生成的 RSA 金鑰大小也可以使用以下命令設定

[ req ]
default_bits = 4096

也可以使用 Linux 核心原始碼樹的根節點中的 x509.genkey 金鑰生成配置檔案和 openssl 命令手動生成金鑰私有/公共檔案。 以下是生成公共/私有金鑰檔案的示例

openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \
   -config x509.genkey -outform PEM -out kernel_key.pem \
   -keyout kernel_key.pem

然後可以在 CONFIG_MODULE_SIG_KEY 選項中指定生成的 kernel_key.pem 檔案的完整路徑名,並且將使用其中的證書和金鑰,而不是自動生成的金鑰對。

核心中的公鑰

核心包含一個公鑰環,root 使用者可以檢視它。 它們位於一個名為“.builtin_trusted_keys”的金鑰環中,可以透過以下方式檢視

[root@deneb ~]# cat /proc/keys
...
223c7853 I------     1 perm 1f030000     0     0 keyring   .builtin_trusted_keys: 1
302d2d52 I------     1 perm 1f010000     0     0 asymmetri Fedora kernel signing key: d69a84e6bce3d216b979e9505b3e3ef9a7118079: X509.RSA a7118079 []
...

除了專門為模組簽名生成的公鑰之外,還可以在 CONFIG_SYSTEM_TRUSTED_KEYS 配置選項引用的 PEM 編碼檔案中提供其他受信任的證書。

此外,架構程式碼可以從硬體儲存中獲取公鑰並將它們也新增到其中(例如,來自 UEFI 金鑰資料庫)。

最後,可以透過執行以下操作來新增其他公鑰

keyctl padd asymmetric "" [.builtin_trusted_keys-ID] <[key-file]

例如

keyctl padd asymmetric "" 0x223c7853 <my_public_key.x509

但是請注意,核心僅在新金鑰的 X.509 包裝器已由金鑰有效簽名的情況下,才允許將金鑰新增到 .builtin_trusted_keys,該金鑰在新增金鑰時已駐留在 .builtin_trusted_keys 中。

手動簽名模組

要手動簽名模組,請使用 Linux 核心原始碼樹中提供的 scripts/sign-file 工具。 該指令碼需要 4 個引數

  1. 雜湊演算法(例如,sha256)

  2. 私鑰檔名或 PKCS#11 URI

  3. 公鑰檔名

  4. 要簽名的核心模組

以下是簽名核心模組的示例

scripts/sign-file sha512 kernel-signkey.priv \
        kernel-signkey.x509 module.ko

使用的雜湊演算法不必與配置的演算法匹配,但如果不匹配,您應該確保該雜湊演算法已內建到核心中,或者可以在不需要自身的情況下載入。

如果私鑰需要密碼或 PIN,則可以在 $KBUILD_SIGN_PIN 環境變數中提供它。

已簽名模組和剝離

已簽名模組只是在末尾附加了一個數字簽名。 模組檔案末尾的字串 ~Module signature appended~. 確認存在簽名,但不確認簽名是否有效!

已簽名模組是脆弱的,因為簽名位於定義的 ELF 容器之外。 因此,一旦計算並附加簽名,就可能無法剝離它們。 請注意,整個模組都是已簽名的有效負載,包括簽名時存在的任何和所有除錯資訊。

載入已簽名模組

使用 insmod、modprobe、init_module()finit_module() 載入模組,與未簽名模組完全相同,因為使用者空間中沒有進行任何處理。 簽名檢查全部在核心中完成。

無效簽名和未簽名模組

如果啟用了 CONFIG_MODULE_SIG_FORCE 或在核心命令列上提供了 module.sig_enforce=1,則核心只會載入它具有公鑰的有效簽名模組。 否則,它也會載入未簽名的模組。 對於核心擁有金鑰但證明簽名不匹配的任何模組,將不允許載入。

將拒絕任何具有無法解析的簽名的模組。

管理/保護私鑰

由於私鑰用於簽名模組,因此病毒和惡意軟體可以使用私鑰簽名模組並危及作業系統。 私鑰必須被銷燬或移動到安全位置,並且不能保留在核心原始碼樹的根節點中。

如果您使用相同的私鑰對多個核心配置的模組進行簽名,則必須確保模組版本資訊足以防止將模組載入到不同的核心中。 可以設定 CONFIG_MODVERSIONS=y 或透過更改 EXTRAVERSIONCONFIG_LOCALVERSION 來確保每個配置都具有不同的核心發行字串。