Schéma de signature APK v2

APK Signature Scheme v2 est un schéma de signature de fichier complet qui augmente la vitesse de vérification et renforce les garanties d'intégrité en détectant toute modification des 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 ZIP Central Directory. À 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 rétrocompatibilité 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 est situé juste 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 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 uint64-length-prefixed ID-value :
    • 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 ZIP End of Central Directory à 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.

Bloc de 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 la forme d'un bloc APK Signature Scheme v2. Pour chaque signataire, les informations suivantes sont stockées :

  • (algorithme de signature, condensé, 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 la signature à utiliser lorsque plusieurs signatures prises en charge sont rencontrées. Cela permet l'introduction de méthodes de signature plus fortes à l'avenir d'une manière rétrocompatible. 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 little-endian, tous les champs préfixés de longueur utilisent uint32 pour la longueur) :

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

ID d'algorithme de signature

  • 0x0101—RSASSA-PSS avec résumé SHA2-256, SHA2-256 MGF1, 32 octets de sel, fin : 0xbc
  • 0x0102—RSASSA-PSS avec résumé SHA2-512, SHA2-512 MGF1, 64 octets de sel, fin : 0xbc
  • 0x0103—RSASSA-PKCS1-v1_5 avec résumé SHA2-256. Ceci est pour les systèmes de construction qui nécessitent des signatures déterministes.
  • 0x0104—RSASSA-PKCS1-v1_5 avec résumé SHA2-512. Ceci est pour les 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 plate-forme Android. Les outils de signature peuvent prendre en charge un sous-ensemble des 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é par l'intégrité

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

  1. Contenu des entrées ZIP (de l'offset 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 signature

Figure 2. Sections APK après signature

APK Signature Scheme v2 protège l'intégrité des sections 1, 3, 4 et les blocs de 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 de signed data qui sont, à leur tour, protégés par une ou plusieurs signatures.

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

Récapitulatif APK

Figure 3. Récapitulatif 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 les retours en arrière

Un attaquant pourrait tenter de faire vérifier un APK signé v2 en tant qu'APK signé v1 sur les plates-formes Android qui prennent en charge la vérification des APK signés 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 fichiers APK qui n'ont pas de signature pour le schéma de signature APK que le vérificateur préfère dans cet ensemble (par exemple, le 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 des signatures plus fortes du bloc APK Signature Scheme v2. Pour atténuer cette attaque, la liste des ID d'algorithmes 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

Dans Android 7.0 et versions ultérieures, les fichiers 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 vérifient que les signatures v1.

Processus de vérification de signature APK

Figure 4. Processus de vérification de 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 de fin de répertoire central ZIP.
    3. ZIP La fin du répertoire central n'est pas suivie de plus de 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 l' signature algorithm ID pris en charge le plus puissant parmi signatures . L'ordre de force dépend de chaque version d'implémentation/plate-forme.
    2. Vérifiez la signature correspondante à partir des signatures par rapport aux signed data à l'aide public key . (Il est maintenant sûr d'analyser signed data .)
    3. Vérifiez que la liste ordonnée des ID d'algorithme de signature dans les digests et signatures est identique. (Ceci permet d'empêcher 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 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 se produit à l'étape 3 ou 4.

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

L'APK signé JAR est un fichier 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 PKCS #7 CMS ContentInfo avec une structure SignedData dont la signature est vérifiée sur le fichier <signer>.SF.
  3. Le fichier <signataire>.SF contient un résumé complet du fichier META-INF/MANIFEST.MF et des résumés de chaque section de META-INF/MANIFEST.MF. Le résumé du fichier entier du 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 condensé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é.