APK 署名スキーム v2

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

APK 署名スキーム v2 は、検証速度を向上させ、APK の保護された部分への変更を検出することで整合性の保証を強化するファイル全体の署名スキームです。

APK 署名スキーム v2 を使用して署名すると、 APK 署名ブロックが APK ファイルの ZIP セントラル ディレクトリ セクションの直前に挿入されます。 APK 署名ブロック内では、v2 署名と署名者の ID 情報がAPK 署名スキーム v2 ブロックに保存されます。

署名前後の APK

図 1.署名前後の APK

APK 署名スキーム v2 は、Android 7.0 (Nougat) で導入されました。 APK を Android 6.0 (Marshmallow) 以前のデバイスにインストールできるようにするには、v2 スキームで署名する前に、 JAR 署名を使用して APK に署名する必要があります。

APK署名ブロック

v1 APK 形式との下位互換性を維持するために、v2 以降の APK 署名は、APK 署名スキーム v2 をサポートするために導入された新しいコンテナーである APK 署名ブロック内に保存されます。 APK ファイルでは、APK 署名ブロックは、ファイルの末尾にある ZIP セントラル ディレクトリの直前にあります。

ブロックには、APK 内でブロックを見つけやすくする方法でラップされた ID と値のペアが含まれています。 APK の v2 署名は、ID 0x7109871a の ID と値のペアとして保存されます。

フォーマット

APK 署名ブロックの形式は次のとおりです (すべての数値フィールドはリトル エンディアンです)。

  • size of block (バイト単位) (このフィールドを除く) (uint64)
  • uint64-length-prefixed ID-value ペアのシーケンス:
    • ID (uint32)
    • value (可変長: ペアの長さ - 4 バイト)
  • size of blockバイト)—最初のフィールドと同じ (uint64)
  • magic 「APK Sig Block 42」(16バイト)

APK は、最初に ZIP セントラル ディレクトリの開始を検出することによって解析されます (ファイルの末尾にある ZIP End of Central Directory レコードを検出し、次にレコードからセントラル ディレクトリの開始オフセットを読み取ります)。 magicの値は、中央ディレクトリの前にあるものが APK 署名ブロックである可能性が高いことを簡単に確立する方法を提供します。 size of block 、ファイル内のブロックの開始を効率的に指します。

ブロックを解釈するときは、ID が不明な ID と値のペアを無視する必要があります。

APK 署名スキーム v2 ブロック

APK は、それぞれが署名鍵で表される 1 つ以上の署名者/ID によって署名されます。この情報は、APK 署名スキーム v2 ブロックとして保存されます。署名者ごとに、次の情報が保存されます。

  • (署名アルゴリズム、ダイジェスト、署名) タプル。ダイジェストは、APK のコンテンツの整合性チェックから署名の検証を分離するために保存されます。
  • 署名者の ID を表す X.509 証明書チェーン。
  • キーと値のペアとしての追加の属性。

署名者ごとに、指定されたリストからサポートされている署名を使用して APK が検証されます。署名アルゴリズムが不明な署名は無視されます。サポートされている複数の署名が検出された場合に使用する署名を選択するのは、各実装次第です。これにより、下位互換性のある方法で、将来的により強力な署名方法を導入できます。推奨されるアプローチは、最強の署名を検証することです。

フォーマット

APK 署名スキーム v2 ブロックは、ID 0x7109871aで APK 署名ブロック内に保存されます。

APK 署名スキーム v2 ブロックの形式は次のとおりです (すべての数値はリトル エンディアンであり、すべての長さのプレフィックス フィールドは長さに uint32 を使用します)。

  • 長さがプレフィックスされたsignerの長さがプレフィックスされたシーケンス:
    • 長さ接頭辞のsigned data :
      • 長さでプレフィックスされたdigestsの長さでプレフィックスされたシーケンス:
      • X.509 certificatesの長さプレフィックス シーケンス:
        • 長さがプレフィックスされた X.509 certificate (ASN.1 DER 形式)
      • 長さでプレフィックスされたadditional attributesの長さでプレフィックスされたシーケンス:
        • ID (uint32)
        • value (可変長: 追加属性の長さ - 4 バイト)
    • 長さプレフィックス付きsignaturesの長さプレフィックス シーケンス:
      • signature algorithm ID (uint32)
      • signed dataに対する長さプレフィックス付きsignature
    • 長さがプレフィックスされたpublic key (SubjectPublicKeyInfo、ASN.1 DER 形式)

署名アルゴリズム ID

  • 0x0101 - SHA2-256 ダイジェスト、SHA2-256 MGF1、32 バイトのソルト、トレーラー付きの RSASSA-PSS: 0xbc
  • 0x0102 - SHA2-512 ダイジェスト、SHA2-512 MGF1、64 バイトのソルト、トレーラーを含む RSASSA-PSS: 0xbc
  • 0x0103 — SHA2-256 ダイジェストを含む RSASSA-PKCS1-v1_5。これは、決定論的な署名を必要とするビルド システム用です。
  • 0x0104 — SHA2-512 ダイジェストを含む RSASSA-PKCS1-v1_5。これは、決定論的な署名を必要とするビルド システム用です。
  • 0x0201:SHA2-256 ダイジェストを使用する ECDSA
  • 0x0202:SHA2-512 ダイジェストを使用する ECDSA
  • 0x0301 - SHA2-256 ダイジェストによる DSA

上記の署名アルゴリズムはすべて、Android プラットフォームでサポートされています。署名ツールは、アルゴリズムのサブセットをサポートしている場合があります。

サポートされている鍵のサイズと EC 曲線:

  • RSA: 1024、2048、4096、8192、16384
  • EC: NIST P-256、P-384、P-521
  • DSA: 1024、2048、3072

完全性が保護されたコンテンツ

APK のコンテンツを保護する目的で、APK は次の 4 つのセクションで構成されます。

  1. ZIP エントリの内容 (オフセット 0 から APK 署名ブロックの開始まで)
  2. APK署名ブロック
  3. ZIP セントラル ディレクトリ
  4. セントラル ディレクトリの ZIP エンド

署名後の APK セクション

図 2.署名後の APK セクション

APK 署名スキーム v2 は、セクション 1、3、4、およびセクション 2 内に含まれる APK 署名スキーム v2 ブロックのsigned dataブロックの整合性を保護します。

セクション 1、3、および 4 の完全性は、1 つまたは複数の署名によって保護されるsigned dataブロックに格納された内容の 1 つまたは複数のダイジェストによって保護されます。

セクション 1、3、および 4 のダイジェストは、2 レベルのマークル ツリーと同様に、次のように計算されます。各セクションは、連続する 1 MB (2 20バイト) のチャンクに分割されます。各セクションの最後のチャンクは短くなる場合があります。各チャンクのダイジェストは、バイト0xa5 、チャンクの長さ (バイト単位) (リトル エンディアン uint32)、およびチャンクの内容を連結して計算されます。トップレベルのダイジェストは、バイト0x5aの連結、チャンクの数 (リトル エンディアン uint32)、およびチャンクが APK に表示される順序でのチャンクのダイジェストの連結に対して計算されます。ダイジェストはチャンク形式で計算され、並列化することで計算を高速化できます。

APK ダイジェスト

図 3. APK ダイジェスト

セクション 4 (セントラル ディレクトリの ZIP エンド) の保護は、ZIP セントラル ディレクトリのオフセットを含むセクションによって複雑になります。たとえば、新しい署名が追加された場合など、APK 署名ブロックのサイズが変更されると、オフセットが変更されます。したがって、セントラル ディレクトリの ZIP エンドでダイジェストを計算する場合、ZIP セントラル ディレクトリのオフセットを含むフィールドは、APK 署名ブロックのオフセットを含むものとして扱われなければなりません。

ロールバック保護

攻撃者は、v2 署名 APK の検証をサポートする Android プラットフォームで、v2 署名 APK を v1 署名 APK として検証しようとする可能性があります。この攻撃を軽減するには、v1 署名済みの v2 署名済み APK の META-INF/*.SF ファイルのメイン セクションに X-Android-APK-Signed 属性を含める必要があります。属性の値は、コンマで区切られた一連の APK 署名スキーム ID (このスキームの ID は 2) です。 v1 署名を検証する場合、APK 検証者は、検証者がこのセットから優先する APK 署名スキーム (v2 スキームなど) の署名を持たない APK を拒否する必要があります。この保護は、内容の META-INF/*.SF ファイルが v1 署名によって保護されているという事実に依存しています。 JAR 署名付き APK 検証のセクションを参照してください。

攻撃者は、APK 署名スキーム v2 ブロックからより強力な署名を取り除こうとする可能性があります。この攻撃を緩和するために、APK の署名に使用された署名アルゴリズム ID のリストは、各署名によって保護されているsigned dataブロックに保存されます。

検証

Android 7.0 以降では、APK 署名スキーム v2+ または JAR 署名 (v1 スキーム) に従って APK を検証できます。古いプラットフォームは v2 署名を無視し、v1 署名のみを検証します。

APK 署名検証プロセス

図 4. APK 署名検証プロセス (赤字の新しいステップ)

APK 署名スキーム v2 検証

  1. APK 署名ブロックを見つけて、次のことを確認します。
    1. APK 署名ブロックの 2 つのサイズ フィールドに同じ値が含まれています。
    2. ZIP Central Directory の直後に、ZIP End of Central Directory レコードが続きます。
    3. セントラル ディレクトリの ZIP エンドの後にデータが続きません。
  2. APK 署名ブロック内の最初の APK 署名スキーム v2 ブロックを見つけます。 v2 ブロックが存在する場合は、手順 3 に進みます。それ以外の場合は、 v1 スキームを使用した APK の検証に戻ります。
  3. APK 署名スキーム v2 ブロックの各signerに対して:
    1. signatures から、サポートされている最も強力なsignatures signature algorithm IDを選択します。強度の順序は、各実装/プラットフォーム バージョンまでです。
    2. public keyを使用して、 signatures signed dataに対するsignatureから対応する署名を検証します。 ( signed dataを安全に解析できるようになりました。)
    3. digestssignaturesの署名アルゴリズム ID の順序付きリストが同一であることを確認します。 (これは、署名の削除/追加を防ぐためです。)
    4. 署名アルゴリズムで使用されるダイジェスト アルゴリズムと同じダイジェスト アルゴリズムを使用して、 APK コンテンツのダイジェストを計算します。
    5. 計算されたダイジェストが、 digestからの対応するdigestsと同一であることを確認します。
    6. certificates書の最初のcertificateの SubjectPublicKeyInfo がpublic keyと同一であることを確認します。
  4. 少なくとも 1 人のsignerが見つかり、見つかったsignerごとにステップ 3 が成功した場合、検証は成功します。

: ステップ 3 または 4 でエラーが発生した場合は、v1 スキームを使用して APK を検証しないでください。

JAR 署名付き APK 検証 (v1 スキーム)

JAR 署名付き APK は、標準の署名済み JARであり、META-INF/MANIFEST.MF にリストされているエントリを正確に含む必要があり、すべてのエントリが同じ署名者のセットによって署名されている必要があります。その完全性は次のように検証されます。

  1. 各署名者は、META-INF/<signer>.SF および META-INF/<signer>.(RSA|DSA|EC) JAR エントリで表されます。
  2. <signer>.(RSA|DSA|EC) は、署名が <signer>.SF ファイルで検証されるSignedData 構造を持つ PKCS #7 CMS ContentInfoです。
  3. <signer>.SF ファイルには、META-INF/MANIFEST.MF のファイル全体のダイジェストと、META-INF/MANIFEST.MF の各セクションのダイジェストが含まれています。 MANIFEST.MF のファイル全体のダイジェストが検証されます。それが失敗した場合、各 MANIFEST.MF セクションのダイジェストが代わりに検証されます。
  4. META-INF/MANIFEST.MF には、整合性が保護された JAR エントリごとに、エントリの非圧縮コンテンツのダイジェストを含む対応する名前のセクションが含まれます。これらのダイジェストはすべて検証済みです。
  5. MANIFEST.MF にリストされておらず、JAR 署名の一部ではない JAR エントリが APK に含まれている場合、APK 検証は失敗します。

したがって、保護チェーンは <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> 整合性が保護された各 JAR エントリの内容です。