ハードウェア格納型キーストア

システムオンチップ(SoC)に信頼できる実行環境(TEE)が実現されているため、Android デバイスでは、ハードウェア格納型の強力なセキュリティ サービスを、Android OS、プラットフォーム サービス、さらにはサードパーティ アプリに提供できます。Android 固有の拡張機能をお探しのデベロッパーは、android.security.keystore にアクセスしてください。

6.0 より前の Android には、Keymaster Hardware Abstraction Layer(HAL)のバージョン 0.2 および 0.3 で提供される、シンプルなハードウェア格納型の暗号化サービス API がすでに存在し、キーストアにより、デジタル署名と検証オペレーションに加えて、非対称署名鍵ペアの生成とインポートが可能でした。この機能は多くのデバイスにすでに実装されていますが、多くのセキュリティ目標は、署名 API だけでは簡単に実現できません。Android 6.0 のキーストアは、Keystore API を拡張し、より幅広い機能を提供します。

Android 6.0 では、キーストアにより、対称暗号プリミティブ、AES と HMAC、ハードウェア格納型鍵のためのアクセス制御システムが追加されました。アクセス制御は、鍵の生成時に指定され、鍵の存続期間にわたって適用されます。ユーザーが認証された後ではじめて、指定された目的または指定された暗号パラメータでのみ、鍵を使用できるように制限できます。詳細については、承認タグおよび関数のページをご覧ください。

Android 6.0 のキーストアは、暗号プリミティブの範囲を拡張するだけでなく、次の機能も追加します。

  • 鍵の使用を制限し、鍵の不正使用によるセキュリティ侵害のリスクを削減するための使用制御スキーム
  • 指定されたユーザーとクライアント、定義された期間に鍵の使用を制限するためのアクセス制御スキーム

Android 7.0 では、Keymaster 2 の鍵構成証明とバージョン バインディングのサポートが追加されました。鍵構成証明は、鍵の詳細な説明とそのアクセス制御を含む公開鍵証明書を提供し、鍵がセキュア ハードウェアに存在することとその構成をリモートで検証できるようにします。

バージョン バインディングは、オペレーティング システムおよびパッチレベルのバージョンに鍵をバインドします。これにより、攻撃者が古いバージョンのシステムまたは TEE ソフトウェアに脆弱性を見つけても、デバイスを脆弱なバージョンにロールバックして新しいバージョンで作成された鍵を使用することができなくなります。さらに、特定のバージョンおよびパッチレベルの鍵が、新しいバージョンまたはパッチレベルにアップグレードされたデバイスで使用された場合、鍵は使用可能になる前にアップグレードされ、鍵の以前のバージョンは無効化されます。デバイスをアップグレードすると鍵はデバイスとともに「アップグレード」されますが、デバイスを以前のリリースに戻すとその鍵は使用できなくなります。

Android 8.0 では、Keymaster 3 は古いスタイルの C 構造のハードウェア抽象化レイヤ(HAL)から、新しいハードウェア インターフェース定義言語(HIDL)の定義から生成された C++ HAL インターフェースに移行しました。変更の一部として、引数の型の多くが変更されましたが、新しい型とメソッドは古い型と HAL の struct メソッドに 1 対 1 で対応しています。詳細については、関数ページをご覧ください。

このインターフェースの改訂に加えて、Android 8.0 では Keymaster 2 の構成証明機能が拡張され、ID 構成証明がサポートされるようになりました。ID 構成証明は、デバイスのシリアル番号、製品名、電話 ID(IMEI / MEID)など、ハードウェア識別子の強力な証明機能を提供する、オプションの限定的なメカニズムです。この追加機能を実装するには、ASN.1 構成証明スキーマを変更して ID 構成証明を追加します。Keymaster の実装では、関連するデータ項目を取得するセキュアな方法を見つけるとともに、機能をセキュアかつ恒久的に無効にするメカニズムを定義する必要があります。

Android 9 には、次の更新が含まれています。

  • Keymaster 4 へのアップデート
  • 埋め込みセキュア エレメントのサポート
  • セキュア鍵のインポートのサポート
  • 3DES 暗号化のサポート
  • boot.img と system.img で別々にバージョンを設定して個々に更新できるようにするためのバージョン バインディングの変更

用語集

ここでは、キーストアのコンポーネントとそれらの関係の概要を簡単に説明します。

AndroidKeystore は、アプリがキーストア機能にアクセスするために使用する Android Framework API およびコンポーネントです。標準の Java Cryptography Architecture API の拡張として実装され、アプリの固有のプロセス空間で実行される Java コードで構成されます。AndroidKeystore は、リクエストをキーストア デーモンに転送することで、キーストアの動作に対するアプリ リクエストを実行します。

キーストア デーモンは、Android システムのデーモンであり、Binder API を通じてすべてのキーストア機能へのアクセスを提供します。キーストアができることを格納のみに限定し、使用も公開もできないように暗号化された、実際の秘密鍵マテリアルを含む「鍵 blob」を格納する役割を果たします。

keymasterd は、Keymaster TA へのアクセスを提供する HIDL サーバーです(この名称は標準化されておらず、コンセプトを示す目的で使用されています)。

Keymaster TA(TA: 信頼できるアプリ)は、セキュア コンテキストで実行されるソフトウェアであり、多くの場合 ARM SoC の TrustZone 内にあります。すべてのセキュアなキーストア オペレーションを提供する、未処理の鍵マテリアルにアクセスする、鍵のすべてのアクセス制御条件を検証するなどの機能を果たします。

LockSettingsService は、パスワード認証と指紋認証の両方のユーザー認証を行う Android システム コンポーネントです。キーストアの一部ではありませんが、キーストアの鍵オペレーションは多くの場合ユーザー認証を必要とするため、キーストアと関連があります。LockSettingsService は、ゲートキーパー TA およびフィンガープリント TA とやり取りしてキーストア デーモンに提供する認証トークンを取得します。認証トークンは最終的に Keymaster TA アプリによって使用されます。

ゲートキーパー TA(TA: 信頼できるアプリ)は、セキュア コンテキストで実行される別のコンポーネントで、ユーザー パスワードの認証と認証トークンの生成を行います。認証トークンは、特定の時点で特定のユーザーが認証されたことを Keymaster TA に証明するために使用されます。

フィンガープリント TA(TA: 信頼できるアプリ)は、セキュア コンテキストで実行される別のコンポーネントで、ユーザーの指紋認証と認証トークンの生成を行います。認証トークンは、特定の時点で特定のユーザーが認証されたことを Keymaster TA に証明するために使用されます。

アーキテクチャ

Android Keystore API と基盤となる Keymaster HAL は、基本的な(しかし十分な)暗号プリミティブのセットを提供し、アクセス制御されたハードウェア格納型鍵を使用するプロトコルの実装を可能にします。

Keymaster HAL は、キーストア サービスがハードウェア格納型暗号サービスを提供するために使用する、動的読み込みが可能な OEM 提供のライブラリです。セキュリティを確保するため、HAL 実装はユーザー空間で、さらにはカーネル空間でも、機密性の高いオペレーションを実行しません。機密性の高いオペレーションは、カーネル インターフェースでアクセスされるセキュア プロセッサに委任されます。つまり、アーキテクチャは次のようになります。

Keymaster へのアクセス

図 1.Keymaster へのアクセス

Android デバイス内では、Keymaster HAL の「クライアント」は複数のレイヤ(アプリ、フレームワーク、キーストア デーモンなど)で構成されますが、このドキュメントの目的からは無視できます。つまり、ここに記載されている Keymaster HAL API は下位レベルの API であり、プラットフォーム内部のコンポーネントによって使用され、アプリ デベロッパーには公開されません。上位レベルの API は、Android デベロッパー サイトで説明されています。

Keymaster HAL の目的はセキュリティに対応したアルゴリズムを実装することではなく、セキュア環境へのリクエストをマーシャリングおよびマーシャリング解除することに限られます。ワイヤ形式は実装で定義されます。

以前のバージョンとの互換性

Keymaster 1 HAL は、以前リリースされた HAL(Keymaster 0.2 および 0.3 など)と完全に非互換です。古い Keymaster HAL で起動する Android 5.0 以前のデバイスでの相互運用性を高めるために、既存のハードウェア ライブラリへの呼び出しを Keymaster 1 HAL に実装するアダプターが、キーストアによって提供されています。つまり、Keymaster 1 HAL のすべての機能を提供することはできません。特に、サポートされるアルゴリズムは RSA と ECDSA のみであり、鍵認証の適用はすべてアダプターにより非セキュア環境で実行されます。

Keymaster 2 では、get_supported_* メソッドが削除されて、finish()メソッドが入力を受け取れるようになったことで、HAL インターフェースがさらに簡素化されました。これにより、入力を一度にまとめて利用できる場合は TEE へのラウンド トリップの回数が減り、AEAD 復号の実装が簡単になります。

Android 8.0 では、Keymaster 3 は古いスタイルの C 構造の HAL から、新しいハードウェア インターフェース定義言語(HIDL)の定義から生成された C++ HAL インターフェースに移行しました。新しいスタイルの HAL 実装は、生成された IKeymasterDevice クラスをサブクラス化して純粋な仮想メソッドを実装することにより、作成されます。変更の一部として、引数の型の多くが変更されましたが、新しい型とメソッドは古い型と HAL の struct メソッドに 1 対 1 で対応しています。

HIDL の概要

ハードウェア インターフェース定義言語(HIDL)は、ハードウェア インターフェースを指定するための、言語に依存しない実装メカニズムを提供します。現在、HIDL ツールは C++ および Java インターフェースの生成をサポートしています。信頼できる実行環境(TEE)の実装ではほとんどの場合 C++ ツールのほうが便利であると思われるため、このドキュメントでは C++ 表現についてのみ説明します。

HIDL インターフェースは、次のように表現されるメソッドのセットで構成されます。

      methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
    

さまざまな事前定義された型が存在し、HAL では新しい列挙型と構造型を定義できます。HIDL の詳細については、リファレンス セクションをご覧ください。

Keymaster 3 の IKeymasterDevice.hal のメソッドの例を次に示します。

generateKey(vec<KeyParameter> keyParams)
            generates(ErrorCode error, vec<uint8_t> keyBlob,
                      KeyCharacteristics keyCharacteristics);

これは、keymaster2 HAL の次のメソッドと同等です。

keymaster_error_t (*generate_key)(
            const struct keymaster2_device* dev,
            const keymaster_key_param_set_t* params,
            keymaster_key_blob_t* key_blob,
            keymaster_key_characteristics_t* characteristics);
    

HIDL バージョンでは、dev 引数は暗黙的に指定されるため、削除されます。params 引数は、key_parameter_t オブジェクトの配列を参照するポインタを含む構造体ではなくなり、KeyParameterオブジェクトを含む vec(ベクター)になりました。戻り値は、鍵 blob の uint8_t 値のベクターを含む「generates」句内にリストされます。

HIDL コンパイラによって生成される C++ 仮想メソッドは次のようになります。

    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                             generateKey_cb _hidl_cb) override;
    

ここで、generate_cb は次のように定義される関数ポインタです。

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                       const KeyCharacteristics& keyCharacteristics)>
    

つまり、generate_cb は、generate 句にリストされる戻り値を受け取る関数です。HAL 実装クラスは、この generateKey メソッドをオーバーライドし、generate_cb 関数ポインタを呼び出してオペレーションの結果を呼び出し元に返します。関数ポインタの呼び出しは同期呼び出しであることにご注意ください。呼び出し元は generateKey を呼び出し、generateKey は指定された関数ポインタを呼び出します。関数ポインタの実行が完了すると generateKey 実装に制御を戻し、それから呼び出し元に戻ります。

詳細な例については、hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp のデフォルト実装をご覧ください。 デフォルト実装では、古いスタイルの keymaster0、keymaster1、または keymaster2 の HAL を装備したデバイスに対する下位互換性が提供されます。