密鑰和 ID 證明

Keystore 提供了一個更安全的地方來以受控方式創建、存儲和使用加密密鑰。當硬件支持的密鑰存儲可用並使用時,密鑰材料更安全,不會從設備中提取,並且 Keymaster 會實施難以破壞的限制。

但是,只有在已知密鑰庫密鑰位於硬件支持的存儲中時,這才是正確的。在 Keymaster 1 中,應用程序或遠程服務器無法可靠​​地驗證是否是這種情況。密鑰庫守護進程加載了可用的 keymaster HAL,並相信 HAL 所說的關於密鑰硬件支持的任何內容。

為了解決這個問題,Keymaster 在 Android 7.0 (Keymaster 2) 中引入了密鑰認證,在 Android 8.0 (Keymaster 3) 中引入了 ID 認證。

密鑰證明旨在提供一種方法來強有力地確定非對稱密鑰對是否由硬件支持、密鑰的屬性是什麼以及對其使用施加了哪些限制。

ID 證明允許設備提供其硬件標識符的證明,例如序列號或 IMEI。

關鍵證明

為了支持密鑰證明,Android 7.1 向 HAL 引入了一組標籤、類型和方法。

標籤

  • Tag::ATTESTATION_CHALLENGE
  • Tag::INCLUDE_UNIQUE_ID
  • Tag::RESET_SINCE_ID_ROTATION

類型

Keymaster 2 及以下

typedef struct {
    keymaster_blob_t* entries;
    size_t entry_count;
} keymaster_cert_chain_t;

AttestKey方法

鑰匙大師 3

    attestKey(vec<uint8_t> keyToAttest, vec<KeyParameter> attestParams)
        generates(ErrorCode error, vec<vec<uint8_t>> certChain);

Keymaster 2 及以下

keymaster_error_t (*attest_key)(const struct keymaster2_device* dev,
        const keymaster_key_blob_t* key_to_attest,
        const keymaster_key_param_set_t* attest_params,
        keymaster_cert_chain_t* cert_chain);
  • dev是 keymaster 設備結構。
  • keyToAttest是將為其創建證明的generateKey返回的密鑰 blob。
  • attestParams是證明所需的任何參數的列表。這包括Tag::ATTESTATION_CHALLENGE和可能的Tag::RESET_SINCE_ID_ROTATION ,以及Tag::APPLICATION_IDTag::APPLICATION_DATA 。如果在密鑰生成期間指定了後兩者,則它們是解密密鑰 blob 所必需的。
  • certChain是輸出參數,它返回一個證書數組。條目 0 是證明證書,這意味著它證明來自keyToAttest的密鑰並包含證明擴展。

attestKey方法被認為是對被證明密鑰的公鑰操作,因為它可以隨時調用,不需要滿足授權約束。例如,如果被證明的密鑰需要用戶認證才能使用,則可以在沒有用戶認證的情況下生成證明。

認證證書

證明證書是標準 X.509 證書,具有可選的證明擴展,其中包含證明密鑰的描述。該證書使用工廠提供的證明密鑰進行簽名,該證明密鑰使用與被證明密鑰相同的算法(RSA 代表 RSA,EC 代表 EC)。

證明證書包含下表中的字段,不能包含任何附加字段。一些字段指定一個固定的字段值。 CTS 測試驗證證書內容是否與定義完全一致。

證書序列

字段名稱(參見RFC 5280價值
tbs證書TBSC證書序列
簽名算法用於簽署密鑰的算法的 AlgorithmIdentifier:
ECDSA 用於 EC 密鑰,RSA 用於 RSA 密鑰。
簽名值BIT STRING,在 ASN.1 DER 編碼的 tbsCertificate 上計算的簽名。

TBSC證書序列

字段名稱(參見RFC 5280價值
version INTEGER 2(表示 v3 證書)
serialNumber INTEGER 1(固定值:所有證書都相同)
signature用於簽署密鑰的算法的算法標識符:ECDSA 用於 EC 密鑰,RSA 用於 RSA 密鑰。
issuer與批處理證明密鑰的主題字段相同。
validity兩個日期的序列,包含Tag::ACTIVE_DATETIMETag::USAGE_EXPIRE_DATETIME的值。這些值自 1970 年 1 月 1 日起以毫秒為單位。請參閱RFC 5280以了解證書中正確的日期表示。
如果Tag::ACTIVE_DATETIME不存在,請使用Tag::CREATION_DATETIME的值。如果Tag::USAGE_EXPIRE_DATETIME不存在,則使用批處理證明密鑰證書的到期日期。
subject CN = "Android Keystore Key"(固定值:所有證書相同)
subjectPublicKeyInfo SubjectPublicKeyInfo 包含已證明的公鑰。
extensions/Key Usage digitalSignature:設置密鑰是否有目的KeyPurpose::SIGNKeyPurpose::VERIFY 。所有其他位未設置。
extensions/CRL Distribution Points價值待定
extensions/"attestation" OID 為 1.3.6.1.4.1.11129.2.1.17;內容在下面的證明擴展部分中定義。與所有 X.509 證書擴展一樣,內容表示為 OCTET_STRING,其中包含證明 SEQUENCE 的 DER 編碼。

證明擴展

attestation擴展包含與密鑰關聯的 keymaster 授權的完整描述,其結構直接對應於 Android 和 keymaster HAL 中使用的授權列表。授權列表中的每個標籤都由一個 ASN.1 SEQUENCE條目表示,用 keymaster 標籤號顯式標記,但類型描述符(四個高位)被屏蔽掉。

例如,在 Keymaster 3 中, Tag::PURPOSE在 types.hal 中定義為ENUM_REP | 1 .對於證明擴展,刪除ENUM_REP值,留下標記1 。 (對於 Keymaster 2 及以下版本, KM_TAG_PURPOSE在 keymaster_defs.h 中定義。)

根據下表,值以直接的方式轉換為 ASN.1 類型:

鑰匙大師類型ASN.1 型
ENUM整數
ENUM_REP整數集
UINT整數
UINT_REP整數集
ULONG整數
ULONG_REP整數集
DATE INTEGER(自 1970 年 1 月 1 日 00:00:00 GMT 以來的毫秒數)
BOOL NULL(在 keymaster 中,標籤存在意味著真,不存在意味著假。
相同的語義適用於 ASN.1 編碼)
BIGNUM目前未使用,因此未定義映射
BYTES OCTET_STRING

架構

證明擴展內容由以下 ASN.1 模式描述。

KeyDescription ::= SEQUENCE {
  attestationVersion         INTEGER, # KM2 value is 1. KM3 value is 2. KM4 value is 3.
  attestationSecurityLevel   SecurityLevel,
  keymasterVersion           INTEGER,
  keymasterSecurityLevel     SecurityLevel,
  attestationChallenge       OCTET_STRING,
  uniqueId                   OCTET_STRING,
  softwareEnforced           AuthorizationList,
  teeEnforced                AuthorizationList,
}

SecurityLevel ::= ENUMERATED {
  Software                   (0),
  TrustedEnvironment         (1),
  StrongBox                  (2),
}

AuthorizationList ::= SEQUENCE {
  purpose                     [1] EXPLICIT SET OF INTEGER OPTIONAL,
  algorithm                   [2] EXPLICIT INTEGER OPTIONAL,
  keySize                     [3] EXPLICIT INTEGER OPTIONAL.
  digest                      [5] EXPLICIT SET OF INTEGER OPTIONAL,
  padding                     [6] EXPLICIT SET OF INTEGER OPTIONAL,
  ecCurve                     [10] EXPLICIT INTEGER OPTIONAL,
  rsaPublicExponent           [200] EXPLICIT INTEGER OPTIONAL,
  rollbackResistance          [303] EXPLICIT NULL OPTIONAL, # KM4
  activeDateTime              [400] EXPLICIT INTEGER OPTIONAL
  originationExpireDateTime   [401] EXPLICIT INTEGER OPTIONAL
  usageExpireDateTime         [402] EXPLICIT INTEGER OPTIONAL
  noAuthRequired              [503] EXPLICIT NULL OPTIONAL,
  userAuthType                [504] EXPLICIT INTEGER OPTIONAL,
  authTimeout                 [505] EXPLICIT INTEGER OPTIONAL,
  allowWhileOnBody            [506] EXPLICIT NULL OPTIONAL,
  trustedUserPresenceRequired [507] EXPLICIT NULL OPTIONAL, # KM4
  trustedConfirmationRequired [508] EXPLICIT NULL OPTIONAL, # KM4
  unlockedDeviceRequired      [509] EXPLICIT NULL OPTIONAL, # KM4
  allApplications             [600] EXPLICIT NULL OPTIONAL,
  applicationId               [601] EXPLICIT OCTET_STRING OPTIONAL,
  creationDateTime            [701] EXPLICIT INTEGER OPTIONAL,
  origin                      [702] EXPLICIT INTEGER OPTIONAL,
  rollbackResistant           [703] EXPLICIT NULL OPTIONAL, # KM2 and KM3 only.
  rootOfTrust                 [704] EXPLICIT RootOfTrust OPTIONAL,
  osVersion                   [705] EXPLICIT INTEGER OPTIONAL,
  osPatchLevel                [706] EXPLICIT INTEGER OPTIONAL,
  attestationApplicationId    [709] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdBrand          [710] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdDevice         [711] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdProduct        [712] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdSerial         [713] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdImei           [714] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdMeid           [715] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdManufacturer   [716] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  attestationIdModel          [717] EXPLICIT OCTET_STRING OPTIONAL, # KM3
  vendorPatchLevel            [718] EXPLICIT INTEGER OPTIONAL, # KM4
  bootPatchLevel              [719] EXPLICIT INTEGER OPTIONAL, # KM4
}

RootOfTrust ::= SEQUENCE {
  verifiedBootKey            OCTET_STRING,
  deviceLocked               BOOLEAN,
  verifiedBootState          VerifiedBootState,
  verifiedBootHash           OCTET_STRING, # KM4
}

VerifiedBootState ::= ENUMERATED {
  Verified                   (0),
  SelfSigned                 (1),
  Unverified                 (2),
  Failed                     (3),
}

鍵描述字段

keymasterVersionattestationChallenge字段是按位置標識的,而不是按標籤標識的,因此編碼形式的標籤僅指定字段類型。其餘字段被隱式標記為架構中指定的。

字段名稱類型價值
attestationVersion整數證明架構的版本:1、2 或 3。
attestationSecurity安全級別此證明的安全級別。可以獲得硬件支持的密鑰的軟件證明。如果 Android 系統遭到入侵,則無法信任此類證明。
keymasterVersion整數keymaster 設備的版本:0、1、2、3 或 4。
keymasterSecurity安全級別keymaster 實現的安全級別。
attestationChallenge OCTET_STRING Tag::ATTESTATION_CHALLENGE的值,指定給證明請求。
uniqueId OCTET_STRING可選的唯一 ID,如果鍵有Tag::INCLUDE_UNIQUE_ID則存在
softwareEnforced授權清單TEE 未強制執行的可選密鑰管理員授權(如果有)。
teeEnforced授權清單可選的,由 TEE 強制執行的 Keymaster 授權(如果有)。

授權列表字段

AuthorizationList字段都是可選的,由 keymaster 標記值標識,類型位被屏蔽。使用顯式標記,因此字段還包含指示其 ASN.1 類型的標記,以便於解析。

有關每個字段值的詳細信息,請參閱types.hal 3 的 types.hal 和keymaster_defs.h 2 及以下版本的 keymaster_defs.h。通過省略KM_TAG前綴並將其餘部分更改為駝峰式大小寫,將 Keymaster 標記名稱轉換為字段名稱,因此Tag::KEY_SIZE變為keySize

RootOfTrust 字段

RootOfTrust字段是按位置標識的。

字段名稱類型價值
verifiedBootKey OCTET_STRING用於驗證系統映像的密鑰的安全散列。推薦使用 SHA-256。
deviceLocked布爾值如果引導加載程序被鎖定,則為真,這意味著只能刷新簽名的映像,並且已完成驗證引導檢查。
verifiedBootState驗證啟動狀態已驗證啟動的狀態。
verifiedBootHash OCTET_STRING受驗證啟動保護的所有數據的摘要。對於使用 Verified Boot 的 Android Verified Boot 實現的設備,此值包含VBMeta struct或 Verified Boot 元數據結構的摘要。要了解有關如何計算此值的更多信息,請參閱VBMeta 摘要

VerifiedBootState 值

verifiedBootState的值有以下含義:

價值意義
Verified表示從引導加載程序延伸到已驗證分區的完整信任鏈,包括引導加載程序、引導分區和所有已驗證分區。
在這種狀態下, verifiedBootKey值是嵌入證書的哈希值,即刻錄到 ROM 中的不可更改的證書。
SelfSigned指示引導分區已使用嵌入式證書進行驗證,並且簽名有效。在允許引導過程繼續之前,引導加載程序會顯示警告和公鑰指紋。
在這種狀態下, verifiedBootKey值是自簽名證書的哈希值。
Unverified表示可以自由修改設備。設備完整性留給用戶進行帶外驗證。引導加載程序在允許引導過程繼續之前向用戶顯示警告。
在此狀態下, verifiedBootKey值為空。
Failed表示設備驗證失敗。沒有證明證書實際上包含此值,因為在此狀態下引導加載程序會停止。為了完整起見,將其包含在此處。

安全級別值

securityLevel的值有以下含義:

價值意義
Software創建或管理相關元素(證明或密鑰)的代碼是在 Android 系統中實現的,如果該系統受到破壞,可能會被更改。
TrustedEnvironment創建或管理相關元素(證明或密鑰)的代碼在可信執行環境 (TEE) 中實現。如果 TEE 受到破壞,它可能會被更改,但 TEE 對遠程破壞具有高度抵抗力,並且對直接硬件攻擊的破壞具有中等抵抗力。
StrongBox創建或管理相關元素(證明或密鑰)的代碼在專用硬件安全模塊中實現。如果硬件安全模塊被破壞,它可以被改變,但它對遠程破壞具有高度抵抗力,並且對直接硬件攻擊的破壞具有高度抵抗力。

唯一身份

唯一 ID 是一個 128 位的值,用於標識設備,但僅限於有限的時間段。該值通過以下方式計​​算:

HMAC_SHA256(T || C || R, HBK)

在哪裡:

  • T是“時間計數器值”,通過將Tag::CREATION_DATETIME的值除以 2592000000 計算得出,去掉任何餘數。 T每 30 天變化一次(2592000000 = 30 * 24 * 60 * 60 * 1000)。
  • CTag::APPLICATION_ID的值
  • 如果在 attest_key 調用的 attest_params 參數中存在Tag::RESET_SINCE_ID_ROTATION ,則R為 1,如果不存在標記,則為 0。
  • HBK是受信任的執行環境已知的獨特的硬件綁定機密,並且從未被它透露。秘密包含至少 128 位的熵,並且對於單個設備是唯一的(考慮到 128 位的熵,概率唯一性是可以接受的)。 HBK 應該通過 HMAC 或 AES_CMAC 從融合的密鑰材料中派生。

將 HMAC_SHA256 輸出截斷為 128 位。

證明密鑰和證書

兩個密鑰,一個 RSA 和一個 ECDSA,以及相應的證書鏈,被安全地配置到設備中。

身份證明

Android 8.0 包括對具有 Keymaster 3 的設備的 ID 證明的可選支持。ID 證明允許設備提供其硬件標識符的證明,例如序列號或 IMEI。雖然是一個可選功能,但強烈建議所有 Keymaster 3 實現都提供支持,因為能夠證明設備的身份使得真正的零接觸遠程配置等用例更加安全(因為遠程端可以確定它正在與正確的設備通話,而不是欺騙其身份的設備)。

ID 證明的工作原理是創建設備硬件標識符的副本,只有可信執行環境 (TEE) 才能在設備出廠前訪問這些副本。用戶可以解鎖設備的引導加載程序並更改系統軟件和 Android 框架報告的標識符。 TEE 持有的標識符的副本不能以這種方式被操縱,確保設備 ID 證明只會證明設備的原始硬件標識符,從而阻止欺騙嘗試。

ID 證明的主要 API 表面構建在 Keymaster 2 引入的現有密鑰證明機制之上。當為 keymaster 持有的密鑰請求證明證書時,調用者可以請求將設備的硬件標識符包含在證明證書的元數據中。如果密鑰保存在 TEE 中,則證書將鏈接回已知的信任根。此類證書的接收者可以驗證證書及其內容(包括硬件標識符)是否由 TEE 編寫。當被要求在證明證書中包含硬件標識符時,TEE 僅證明其存儲中保存的標識符,如工廠車間所填充的那樣。

存儲屬性

保存設備標識符的存儲需要具有以下屬性:

  • 從設備的原始標識符派生的值在設備出廠前被複製到存儲中。
  • destroyAttestationIds()方法可以永久銷毀標識符派生數據的此副本。永久銷毀意味著數據被完全刪除,因此無論是恢復出廠設置還是在設備上執行的任何其他程序都無法恢復它。這對於用戶解鎖引導加載程序並更改系統軟件並修改 Android 框架返回的標識符的設備尤其重要。
  • RMA 設施應該能夠生成硬件標識符派生數據的新副本。這樣,通過 RMA 的設備可以再次執行 ID 認證。 RMA 工具使用的機制必須受到保護,以便用戶不能自己調用它,因為這將允許他們獲得欺騙 ID 的證明。
  • 除了 TEE 中的 Keymaster 可信應用程序之外,沒有任何代碼能夠讀取存儲在存儲中的標識符派生數據。
  • 存儲是防篡改的:如果存儲的內容已被修改,則 TEE 將其視為內容的副本已被破壞並拒絕所有 ID 證明嘗試。這是通過對存儲進行簽名或 MAC 化來實現的,如下所述
  • 存儲不保存原始標識符。因為 ID 證明涉及質詢,所以調用者總是提供要證明的標識符。 TEE 只需要驗證這些值是否與它們最初擁有的值匹配。存儲原始值而不是值的安全散列可以實現這種驗證。

建造

要創建具有上面列出的屬性的實現,請將 ID 派生值存儲在以下構造 S 中。不要存儲 ID 值的其他副本,除了系統中的正常位置,設備所有者可以通過生根來修改:

S = D || HMAC(HBK, D)

在哪裡:

  • D = HMAC(HBK, ID 1 ) || HMAC(HBK, ID 2 ) || ... || HMAC(HBK, ID n )
  • HMAC是具有適當安全散列的 HMAC 結構(推薦使用 SHA-256)
  • HBK是硬件綁定密鑰,不用於任何其他目的
  • ID 1 ...ID n是原始 ID 值;特定值與特定索引的關聯取決於實現,因為不同的設備將具有不同數量的標識符
  • ||表示串聯

因為 HMAC 輸出是固定大小的,所以不需要標頭或其他結構來找到單獨的 ID 哈希或 D 的 HMAC。除了檢查提供的值以執行證明之外,實現需要通過從 S 中提取 D 來驗證 S ,計算 HMAC(HBK, D) 並將其與 S 中的值進行比較,以驗證沒有單個 ID 被修改/損壞。此外,實現必須對所有單個 ID 元素和 S 的驗證使用恆定時間比較。無論提供的 ID 數量和測試的任何部分是否正確匹配,比較時間都必須是恆定的。

硬件標識符

ID 證明支持以下硬件標識符:

  1. 品牌名稱,由 Android 中的Build.BRAND返回
  2. 設備名稱,由 Android 中的Build.DEVICE返回
  3. 產品名稱,由 Android 中的Build.PRODUCT返回
  4. 製造商名稱,由 Android 中的Build.MANUFACTURER返回
  5. 模型名稱,由 Android 中的Build.MODEL返回
  6. 序列號
  7. 所有收音機的 IMEI
  8. 所有電台的 MEID

為了支持設備 ID 證明,設備證明這些標識符。所有運行 Android 的設備都有前六個,它們是此功能工作所必需的。如果設備具有任何集成的蜂窩無線電,則設備還必須支持對無線電的 IMEI 和/或 MEID 的認證。

通過執行密鑰證明並在請求中包含要證明的設備標識符來請求 ID 證明。標識符標記為:

  • ATTESTATION_ID_BRAND
  • ATTESTATION_ID_DEVICE
  • ATTESTATION_ID_PRODUCT
  • ATTESTATION_ID_MANUFACTURER
  • ATTESTATION_ID_MODEL
  • ATTESTATION_ID_SERIAL
  • ATTESTATION_ID_IMEI
  • ATTESTATION_ID_MEID

要證明的標識符是 UTF-8 編碼的字節字符串。這種格式也適用於數字標識符。每個要證明的標識符都表示為 UTF-8 編碼的字符串。

如果設備不支持 ID 證明(或之前調用了destroyAttestationIds()並且設備無法再證明其 ID),則任何包含一個或多個這些標籤的密鑰證明請求都會失敗,並顯示ErrorCode::CANNOT_ATTEST_IDS

如果設備支持 ID 證明並且一個或多個上述標籤已包含在密鑰證明請求中,則 TEE 會驗證每個標籤提供的標識符與其硬件標識符的副本是否匹配。如果一個或多個標識符不匹配,則整個證明將失敗並顯示ErrorCode::CANNOT_ATTEST_IDS 。多次提供同一個標籤是有效的。這可能很有用,例如,在證明 IMEI 時:一個設備可能有多個帶有多個 IMEI 的無線電。如果每個ATTESTATION_ID_IMEI提供的值與設備的無線電之一匹配,則證明請求有效。這同樣適用於所有其他標籤。

如果證明成功,則使用上述模式將證明 ID 添加到已頒發證明證書的證明擴展(OID 1.3.6.1.4.1.11129.2.1.17) 中。 Keymaster 2 證明架構的更改以粗體顯示,並帶有註釋。

Java API

本節僅供參考。 Keymaster 實現者既不實現也不使用 Java API。這是為了幫助實施者了解應用程序如何使用該功能。系統組件可能會以不同的方式使用它,這就是為什麼本節不應被視為規範的原因。