Android 11 est compatible avec un schéma de signature compatible avec le streaming grâce à APK Signature Scheme v4. La signature v4 est basée sur l'arbre de hachage Merkle calculé sur tous les octets de l'APK. Le schéma suit exactement la structure de l'arborescence de hachage fs-verity (par exemple, en ajoutant des zéros au sel et au dernier bloc). Android 11 stocke la signature dans un fichier distinct, <apk name>.apk.idsig. Une signature v4 nécessite une signature v2 ou v3 complémentaire.
Format de fichier
Tous les champs numériques sont au format little endian. Tous les champs occupent exactement le nombre d'octets de leur sizeof(), sans ajout de marge intérieure ni d'alignement implicites.
La structure d'assistance suivante simplifie les définitions :
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
Contenu du fichier principal :
struct V4Signature {
int32 version; // only version 2 is supported as of now
sized_bytes<int32> hashing_info;
sized_bytes<int32> signing_info;
sized_bytes<int32> merkle_tree; // optional
};hashing_info est le paramètre utilisé pour la génération de l'arbre de hachage, ainsi que le hachage racine :
struct hashing_info.bytes {
int32 hash_algorithm; // only 1 == SHA256 supported
int8 log2_blocksize; // only 12 (block size 4096) supported now
sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};signing_info est la structure suivante :
struct signing_info.bytes {
sized_bytes<int32> apk_digest; // used to match with the corresponding APK
sized_bytes<int32> x509_certificate; // ASN.1 DER form
sized_bytes<int32> additional_data; // a free-form binary data blob
sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
int32 signature_algorithm_id; // see the APK v2 doc for the list
sized_bytes<int32> signature;
};apk_digest est extrait du bloc de signature v3 de l'APK. Si ce bloc n'est pas présent, il est extrait du bloc v2 (voir apk_digest).
Pour créer et valider un code signature, vous devez sérialiser les données suivantes dans un blob binaire et les transmettre à l'algorithme de signature et de validation en tant que données signées :
struct V4DataForSigning {
int32 size;
int64 file_size; // the size of the file that's been hashed.
hashing_info.hash_algorithm;
hashing_info.log2_blocksize;
hashing_info.salt;
hashing_info.raw_root_hash;
signing_info.apk_digest;
signing_info.x509_certificate;
signing_info.additional_data;
};merkle_tree correspond à l'intégralité de l'arbre Merkle de l'APK, calculée comme décrit dans la documentation fs-verity.
Producteurs et consommateurs
L'outil apksigner du SDK Android génère le fichier de signature v4 si vous l'exécutez avec les paramètres par défaut. Vous pouvez désactiver la signature v4 de la même manière que les autres schémas de signature. L'outil peut également vérifier si la signature v4 est valide.
adb s'attend à ce que le fichier .apk.idsig soit présent à côté de l'APK lors de l'exécution de la commande adb install --incremental. adb utilise également le fichier IDSIG pour essayer l'installation incrémentielle par défaut et revient à une installation normale s'il est manquant ou non valide.
Lorsqu'une session d'installation est créée, la nouvelle API d'installation en streaming dans PackageInstaller accepte la signature v4 dépouillée comme argument distinct lors de l'ajout d'un fichier à la session.
À ce stade, signing_info est transmis à IncFS en tant que blob entier. IncFS extrait le hachage racine du blob.
Lorsque la session d'installation est validée, PackageManagerService effectue un appel ioctl pour récupérer le blob signing_info à partir d'IncFS, l'analyse et vérifie la signature.
Le composant Incremental Data Loader diffuse la partie de l'arborescence Merkle de la signature via l'API native du chargeur de données. La commande shell du service package install-incremental accepte le fichier de signature v4 dépouillé encodé en Base64 comme paramètre pour chaque fichier ajouté. L'arbre de Merkle correspondant doit être envoyé dans le stdin de la commande.
apk_digest
apk_digest est le premier résumé de contenu disponible dans l'ordre :
- V3, bloc de 1 Mo, SHA2-512 (
CONTENT_DIGEST_CHUNKED_SHA512) - V3, bloc de 4 Ko, SHA2-256 (
CONTENT_DIGEST_VERITY_CHUNKED_SHA256) - V3, bloc de 1 Mo, SHA2-256 (
CONTENT_DIGEST_CHUNKED_SHA256) - V2, SHA2-512
- V2, SHA2-256
Consultez la séquence de signataires avec préfixe de longueur dans le schéma de signature des fichiers APK v3.
Validation et tests
Le processus de validation des fichiers APK v4 est illustré dans la figure suivante :

Figure 1. Processus de validation des APK v4.
Validez l'implémentation à l'aide des tests unitaires de fonctionnalité et de CTS :
CtsIncrementalInstallHostTestCases/android/cts/hostsidetests/incrementalinstall
Tester le format de la signature
Pour tester le format de signature, configurez un environnement de compilation et exécutez les tests manuels suivants :
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Tester le format de signature avec le SDK Android (ADB et apksigner)
Utilisez cette procédure pour tester le format de signature avec le SDK Android :
- Configurez un environnement de compilation et assurez-vous d'avoir implémenté IncFS.
- Flashez la compilation sur un appareil physique ou un émulateur cible.
- Générez ou obtenez un APK existant, puis créez une clé de signature de débogage.
- Signez et installez l'APK avec le format de signature v4 à partir du dossier build-tools.
Sign
$ ./apksigner sign --ks debug.keystore game.apk
Installer
$ ./adb install game.apk
Où trouver ces tests ?
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java