APK-Signaturschema v2

Das APK-Signaturschema v2 ist ein Signaturschema für ganze Dateien, das die Überprüfungsgeschwindigkeit erhöht und die Integritätsgarantien stärkt, indem Änderungen an den geschützten Teilen der APK erkannt werden.

Durch das Signieren mit APK Signature Scheme v2 wird ein APK Signing Block unmittelbar vor dem Abschnitt ZIP Central Directory in die APK-Datei eingefügt. Innerhalb des APK-Signaturblocks werden v2-Signaturen und Unterzeichneridentitätsinformationen in einem APK-Signaturschema v2-Block gespeichert.

APK vor und nach der Unterzeichnung

Abbildung 1. APK vor und nach dem Signieren

APK Signature Scheme v2 wurde in Android 7.0 (Nougat) eingeführt. Um eine APK auf Android 6.0 (Marshmallow) und älteren Geräten installierbar zu machen, sollte die APK mit der JAR-Signatur signiert werden , bevor sie mit dem v2-Schema signiert wird.

APK Signing Block

Um die Abwärtskompatibilität mit dem APK-Format v1 aufrechtzuerhalten, werden v2 und neuere APK-Signaturen in einem APK-Signaturblock gespeichert, einem neuen Container, der zur Unterstützung des APK-Signaturschemas v2 eingeführt wurde. In einer APK-Datei befindet sich der APK-Signaturblock unmittelbar vor dem zentralen ZIP-Verzeichnis, das sich am Ende der Datei befindet.

Der Block enthält ID-Wert-Paare, die so umbrochen sind, dass das Auffinden des Blocks in der APK einfacher ist. Die v2-Signatur der APK wird als ID-Wert-Paar mit der ID 0x7109871a gespeichert.

Format

Das Format des APK-Signaturblocks lautet wie folgt (alle numerischen Felder sind Little-Endian-Felder):

  • size of block in Bytes (ohne dieses Feld) (uint64)
  • Sequenz von ID-Wert-Paaren mit Uint64-Länge und Präfix:
    • ID (uint32)
    • value (variable Länge: Länge des Paares - 4 Bytes)
  • size of block in Bytes - wie das allererste Feld (uint64)
  • magic "APK Sig Block 42" (16 Bytes)

APK wird analysiert, indem zuerst der Anfang des ZIP-Zentralverzeichnisses gefunden wird (indem der ZIP-Datensatz für das Ende des Zentralverzeichnisses am Ende der Datei gefunden und dann der Startversatz des Zentralverzeichnisses aus dem Datensatz gelesen wird). Der magic Wert bietet eine schnelle Möglichkeit, um festzustellen, dass vor dem Central Directory wahrscheinlich der APK-Signaturblock steht. Die size of block dann effizient auf den Blockanfang in der Datei.

ID-Wert-Paare mit unbekannten IDs sollten bei der Interpretation des Blocks ignoriert werden.

APK Signature Scheme v2 Block

APK wird von einem oder mehreren Unterzeichnern / Identitäten signiert, die jeweils durch einen Signaturschlüssel dargestellt werden. Diese Informationen werden als APK Signature Scheme v2 Block gespeichert. Für jeden Unterzeichner werden die folgenden Informationen gespeichert:

  • (Signaturalgorithmus, Digest, Signatur) Tupel. Der Digest wird gespeichert, um die Überprüfung der Signatur von der Integritätsprüfung des APK-Inhalts zu entkoppeln.
  • X.509-Zertifikatkette, die die Identität des Unterzeichners darstellt.
  • Zusätzliche Attribute als Schlüssel-Wert-Paare.

Für jeden Unterzeichner wird die APK anhand einer unterstützten Signatur aus der bereitgestellten Liste überprüft. Signaturen mit unbekannten Signaturalgorithmen werden ignoriert. Es liegt an jeder Implementierung, zu entscheiden, welche Signatur verwendet werden soll, wenn mehrere unterstützte Signaturen auftreten. Dies ermöglicht die Einführung stärkerer Signaturmethoden in der Zukunft auf abwärtskompatible Weise. Der vorgeschlagene Ansatz besteht darin, die stärkste Signatur zu überprüfen.

Format

Der Block APK Signature Scheme v2 wird im APK Signing Block unter der ID 0x7109871a .

Das Format des APK Signature Scheme v2-Blocks lautet wie folgt (alle numerischen Werte sind Little-Endian-Werte, alle Felder mit Längenpräfix verwenden uint32 für die Länge):

  • Sequenz mit Längenpräfix des signer mit Längenpräfix:
    • signed data Längenpräfix:
      • Sequenz mit Längenpräfix von Digests mit digests :
      • Längenpräfixierte Sequenz von X.509- certificates :
        • X.509- certificate Längenpräfix (ASN.1 DER-Formular)
      • Längenpräfix-Sequenz von additional attributes mit Längenpräfix:
        • ID (uint32)
        • value (variable Länge: Länge des zusätzlichen Attributs - 4 Bytes)
    • Längenpräfix-Sequenz von Längenpräfix- signatures :
      • signature algorithm ID (uint32)
      • signature Längenpräfix über signed data
    • public key Längenpräfix (SubjectPublicKeyInfo, ASN.1 DER-Formular)

Signaturalgorithmus-IDs

  • 0x0101 - RSASSA-PSS mit SHA2-256-Digest, SHA2-256 MGF1, 32 Byte Salz, Trailer: 0xbc
  • 0x0102 - RSASSA-PSS mit SHA2-512-Digest, SHA2-512 MGF1, 64 Byte Salz, Trailer: 0xbc
  • 0x0103 - RSASSA-PKCS1-v1_5 mit SHA2-256-Digest. Dies gilt für Build-Systeme, die deterministische Signaturen erfordern.
  • 0x0104 - RSASSA-PKCS1-v1_5 mit SHA2-512-Digest. Dies gilt für Build-Systeme, die deterministische Signaturen erfordern.
  • 0x0201 - ECDSA mit SHA2-256-Digest
  • 0x0202 - ECDSA mit SHA2-512-Digest
  • 0x0301 - DSA mit SHA2-256-Digest

Alle oben genannten Signaturalgorithmen werden von der Android-Plattform unterstützt. Signaturwerkzeuge unterstützen möglicherweise eine Teilmenge der Algorithmen.

Unterstützte Tastengrößen und EC-Kurven:

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

Integritätsgeschützte Inhalte

Zum Schutz von APK-Inhalten besteht eine APK aus vier Abschnitten:

  1. Inhalt der ZIP-Einträge (von Offset 0 bis zum Start des APK Signing Block)
  2. APK Signing Block
  3. Zentrales ZIP-Verzeichnis
  4. ZIP Ende des zentralen Verzeichnisses

APK-Abschnitte nach der Unterzeichnung

Abbildung 2. APK-Abschnitte nach dem Signieren

Das APK-Signaturschema v2 schützt die Integrität der Abschnitte 1, 3, 4 und der signed data Datenblöcke des APK-Signaturschemas v2, die in Abschnitt 2 enthalten sind.

Die Integrität der Abschnitte 1, 3 und 4 wird durch eine oder mehrere Zusammenfassungen ihres Inhalts geschützt, die in signed data Datenblöcken gespeichert sind, die wiederum durch eine oder mehrere Signaturen geschützt sind.

Der Digest über die Abschnitte 1, 3 und 4 wird wie folgt berechnet, ähnlich einem zweistufigen Merkle-Baum . Jeder Abschnitt ist in aufeinanderfolgende 1-MB-Blöcke (2 bis 20 Byte) aufgeteilt. Der letzte Block in jedem Abschnitt kann kürzer sein. Der Digest jedes Chunks wird über die Verkettung von Byte 0xa5 , die Länge des 0xa5 in Bytes (Little-Endian uint32) und den Inhalt des 0xa5 berechnet. Der Digest der obersten Ebene wird über die Verkettung von Byte 0x5a , die Anzahl der Chunks (Little-Endian-Uint32) und die Verkettung der Digests der Chunks in der Reihenfolge berechnet, in der die Chunks in der APK angezeigt werden. Der Digest wird in Chunk-Form berechnet, um die Berechnung durch Parallelisierung zu beschleunigen.

APK verdauen

Abbildung 3. APK-Digest

Der Schutz von Abschnitt 4 (ZIP-Ende des zentralen Verzeichnisses) wird durch den Abschnitt erschwert, der den Versatz des zentralen ZIP-Verzeichnisses enthält. Der Versatz ändert sich, wenn sich die Größe des APK-Signaturblocks ändert, z. B. wenn eine neue Signatur hinzugefügt wird. Wenn Sie also einen Digest über das ZIP-Ende des zentralen Verzeichnisses berechnen, muss das Feld, das den Versatz des zentralen ZIP-Verzeichnisses enthält, so behandelt werden, dass es den Versatz des APK-Signaturblocks enthält.

Rollback-Schutz

Ein Angreifer könnte versuchen, eine von v2 signierte APK auf Android-Plattformen, die die Überprüfung von von v2 signierten APK unterstützen, als v1-signierte APK überprüfen zu lassen. Um diesen Angriff abzuwehren, müssen v2-signierte APKs, die auch v1-signiert sind, im Hauptabschnitt ihrer META-INF / *. SF-Dateien ein X-Android-APK-signiertes Attribut enthalten. Der Wert des Attributs ist ein durch Kommas getrennter Satz von APK-Signaturschema-IDs (die ID dieses Schemas ist 2). Bei der Überprüfung der v1-Signatur muss der APK-Prüfer APKs ablehnen, die keine Signatur für das APK-Signaturschema haben, das der Prüfer aus diesem Satz bevorzugt (z. B. v2-Schema). Dieser Schutz beruht auf der Tatsache, dass Inhalte von META-INF / *. SF-Dateien durch v1-Signaturen geschützt sind. Weitere Informationen finden Sie im Abschnitt zur JAR-signierten APK-Überprüfung .

Ein Angreifer könnte versuchen, stärkere Signaturen aus dem Block APK Signature Scheme v2 zu entfernen. Um diesen Angriff abzuschwächen, wird die Liste der Signaturalgorithmus-IDs, mit denen die APK signiert wurde, im signed data Datenblock gespeichert, der durch jede Signatur geschützt ist.

Überprüfung

In Android 7.0 und höher können APKs gemäß dem APK-Signaturschema v2 + oder der JAR-Signatur (v1-Schema) überprüft werden. Ältere Plattformen ignorieren v2-Signaturen und überprüfen nur v1-Signaturen.

Überprüfungsprozess der APK-Signatur

Abbildung 4. Überprüfungsprozess der APK-Signatur (neue Schritte in Rot)

Überprüfung des APK-Signaturschemas v2

  1. Suchen Sie den APK-Signaturblock und überprüfen Sie Folgendes:
    1. Zwei Größenfelder des APK-Signaturblocks enthalten denselben Wert.
    2. Auf ZIP Central Directory folgt unmittelbar der ZIP-Datensatz zum Ende des Central Directory.
    3. Auf das ZIP-Ende des zentralen Verzeichnisses folgen keine weiteren Daten.
  2. Suchen Sie den ersten Block des APK-Signaturschemas v2 im APK-Signaturblock. Wenn der v2-Block vorhanden ist, fahren Sie mit Schritt 3 fort. Andernfalls können Sie die APK mithilfe des v1-Schemas überprüfen.
  3. Für jeden signer im Block APK Signature Scheme v2:
    1. Wählen Sie die stärksten unterstützte signature algorithm ID von signatures . Die Reihenfolge der Stärken hängt von jeder Implementierungs- / Plattformversion ab.
    2. Überprüfen Sie die entsprechende signature von signatures anhand signed data mit dem public key . (Es ist jetzt sicher, signed data zu analysieren.)
    3. Stellen Sie sicher, dass die geordnete Liste der Signaturalgorithmus-IDs in digests und signatures identisch ist. (Dies soll das Entfernen / Hinzufügen von Signaturen verhindern.)
    4. Berechnen Sie den Digest von APK-Inhalten mit demselben Digest-Algorithmus wie den Digest-Algorithmus, der vom Signaturalgorithmus verwendet wird.
    5. Stellen Sie sicher, dass der berechnete Digest mit dem entsprechenden digest aus digests identisch ist.
    6. Stellen Sie sicher , dass SubjectPublicKeyInfo des ersten certificate von certificates identisch ist mit public key .
  4. Die Überprüfung ist erfolgreich, wenn mindestens ein signer gefunden wurde und Schritt 3 für jeden gefundenen signer .

Hinweis : APK darf nicht mit dem Schema v1 überprüft werden, wenn in Schritt 3 oder 4 ein Fehler auftritt.

JAR-signierte APK-Überprüfung (v1-Schema)

Die JAR-signierte APK ist eine standardmäßig signierte JAR , die genau die in META-INF / MANIFEST.MF aufgeführten Einträge enthalten muss und bei der alle Einträge von derselben Gruppe von Unterzeichnern signiert werden müssen. Seine Integrität wird wie folgt überprüft:

  1. Jeder Unterzeichner wird durch einen JAR-Eintrag META-INF / <signer> .SF und META-INF / <signer>. (RSA | DSA | EC) dargestellt.
  2. <signer>. (RSA | DSA | EC) ist eine PKCS # 7 CMS ContentInfo mit SignedData-Struktur, deren Signatur über die <signer> .SF-Datei überprüft wird.
  3. Die <Signer> .SF-Datei enthält einen Digest für die gesamte Datei von META-INF / MANIFEST.MF und Digests für jeden Abschnitt von META-INF / MANIFEST.MF. Der Digest der gesamten Datei von MANIFEST.MF wird überprüft. Wenn dies fehlschlägt, wird stattdessen der Digest jedes MANIFEST.MF-Abschnitts überprüft.
  4. META-INF / MANIFEST.MF enthält für jeden integritätsgeschützten JAR-Eintrag einen entsprechend benannten Abschnitt, der den Digest des unkomprimierten Inhalts des Eintrags enthält. Alle diese Digests werden überprüft.
  5. Die APK-Überprüfung schlägt fehl, wenn die APK JAR-Einträge enthält, die nicht in MANIFEST.MF aufgeführt sind und nicht Teil der JAR-Signatur sind.

Die Schutzkette ist somit <signer>. (RSA | DSA | EC) -> <signer> .SF -> MANIFEST.MF -> Inhalt jedes integritätsgeschützten JAR-Eintrags.