APK Signature Scheme v2 est un schéma de signature de l'intégralité 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, juste avant la section ZIP Central Directory. 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.
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 d'APK
Pour assurer la rétrocompatibilité avec le format APK v1, les signatures APK v2 et ultérieures sont stockées dans un bloc de signature d'APK, un nouveau conteneur introduit pour prendre en charge le schéma de signature d'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 d'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 (hors champ) (uint64)- Séquence de paires ID/valeur avec préfixe uint64-length :
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'APK est analysé en trouvant d'abord le début du répertoire central ZIP (en trouvant l'enregistrement de fin ZIP du répertoire central à 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:
- (algorithme de signature, condensé, 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 robustes et rétrocompatibles. L'approche suggérée consiste à vérifier 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 v2 du schéma de signature de l'APK est le suivant (toutes les valeurs numériques sont few-endian, tous les champs avec 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 préfixée par la longueur d'
digests
préfixée par la longueur :signature algorithm ID
(uint32)- (préfixe de longueur)
digest
: consultez la section Contenus protégés par l'intégrité.
- Séquence X.509
certificates
avec préfixe de longueur :certificate
X.509 avec préfixe de longueur (format ASN.1 DER)
- Séquence préfixée par la longueur d'
additional attributes
préfixée par la longueur :ID
(uint32)value
(longueur de la variable: longueur de l'attribut supplémentaire - 4 octets)
- Séquence préfixée par la longueur d'
- Séquence avec un préfixe de longueur de
signatures
avec le 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 d'algorithme 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, panneau : 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 ZIP du répertoire central
Le schéma de signature APK v2 protège l'intégrité des sections 1, 3 et 4, ainsi que les blocs signed data
du bloc v2 du schéma de signature APK contenu 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.
La protection de la section 4 (fin ZIP du répertoire central) est compliquée par la section contenant le décalage du répertoire ZIP Central. 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 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 refuser les APK qui ne disposent pas d'une 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 limiter cette attaque, la liste des ID d'algorithme de signature avec lesquels l'APK a été 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 vérifiés selon le schéma de signature APK v2+ ou la signature JAR (schéma v1). Les plates-formes plus anciennes ignorent les signatures v2 et ne valident que les signatures v1.
Validation du schéma de signature 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 par 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, vérifiez l'APK à l'aide du schéma v1.
- Pour chaque
signer
du bloc APK Signature Scheme v2 :- Choisissez le
signature algorithm ID
le plus puissant compatible avecsignatures
. 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 la suppression/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 de la première
certificate
decertificates
est identique àpublic key
.
- Choisissez le
- La validation aboutit si au moins un élément
signer
a été trouvé et que l'étape 3 a réussi pour chaquesigner
trouvé.
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 JAR standard signé 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 JAR META-INF/<signer>.SF et META-INF/<signer>.(RSA|DSA|EC).
- <signer>.(RSA|DSA|EC) est un ContentInfo PKCS #7 CMS avec une structure SignedData dont la signature est validée sur le fichier <signer>.SF.
- Le fichier .SF <signer> contient un condensé complet de META-INF/MANIFEST.MF, ainsi que des condensés de chaque section de META-INF/MANIFEST.MF. Le récapitulatif de l'ensemble du fichier MANIFEST.MF est validé. En cas d'échec, le condensé de chaque section MANIFEST.MF est vérifié à 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 vérifié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 qui 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é.