APK-Signaturschema v4

Android 11 unterstützt ein Streaming-kompatibles Signaturschema mit dem APK Signature Scheme v4. Die v4-Signatur basiert auf dem über alle Bytes der APK berechneten Merkle-Hash-Baum. Es folgt genau der Struktur des fs-verity- Hash-Baums (zum Beispiel das Auffüllen des Salzes mit Nullen und das Auffüllen des letzten Blocks mit Nullen). Android 11 speichert die Signatur in einer separaten Datei, <apk name>.apk.idsig Eine v4-Signatur erfordert eine ergänzende v2- oder v3 -Signatur.

Datei Format

Alle numerischen Felder sind in Little Endian. Alle Felder belegen genau die Anzahl an Bytes wie ihre sizeof() , ohne implizite Auffüllung oder Ausrichtung.

Unten finden Sie eine Hilfsstruktur zur Vereinfachung der Definitionen.

template <class SizeT>
struct sized_bytes {
        SizeT size;
        byte bytes[size];
};

Inhalt der Hauptdatei:

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 sind die Parameter, die für die Hash-Baum-Generierung verwendet werden, + der Root-Hash:

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 ist die folgende Struktur:

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 wird aus dem v3-Signaturblock der APK oder, falls nicht vorhanden, aus dem v2-Block entnommen (siehe apk_digest ).

Um einen signature zu erstellen und zu überprüfen, müssen die folgenden Daten in einen Binärblob serialisiert und als signierte Daten an den Signatur-/Verifizierungsalgorithmus übergeben werden:

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;
};
  1. merkle_tree ist der gesamte Merkle-Baum der APK, berechnet wie in der fs-verity -Dokumentation beschrieben.

Produzenten und Konsumenten

Das Android SDK-Tool apksigner generiert jetzt die v4-Signaturdatei, wenn Sie es mit Standardparametern ausführen. Die v4-Signatur kann auf die gleiche Weise wie die anderen Signaturschemata deaktiviert werden. Es kann auch überprüfen, ob die v4-Signatur gültig ist.

adb erwartet, dass die Datei .apk.idsig neben der .apk vorhanden ist, wenn der Befehl adb install --incremental ausgeführt wird
Außerdem wird standardmäßig die .idsig-Datei verwendet, um eine inkrementelle Installation zu versuchen, und es wird auf eine reguläre Installation zurückgegriffen, wenn diese fehlt oder ungültig ist.

Wenn eine Installationssitzung erstellt wird, akzeptiert die neue Streaming-Installations-API im PackageInstaller die entfernte v4-Signatur als separates Argument, wenn der Sitzung eine Datei hinzugefügt wird. An diesem Punkt wird signing_info als gesamter Blob an incfs übergeben. Incfs extrahiert Root-Hash aus dem Blob.

Wenn die Installationssitzung festgeschrieben wird, führt PackageManagerService einen ioctl aus, um den signing_info-Blob von incfs abzurufen, analysiert ihn und überprüft die Signatur.

Von der inkrementellen Data Loader-Komponente wird erwartet, dass sie den Merkle-Baum-Teil der Signatur über die native API des Data Loaders streamt.
package -Shell-Befehl install-incremental akzeptiert die entfernte v4-Signaturdatei, die als Base64 codiert ist, als Parameter für jede hinzugefügte Datei. Der entsprechende Merkle-Baum muss in die stdin des Befehls gesendet werden.

apk_digest

apk_digest ist der erste verfügbare Inhalts-Digest in der Reihenfolge:

  1. V3, 1-MB-Block, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
  2. V3, 4-KB-Block, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
  3. V3, 1-MB-Block, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
  4. V2, SHA2-512,
  5. V2, SHA2-256.

Siehe längenpräfixierte Sequenz von längenpräfixierten Signaturen in APK Signature Scheme v3.

APK-Validierungsprozess v4
Abbildung 1 : APK-Validierungsprozess v4

Validierung und Tests

Validieren Sie die Implementierung mithilfe von Feature Unit Tests und CTS.

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/incrementalinstall

Testen des Signaturformats

Um das Signaturformat zu testen, richten Sie eine Entwicklungsumgebung ein und führen Sie die folgenden manuellen Tests durch:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

Testen des Signaturformats mit Android SDK (ADB und apksigner)

Um das Signaturformat mit Android SDK zu testen, richten Sie eine Entwicklungsumgebung ein und stellen Sie sicher, dass Sie die Implementierung von IncFS abgeschlossen haben. Anschließend flashen Sie den Build auf einem physischen Zielgerät oder Emulator. Sie müssen ein vorhandenes APK generieren oder abrufen und dann einen Debug-Signaturschlüssel erstellen. Signieren und installieren Sie abschließend die APK mit dem v4-Signaturformat aus dem Build-Tools-Ordner.

Zeichen

$ ./apksigner sign --ks debug.keystore game.apk

Installieren

$ ./adb install game.apk

Wo sind diese Tests zu finden?

/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java