Le schéma de signature des fichiers APK v2 est un schéma de signature de l'ensemble du fichier qui augmente la vitesse de vérification et renforce les garanties d'intégrité en détectant toute modification apportée aux parties protégées de l'APK.
La signature à l'aide du schéma de signature APK v2 insère un bloc de signature APK dans le fichier APK immédiatement avant la section du répertoire central ZIP. Dans le bloc de signature de l'APK, les signatures v2 et les informations d'identité du signataire sont stockées dans un bloc APK Signature Scheme v2.
Figure 1 : APK avant et après la signature
APK Signature Scheme v2 a été introduit dans Android 7.0 (Nougat). Pour qu'un APK puisse être installé sur Android 6.0 (Marshmallow) et les appareils plus anciens, il doit être signé à l'aide de la signature JAR avant d'être signé avec le schéma v2.
Bloc de signature de l'APK
Pour assurer la rétrocompatibilité avec le format APK v1, les signatures APK v2 et versions ultérieures sont stockées dans un bloc de signature APK, un nouveau conteneur introduit pour prendre en charge le schéma de signature APK v2. Dans un fichier APK, le bloc de signature de l'APK se trouve immédiatement avant le répertoire central ZIP, qui se trouve à la fin du fichier.
Le bloc contient des paires ID-valeur encapsulées de manière à faciliter la localisation du bloc dans l'APK. La signature v2 de l'APK est stockée sous la forme d'une paire d'ID-valeur avec l'ID 0x7109871a.
Format
Le format du bloc de signature de l'APK est le suivant (tous les champs numériques sont en ordre petit-endian):
size of block
en octets (à l'exception de ce champ) (uint64)- Séquence de paires d'ID-valeur préfixées par une longueur uint64 :
ID
(uint32)value
(longueur variable: longueur de la paire - 4 octets)
size of block
en octets (identique au tout premier champ (uint64))magic
"APK Sig Block 42" (16 octets)
L'analyse de l'APK commence par trouver le début du répertoire central ZIP (en recherchant l'enregistrement de fin du répertoire central ZIP à la fin du fichier, puis en lisant le décalage de début du répertoire central à partir de l'enregistrement). La valeur magic
permet de déterminer rapidement que ce qui précède le répertoire central est probablement le bloc de signature de l'APK. La valeur size of
block
pointe ensuite efficacement sur le début du bloc dans le fichier.
Les paires d'ID-valeurs avec des ID inconnus doivent être ignorées lors de l'interprétation du bloc.
Bloc APK Signature Scheme v2
L'APK est signé par un ou plusieurs signataires/identités, chacun représenté par une clé de signature. Ces informations sont stockées sous forme de bloc APK Signature Scheme v2. Pour chaque signataire, les informations suivantes sont stockées:
- Tuples (algorithme de signature, récapitulatif, signature). Le récapitulatif est stocké pour dissocier la validation de la signature de la vérification de l'intégrité du contenu de l'APK.
- Chaîne de certificats X.509 représentant l'identité du signataire.
- Attributs supplémentaires sous forme de paires clé-valeur.
Pour chaque signataire, l'APK est validé à l'aide d'une signature compatible de la liste fournie. Les signatures avec des algorithmes de signature inconnus sont ignorées. Il appartient à chaque implémentation de choisir la signature à utiliser lorsqu'il existe plusieurs signatures compatibles. Cela permet d'introduire à l'avenir des méthodes de signature plus sécurisées de manière rétrocompatible. L'approche suggérée consiste à valider la signature la plus forte.
Format
Le bloc APK Signature Scheme v2 est stocké dans le bloc de signature APK sous l'ID 0x7109871a
.
Le format du bloc du schéma de signature APK v2 est le suivant (toutes les valeurs numériques sont en ordre peu endian, tous les champs avec un préfixe de longueur utilisent uint32 pour la longueur):
- Séquence avec préfixe de longueur de
signer
avec préfixe de longueur :signed data
avec préfixe de longueur :- Séquence avec préfixe de longueur de
digests
avec préfixe de longueur :signature algorithm ID
(uint32)- (préfixe de longueur)
digest
: consultez la section Contenus protégés contre l'intégrité.
- Séquence avec préfixe de longueur de
certificates
X.509 :certificate
X.509 avec préfixe de longueur (format ASN.1 DER)
- Séquence avec préfixe de longueur de
additional attributes
avec préfixe de longueur :ID
(uint32)value
(longueur variable: longueur de l'attribut supplémentaire - 4 octets)
- Séquence avec préfixe de longueur de
- Séquence avec préfixe de longueur de
signatures
avec préfixe de longueur :signature algorithm ID
(uint32)signature
avec préfixe de longueur sursigned data
public key
avec préfixe de longueur (SubjectPublicKeyInfo, format ASN.1 DER)
ID des algorithmes de signature
- 0x0101 : RSASSA-PSS avec condensé SHA2-256, MGF1 SHA2-256, 32 octets de sel, postscript : 0xbc
- 0x0102 : RSASSA-PSS avec condensé SHA2-512, MGF1 SHA2-512, 64 octets de sel, postscript : 0xbc
- 0x0103 : RSASSA-PKCS1-v1_5 avec condensé SHA2-256 Il s'agit des systèmes de compilation qui nécessitent des signatures déterministes.
- 0x0104 : RSASSA-PKCS1-v1_5 avec condensé SHA2-512. Il s'agit des systèmes de compilation qui nécessitent des signatures déterministes.
- 0x0201 : ECDSA avec condensé SHA2-256
- 0x0202 : ECDSA avec condensé SHA2-512
- 0x0301 : DSA avec condensé SHA2-256
Tous les algorithmes de signature ci-dessus sont compatibles avec la plate-forme Android. Les outils de signature peuvent prendre en charge un sous-ensemble des algorithmes.
Tailles de clés et courbes elliptiques compatibles:
- RSA: 1 024, 2 048, 4 096, 8 192, 16 384
- EC: NIST P-256, P-384, P-521
- DSA: 1 024, 2 048, 3 072
Contenus protégés par l'intégrité
Pour protéger le contenu d'un APK, celui-ci se compose de quatre sections:
- Contenu des entrées ZIP (de l'offset 0 jusqu'au début du bloc de signature de l'APK)
- Bloc de signature de l'APK
- Répertoire central ZIP
- Fin de l'annuaire central (ZIP)
Figure 2. Sections de l'APK après signature
Le schéma de signature des fichiers APK v2 protège l'intégrité des sections 1, 3, 4 et des blocs signed data
du schéma de signature des fichiers APK v2 contenus dans la section 2.
L'intégrité des sections 1, 3 et 4 est protégée par un ou plusieurs récapitulatifs de leur contenu stockés dans des blocs signed data
, qui sont à leur tour protégés par une ou plusieurs signatures.
Le récapitulatif des sections 1, 3 et 4 est calculé comme suit, comme un arbre de Merkle à deux niveaux.
Chaque section est divisée en fragments consécutifs de 1 Mo (220 octets). Le dernier segment de chaque section peut être plus court. Le récapitulatif de chaque segment est calculé sur la concaténation de l'octet 0xa5
, de la longueur du segment en octets (uint32 little-endian) et du contenu du segment. Le récapitulatif de niveau supérieur est calculé sur la concaténation de l'octet 0x5a
, du nombre de blocs (uint32 little-endian) et de la concaténation des récapitulatifs des blocs dans l'ordre dans lequel ils apparaissent dans l'APK. Le récapitulatif est calculé par blocs pour accélérer le calcul en le parallélisant.
Figure 3. Condensé de l'APK
La protection de la section 4 (fin du répertoire central ZIP) est compliquée par la section contenant le décalage du répertoire central ZIP. Le décalage change lorsque la taille du bloc de signature de l'APK change, par exemple, lorsqu'une nouvelle signature est ajoutée. Par conséquent, lors du calcul du récapitulatif sur la fin du répertoire central ZIP, le champ contenant le décalage du répertoire central ZIP doit être traité comme contenant le décalage du bloc de signature de l'APK.
Protections contre le rollback
Un pirate informatique peut tenter de faire valider un APK signé en version 2 comme un APK signé en version 1 sur les plates-formes Android compatibles avec la validation des APK signés en version 2. Pour atténuer cette attaque, les APK signés en version 2 qui sont également signés en version 1 doivent contenir un attribut X-Android-APK-Signed dans la section principale de leurs fichiers META-INF/*.SF. La valeur de l'attribut est un ensemble d'ID de schéma de signature d'APK séparés par une virgule (l'ID de ce schéma est 2). Lors de la validation de la signature v1, le vérificateur d'APK doit rejeter les APK qui ne comportent pas de signature pour le schéma de signature d'APK préféré par le vérificateur dans cet ensemble (par exemple, le schéma v2). Cette protection repose sur le fait que les contenus des fichiers META-INF/*.SF sont protégés par des signatures v1. Consultez la section sur la validation des APK signés JAR.
Un pirate informatique peut tenter de supprimer les signatures plus sécurisées du bloc APK Signature Scheme v2. Pour atténuer cette attaque, la liste des ID d'algorithme de signature avec lesquels l'APK était signé est stockée dans le bloc signed data
, qui est protégé par chaque signature.
Validation
Dans Android 7.0 et versions ultérieures, les APK peuvent être validés selon le schéma de signature APK v2 ou version ultérieure ou la signature JAR (schéma v1). Les plates-formes plus anciennes ignorent les signatures v2 et ne valident que les signatures v1.
Figure 4. Processus de validation de la signature de l'APK (nouvelles étapes en rouge)
Vérification du schéma de signature des fichiers APK v2
- Recherchez le bloc de signature de l'APK et vérifiez les points suivants :
- Deux champs de taille du bloc de signature de l'APK contiennent la même valeur.
- L'enregistrement ZIP End of Central Directory est immédiatement suivi de l'enregistrement ZIP Central Directory.
- La fin du répertoire central ZIP n'est pas suivie d'autres données.
- Recherchez le premier bloc APK Signature Scheme v2 dans le bloc de signature APK. Si le bloc v2 est présent, passez à l'étape 3. Sinon, utilisez le schéma v1 pour vérifier l'APK.
- Pour chaque
signer
dans le bloc APK Signature Scheme v2 :- Choisissez le
signature algorithm ID
le plus puissant compatible danssignatures
. L'ordre de force dépend de chaque implémentation/version de plate-forme. - Vérifiez le
signature
correspondant designatures
avecsigned data
à l'aide depublic key
. (Vous pouvez désormais analysersigned data
en toute sécurité.) - Vérifiez que la liste ordonnée des ID d'algorithme de signature dans
digests
etsignatures
est identique. (Cela permet d'éviter le retrait/l'ajout de signature.) - Calculez le condensé du contenu de l'APK à l'aide du même algorithme de condensé que celui utilisé par l'algorithme de signature.
- Vérifiez que le récapitulatif calculé est identique à l'
digest
correspondant dedigests
. - Vérifiez que SubjectPublicKeyInfo du premier
certificate
decertificates
est identique àpublic key
.
- Choisissez le
- La validation aboutit si au moins un
signer
a été détecté et que l'étape 3 a réussi pour chaquesigner
détecté.
Remarque: L'APK ne doit pas être validé à l'aide du schéma v1 si une erreur se produit à l'étape 3 ou 4.
Vérification des APK signés avec JAR (schéma v1)
L'APK signé par JAR est un fichier JAR signé standard, qui doit contenir exactement les entrées listées dans META-INF/MANIFEST.MF et où toutes les entrées doivent être signées par le même ensemble de signataires. Son intégrité est vérifiée comme suit:
- Chaque signataire est représenté par une entrée META-INF/<signer>.SF et META-INF/<signer>.(RSA|DSA|EC) JAR.
- <signer>.(RSA|DSA|EC) est un ContentInfo CMS PKCS 7 avec une structure SignedData dont la signature est validée sur le fichier <signer>.SF.
- Le fichier <signer>.SF contient un récapitulatif de l'ensemble du fichier META-INF/MANIFEST.MF et des récapitulatifs de chaque section de META-INF/MANIFEST.MF. Le récapitulatif de l'ensemble du fichier MANIFEST.MF est validé. Si cette opération échoue, le récapitulatif de chaque section MANIFEST.MF est validé à la place.
- META-INF/MANIFEST.MF contient, pour chaque entrée JAR protégée par l'intégrité, une section correspondante contenant le récapitulatif du contenu non compressé de l'entrée. Tous ces récapitulatifs sont validés.
- La validation de l'APK échoue si l'APK contient des entrées JAR qui ne sont pas listées dans le fichier MANIFEST.MF et ne font pas partie de la signature JAR.
La chaîne de protection est donc <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> contenu de chaque entrée JAR protégée par l'intégrité.