Signature des versions pour la publication

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Les images du système d'exploitation Android utilisent des signatures cryptographiques à deux endroits :

  1. Chaque fichier .apk à l'intérieur de l'image doit être signé. Le gestionnaire de packages d'Android utilise une signature .apk de deux manières :
    • Lorsqu'une application est remplacée, elle doit être signée par la même clé que l'ancienne application afin d'avoir accès aux données de l'ancienne application. Cela est vrai à la fois pour mettre à jour les applications utilisateur en écrasant le .apk et pour remplacer une application système avec une version plus récente installée sous /data .
    • Si deux applications ou plus souhaitent partager un ID utilisateur (afin de pouvoir partager des données, etc.), elles doivent être signées avec la même clé.
  2. Les packages de mise à jour OTA doivent être signés avec l'une des clés attendues par le système, sinon le processus d'installation les rejettera.

Libérer les clés

L'arborescence Android inclut des clés de test sous build/target/product/security . La création d'une image de système d'exploitation Android à l'aide make signera tous les fichiers .apk à l'aide des clés de test. Étant donné que les clés de test sont connues du public, n'importe qui peut signer ses propres fichiers .apk avec les mêmes clés, ce qui peut lui permettre de remplacer ou de détourner des applications système intégrées à l'image de votre système d'exploitation. Pour cette raison, il est essentiel de signer toute image de système d'exploitation Android publiée ou déployée publiquement avec un ensemble spécial de clés de version auxquelles vous seul avez accès.

Pour générer votre propre ensemble unique de clés de version, exécutez ces commandes à partir de la racine de votre arborescence Android :

subject='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
mkdir ~/.android-certs
for x in releasekey platform shared media networkstack; do \
    ./development/tools/make_key ~/.android-certs/$x "$subject"; \
  done

$subject doit être modifié pour refléter les informations de votre organisation. Vous pouvez utiliser n'importe quel répertoire, mais veillez à choisir un emplacement sauvegardé et sécurisé. Certains fournisseurs choisissent de chiffrer leur clé privée avec une phrase de passe forte et de stocker la clé chiffrée dans le contrôle de code source ; d'autres stockent leurs clés de version entièrement ailleurs, comme sur un ordinateur isolé.

Pour générer une image de version, utilisez :

make dist
sign_target_files_apks \
-o \    # explained in the next section
--default_key_mappings ~/.android-certs out/dist/*-target_files-*.zip \
signed-target_files.zip

Le script sign_target_files_apks prend un .zip de fichiers cibles en entrée et produit un nouveau .zip de fichiers cibles dans lequel tous les fichiers .apk ont été signés avec de nouvelles clés. Les images nouvellement signées peuvent être trouvées sous IMAGES/ signed-target_files.zip .

Signature de packages OTA

Un zip de fichiers cibles signé peut être converti en un zip de mise à jour OTA signé à l'aide de la procédure suivante :
ota_from_target_files \
-k  (--package_key) 
signed-target_files.zip \
signed-ota_update.zip

Signatures et chargement latéral

Le chargement indépendant ne contourne pas le mécanisme normal de vérification de la signature du paquet de récupération - avant d'installer un paquet, la récupération vérifiera qu'il est signé avec l'une des clés privées correspondant aux clés publiques stockées dans la partition de récupération, comme il le ferait pour un paquet livré sur le -air.

Les packages de mise à jour reçus du système principal sont généralement vérifiés deux fois : une fois par le système principal, à l'aide de la méthode RecoverySystem.verifyPackage() dans l'API Android, puis à nouveau par la récupération. L'API RecoverySystem vérifie la signature par rapport aux clés publiques stockées dans le système principal, dans le fichier /system/etc/security/otacerts.zip (par défaut). La restauration vérifie la signature par rapport aux clés publiques stockées sur le disque RAM de la partition de restauration, dans le fichier /res/keys .

Par défaut, les fichiers cibles .zip produits par la construction définissent le certificat OTA pour qu'il corresponde à la clé de test. Sur une image publiée, un certificat différent doit être utilisé afin que les appareils puissent vérifier l'authenticité du package de mise à jour. Passer l'indicateur -o à sign_target_files_apks , comme indiqué dans la section précédente, remplace le certificat de clé de test par le certificat de clé de version de votre répertoire certs.

Normalement, l'image système et l'image de récupération stockent le même ensemble de clés publiques OTA. En ajoutant une clé uniquement au jeu de clés de récupération, il est possible de signer des packages qui ne peuvent être installés que via le chargement latéral (en supposant que le mécanisme de téléchargement de mise à jour du système principal effectue correctement la vérification par rapport à otacerts.zip). Vous pouvez spécifier des clés supplémentaires à inclure uniquement dans la récupération en définissant la variable PRODUCT_EXTRA_RECOVERY_KEYS dans votre définition de produit :

vendor/yoyodyne/tardis/products/tardis.mk
 [...]

PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload

Cela inclut la clé publique vendor/yoyodyne/security/tardis/sideload.x509.pem dans le fichier de clés de récupération afin qu'il puisse installer les packages signés avec. Cependant, la clé supplémentaire n'est pas incluse dans otacerts.zip, de sorte que les systèmes qui vérifient correctement les packages téléchargés n'invoquent pas la récupération des packages signés avec cette clé.

Certificats et clés privées

Chaque clé se présente sous la forme de deux fichiers : le certificat , qui porte l'extension .x509.pem, et la clé privée , qui porte l'extension .pk8. La clé privée doit être gardée secrète et est nécessaire pour signer un paquet. La clé peut elle-même être protégée par un mot de passe. Le certificat, en revanche, ne contient que la moitié publique de la clé, de sorte qu'il peut être largement distribué. Il est utilisé pour vérifier qu'un paquet a été signé par la clé privée correspondante.

La version standard d'Android utilise cinq clés, qui résident toutes dans build/target/product/security :

clé de test
Clé générique par défaut pour les packages qui ne spécifient pas de clé autrement.
Plate-forme
Clé de test pour les packages qui font partie de la plate-forme principale.
partagé
Clé de test pour les éléments partagés dans le processus d'accueil/de contacts.
médias
Clé de test pour les packages faisant partie du système de média/téléchargement.
pile de réseaux
Clé de test pour les packages faisant partie du système de mise en réseau. La clé networkstack est utilisée pour signer les fichiers binaires conçus comme des composants système modulaires . Si vos mises à jour de module sont construites séparément et intégrées en tant que pré-constructions dans l'image de votre appareil, vous n'aurez peut-être pas besoin de générer une clé networkstack dans l'arborescence source Android.

Les packages individuels spécifient l'une de ces clés en définissant LOCAL_CERTIFICATE dans leur fichier Android.mk. (testkey est utilisé si cette variable n'est pas définie.) Vous pouvez également spécifier une clé entièrement différente par nom de chemin, par exemple :

device/yoyodyne/apps/SpecialApp/Android.mk
 [...]

LOCAL_CERTIFICATE := device/yoyodyne/security/special

Maintenant, la construction utilise la device/yoyodyne/security/special.{x509.pem,pk8} pour signer SpecialApp.apk. La construction ne peut utiliser que des clés privées qui ne sont pas protégées par un mot de passe.

Options de signature avancées

Remplacement de la clé de signature APK

Le script de signature sign_target_files_apks fonctionne sur les fichiers cibles générés pour une génération. Toutes les informations sur les certificats et les clés privées utilisées au moment de la génération sont incluses dans les fichiers cibles. Lors de l'exécution du script de signature pour signer la libération, les clés de signature peuvent être remplacées en fonction du nom de la clé ou du nom de l'APK.

Utilisez les --key_mapping et --default_key_mappings pour spécifier le remplacement de clé en fonction des noms de clé :

  • L' --key_mapping src_key = dest_key spécifie le remplacement d'une clé à la fois.
  • Le drapeau --default_key_mappings dir spécifie un répertoire avec cinq clés pour remplacer toutes les clés dans build/target/product/security ; cela revient à utiliser cinq fois --key_mapping pour spécifier les mappages.
build/target/product/security/testkey      = dir/releasekey
build/target/product/security/platform     = dir/platform
build/target/product/security/shared       = dir/shared
build/target/product/security/media        = dir/media
build/target/product/security/networkstack = dir/networkstack

Utilisez l' --extra_apks apk_name1,apk_name2,... = key pour spécifier les remplacements de clés de signature en fonction des noms APK. Si key est laissée vide, le script traite les fichiers APK spécifiés comme pré-signés.

Pour le produit tardis hypothétique, vous avez besoin de six clés protégées par mot de passe : cinq pour remplacer les cinq dans build/target/product/security , et une pour remplacer la clé supplémentaire device/yoyodyne/security/special requise par SpecialApp dans l'exemple ci-dessus. Si les clés se trouvaient dans les fichiers suivants :

vendor/yoyodyne/security/tardis/releasekey.x509.pem
vendor/yoyodyne/security/tardis/releasekey.pk8
vendor/yoyodyne/security/tardis/platform.x509.pem
vendor/yoyodyne/security/tardis/platform.pk8
vendor/yoyodyne/security/tardis/shared.x509.pem
vendor/yoyodyne/security/tardis/shared.pk8
vendor/yoyodyne/security/tardis/media.x509.pem
vendor/yoyodyne/security/tardis/media.pk8
vendor/yoyodyne/security/tardis/networkstack.x509.pem
vendor/yoyodyne/security/tardis/networkstack.pk8
vendor/yoyodyne/security/special.x509.pem
vendor/yoyodyne/security/special.pk8           # NOT password protected
vendor/yoyodyne/security/special-release.x509.pem
vendor/yoyodyne/security/special-release.pk8   # password protected

Ensuite, vous signeriez toutes les applications comme ceci :

./build/make/tools/releasetools/sign_target_files_apks \
    --default_key_mappings vendor/yoyodyne/security/tardis \
    --key_mapping vendor/yoyodyne/security/special=vendor/yoyodyne/security/special-release \
    --extra_apks PresignedApp= \
    -o tardis-target_files.zip \
    signed-tardis-target_files.zip

Cela fait apparaître ce qui suit :

Enter password for vendor/yoyodyne/security/special-release key>
Enter password for vendor/yoyodyne/security/tardis/networkstack key>
Enter password for vendor/yoyodyne/security/tardis/media key>
Enter password for vendor/yoyodyne/security/tardis/platform key>
Enter password for vendor/yoyodyne/security/tardis/releasekey key>
Enter password for vendor/yoyodyne/security/tardis/shared key>
    signing: Phone.apk (vendor/yoyodyne/security/tardis/platform)
    signing: Camera.apk (vendor/yoyodyne/security/tardis/media)
    signing: NetworkStack.apk (vendor/yoyodyne/security/tardis/networkstack)
    signing: Special.apk (vendor/yoyodyne/security/special-release)
    signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey)
        [...]
    signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared)
    signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared)
NOT signing: PresignedApp.apk
        (skipped due to special cert string)
rewriting SYSTEM/build.prop:
  replace:  ro.build.description=tardis-user Eclair ERC91 15449 test-keys
     with:  ro.build.description=tardis-user Eclair ERC91 15449 release-keys
  replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
     with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
    signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform)
rewriting RECOVERY/RAMDISK/default.prop:
  replace:  ro.build.description=tardis-user Eclair ERC91 15449 test-keys
     with:  ro.build.description=tardis-user Eclair ERC91 15449 release-keys
  replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
     with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
using:
    vendor/yoyodyne/security/tardis/releasekey.x509.pem
for OTA package verification
done.

Après avoir invité l'utilisateur à fournir des mots de passe pour toutes les clés protégées par mot de passe, le script signe à nouveau tous les fichiers APK dans la cible d'entrée .zip avec les clés de libération. Avant d'exécuter la commande, vous pouvez également définir la variable d'environnement ANDROID_PW_FILE sur un nom de fichier temporaire ; le script invoque alors votre éditeur pour vous permettre d'entrer des mots de passe pour toutes les clés (cela peut être un moyen plus pratique d'entrer des mots de passe).

Remplacement de la clé de signature APEX

Android 10 introduit le format de fichier APEX pour l'installation de modules système de niveau inférieur. Comme expliqué dans Signature APEX , chaque fichier APEX est signé avec deux clés : une pour l'image du système de fichiers mini dans un APEX et l'autre pour l'ensemble de l'APEX.

Lors de la signature d'une version, les deux clés de signature d'un fichier APEX sont remplacées par des clés de version. La clé de charge utile du système de fichiers est spécifiée avec l'indicateur --extra_apex_payload et la clé de signature de fichier APEX entière est spécifiée avec l'indicateur --extra_apks .

Pour le produit tardis, supposez que vous disposez de la configuration de clé suivante pour les fichiers APEX com.android.conscrypt.apex , com.android.media.apex et com.android.runtime.release.apex .

name="com.android.conscrypt.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED"
name="com.android.media.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED"
name="com.android.runtime.release.apex" public_key="vendor/yoyodyne/security/testkeys/com.android.runtime.avbpubkey" private_key="vendor/yoyodyne/security/testkeys/com.android.runtime.pem" container_certificate="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.x509.pem" container_private_key="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.pk8"

Et vous avez les fichiers suivants qui contiennent les clés de version :

vendor/yoyodyne/security/runtime_apex_container.x509.pem
vendor/yoyodyne/security/runtime_apex_container.pk8
vendor/yoyodyne/security/runtime_apex_payload.pem

La commande suivante remplace les clés de signature pour com.android.runtime.release.apex et com.android.tzdata.apex lors de la signature de la version. En particulier, com.android.runtime.release.apex est signé avec les clés de version spécifiées ( runtime_apex_container pour le fichier APEX et runtime_apex_payload pour la charge utile de l'image du fichier). com.android.tzdata.apex est traité comme pré-signé. Tous les autres fichiers APEX sont gérés par la configuration par défaut, comme indiqué dans les fichiers cibles.

./build/make/tools/releasetools/sign_target_files_apks \
    --default_key_mappings   vendor/yoyodyne/security/tardis \
    --extra_apks             com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_container \
    --extra_apex_payload_key com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_payload.pem \
    --extra_apks             com.android.media.apex= \
    --extra_apex_payload_key com.android.media.apex= \
    -o tardis-target_files.zip \
    signed-tardis-target_files.zip

L'exécution de la commande ci-dessus donne les journaux suivants :

        [...]
    signing: com.android.runtime.release.apex                  container (vendor/yoyodyne/security/runtime_apex_container)
           : com.android.runtime.release.apex                  payload   (vendor/yoyodyne/security/runtime_apex_payload.pem)
NOT signing: com.android.conscrypt.apex
        (skipped due to special cert string)
NOT signing: com.android.media.apex
        (skipped due to special cert string)
        [...]

Autres options

Le script de signature sign_target_files_apks réécrit la description de build et l'empreinte digitale dans les fichiers de propriétés de build pour indiquer que la build est une build signée. L'indicateur --tag_changes contrôle les modifications apportées à l'empreinte digitale. Exécutez le script avec -h pour voir la documentation sur tous les drapeaux.

Génération manuelle des clés

Android utilise des clés RSA 2048 bits avec un exposant public 3. Vous pouvez générer des paires certificat/clé privée à l'aide de l'outil openssl de openssl.org :

# generate RSA key
openssl genrsa -3 -out temp.pem 2048
Generating RSA private key, 2048 bit long modulus
....+++
.....................+++
e is 3 (0x3)

# create a certificate with the public part of the key
openssl req -new -x509 -key temp.pem -out releasekey.x509.pem -days 10000 -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'

# create a PKCS#8-formatted version of the private key
openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt

# securely delete the temp.pem file
shred --remove temp.pem

La commande openssl pkcs8 donnée ci-dessus crée un fichier .pk8 sans mot de passe, utilisable avec le système de construction. Pour créer un .pk8 sécurisé avec un mot de passe (ce que vous devriez faire pour toutes les clés de version réelles), remplacez l'argument -nocrypt par -passout stdin ; alors openssl chiffrera la clé privée avec un mot de passe lu à partir de l'entrée standard. Aucune invite n'est imprimée, donc si stdin est le terminal, le programme semblera se bloquer alors qu'il n'attend que vous pour entrer un mot de passe. D'autres valeurs peuvent être utilisées pour l'argument-passout pour lire le mot de passe à partir d'autres emplacements ; pour plus de détails, consultez la documentation openssl .

Le fichier intermédiaire temp.pem contient la clé privée sans aucune sorte de protection par mot de passe, donc jetez-le soigneusement lors de la génération des clés de version. En particulier, l'utilitaire GNUshred peut ne pas être efficace sur le réseau ou les systèmes de fichiers journalisés. Vous pouvez utiliser un répertoire de travail situé sur un disque RAM (comme une partition tmpfs) lors de la génération de clés pour vous assurer que les intermédiaires ne sont pas exposés par inadvertance.

Création de fichiers images

Une fois que vous avez signé-target-files.zip, vous devez créer l'image afin de pouvoir la mettre sur un appareil. Pour créer l'image signée à partir des fichiers cibles, exécutez la commande suivante à partir de la racine de l'arborescence Android :

img_from_target_files signed-target-files.zip signed-img.zip
Le fichier résultant, signé- signed-img.zip , contient tous les fichiers .img. Pour charger une image sur un périphérique, utilisez fastboot comme suit :
fastboot update signed-img.zip