バージョン バインディング

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 に格納します。
    • ブートローダーは、確認付きブートで検証されたすべてのデータのハッシュを Keymaster に供給できます。
  • Android 9 では、以下のタグを使用して、以下のパーティションのバージョン情報を提供します。
    • VENDOR_PATCH_LEVEL: vendor パーティション
    • BOOT_PATCH_LEVEL: boot パーティション
    • OS_PATCH_LEVELOS_VERSION: system パーティション(OS_VERSIONboot.img ヘッダーから削除されました)
  • Keymaster 実装は、すべてのパッチレベルを独立して処理する必要があります。すべてのバージョン情報が、鍵に関連付けられた値と一致する場合、鍵が使用可能になり、必要に応じて IKeymaster::upgradeDevice() が上位のパッチレベルに昇格します。

HAL の変更

Android 7.1 では、バージョン バインディングとバージョン構成証明をサポートするために、タグ Tag::OS_VERSION および Tag::OS_PATCHLEVEL と、メソッド configure および upgradeKey が追加されました。Keymaster 2 以降の実装では、新たに生成(または更新)されたすべての鍵に対して、自動的にバージョンタグが追加されます。さらに、現在のシステム OS バージョンまたはパッチレベルと一致する OS バージョンまたはパッチレベルを持たない鍵を使用しようとすると、ErrorCode::KEY_REQUIRES_UPGRADE で拒否されます。

Tag::OS_VERSION は、Android システム バージョンのメジャー / マイナー / サブマイナー バージョンを MMmmss として表す UINT 値です。MM はメジャー バージョン、mm はマイナー バージョン、ss はサブマイナー バージョンです。たとえば、6.1.2 は 060102 と表現されます。

Tag::OS_PATCHLEVEL は、システムの最終更新の年と月を YYYYMM として表す UINT 値です。YYYY は 4 桁の年、MM は 2 桁の月です。たとえば、2016 年 3 月は 201603 と表現されます。

UpgradeKey

システム イメージの新しい 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 は鍵をアップグレードするために必要なパラメータです。これには、生成中に鍵 blob が提供された場合、それを復号するために必要な Tag::APPLICATION_IDTag::APPLICATION_DATA が含まれます。
  • upgradedKeyBlob は、新しい鍵 blob を返すために使用される出力パラメータです。

解析できない鍵 blob または他の原因で無効になっている鍵 blob で upgradeKey が呼び出された場合は、ErrorCode::INVALID_KEY_BLOB が返されます。パッチレベルが現在のシステムの値より大きい鍵で呼び出された場合は、ErrorCode::INVALID_ARGUMENT が返されます。OS バージョンが現在のシステムの値よりも大きい鍵で呼び出され、システム値がゼロでない場合は、ErrorCode::INVALID_ARGUMENT が返されます。ゼロ以外の OS バージョンのゼロへのアップグレードは許容されます。セキュア環境と通信する際にエラーイベントが発生した場合は、適切なエラー値(ErrorCode::SECURE_HW_ACCESS_DENIEDErrorCode::SECURE_HW_BUSY など)が返されます。それ以外の場合は、ErrorCode::OK が返され、upgradedKeyBlob に新しい鍵 blob が返されます。

keyBlobToUpgradeupgradeKey 呼び出し後も有効なままであり、デバイスがダウングレードされた場合、理論的には再度使用できます。実際には、キーストアは通常、upgradeKey を呼び出した直後に keyBlobToUpgrade blob で deleteKey を呼び出します。keyBlobToUpgrade にタグ Tag::ROLLBACK_RESISTANT が付けられている場合、upgradedKeyBlob もそのタグを持つ(つまり、ロールバック耐性を持つ)必要があります。

セキュア構成

バージョン バインディングを実装するには、Keymaster TA が現在の OS バージョンとパッチレベル(バージョン情報)をセキュアな方法で受け取り、受け取った情報が実行中のシステムに関する情報と厳密に一致することを保証する方法が必要です。

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 が含まれます。このメソッドは、HAL を開いた後で、他のメソッドを呼び出す前に、keymaster2 クライアントによって呼び出されます。configure より前に他のメソッドが呼び出されると、TA は ErrorCode::KEYMASTER_NOT_CONFIGURED を返します。

デバイスの起動後に初めて configure が呼び出されたときは、バージョン情報がブートローダーによって提供されたものと一致していることを確認する必要があります。バージョン情報が一致しない場合、configureErrorCode::INVALID_ARGUMENT を返し、他のすべての Keymaster メソッドは引き続き ErrorCode::KEYMASTER_NOT_CONFIGURED を返します。バージョン情報が一致した場合、configureErrorCode::OK を返し、他の Keymaster メソッドはエラーを返さなくなります。

その後の configure 呼び出しは、最初の呼び出しで返された値と同じ値を返し、Keymaster の状態を変更することはありません。

configure は、コンテンツの検証を目的とするシステムによって呼び出されるため、攻撃者がシステム イメージを侵害して、ブートイメージと一致するがシステムの実際のバージョンとは異なるバージョン情報を提供するように仕向ける機会がわずかながらあります。ブートイメージ検証とシステム イメージ コンテンツの dm-verity 検証を組み合わせると、システム起動の初期に configure が呼び出されることも関係して、上記の機会の悪用が困難になります。