版本綁定

在 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可以繼續在唯讀屬性中儲存補丁等級和作業系統版本
    • vendor.img將補丁層級儲存在唯讀屬性ro.vendor.build.version.security_patch中。
    • 引導程式可以向 keymaster 提供透過驗證引導驗證的所有資料的雜湊值。
  • 在 Android 9 中,使用以下標籤提供以下分區的版本資訊:
    • VENDOR_PATCH_LEVELvendor分區
    • BOOT_PATCH_LEVELboot分區
    • OS_PATCH_LEVELOS_VERSIONsystem分割區。 ( OS_VERSION已從boot.img標頭中刪除。
  • Keymaster 實作應獨立處理所有補丁層級。如果所有版本資訊都與與金鑰關聯的值匹配,則金鑰可​​用,並且IKeymaster::upgradeDevice()在需要時捲動到更高的補丁層。

哈爾變化

為了支援版本綁定和版本證明,Android 7.1 新增了標籤Tag::OS_VERSIONTag::OS_PATCHLEVEL以及方法configureupgradeKey 。 Keymaster 2+ 實作會自動將版本標籤新增至所有新產生(或更新)的金鑰。此外,任何嘗試使用作業系統版本或修補程式等級與目前系統作業系統版本或修補程式等級不符的金鑰都會被拒絕,並顯示ErrorCode::KEY_REQUIRES_UPGRADE

Tag::OS_VERSION是一個UINT值,表示 Android 系統版本的主要、次要和次要部分,如 MMmmss,其中 MM 是主要版本,mm 是次要版本,ss 是次要版本。例如,6.1.2 將表示為 060102。

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

升級金鑰

為了允許密鑰升級到新的作業系統版本和系統映像的補丁級別,Android 7.1在HAL中新增了upgradeKey方法:

鑰匙大師3

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

鑰匙大師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_IDTag::APPLICATION_DATA ,如果在產生期間提供了它們,則它們是解密金鑰 blob 所必需的。
  • upgradedKeyBlob是輸出參數,用於傳回新的金鑰 Blob。

如果使用無法解析或無效的金鑰 blob 呼叫upgradeKey ,則傳回ErrorCode::INVALID_KEY_BLOB 。如果使用修補程式等級大於目前系統值的鍵呼叫它,則傳回ErrorCode::INVALID_ARGUMENT 。如果使用作業系統版本大於目前系統值的鍵呼叫它,且系統值非零,則傳回ErrorCode::INVALID_ARGUMENT 。允許作業系統版本從非零升級到零。如果與安全世界通訊發生錯誤,它會傳回適當的錯誤值(例如ErrorCode::SECURE_HW_ACCESS_DENIEDErrorCode::SECURE_HW_BUSY )。否則,它會傳回ErrorCode::OK並在upgradedKeyBlob中傳回一個新的金鑰 blob。

keyBlobToUpgradeupgradeKey呼叫後仍然有效,並且理論上如果設備降級可以再次使用。在實作中,金鑰庫通常會在呼叫upgradeKey之後不久對keyBlobToUpgrade blob 呼叫deleteKey 。如果keyBlobToUpgrade具有標籤Tag::ROLLBACK_RESISTANT ,則upgradedKeyBlob也應該具有它(並且應該具有回滾抗性)。

安全性設定

為了實現版本綁定,金鑰主TA需要一種方法來安全地接收當前作業系統版本和修補程式層級(版本資訊),並確保其接收到的資訊與正在運行的系統的資訊高度相符。

為了支援向 TA 安全傳送版本訊息,在啟動映像標頭中新增了OS_VERSION欄位。啟動映像建置腳本會自動填入此欄位。 OEM 和 keymaster TA 實施者需要共同修改設備引導程序,以從引導映像中提取版本信息,並在非安全系統引導之前將其傳遞給 TA。這確保了攻擊者無法幹擾向 TA 提供版本資訊。

還需要確保系統映像與啟動映像具有相同的版本資訊。為此,configure 方法已新增至 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的事實相結合,應該會使這個機會視窗難以被利用。