硬體支援的 KeyStore

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

詞彙解釋

以下簡要介紹 Keystore 元件及其關係。

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

建築

Android Keystore API 和基礎 KeyMint HAL 提供基本但足夠的加密編譯原始碼集,可讓您使用存取權控管的硬體金鑰實作通訊協定。

KeyMint HAL 是金鑰儲存庫服務使用的原始設備製造商 (OEM) 服務,可提供硬體支援的加密編譯服務。為確保私密金鑰內容安全無虞,HAL 實作不會在使用者空間或核心空間中執行任何敏感作業。相反地,在 Android 中執行的 KeyMint HAL 服務會將敏感作業委派給在某種安全環境中執行的 TA,通常會以某種實作定義的匯入/匯出線路格式,對要求進行匯入和匯出。

產生的架構如下所示:

存取 KeyMint

圖 1. 可存取 KeyMint。

KeyMint HAL API 是低階 API,由平台內部元件使用,不會公開給應用程式開發人員。Android 開發人員網站說明瞭應用程式可用的較高階 Java API。

存取權控管

Android KeyStore 提供一個集中元件,用於儲存及使用硬體支援的加密編譯金鑰,適用於應用程式和其他系統元件。因此,任何個別金鑰的存取權通常只限於建立金鑰的應用程式或系統元件。

KeyStore 網域

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

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

在內部,框架程式碼也會在載入金鑰後收到專屬的數字金鑰 ID。這個數字 ID 會用於 KEY_ID 網域內的索引鍵描述項做為識別碼。不過,存取控制功能仍會執行:即使一個應用程式發現另一個應用程式的金鑰 ID,在一般情況下也無法使用該 ID。

不過,應用程式可以將金鑰授權給其他應用程式 (以 UID 識別) 使用。這項授權作業會傳回專屬的授權 ID,用於 GRANT 網域中索引鍵描述項的 ID。再次強調,系統仍會執行存取權控管:即使第三方應用程式發現授權對象金鑰的授權 ID,也無法使用該金鑰。

Keystore 也支援兩個其他金鑰描述詞網域,用於其他系統元件,但不適用於應用程式建立的金鑰:

  • BLOB 網域表示金鑰描述項中沒有金鑰 ID;相反地,金鑰描述項會保留金鑰 blob 本身,而用戶端會處理金鑰 blob 儲存空間。此類別由需要在掛載資料分割區之前存取 KeyStore 的用戶端 (例如 vold) 使用。
  • SELINUX 網域可讓系統元件共用金鑰,且存取權由與 SELinux 標籤相對應的數字 ID 控管 (請參閱 keystore_key 的 SELinux 政策)。

keystore_key 的 SELinux 政策

Domain::SELINUX 索引鍵描述元檔案中會設定用於 Domain::SELINUX 索引鍵描述元的 ID 值。keystore2_key_context這些檔案中的每一行都會將數字對應至 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 可供殼層使用的命名空間。主要用於測試,但也可以透過指令列在使用者版本上使用。
100 vold_key 供 vold 使用的值。
101 odsign_key 由裝置端簽署 Daemon 使用。
102 wifi_key AID_WIFI(1010) 由 Android 的 Wifi 子系統 (包括 wpa_supplicant) 使用。
103 locksettings_key LockSettingsService 使用
120 resume_on_reboot_key AID_SYSTEM(1000) 由 Android 系統伺服器用於支援重新啟動時的繼續作業。

存取向量

除了控管金鑰的整體存取權外,Keystore 還可控管可在金鑰上執行哪些作業。keystore2_key 權限的說明詳見 KeyPermission.aidl 檔案。

系統權限

除了「keystore_key 的 SELinux 政策」一文所述的個別金鑰存取權控制項之外,下表還說明執行各種系統和維護作業所需的其他 SELinux 權限:

權限 意義
add_auth 必須新增驗證權杖至 Keystore,並由 Gatekeeper 或 BiometricManager 等驗證供應商使用。
clear_ns 必須使用此權限才能刪除特定命名空間中的所有鍵;用於應用程式解除安裝時的維護作業。
list 系統需要這些屬性,才能依據各種屬性 (例如擁有權或是否受限於驗證) 列舉金鑰。呼叫端不需要這項權限來列舉自己的命名空間 (get_info 權限已涵蓋)。
lock 必須通知 KeyStore 裝置已鎖定,進而淘汰超級金鑰,確保驗證綁定的金鑰無法使用。
unlock 必須通知 KeyStore 裝置已解鎖,並恢復保護驗證綁定金鑰的超級金鑰存取權。
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 轉換至由新硬體介面定義語言 (HIDL) 定義所產生的 C++ HAL 介面。在變更過程中,許多引數類型都已變更,但類型和方法與舊類型和 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 也包含新版的 KeyStore 系統 Daemon,以 Rust 重寫,稱為 keystore2

Android 13

Android 13 新增了 KeyMint HAL 第 2 版,可為簽署和金鑰協議提供 Curve25519 支援。