Schéma de signature APK v2

APK Signature Scheme v2 est un système de signature de fichier entier 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 du répertoire central ZIP. À l'intérieur du bloc de signature APK, les signatures v2 et les informations d'identité du signataire sont stockées dans un bloc APK Signature Scheme v2 .

APK avant et après la signature

Figure 1. APK avant et après la signature

APK Signature Scheme v2 a été introduit dans Android 7.0 (Nougat). Pour rendre un APK installable sur Android 6.0 (Marshmallow) et les appareils plus anciens, l'APK doit être signé à l'aide de la signature JAR avant d'être signé avec le schéma v2.

Bloc de signature APK

Pour maintenir la compatibilité ascendante avec le format APK v1, les signatures APK v2 et plus récentes 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 APK se trouve juste avant le répertoire central ZIP, qui se trouve à la fin du fichier.

Le bloc contient des paires ID-valeur enveloppées de manière à faciliter la localisation du bloc dans l'APK. La signature v2 de l'APK est stockée sous forme de paire ID-valeur avec l'ID 0x7109871a.

Format

Le format du bloc de signature APK est le suivant (tous les champs numériques sont en petit-boutiste) :

  • size of block en octets (hors ce champ) (uint64)
  • Séquence de paires ID-valeur préfixées par la longueur uint64 :
    • ID (uint32)
    • value (longueur variable : longueur de la paire - 4 octets)
  • size of block en octets : identique à celle du tout premier champ (uint64)
  • magic «APK Sig Block 42» (16 octets)

L'APK est analysé en recherchant d'abord le début du répertoire central ZIP (en recherchant l'enregistrement ZIP de fin 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 fournit un moyen rapide d'établir que ce qui précède le répertoire central est probablement le bloc de signature APK. La size of block pointe alors efficacement vers le début du bloc dans le fichier.

Les paires ID-valeur avec des ID inconnus doivent être ignorées lors de l'interprétation du bloc.

Blocage du schéma de signature APK 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, résumé, signature) tuples. Le résumé est stocké pour dissocier la vérification 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 vérifié à l'aide d'une signature prise en charge dans la liste fournie. Les signatures avec des algorithmes de signature inconnus sont ignorées. Il appartient à chaque implémentation de choisir quelle signature utiliser lorsque plusieurs signatures prises en charge sont rencontrées. Cela permettra d’introduire à l’avenir des méthodes de signature plus puissantes 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 APK Signature Scheme v2 est le suivant (toutes les valeurs numériques sont en petit-boutiste, tous les champs préfixés par la longueur utilisent uint32 pour la longueur) :

  • séquence de signer avec préfixe de longueur :
    • signed data avec préfixe de longueur :
      • séquence de digests avec préfixe de longueur :
      • séquence de certificates X.509 avec préfixe de longueur :
        • certificate X.509 avec préfixe de longueur (formulaire ASN.1 DER)
      • séquence d' additional attributes préfixés par la longueur :
        • ID (uint32)
        • value (longueur variable : longueur de l'attribut supplémentaire - 4 octets)
    • séquence de signatures avec préfixe de longueur :
      • signature algorithm ID (uint32)
      • signature avec préfixe de longueur sur signed data
    • public key avec préfixe de longueur (SubjectPublicKeyInfo, formulaire ASN.1 DER)

ID d’algorithme de signature

  • 0x0101 : RSASSA-PSS avec résumé SHA2-256, SHA2-256 MGF1, 32 octets de sel, bande-annonce : 0xbc
  • 0x0102 : RSASSA-PSS avec résumé SHA2-512, SHA2-512 MGF1, 64 octets de sel, bande-annonce : 0xbc
  • 0x0103 : RSASSA-PKCS1-v1_5 avec résumé SHA2-256. Ceci est destiné aux systèmes de construction qui nécessitent des signatures déterministes.
  • 0x0104 : RSASSA-PKCS1-v1_5 avec résumé SHA2-512. Ceci est destiné aux systèmes de construction qui nécessitent des signatures déterministes.
  • 0x0201 : ECDSA avec résumé SHA2-256
  • 0x0202 : ECDSA avec résumé SHA2-512
  • 0x0301 : DSA avec résumé SHA2-256

Tous les algorithmes de signature ci-dessus sont pris en charge par la plateforme Android. Les outils de signature peuvent prendre en charge un sous-ensemble d'algorithmes.

Tailles de clés et courbes EC prises en charge :

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

Contenu protégé en intégrité

Aux fins de protection du contenu d'un APK, un APK se compose de quatre sections :

  1. Contenu des entrées ZIP (du décalage 0 jusqu'au début du bloc de signature APK)
  2. Bloc de signature APK
  3. Répertoire central ZIP
  4. ZIP Fin du répertoire central

Sections APK après la signature

Figure 2. Sections APK après la signature

APK Signature Scheme v2 protège l’intégrité des sections 1, 3, 4 et les blocs signed data du bloc APK Signature Scheme v2 contenus dans la section 2.

L'intégrité des sections 1, 3 et 4 est protégée par un ou plusieurs résumés de leur contenu stockés dans des blocs signed data qui sont, à leur tour, protégés par une ou plusieurs signatures.

Le résumé des sections 1, 3 et 4 est calculé comme suit, similaire à un arbre Merkle à deux niveaux. Chaque section est divisée en morceaux consécutifs de 1 Mo (2 à 20 octets). Le dernier morceau de chaque section peut être plus court. Le résumé de chaque morceau est calculé sur la concaténation de l'octet 0xa5 , la longueur du morceau en octets (little-endian uint32) et le contenu du morceau. Le résumé de niveau supérieur est calculé sur la concaténation de l'octet 0x5a , le nombre de fragments (little-endian uint32) et la concaténation des résumés des fragments dans l'ordre dans lequel les fragments apparaissent dans l'APK. Le résumé est calculé de manière fragmentée pour permettre d'accélérer le calcul en le parallélisant.

Résumé de l'APK

Figure 3. Résumé de l'APK

La protection de la section 4 (ZIP End of Central Directory) est compliquée par la section contenant le décalage du ZIP Central Directory. Le décalage change lorsque la taille du bloc de signature APK change, par exemple lorsqu'une nouvelle signature est ajoutée. Ainsi, lors du calcul du résumé sur la fin ZIP du répertoire central, le champ contenant le décalage du répertoire central ZIP doit être traité comme contenant le décalage du bloc de signature APK.

Protections contre la restauration

Un attaquant pourrait tenter de faire vérifier un APK signé v2 en tant qu’APK signé v1 sur les plates-formes Android prenant en charge la vérification de l’APK signé v2. Pour atténuer cette attaque, les APK signés v2 qui sont également signés v1 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 des virgules (l'ID de ce schéma est 2). Lors de la vérification de la signature v1, le vérificateur APK doit rejeter les APK qui n'ont pas de signature pour le schéma de signature APK que le vérificateur préfère parmi cet ensemble (par exemple, schéma v2). Cette protection repose sur le fait que le contenu des fichiers META-INF/*.SF est protégé par des signatures v1. Consultez la section sur la vérification de l'APK signé JAR .

Un attaquant pourrait tenter de supprimer les signatures plus fortes du bloc APK Signature Scheme v2. Pour atténuer 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.

Vérification

Sous 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 vérifient uniquement les signatures v1.

Processus de vérification de la signature APK

Figure 4. Processus de vérification de la signature APK (nouvelles étapes en rouge)

Vérification du schéma de signature APK v2

  1. Localisez le bloc de signature APK et vérifiez que :
    1. Deux champs de taille du bloc de signature APK contiennent la même valeur.
    2. Le répertoire central ZIP est immédiatement suivi de l'enregistrement ZIP de fin du répertoire central.
    3. ZIP La fin du répertoire central n'est pas suivie par d'autres données.
  2. Localisez le premier bloc APK Signature Scheme v2 à l’intérieur du bloc de signature APK. Si le bloc v2 est présent, passez à l'étape 3. Sinon, revenez à la vérification de l'APK à l'aide du schéma v1 .
  3. Pour chaque signer du bloc APK Signature Scheme v2 :
    1. Choisissez signature algorithm ID pris en charge le plus puissant parmi signatures . L’ordre des forces dépend de chaque version d’implémentation/plateforme.
    2. Vérifiez la signature correspondante des signatures par rapport signed data à l'aide public key . (Il est désormais possible d'analyser signed data en toute sécurité.)
    3. Vérifiez que la liste ordonnée des ID d’algorithme de signature dans digests et signatures est identique. (Cela permet d'éviter la suppression/l'ajout de signature.)
    4. Calculez le résumé du contenu APK en utilisant le même algorithme de résumé que l'algorithme de résumé utilisé par l'algorithme de signature.
    5. Vérifiez que le résumé calculé est identique au digest correspondant de digests .
    6. Vérifiez que SubjectPublicKeyInfo du premier certificate de certificates est identique à public key .
  4. La vérification réussit si au moins un signer a été trouvé et si l'étape 3 a réussi pour chaque signer trouvé.

Remarque : L'APK ne doit pas être vérifié à l'aide du schéma v1 si un échec survient à l'étape 3 ou 4.

Vérification APK signée JAR (schéma v1)

L'APK signé par JAR est un JAR signé standard , qui doit contenir exactement les entrées répertorié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 :

  1. Chaque signataire est représenté par une entrée JAR META-INF/<signer>.SF et META-INF/<signer>.(RSA|DSA|EC).
  2. <signer>.(RSA|DSA|EC) est un CMS ContentInfo PKCS #7 avec structure SignedData dont la signature est vérifiée sur le fichier <signer>.SF.
  3. Le fichier <signer>.SF contient un résumé complet du fichier META-INF/MANIFEST.MF et un résumé de chaque section de META-INF/MANIFEST.MF. Le résumé complet du fichier MANIFEST.MF est vérifié. Si cela échoue, le résumé de chaque section MANIFEST.MF est vérifié à la place.
  4. META-INF/MANIFEST.MF contient, pour chaque entrée JAR protégée en intégrité, une section nommée en conséquence contenant le résumé du contenu non compressé de l'entrée. Tous ces résumés sont vérifiés.
  5. La vérification de l'APK échoue si l'APK contient des entrées JAR qui ne sont pas répertoriées dans 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 en intégrité.