APK署名スキームv3

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

Android 9 はAPK キー ローテーションをサポートしています。これにより、アプリは APK 更新の一部として署名キーを変更できます。ローテーションを実用的にするために、APK は新しい署名鍵と古い署名鍵の間の信頼レベルを示す必要があります。キー ローテーションをサポートするために、 APK 署名スキームを v2 から v3 に更新して、新しいキーと古いキーを使用できるようにしました。 V3 では、サポートされている SDK バージョンに関する情報と、回転証明構造体が APK 署名ブロックに追加されています。

APK署名ブロック

v1 APK 形式との下位互換性を維持するために、v2 および v3 APK 署名は、ZIP セントラル ディレクトリの直前にある APK 署名ブロック内に保存されます。

v3 APK 署名ブロックの形式はv2 と同じです。 APK の v3 署名は、ID 0xf05368c0 の ID と値のペアとして保存されます。

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

v3 スキームは、 v2 スキームと非常に似ているように設計されています。これは、同じ一般的な形式を持ち、同じ署名アルゴリズム ID 、鍵サイズ、および EC 曲線をサポートします。

ただし、v3 スキームでは、サポートされている SDK バージョンと回転証明構造体に関する情報が追加されています。

フォーマット

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

APK 署名スキーム v3 ブロックの形式は、v2 の形式に従います。

  • 長さがプレフィックスされたsignerの長さがプレフィックスされたシーケンス:
    • 長さ接頭辞のsigned data :
      • 長さでプレフィックスされたdigestsの長さでプレフィックスされたシーケンス:
        • signature algorithm ID (4 バイト)
        • digest (長さのプレフィックス)
      • X.509 certificatesの長さプレフィックス シーケンス:
        • 長さがプレフィックスされた X.509 certificate (ASN.1 DER 形式)
      • minSDK (uint32) - プラットフォームのバージョンがこの数値より低い場合、この署名者は無視されます。
      • maxSDK (uint32) - プラットフォームのバージョンがこの数値を超える場合、この署名者は無視されます。
      • 長さでプレフィックスされたadditional attributesの長さでプレフィックスされたシーケンス:
        • ID (uint32)
        • value (可変長: 追加属性の長さ - 4 バイト)
        • ID - 0x3ba06f8c
        • value -回転証明構造体
    • minSDK (uint32) - 署名済みデータ セクションの minSDK 値の複製 - 現在のプラットフォームが範囲内にない場合に、この署名の検証をスキップするために使用されます。署名されたデータ値と一致する必要があります。
    • maxSDK (uint32) - 署名済みデータ セクションの maxSDK 値の複製 - 現在のプラットフォームが範囲内にない場合に、この署名の検証をスキップするために使用されます。署名されたデータ値と一致する必要があります。
    • 長さプレフィックス付きsignaturesの長さプレフィックス シーケンス:
      • signature algorithm ID (uint32)
      • signed dataに対する長さプレフィックス付きsignature
    • 長さがプレフィックスされたpublic key (SubjectPublicKeyInfo、ASN.1 DER 形式)

Proof-of-rotation と self-trusted-old-certs 構造体

証明ローテーション構造体により、アプリは、通信相手の他のアプリでブロックされることなく、署名証明書をローテーションできます。これを実現するために、アプリの署名には次の 2 つの新しいデータが含まれています。

  • アプリの署名証明書は、前任者が信頼されている場合はどこでも信頼できるという第三者の主張
  • アプリ自体がまだ信頼しているアプリの古い署名証明書

signed-data セクションの Proof-of-rotation 属性は、単一リンクのリストで構成され、各ノードには、以前のバージョンのアプリに署名するために使用された署名証明書が含まれています。この属性は、概念的な回転証明と自己信頼の古い証明書のデータ構造を含むことを意図しています。リストは、ルート ノードに対応する最も古い署名証明書を使用してバージョン順に並べられます。 Proof-of-rotation データ構造は、各ノードの証明書がリストの次の証明書に署名することによって構築され、したがって、古いキーと同じくらい信頼できるはずであるという証拠を新しいキーのそれぞれに吹き込みます。

self-trusted-old-certs データ構造は、セット内のメンバーシップとプロパティを示すフラグを各ノードに追加することによって構築されます。たとえば、特定のノードの署名証明書が Android 署名権限を取得するために信頼されていることを示すフラグが存在する場合があります。このフラグを使用すると、古い証明書で署名された他のアプリに、新しい署名証明書で署名されたアプリで定義された署名権限を引き続き付与できます。回転証明属性全体が v3 signerフィールドの署名済みデータ セクションに存在するため、含まれる apk の署名に使用されるキーによって保護されます。

この形式では、複数の署名キーと、異なる祖先署名証明書を 1 つに収束させること (共通シンクへの複数の開始ノード) を排除します。

フォーマット

回転証明は、ID 0x3ba06f8cの下の APK 署名スキーム v3 ブロック内に保存されます。その形式は次のとおりです。

  • 長さでプレフィックスされたlevelsの、長さでプレフィックスされたシーケンス:
    • 長さがプレフィックスされたsigned data (以前の証明書による - 存在する場合)
      • 長さがプレフィックスされた X.509 certificate (ASN.1 DER 形式)
      • signature algorithm ID (uint32) - 前のレベルで証明書によって使用されたアルゴリズム
    • flags (uint32) - この証明書を self-trusted-old-certs 構造体に含める必要があるかどうか、およびどの操作に対してかを示すフラグ。
    • signature algorithm ID (uint32) - 次のレベルの署名済みデータ セクションの ID と一致する必要があります。
    • 上記のsigned dataに対する長さプレフィックスsignature

複数の証明書

Android は現在、複数の証明書で署名された APK を、構成する証明書とは別の一意の署名 ID を持つものとして扱います。したがって、署名付きデータ セクションの回転証明属性は有向非巡回グラフを形成します。これは、特定のバージョンの署名者の各セットが 1 つのノードを表す、単一リンク リストとしてより適切に表示できます。これにより、proof-of-rotation 構造体がさらに複雑になります (以下の複数署名者バージョン)。特に、順序付けが問題になります。さらに、APK に個別に署名することはできなくなりました。なぜなら、ローテーション証明構造には、1 つずつ署名するのではなく、新しい証明書セットに署名する古い署名証明書が必要だからです。たとえば、キー A によって署名された APK が、2 つの新しいキー B および C によって署名されることを希望している場合、B の署名者に A または B による署名だけを含めることはできません。これは、B および C とは異なる署名 ID であるためです。そのような構造体を構築する前に署名者が調整しなければならないことを意味します。

複数の署名者の回転証明属性

  • 長さプレフィックスsetsの長さプレフィックス シーケンス:
    • signed data (前のセットによる - 存在する場合)
      • 長さがプレフィックスされたcertificatesのシーケンス
        • 長さがプレフィックスされた X.509 certificate (ASN.1 DER 形式)
      • 一連のsignature algorithm IDs (uint32) - 前のセットの証明書ごとに 1 つ、同じ順序で。
    • flags (uint32) - この一連の証明書を self-trusted-old-certs 構造体に含める必要があるかどうか、およびどの操作に対して行うかを示すフラグ。
    • 長さプレフィックス付きsignaturesの長さプレフィックス シーケンス:
      • signature algorithm ID (uint32) - 署名済みデータ セクションの ID と一致する必要があります
      • 上記のsigned dataに対する長さプレフィックスsignature

回転証明構造体の複数の先祖

v3 スキームは、同じアプリの同じ署名キーにローテーションする 2 つの異なるキーも処理しません。これは、買収の場合とは異なります。買収した会社は、買収したアプリを移動して、その署名キーを使用してアクセス許可を共有したいと考えています。新しいアプリはパッケージ名で識別され、独自の回転証明構造体を含む可能性があるため、この買収はサポートされているユースケースと見なされます。同じ証明書に到達するための 2 つの異なるパスを持つ同じアプリのサポートされていないケースは、キー ローテーション設計で行われた多くの仮定を破ります。

検証

Android 9 以降では、APK 署名スキーム v3、v2 スキーム、または v1 スキームに従って APK を検証できます。古いプラットフォームは v3 署名を無視し、v2 署名を検証してから v1 を検証しようとします。

APK 署名検証プロセス

図 1. APK 署名検証プロセス

APK 署名スキーム v3 検証

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

検証

デバイスが v3 を適切にサポートしていることをテストするには、 cts/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java CTS テストを実行します。