受信任和加密的金鑰

受信任和加密的金鑰是新增到現有核心金鑰環服務中的兩種新金鑰型別。這兩種新型別都是可變長度對稱金鑰,並且在這兩種情況下,所有金鑰都在核心中建立,使用者空間僅檢視、儲存和載入加密的 blob。 受信任金鑰需要 Trust Source 以獲得更高的安全性,而加密金鑰可以在任何系統上使用。 為了方便起見,所有使用者級別 blob 都以十六進位制 ASCII 顯示和載入,並進行完整性驗證。

Trust Source

信任源為受信任金鑰提供安全來源。 本節列出了當前支援的信任源,以及它們的安全性考慮因素。 信任源是否足夠安全取決於其實現的強度和正確性,以及特定用例的威脅環境。 由於核心不知道環境是什麼,並且沒有信任指標,因此依賴於受信任金鑰的使用者來確定信任源是否足夠安全。

  • 儲存信任根

    1. TPM(可信平臺模組:硬體裝置)

      紮根於儲存根金鑰 (SRK),該金鑰永遠不會離開提供加密操作以建立儲存信任根的 TPM。

    2. TEE(可信執行環境:基於 Arm TrustZone 的 OP-TEE)

      紮根於硬體唯一金鑰 (HUK),該金鑰通常燒錄在片上保險絲中,並且只能由 TEE 訪問。

    3. CAAM(加密加速和保證模組:NXP SoC 上的 IP)

      當啟用高保證啟動 (HAB) 並且 CAAM 處於安全模式時,信任紮根於 OTPMK,OTPMK 是一個永不公開的 256 位金鑰,在製造時隨機生成並熔斷到每個 SoC 中。 否則,將使用一個通用的固定測試金鑰。

    4. DCP(資料協處理器:各種 i.MX SoC 的加密加速器)

      紮根於一次性可程式設計金鑰 (OTP),該金鑰通常燒錄在片上保險絲中,並且只能由 DCP 加密引擎訪問。 DCP 提供兩個可用作信任根的金鑰:OTP 金鑰和 UNIQUE 金鑰。 預設是使用 UNIQUE 金鑰,但可以透過模組引數 (dcp_use_otp_key) 選擇 OTP 金鑰。

  • 執行隔離

    1. TPM

      在隔離的執行環境中執行的固定操作集。

    2. TEE

      在透過安全/可信啟動過程驗證的隔離執行環境中執行的可自定義的操作集。

    3. CAAM

      在隔離的執行環境中執行的固定操作集。

    4. DCP

      在隔離的執行環境中執行的固定加密操作集。 只有基本的 blob 金鑰加密在那裡執行。 實際的金鑰密封/解封是在主處理器/核心空間中完成的。

  • 可選擇繫結到平臺完整性狀態

    1. TPM

      金鑰可以選擇性地密封到指定的 PCR(完整性測量)值,並且只有在 PCR 和 blob 完整性驗證匹配時才能由 TPM 解封。 載入的受信任金鑰可以使用新的(未來的)PCR 值進行更新,因此金鑰可以輕鬆遷移到新的 PCR 值,例如在更新核心和 initramfs 時。 同一個金鑰可以在不同的 PCR 值下儲存多個 blob,因此可以輕鬆支援多次啟動。

    2. TEE

      依賴於安全/可信啟動過程來保證平臺完整性。 可以透過基於 TEE 的測量啟動過程對其進行擴充套件。

    3. CAAM

      依賴於 NXP SoC 的高保證啟動 (HAB) 機制來保證平臺完整性。

    4. DCP

      依賴於安全/可信啟動過程(供應商稱為 HAB)來保證平臺完整性。

  • 介面和 API

    1. TPM

      TPM 具有完善的文件、標準化介面和 API。

    2. TEE

      TEE 具有完善的文件、標準化客戶端介面和 API。 有關更多詳細資訊,請參閱 Documentation/driver-api/tee.rst

    3. CAAM

      介面特定於晶片供應商。

    4. DCP

      供應商特定的 API,作為 drivers/crypto/mxs-dcp.c 中 DCP 密碼驅動程式的一部分實現。

  • 威脅模型

    在使用它們來保護安全相關資料時,必須評估特定信任源的強度和針對給定目的的適用性。

金鑰生成

受信任金鑰

新金鑰是從隨機數建立的。 它們使用儲存金鑰層次結構中的子金鑰進行加密/解密。 子金鑰的加密和解密必須受到信任源中強大的訪問控制策略的保護。 使用中的隨機數生成器根據所選的信任源而有所不同

  • TPM:基於硬體裝置的 RNG

    金鑰在 TPM 中生成。 隨機數的強度可能因裝置製造商而異。

  • TEE:基於 Arm TrustZone 的 OP-TEE 基於 RNG

    RNG 可以根據平臺需求進行定製。 它可以是來自平臺特定硬體 RNG 的直接輸出,也可以是基於軟體的 Fortuna CSPRNG,可以透過多個熵源進行播種。

  • CAAM:核心 RNG

    使用普通的核心隨機數生成器。 要從 CAAM HWRNG 對其進行播種,請啟用 CRYPTO_DEV_FSL_CAAM_RNG_API 並確保探測到該裝置。

  • DCP(資料協處理器:各種 i.MX SoC 的加密加速器)

    DCP 硬體裝置本身不提供專用的 RNG 介面,因此使用核心預設 RNG。 具有 DCP 的 SoC(如 i.MX6ULL)確實具有獨立於 DCP 的專用硬體 RNG,可以啟用該 RNG 來支援核心 RNG。

使用者可以透過在核心命令列上指定 trusted.rng=kernel 來覆蓋此設定,以使用核心的隨機數池覆蓋所使用的 RNG。

加密金鑰

加密金鑰不依賴於信任源,並且速度更快,因為它們使用 AES 進行加密/解密。 新金鑰要麼從核心生成的隨機數建立,要麼從使用者提供的解密資料建立,並使用指定的“主”金鑰進行加密/解密。 “主”金鑰可以是受信任金鑰型別或使用者金鑰型別。 加密金鑰的主要缺點是,如果它們沒有紮根於受信任金鑰,則它們的安全性僅與加密它們的 user key 一樣安全。 因此,應以儘可能安全的方式載入主使用者金鑰,最好是在啟動初期。

用法

受信任金鑰用法:TPM

TPM 1.2:預設情況下,受信任金鑰在 SRK 下密封,SRK 具有預設的授權值(20 個位元組的 0)。 這可以在使用 TrouSerS 實用程式進行 takeownership 時設定:“tpm_takeownership -u -z”。

TPM 2.0:使用者必須首先建立一個儲存金鑰並使其持久化,以便金鑰在重新啟動後可用。 這可以使用以下命令完成。

使用 IBM TSS 2 堆疊

#> tsscreateprimary -hi o -st
Handle 80000000
#> tssevictcontrol -hi o -ho 80000000 -hp 81000001

或使用 Intel TSS 2 堆疊

#> tpm2_createprimary --hierarchy o -G rsa2048 -c key.ctxt
[...]
#> tpm2_evictcontrol -c key.ctxt 0x81000001
persistentHandle: 0x81000001

用法

keyctl add trusted name "new keylen [options]" ring
keyctl add trusted name "load hex_blob [pcrlock=pcrnum]" ring
keyctl update key "update [options]"
keyctl print keyid

options:
   keyhandle=    ascii hex value of sealing key
                   TPM 1.2: default 0x40000000 (SRK)
                   TPM 2.0: no default; must be passed every time
   keyauth=      ascii hex auth for sealing key default 0x00...i
                 (40 ascii zeros)
   blobauth=     ascii hex auth for sealed data default 0x00...
                 (40 ascii zeros)
   pcrinfo=      ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
   pcrlock=      pcr number to be extended to "lock" blob
   migratable=   0|1 indicating permission to reseal to new PCR values,
                 default 1 (resealing allowed)
   hash=         hash algorithm name as a string. For TPM 1.x the only
                 allowed value is sha1. For TPM 2.x the allowed values
                 are sha1, sha256, sha384, sha512 and sm3-256.
   policydigest= digest for the authorization policy. must be calculated
                 with the same hash algorithm as specified by the 'hash='
                 option.
   policyhandle= handle to an authorization policy session that defines the
                 same policy and with the same hash algorithm as was used to
                 seal the key.

“keyctl print”返回密封金鑰的 ascii 十六進位制副本,該副本採用標準的 TPM_STORED_DATA 格式。 新金鑰的金鑰長度始終以位元組為單位。 受信任金鑰可以是 32 - 128 位元組(256 - 1024 位),上限是為了適應具有所有必要結構/填充的 2048 位 SRK (RSA) 金鑰長度。

受信任金鑰用法:TEE

用法

keyctl add trusted name "new keylen" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid

“keyctl print”返回密封金鑰的 ASCII 十六進位制副本,該副本採用 TEE 裝置實現特定的格式。 新金鑰的金鑰長度始終以位元組為單位。 受信任金鑰可以是 32 - 128 位元組(256 - 1024 位)。

受信任金鑰用法:CAAM

用法

keyctl add trusted name "new keylen" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid

“keyctl print”返回密封金鑰的 ASCII 十六進位制副本,該副本採用 CAAM 特定的格式。 新金鑰的金鑰長度始終以位元組為單位。 受信任金鑰可以是 32 - 128 位元組(256 - 1024 位)。

受信任金鑰用法:DCP

用法

keyctl add trusted name "new keylen" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid

“keyctl print”返回密封金鑰的 ASCII 十六進位制副本,該副本採用特定於此 DCP 金鑰 blob 實現的格式。 新金鑰的金鑰長度始終以位元組為單位。 受信任金鑰可以是 32 - 128 位元組(256 - 1024 位)。

加密金鑰用法

加密金鑰的解密部分可以包含簡單的對稱金鑰或更復雜的結構。 更復雜結構的格式是應用程式特定的,由“format”標識。

用法

keyctl add encrypted name "new [format] key-type:master-key-name keylen"
    ring
keyctl add encrypted name "new [format] key-type:master-key-name keylen
    decrypted-data" ring
keyctl add encrypted name "load hex_blob" ring
keyctl update keyid "update key-type:master-key-name"

其中

format:= 'default | ecryptfs | enc32'
key-type:= 'trusted' | 'user'

受信任和加密金鑰用法的示例

建立並儲存一個長度為 32 位元組的名為“kmk”的受信任金鑰。

注意:當使用帶有控制代碼 0x81000001 的持久金鑰的 TPM 2.0 時,請將“keyhandle=0x81000001”附加到引號之間的語句,例如“new 32 keyhandle=0x81000001”。

$ keyctl add trusted kmk "new 32" @u
440502848

$ keyctl show
Session Keyring
       -3 --alswrv    500   500  keyring: _ses
 97833714 --alswrv    500    -1   \_ keyring: _uid.500
440502848 --alswrv    500   500       \_ trusted: kmk

$ keyctl print 440502848
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba

$ keyctl pipe 440502848 > kmk.blob

從儲存的 blob 載入受信任金鑰

$ keyctl add trusted kmk "load `cat kmk.blob`" @u
268728824

$ keyctl print 268728824
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba

在新 PCR 值下重新密封(TPM 特定的)受信任金鑰

$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
$ keyctl print 268728824
010100000000002c0002800093c35a09b70fff26e7a98ae786c641e678ec6ffb6b46d805
77c8a6377aed9d3219c6dfec4b23ffe3000001005d37d472ac8a44023fbb3d18583a4f73
d3a076c0858f6f1dcaa39ea0f119911ff03f5406df4f7f27f41da8d7194f45c9f4e00f2e
df449f266253aa3f52e55c53de147773e00f0f9aca86c64d94c95382265968c354c5eab4
9638c5ae99c89de1e0997242edfb0b501744e11ff9762dfd951cffd93227cc513384e7e6
e782c29435c7ec2edafaa2f4c1fe6e7a781b59549ff5296371b42133777dcc5b8b971610
94bc67ede19e43ddb9dc2baacad374a36feaf0314d700af0a65c164b7082401740e489c9
7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8

受信任金鑰的初始使用者是 EVM,它在啟動時需要一個高質量的對稱金鑰來對檔案元資料進行 HMAC 保護。 使用受信任金鑰可以強烈保證 EVM 金鑰沒有被使用者級別問題破壞,並且當密封到平臺完整性狀態時,可以防止啟動和離線攻擊。 使用上述受信任金鑰“kmk”建立並儲存加密金鑰“evm”

選項 1:省略“format”

$ keyctl add encrypted evm "new trusted:kmk 32" @u
159771175

選項 2:將“format”顯式定義為“default”

$ keyctl add encrypted evm "new default trusted:kmk 32" @u
159771175

$ keyctl print 159771175
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc

$ keyctl pipe 159771175 > evm.blob

從儲存的 blob 載入加密金鑰“evm”

$ keyctl add encrypted evm "load `cat evm.blob`" @u
831684262

$ keyctl print 831684262
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc

使用使用者提供的解密資料例項化加密金鑰“evm”

$ evmkey=$(dd if=/dev/urandom bs=1 count=32 | xxd -c32 -p)
$ keyctl add encrypted evm "new default user:kmk 32 $evmkey" @u
794890253

$ keyctl print 794890253
default user:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382d
bbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0247
17c64 5972dcb82ab2dde83376d82b2e3c09ffc

預計受信任金鑰和加密金鑰的其他用途,例如用於磁碟和檔案加密。 特別是,為了使用加密金鑰掛載 eCryptfs 檔案系統,已經定義了新的格式“ecryptfs”。 有關用法的更多詳細資訊,請參見檔案 Documentation/security/keys/ecryptfs.rst

為了支援有效負載大小為 32 位元組的加密金鑰,已定義了另一種新的格式“enc32”。 這最初將用於 nvdimm 安全性,但可能會擴充套件到需要 32 位元組有效負載的其他用途。

TPM 2.0 ASN.1 金鑰格式

TPM 2.0 ASN.1 金鑰格式旨在易於識別,即使以二進位制形式也是如此(修復了我們在 TPM 1.2 ASN.1 格式中遇到的問題),並且可以擴充套件以新增可匯入金鑰和策略等功能

TPMKey ::= SEQUENCE {
    type            OBJECT IDENTIFIER
    emptyAuth       [0] EXPLICIT BOOLEAN OPTIONAL
    parent          INTEGER
    pubkey          OCTET STRING
    privkey         OCTET STRING
}

type 是區分金鑰的原因,即使以二進位制形式也是如此,因為 TCG 提供的 OID 是唯一的,因此在金鑰的偏移量 3 處形成可識別的二進位制模式。 當前可用的 OID 為

2.23.133.10.1.3 TPM Loadable key.  This is an asymmetric key (Usually
                RSA2048 or Elliptic Curve) which can be imported by a
                TPM2_Load() operation.

2.23.133.10.1.4 TPM Importable Key.  This is an asymmetric key (Usually
                RSA2048 or Elliptic Curve) which can be imported by a
                TPM2_Import() operation.

2.23.133.10.1.5 TPM Sealed Data.  This is a set of data (up to 128
                bytes) which is sealed by the TPM.  It usually
                represents a symmetric key and must be unsealed before
                use.

受信任的金鑰程式碼僅使用 TPM 密封資料 OID。

如果金鑰具有眾所周知的授權“”,則 emptyAuth 為 true。 如果為 false 或不存在,則金鑰需要顯式的授權短語。 大多數使用者空間使用者使用此選項來決定是否提示輸入密碼。

parent 表示父金鑰控制代碼,無論是在 0x81 MSO 空間中,例如 RSA 主儲存金鑰的 0x81000001。 使用者空間程式還支援在 0x40 MSO 空間中指定主控制代碼。 如果發生這種情況,則將使用 TCG 定義的模板動態生成到易失物件中的主金鑰的橢圓曲線變體,並將其用作父金鑰。 當前核心程式碼僅支援 0x81 MSO 形式。

pubkey 是 TPM2B_PRIVATE 的二進位制表示形式,不包括初始 TPM2B 標頭,該標頭可以從 ASN.1 八位位元組字串長度重建。

privkey 是 TPM2B_PUBLIC 的二進位制表示形式,不包括初始 TPM2B 標頭,該標頭可以從 ASN.1 八位位元組字串長度重建。

DCP Blob 格式

資料協處理器 (DCP) 僅使用其 AES 加密引擎提供硬體繫結的 AES 金鑰。 它不提供直接的金鑰密封/解封。 為了使 DCP 硬體加密金鑰可用作信任源,我們定義了自己的自定義格式,該格式使用硬體繫結的金鑰來保護儲存在金鑰 blob 中的密封金鑰。

每當使用 DCP 生成新的受信任金鑰時,我們都會生成一個隨機的 128 位 blob 加密金鑰 (BEK) 和一個 128 位 nonce。 BEK 和 nonce 用於使用 AES-128-GCM 加密受信任的金鑰有效負載。

BEK 本身使用 DCP 的 AES 加密引擎和 AES-128-ECB 使用硬體繫結的金鑰進行加密。 加密的 BEK、生成的 nonce、BEK 加密的有效負載和身份驗證標記與版本號、有效負載長度和身份驗證標記一起構成了 blob 格式。

struct dcp_blob_fmt

DCP BLOB 格式。

定義:

struct dcp_blob_fmt {
    __u8 fmt_version;
    __u8 blob_key[AES_KEYSIZE_128];
    __u8 nonce[AES_KEYSIZE_128];
    __le32 payload_len;
    __u8 payload[];
};

成員

fmt_version

格式版本,當前為 1

blob_key

隨機 AES 128 金鑰,用於加密 payloadblob_key 本身由 DCP 在 AES-128-ECB 模式下使用 OTP 或 UNIQUE 裝置金鑰加密。

nonce

用於 payload 加密的隨機 nonce。

payload_len

純文字 payload 的長度。

payload

payload 本身,使用 AES-128-GCM 和 blob_key 加密,大小為 DCP_BLOB_AUTHLEN 的 GCM 身份驗證標記附加在其末尾。

描述

DCP BLOB 的總大小為 sizeof(struct dcp_blob_fmt) + payload_len + DCP_BLOB_AUTHLEN。