Android 11 は、APK 署名スキーム v4 によるストリーミング対応の署名スキームをサポートしています。v4 署名は、APK の全バイトに対して計算されたマークル ハッシュツリーに基づいています。これは fs-verity ハッシュツリーの構造に厳密に従っています(たとえば、ソルトの 0 パディングと最後のブロックの 0 パディングなど)。Android 11 では署名が別のファイル <apk name>.apk.idsig
に保存されます。v4 署名には、補完的な v2 または v3 署名が必要です。
ファイル形式
数値フィールドはすべてリトル エンディアンです。すべてのフィールドのバイト数は sizeof()
とまったく同じであり、暗黙的なパディングやアライメントは追加されません。
以下に、定義を簡略化するヘルパー構造体を示します。
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
メインファイルのコンテンツ:
struct V4Signature { int32 version; // only version 2 is supported as of now sized_bytes<int32> hashing_info; sized_bytes<int32> signing_info; sized_bytes<int32> merkle_tree; // optional };
hashing_info
は、ハッシュツリーの生成に使用されるパラメータであり、ルートハッシュです。
struct hashing_info.bytes { int32 hash_algorithm; // only 1 == SHA256 supported int8 log2_blocksize; // only 12 (block size 4096) supported now sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page };
signing_info
は次の構造体です。
struct signing_info.bytes { sized_bytes<int32> apk_digest; // used to match with the corresponding APK sized_bytes<int32> x509_certificate; // ASN.1 DER form sized_bytes<int32> additional_data; // a free-form binary data blob sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate int32 signature_algorithm_id; // see the APK v2 doc for the list sized_bytes<int32> signature; };
apk_digest
は APK の v3 署名ブロックから取得されるか、存在しない場合は v2 ブロックから取得されます(apk_digest を参照)
signature
コードを作成して検証するには、次のデータをバイナリ blob にシリアル化し、署名 / 検証アルゴリズムに署名付きデータとして渡す必要があります。
struct V4DataForSigning { int32 size; int64 file_size; // the size of the file that's been hashed. hashing_info.hash_algorithm; hashing_info.log2_blocksize; hashing_info.salt; hashing_info.raw_root_hash; signing_info.apk_digest; signing_info.x509_certificate; signing_info.additional_data; };
プロデューサーとコンシューマー
デフォルトのパラメータを使用して実行した場合、apksigner
Android SDK ツールは v4 署名ファイルを生成するようになりました。v4 署名は、他の署名スキームと同じ方法で無効にできます。また、v4 署名が有効かどうか検証することもできます。
adb
は、adb install --incremental
コマンドの実行時に .apk の次に .apk.idsig ファイルが存在すると想定します
また、デフォルトでは .idsig ファイルを使用して増分インストールを試み、見つからない場合または無効な場合は、通常のインストールに切り替えます。
インストール セッションが作成されると、ファイルをセッションに追加する際に、PackageInstaller
内の新しいストリーミング インストール API が stripped の v4 署名を別の引数として受け取ります。この時点で、signing_info
は blob 全体として incfs に渡されます。incfs は、blob からルートハッシュを抽出します。
インストール セッションが commit されると、PackageManagerService は ioctl を実行し、signing_info
blob を incfs から取得、解析して署名を検証します。
増分データローダ コンポーネントは、データローダのネイティブ API を介して署名のマークルツリー部分をストリーミングすることが求められます。package
サービス シェルコマンド install-incremental
は、base64 としてエンコードされた stripped の v4 署名ファイルを、各追加ファイルのパラメータとして受け取ります。
対応するマークルツリーは、コマンドの stdin
に送信する必要があります。
apk_digest
apk_digest
は、使用可能な最初の整理されたコンテンツ ダイジェストです。
- V3、1 MB ブロック、SHA2-512(CONTENT_DIGEST_CHUNKED_SHA512)、
- V3、4 KB ブロック、SHA2-256(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)、
- V3、1 MB ブロック、SHA2-256(CONTENT_DIGEST_CHUNKED_SHA256)、
- V2、SHA2-512、
- V2、SHA2-256。
APK 署名スキーム v3 の長さプレフィックス付き署名の長さプレフィックス付きシーケンスをご覧ください。
検証とテスト
機能単体テストと CTS を使用して、実装を検証します。
CtsIncrementalInstallHostTestCases
- /android/cts/hostsidetests/incrementalinstall
署名形式をテストする
署名形式をテストするには、開発環境を設定し、次の手動テストを実行します。
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Android SDK(ADB と apksigner)を使用して署名形式をテストする
Android SDK を使用して署名形式をテストするには、開発環境を設定し、IncFS の実装が完了していることを確認します。次に、ターゲットとなる物理デバイスまたはエミュレータにビルドをフラッシュします。既存の APK を生成または取得してから、デバッグ署名鍵を作成する必要があります。最後に、build-tools フォルダから v4 署名形式を使用して APK に署名し、インストールします。
署名
$ ./apksigner sign --ks debug.keystore game.apk
インストール
$ ./adb install game.apk
このテストがある場所
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java