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.
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
:-
signature algorithm ID
(uint32) -
digest
(mit Längenpräfix): Siehe Integritätsgeschützte Inhalte
-
- Längenpräfixierte Sequenz von X.509-
certificates
:- X.509-
certificate
Längenpräfix (ASN.1 DER-Formular)
- X.509-
- 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)
-
- Sequenz mit Längenpräfix von Digests mit
- Längenpräfix-Sequenz von Längenpräfix-
signatures
:-
signature algorithm ID
(uint32) -
signature
Längenpräfix übersigned 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:
- Inhalt der ZIP-Einträge (von Offset 0 bis zum Start des APK Signing Block)
- APK Signing Block
- Zentrales ZIP-Verzeichnis
- ZIP Ende des zentralen Verzeichnisses
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.
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.
Abbildung 4. Überprüfungsprozess der APK-Signatur (neue Schritte in Rot)
Überprüfung des APK-Signaturschemas v2
- Suchen Sie den APK-Signaturblock und überprüfen Sie Folgendes:
- Zwei Größenfelder des APK-Signaturblocks enthalten denselben Wert.
- Auf ZIP Central Directory folgt unmittelbar der ZIP-Datensatz zum Ende des Central Directory.
- Auf das ZIP-Ende des zentralen Verzeichnisses folgen keine weiteren Daten.
- 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.
- Für jeden
signer
im Block APK Signature Scheme v2:- Wählen Sie die stärksten unterstützte
signature algorithm ID
vonsignatures
. Die Reihenfolge der Stärken hängt von jeder Implementierungs- / Plattformversion ab. - Überprüfen Sie die entsprechende
signature
vonsignatures
anhandsigned data
mit dempublic key
. (Es ist jetzt sicher,signed data
zu analysieren.) - Stellen Sie sicher, dass die geordnete Liste der Signaturalgorithmus-IDs in
digests
undsignatures
identisch ist. (Dies soll das Entfernen / Hinzufügen von Signaturen verhindern.) - Berechnen Sie den Digest von APK-Inhalten mit demselben Digest-Algorithmus wie den Digest-Algorithmus, der vom Signaturalgorithmus verwendet wird.
- Stellen Sie sicher, dass der berechnete Digest mit dem entsprechenden
digest
ausdigests
identisch ist. - Stellen Sie sicher , dass SubjectPublicKeyInfo des ersten
certificate
voncertificates
identisch ist mitpublic key
.
- Wählen Sie die stärksten unterstützte
- Die Überprüfung ist erfolgreich, wenn mindestens ein
signer
gefunden wurde und Schritt 3 für jeden gefundenensigner
.
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:
- Jeder Unterzeichner wird durch einen JAR-Eintrag META-INF / <signer> .SF und META-INF / <signer>. (RSA | DSA | EC) dargestellt.
- <signer>. (RSA | DSA | EC) ist eine PKCS # 7 CMS ContentInfo mit SignedData-Struktur, deren Signatur über die <signer> .SF-Datei überprüft wird.
- 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.
- 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.
- 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.