版本繫結

在 Keymaster 1 中,所有 Keymaster 金鑰都會以加密方式繫結至裝置 信任根或驗證開機程序金鑰。在 Keymaster 2 和 3 中,所有 金鑰也會繫結至系統映像檔的作業系統和修補程式等級。 這可確保攻擊者在舊檔中發現弱點 版本的系統或 TEE 軟體無法將裝置復原至安全漏洞 版本,並使用以新版本建立的金鑰。此外,當鍵 搭載指定版本和修補程式的裝置 較新的版本或修補程式等級,金鑰會先升級才能使用。 ,且舊版的金鑰已失效。簡單來說,裝置就是 這些金鑰就會「寫」沿著裝置移動 將裝置還原為先前版本後,金鑰就會重新同步 無法使用。

為了支援 Treble 的模組化結構,並破壞 system.img 的繫結 boot.img、Keymaster 4 將金鑰版本繫結模型改為 每個分區的所有修補程式等級這樣您就能更新每個分區 同時仍提供復原保護機制

在 Android 9 中,bootsystemvendor 每個分區都有自己的修補程式等級

  • 搭載 Android 驗證開機程序 (AVB) 的裝置可加入所有修補程式等級 以及 vbmeta 中的系統版本 讓系統啟動載入程式能提供給 Keymaster。如果是鏈結分區,則分區的版本資訊 位於鏈結的 vbmeta 中。一般來說,版本資訊必須在 vbmeta struct包含驗證資料 (雜湊或 雜湊陣列)。
  • 在不支援 AVB 的裝置上:
    • 驗證開機程序須提供版本的雜湊。 中繼資料提交至系統啟動載入程式,讓系統啟動載入程式可將雜湊提供給 Keymaster。
    • boot.img 可以繼續將修補程式等級儲存在標頭中
    • system.img 可以繼續以唯讀模式儲存修補程式等級和 OS 版本 屬性
    • vendor.img 會將修補程式等級儲存在唯讀屬性中 ro.vendor.build.version.security_patch
    • 系統啟動載入程式可提供雜湊開機程序驗證的所有資料 。
  • 在 Android 9 中,請使用下列標記提供 下列分區:
    • VENDOR_PATCH_LEVELvendor 個分區
    • BOOT_PATCH_LEVELboot 個分區
    • OS_PATCH_LEVELOS_VERSIONsystem 個分區。(OS_VERSION已從以下位置移除: boot.img 標頭。
  • Keymaster 實作應單獨處理所有修補程式等級。索引鍵為 如果所有版本資訊都與某個索引鍵的關聯值相符,即可使用此項目,且 如果發生以下情況,IKeymaster::upgradeDevice() 會擲回較高的修補程式等級 。

HAL 變更

為了支援版本繫結和版本認證,Android 7.1 新增了 標記 Tag::OS_VERSIONTag::OS_PATCHLEVEL,以及 configureupgradeKey 方法。版本標記 Keymaster 2+ 實作項目會自動新增至所有新產生的 (或更新) 鍵。除此之外,任何嘗試使用沒有 OS 的金鑰 與目前系統 OS 版本或修補程式等級相符的版本或修補程式等級 這兩個屬性會分別由 ErrorCode::KEY_REQUIRES_UPGRADE 拒絕。

Tag::OS_VERSION 是一個 UINT 值,代表 Android 系統版本的主要、次要和副次要部分,作為 MMmms MM 是主要版本,mm 代表子版本,s 則是次次要版本 版本。舉例來說,6.1.2 會以 060102 表示。

Tag::OS_PATCHLEVEL 是一個 UINT 值,代表 上次更新系統的年份和月份 (格式為 YYYYMM),其中 YYYY 是 四位數的年份,MM 代表兩位數的月份。例如 2016 年 3 月是 如 201603

升級金鑰

允許金鑰升級至系統的新 OS 版本和修補程式等級 映像檔,Android 7.1 新增了 upgradeKey 方法至 HAL:

Keymaster 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Keymaster 2

keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
    const keymaster_key_blob_t* key_to_upgrade,
    const keymaster_key_param_set_t* upgrade_params,
    keymaster_key_blob_t* upgraded_key);
  • dev」是裝置結構
  • keyBlobToUpgrade 是需要升級的金鑰
  • upgradeParams 是升級金鑰所需的參數。這些 會包含「Tag::APPLICATION_ID」和 Tag::APPLICATION_DATA,必須使用才能解密金鑰 blob。
  • upgradedKeyBlob 是輸出參數,用來傳回 新的鍵 blob。

如果使用無法剖析的鍵 blob 呼叫 upgradeKey,或是 否則會傳回 ErrorCode::INVALID_KEY_BLOB。如果是 呼叫已被呼叫的金鑰,該鍵的修補程式等級大於目前的系統值。 它會傳回 ErrorCode::INVALID_ARGUMENT。如果以金鑰呼叫 作業系統版本大於目前系統值,而系統值 不為零,則會傳回 ErrorCode::INVALID_ARGUMENT。OS 版本 允許從非零升級至零的數值。發生錯誤時 與安全的世界通訊,會傳回適當的錯誤值 (例如 ErrorCode::SECURE_HW_ACCESS_DENIED, ErrorCode::SECURE_HW_BUSY)。如果沒有,則會傳回 ErrorCode::OK 並傳回新的鍵 blob upgradedKeyBlob

keyBlobToUpgrade」在 upgradeKey後仍然有效 呼叫,理論上如果裝置降級,可能會再次使用。於 KeyStore 通常會呼叫 deleteKey keyBlobToUpgrade blob 在呼叫 upgradeKey。如果「keyBlobToUpgrade」含有標記 Tag::ROLLBACK_RESISTANT,接著upgradedKeyBlob應該 也應避免復原

安全設定

如要實作版本繫結,Keymaster TA 必須採取 目前的 OS 版本和修補程式等級 (版本資訊),並確保 收到的資訊密切相關 有些人會將 Cloud Storage 視為檔案系統 但實際上不是

如要以安全的方式將版本資訊傳送至 TA,OS_VERSION 欄位 已新增至開機映像檔標頭。開機映像檔版本 就會自動填入這個欄位原始設備製造商 (OEM) 和 Keymaster TA 實作者 必須搭配運作,修改裝置的系統啟動載入程式,以擷取版本 然後將開機映像檔的資訊傳遞至 TA 啟動。這可確保攻擊者不會幹擾佈建作業 提交版本資訊給 TA。

您也必須確保系統映像檔的版本相同 將資訊當做開機映像檔為此,我們加入了設定方法 加入 Keymaster HAL:

keymaster_error_t (*configure)(const struct keymaster2_device* dev,
  const keymaster_key_param_set_t* params);

params 引數包含 Tag::OS_VERSIONTag::OS_PATCHLEVEL。此方法是由 Keymaster2 用戶端呼叫 開啟 HAL 後,但在呼叫任何其他方法之前。如果任何其他方式 會在設定前呼叫,但 TA 會傳回 ErrorCode::KEYMASTER_NOT_CONFIGURED

裝置啟動後第一次呼叫 configure 時, 請務必確認提供的版本資訊與 開機載入器。如果版本資訊不相符 configure 會傳回 ErrorCode::INVALID_ARGUMENT,而所有項目 其他 Keymaster 方法 ErrorCode::KEYMASTER_NOT_CONFIGURED。如果資訊相符 configure 會傳回 ErrorCode::OK,以及其他 Keymaster 方法。

後續對 configure 的呼叫會傳回 就不會變更 keymaster 的狀態。請注意,這項程序 所有 OTA 均須更新系統和開機映像檔。就無法更新 以便保持版本資訊同步。

因為 configure 將由其內容的系統呼叫 目的在於驗證時,攻擊者有機會利用 並強制系統提供 須符合開機映像檔,但這不是實際的系統版本。 開機映像檔驗證、系統映像檔的 dm-verity 驗證 而且 configure 在程式碼早期呼叫了 系統開機程序會讓這個窗口不易利用。