
Androidのverified bootイメージ(vbmeta)が一般に公開されているテストキーで署名されているかどうかを確認し、リリースビルドの設定ミスを特定するPythonユーティリティです。
NCC Groupのコンサルタントが時折遭遇するエラーとして、Androidビルドが既知の秘密鍵で署名されていることがあります。これにより、セキュアブートが有効なデバイスであっても、デバイスメーカー(ひいてはそのユーザー)は脆弱な状態に置かれます。このブログ記事には2つの目的があります。
Androidベースのデバイスが起動するとき、まずブートローダーが署名済みコードを実行していることが検証され、その後ブートローダーが高水準オペレーティングシステム(HLOS)を検証します。このブログ記事では後者の部分のみを扱います。
各チップセットベンダーはルート・オブ・トラスト(RoT)を異なる方法で実装できますが、一般的にデバイスは e-fuses を設定することで保護されます。チップセットに書き込まれた不変のROMコードがこれらのe-fusesを読み取り、暗号ハッシュのビットとして解釈します。その後、このハッシュを使用して、通常はブートローダーバイナリに含まれる信頼された公開鍵を検証します。公開鍵が検証されると、その鍵は デバイス上で実行される最初の変更可能なコードが署名されていること を暗号的に検証するために使用されます。このプロセスが正しく実装されていれば、ブートローダーを変更しようとする試みはすべて失敗します。Androidベースのデバイス(セキュリティカメラ、スマートプラグ、センサーなど)を製造するOEMは、通常、チップベンダー(すなわちQualcomm)のリファレンスデザインとサンプルコードを製品開発の出発点として使用します。
AVB は、デバイス上で実行されるソフトウェアの完全性を確保するためのメカニズムの一部です。デバイスには、暗号的に検証されるイメージを含む vbmeta という名前のパーティションがあります。ブートローダーが検証に成功すると、デバイスはvbmetaイメージの内容を信頼します。このイメージには、ブートローダーがその後boot、vendor、systemなどのパーティション上に存在するソフトウェアを検証するために使用する情報が含まれています。
利便性のため、チップセットベンダーはOEMのデバイス立ち上げプロセスを簡素化することを目的として、そのままコンパイルが成功するリファレンスコードを提供しています。当初、これらのイメージは、Googleが最初に生成し、すべてのバニラAndroidビルドに存在する テスト用秘密鍵 を使用して署名されています。チップベンダーがこれらのテスト鍵を更新することもありますが、署名用の秘密鍵は依然としてサンプルコードに含まれているため、信頼できないものと見なす必要があります。
NCC Groupは、デバイスメーカーがヒューズの設定によってブートローダーを正しく保護していても、HLOSの署名に使用されるデフォルトのテスト用秘密鍵を変更していないことを発見しました。したがって、ブートローダーは変更できなくても、攻撃者はカスタムHLOSコードをビルドして署名し、AVBプロセスによる検証に合格するパーティションを更新することが可能です。
NCC Groupは、vbmeta.imgに既知の秘密鍵の公開部分が含まれているかどうかをチェックする ツール を作成しました。テスト鍵については、ツールはユーザーが提供するパス(AndroidビルドのBOARD_AVB_KEY_PATH環境変数で指定される)を受け付けるか、ツールに同梱されているGitHubから収集した既知の鍵のコレクションを使用します。
$ python3 test_avb_key.py --help
Usage:
python test_avb_key.py [VBMETA.IMG] [PATH_PRIVATE_KEY]
Parameters:
* Parameter 'VBMETA.IMG' points to a user or userdebug file from an Android build.
Note: the userdebug image fails this test, it is expected.
* Grep Android build for 'BOARD_AVB_KEY_PATH' to obtain path of signing file,
and leave only the path, i.e. 'external/avb/test/data/'.
HLOSソフトウェアがデフォルトの秘密鍵で署名されている場合、その問題がフラグ付けされます。例えば、LineageOSビルドの場合:
$ python test_avb_key.py ./sample/vbmeta/lineage/vbmeta.img ./sample/aosp/external/avb/test/data/
Opening vbmeta file: ./sample/vbmeta/lineage/vbmeta.img
Using known private key for verification: ./sample/aosp/external/avb/test/data/sign_key.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_pik.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_prk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_psk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_puk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_gsi.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_oneplus.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096.pem. Public key found at index: 945
If the script was executed on a vbmeta.img file from an Android user build, there is a problem.
それ以外の場合、ツールは成功メッセージを返します。例えば、Pixel9ビルドの場合:
$ python test_avb_key.py ./sample/vbmeta/pixel9/vbmeta.img ./sample/aosp/external/avb/test/data/
Opening vbmeta file: ./sample/vbmeta/pixel9/vbmeta.img
Using known private key for verification: ./sample/aosp/external/avb/test/data/sign_key.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_pik.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_prk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_psk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_puk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_gsi.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_oneplus.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096_oneplus.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096_realtek.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa8192.pem. Public key not found in vbmeta.img file. That's good.
No issues were found with ./sample/vbmeta/pixel9/vbmeta.img
Android開発者はこのツールをクイックチェックとして使用し、リリース/本番用ビルドが公に知られている秘密鍵で署名されていないことを確認できます。また、ビルドプロセスに統合して、Androidユーザービルドが正しく署名されていることを保証し、そうでない場合はビルドを失敗させることもできます。