硬體支援的 KeyStore

單晶片系統 (SoC) 中的受信任執行環境 (TEE) 可讓 Android 裝置為 Android OS、平台服務,甚至是第三方應用程式提供硬體支援的強大安全服務 (以標準 Java Cryptography Architecture 的 Android 專屬擴充功能形式提供,請參閱 KeyGenParameterSpec)。

詞彙解釋

以下簡要說明 Keystore 元件及其關係。

AndroidKeyStore
應用程式用來存取 KeyStore 功能的 Android Framework API 和元件。這是標準 Java Cryptography Architecture API 的實作項目,但也會新增 Android 專用的擴充功能,並包含在應用程式本身的程序空間中執行的 Java 程式碼。AndroidKeyStore 會將應用程式的 Keystore 行為要求轉送至 keystore 精靈,藉此滿足要求。
金鑰庫精靈
Android 系統精靈,可透過 Binder API 存取所有 KeyStore 功能。這個精靈負責儲存基礎 KeyMint (或 Keymaster) 實作建立的金鑰 Blob,其中包含加密的密鑰資料,因此金鑰庫可以儲存這些資料,但無法使用或揭露。
KeyMint HAL 服務
實作 IKeyMintDevice HAL 的 AIDL 伺服器,可存取基礎 KeyMint TA。
KeyMint 可信任應用程式 (TA)
在安全環境中執行的軟體 (通常是 ARM SoC 上的 TrustZone),可提供所有安全加密編譯作業。這個應用程式可以存取原始金鑰資料,並在允許使用金鑰前,驗證金鑰的所有存取權控制項條件。
LockSettingsService
負責使用者驗證的 Android 系統元件,包括密碼和指紋。這項功能不屬於 Keystore,但與 Keystore 相關,因為 Keystore 支援驗證繫結金鑰的概念:只有在使用者完成驗證後,才能使用金鑰。LockSettingsService 會與 Gatekeeper TA 和指紋 TA 互動,取得驗證權杖,並提供給金鑰儲存空間精靈,而 KeyMint TA 會使用這些權杖。
總機人員 TA
在安全環境中執行的元件,負責驗證使用者密碼及產生驗證權杖,用來向 KeyMint TA 證明特定使用者在特定時間點完成驗證。
指紋 TA
在安全環境中執行的元件,負責驗證使用者指紋,並產生驗證權杖,用於向 KeyMint TA 證明特定使用者在特定時間點完成驗證。

建築

Android Keystore API 和底層的 KeyMint HAL 提供基本但足夠的加密基本元素,可使用存取權控管的硬體支援金鑰實作通訊協定。

KeyMint HAL 是 OEM 提供的服務,Keystore 服務會使用這項服務提供硬體支援的加密編譯服務。為確保私密金鑰內容安全無虞,HAL 實作不會在使用者空間,甚至核心空間中執行任何敏感作業。Android 中執行的 KeyMint HAL 服務會將敏感作業委派給在某種安全環境中執行的 TA,通常是透過以某種實作定義的線路格式封送及解封送要求。

產生的架構如下所示:

存取 KeyMint

圖 1. 存取 KeyMint。

KeyMint HAL API 屬於低階 API,供平台內部元件使用,不會向應用程式開發人員公開。如要瞭解應用程式可用的高階 Java API,請前往 Android 開發人員網站

存取權控管

Android Keystore 提供中央元件,可供應用程式和其他系統元件儲存及使用硬體支援的加密金鑰。因此,通常只有建立金鑰的應用程式或系統元件,才能存取個別金鑰。

KeyStore 網域

為支援這項存取權控管功能,系統會使用金鑰描述元向 Keystore 識別金鑰。這個金鑰描述元會指出描述元所屬的網域,以及該網域中的身分。

Android 應用程式會使用標準 Java Cryptography Architecture 存取 Keystore,並以字串別名識別金鑰。這種識別方法會在內部對應至 Keystore APP 網域,並納入呼叫端的 UID,以區分不同應用程式的金鑰,避免一個應用程式存取另一個應用程式的金鑰。

在內部,架構程式碼也會在載入金鑰後收到專屬的數字金鑰 ID。這個數字 ID 會做為 KEY_ID 網域中金鑰描述元的 ID。不過,存取權控管機制仍會運作:即使某個應用程式發現另一個應用程式的金鑰 ID,在正常情況下也無法使用。

不過,應用程式可能會將金鑰的使用權授予其他應用程式 (以 UID 識別)。這項授權作業會傳回專屬授權 ID,做為 GRANT 網域中金鑰描述元的 ID。同樣地,系統仍會執行存取權控管:即使第三方應用程式發現受讓人金鑰的授權 ID,也無法使用。

金鑰儲存區也支援另外兩個金鑰描述元網域,這些網域用於其他系統元件,不適用於應用程式建立的金鑰:

  • BLOB 網域表示金鑰描述元中沒有金鑰的 ID,而是保存金鑰 blob 本身,且用戶端會處理金鑰 blob 儲存空間。用戶端 (例如 vold) 需要在掛接資料分割區之前存取 Keystore,就會使用這項功能。
  • SELINUX 網域可讓系統元件共用金鑰,存取權則由對應至 SELinux 標籤的數字 ID 管理 (請參閱 keystore_key 的 SELinux 政策)。

keystore_key 的 SELinux 政策

用於 Domain::SELINUX 金鑰描述元的 ID 值是在 keystore2_key_context SELinux 政策檔案中設定。這些檔案中的每一行都會將數字對應至 SELinux 標籤,例如:

# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and
# Settings to share Keystore keys.
102            u:object_r:wifi_key:s0

如果元件需要存取 SELINUX 網域中 ID 為 102 的金鑰,就必須有對應的 SELinux 政策。舉例來說,如要允許 wpa_supplicant 取得及使用這些鍵,請在 hal_wifi_supplicant.te 中新增下列程式碼:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Domain::SELINUX 鍵的數字 ID 會分成不同範圍,以支援不同分區,不會發生衝突:

分區 範圍 設定檔
系統 0 ... 9,999 /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
擴充系統 10,000 ... 19,999 /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
產品 20,000 ... 29,999 /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
供應商 30,000 ... 39,999 /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

系統分區已定義下列特定值:

名稱空間編號 SEPolicy 標籤 UID 說明
0 su_key 超級使用者金鑰。僅用於在 userdebug 和 eng 建構版本上進行測試。使用者建構版本不適用。
1 shell_key 可供 Shell 使用的命名空間。主要用於測試,但也可以從指令列用於使用者建構版本。
100 vold_key 供 vold 使用。
101 odsign_key 裝置端簽署 Daemon 使用。
102 wifi_key AID_WIFI(1010) Android 的 Wi-Fi 子系統 (包括 wpa_supplicant) 會使用這項設定。
103 locksettings_key LockSettingsService 使用
120 resume_on_reboot_key AID_SYSTEM(1000) Android 系統伺服器會使用這項服務,在重新啟動後繼續執行作業。

存取向量

除了控管金鑰的整體存取權,金鑰儲存區還可控管金鑰可執行的作業。keystore2_key 權限說明位於 KeyPermission.aidl 檔案中。

系統權限

除了 keystore_key 的 SELinux 政策中說明的每個金鑰存取控制項之外,下表也列出執行各種系統和維護作業所需的其他 SELinux 權限:

權限 意義
add_auth 將驗證權杖新增至 Keystore 時必須使用,由 Gatekeeper 或 BiometricManager 等驗證供應商使用。
clear_ns 刪除特定命名空間中的所有金鑰時必須使用,應用程式解除安裝時會做為維護作業。
list 系統會根據各種屬性 (例如擁有權或是否與驗證相關聯) 列舉金鑰,因此需要這項屬性。呼叫端列舉自己的命名空間時,不需要這項權限 (由 get_info 權限涵蓋)。
lock 用於通知金鑰儲存區裝置已鎖定,進而逐出超級金鑰,確保驗證繫結金鑰無法使用。
unlock 必須通知金鑰儲存區裝置已解鎖,並還原對超級金鑰的存取權,這些超級金鑰會保護與驗證相關聯的金鑰。
reset 將 Keystore 恢復原廠設定時,必須刪除所有對 Android OS 運作不重要的金鑰。

記錄

在 Android 5 以下版本中,Android 具有簡單的硬體支援加密服務 API,由 Keymaster 硬體抽象層 (HAL) 的 0.2 和 0.3 版提供。金鑰儲存區提供數位簽署和驗證作業,以及產生和匯入非對稱簽署金鑰配對。許多裝置已實作這項功能,但單靠簽章 API 無法輕易達成許多安全性目標。Android 6.0 擴充了 KeyStore API,提供更多功能。

Android 6.0

在 Android 6.0 中,Keymaster 1.0 新增了對稱加密基本元素、AES 和 HMAC,以及硬體支援金鑰的存取控制系統。存取權控管會在金鑰產生期間指定,並在金鑰的生命週期內強制執行。金鑰可設為只能在使用者通過驗證後使用,且只能用於特定用途或搭配特定加密編譯參數。

除了擴充密碼編譯基本功能的範圍,Android 6.0 中的 Keystore 還新增了下列項目:

  • 使用控制機制,限制金鑰使用次數,降低金鑰遭濫用而導致安全漏洞的風險
  • 存取權控管機制,可將金鑰限制為特定使用者、用戶端和定義的時間範圍

Android 7.0

在 Android 7.0 中,Keymaster 2 新增了金鑰認證和版本繫結支援。

金鑰認證 提供含有金鑰詳細說明和存取控制項的公開金鑰憑證,方便遠端驗證金鑰是否位於安全硬體中,以及金鑰的設定。

版本繫結 可將金鑰繫結至作業系統和修補程式等級版本。這可確保攻擊者即使發現舊版系統或 TEE 軟體有弱點,也無法將裝置還原至有安全漏洞的版本,並使用新版建立的金鑰。此外,如果裝置升級至較新版本或修補程式等級,當裝置使用特定版本和修補程式等級的金鑰時,金鑰會先升級,才能使用,且舊版金鑰會失效。裝置升級時,金鑰會隨著裝置向前移動,但如果將裝置還原為先前的版本,金鑰就會無法使用。

Android 8.0

在 Android 8.0 中,Keymaster 3 從舊式 C 結構 HAL 轉換為 C++ HAL 介面,該介面是根據新硬體介面定義語言 (HIDL) 中的定義產生。這項變更會導致許多引數類型發生變化,但類型和方法會與舊類型和 HAL 結構體方法一一對應。

除了修訂這個介面外,Android 8.0 也擴充了 Keymaster 2 的認證功能,支援ID 認證。ID 認證提供有限的選用機制,可強烈認證硬體 ID,例如裝置序號、產品名稱和手機 ID (IMEI 或 MEID)。為實作這項新增功能,Android 8.0 變更了 ASN.1 認證結構定義,新增了 ID 認證。Keymaster 實作項目必須找出安全的方式來擷取相關資料項目,並定義安全且永久停用這項功能的機制。

Android 9

Android 9 的更新內容包括:

  • 更新至 Keymaster 4
  • 支援內嵌安全元件
  • 支援安全金鑰匯入
  • 支援 3DES 加密
  • 變更版本繫結,以便為 boot.imgsystem.img 分別設定版本,允許獨立更新

Android 10

Android 10 推出了 Keymaster HAL 4.1 版,新增了下列功能:

  • 支援僅在裝置解鎖時可使用的金鑰
  • 支援只能在早期開機階段使用的金鑰
  • 選用支援硬體包裝的儲存空間金鑰
  • (選用) 在 StrongBox 中支援裝置專屬認證

Android 12

Android 12 推出了新的 KeyMint HAL,取代 Keymaster HAL,但提供類似功能。除了上述所有功能外,KeyMint HAL 也包含:

  • 支援 ECDH 金鑰協議
  • 支援使用者指定的認證金鑰
  • 支援使用次數有限的金鑰

Android 12 也包含新版的金鑰儲存系統精靈,以 Rust 重新編寫,稱為 keystore2

Android 13

Android 13 新增了 KeyMint HAL 第 2 版,支援用於簽署和金鑰協議的 Curve25519