Architecture de signature sur l'appareil

Depuis Android 12, le module Android Runtime (ART) est un module Mainline. La mise à jour du module peut nécessiter la reconstruction des artefacts de compilation AOT (Ahead-Of-Time) des fichiers JAR bootclasspath et du serveur système. Comme ces artefacts sont sensibles à la sécurité, Android 12 utilise une fonctionnalité appelée signature sur l'appareil pour empêcher leur falsification. Cette page décrit l'architecture de la signature sur l'appareil et ses interactions avec d'autres fonctionnalités de sécurité Android.

Conception de haut niveau

La signature sur l'appareil comporte deux composants principaux :

  • odrefresh fait partie du module ART Mainline. Il est responsable de la génération des artefacts d'exécution. Il compare les artefacts existants à la version installée du module ART, aux fichiers JAR bootclasspath et aux fichiers JAR du serveur système pour déterminer s'ils sont à jour ou s'ils doivent être régénérés. Si c'est le cas, odrefresh les génère et les stocke.

  • odsign est un binaire qui fait partie de la plate-forme Android. Il s'exécute au début du démarrage, juste après le montage de la partition /data. Sa principale responsabilité est d'appeler odrefresh pour vérifier si des artefacts doivent être générés ou mis à jour. Pour tous les artefacts nouveaux ou mis à jour générés par odrefresh, odsign calcule une fonction de hachage. Le résultat d'un tel calcul de hachage est appelé résumé de fichier. Pour tous les artefacts qui existent déjà, odsign vérifie que les résumés des artefacts existants correspondent aux résumés que odsign avait calculés précédemment. Cela garantit que les artefacts n'ont pas été falsifiés.

En cas d'erreur, par exemple lorsque le résumé d'un fichier ne correspond pas, odrefresh et odsign suppriment tous les artefacts existants sur /data et tentent de les régénérer. En cas d'échec, le système revient au mode JIT.

odrefresh et odsign sont protégés par dm-verity et font partie de la chaîne de démarrage validé d'Android.

Calcul des résumés de fichiers avec fs-verity

fs-verity est une fonctionnalité du noyau Linux qui effectue la validation des données de fichier basée sur l'arborescence de Merkle. L'activation de fs-verity sur un fichier entraîne la création d'une arborescence de Merkle sur les données du fichier à l'aide de hachages SHA-256, son stockage dans un emplacement masqué à côté du fichier et le marquage du fichier en lecture seule. fs-verity valide automatiquement les données du fichier par rapport à l'arborescence de Merkle à la demande lors de sa lecture. fs-verity met le hachage racine de l'arborescence de Merkle à disposition en tant que valeur appelée résumé de fichier fs-verity, et fs-verity s'assure que toutes les données lues à partir du fichier sont cohérentes avec ce résumé de fichier.

odsign utilise fs-verity pour améliorer les performances de démarrage en optimisant l'authentification cryptographique des artefacts compilés sur l'appareil au moment du démarrage. Lorsqu'un artefact est généré, odsign active fs-verity sur celui-ci. Lorsque odsign valide un artefact, il valide le résumé de fichier fs-verity au lieu du hachage de fichier complet. Cela élimine la nécessité de lire et de hacher toutes les données de l'artefact au moment du démarrage. Les données d'artefact sont plutôt hachées à la demande par fs-verity lors de leur utilisation, bloc par bloc.

Sur les appareils dont le noyau n'est pas compatible avec fs-verity, odsign revient au calcul des résumés de fichiers dans l'espace utilisateur. odsign utilise le même algorithme de hachage basé sur l'arborescence de Merkle que fs-verity. Les résumés sont donc identiques dans les deux cas. fs-verity est requis sur tous les appareils lancés avec Android 11 ou une version ultérieure.

Stockage des résumés de fichiers

odsign stocke les résumés de fichiers des artefacts dans un fichier distinct appelé odsign.info. Pour s'assurer que odsign.info n'est pas falsifié, il est signé avec une clé de signature qui présente des propriétés de sécurité importantes.odsign.info En particulier, la clé ne peut être générée et utilisée qu'au début du démarrage, lorsque seul le code approuvé est en cours d'exécution. Pour en savoir plus, consultez Clés de signature approuvées.

Validation des résumés de fichiers

À chaque démarrage, si odrefresh détermine que les artefacts existants sont à jour, odsign s'assure que les fichiers n'ont pas été falsifiés depuis leur génération. odsign effectue cette opération en validant les résumés de fichiers. Tout d'abord, il valide la signature de odsign.info. Si la signature est valide, alors odsign vérifie que le résumé de chaque fichier correspond au résumé correspondant dans odsign.info.

Clés de signature approuvées

Android 12 introduit une nouvelle fonctionnalité Keystore appelée clés d'étape de démarrage qui répond aux préoccupations de sécurité suivantes :

  • Qu'est-ce qui empêche un attaquant d'utiliser notre clé de signature pour signer sa propre version de odsign.info ?
  • Qu'est-ce qui empêche un attaquant de générer sa propre clé de signature et de l'utiliser pour signer sa propre version de odsign.info ?

Les clés d'étape de démarrage divisent le cycle de démarrage d'Android en niveaux et lient de manière cryptographique la création et l'utilisation d'une clé à un niveau spécifié. odsign crée sa clé de signature à un niveau précoce, lorsque seul le code approuvé est en cours d'exécution, protégé par dm-verity.

Les niveaux d'étape de démarrage sont numérotés de 0 au nombre magique 1000000000. Lors du processus de démarrage d'Android, vous pouvez augmenter le niveau de démarrage en définissant une propriété système à partir de init.rc. Par exemple, le code suivant définit le niveau de démarrage sur 10 :

setprop keystore.boot_level 10

Les clients de Keystore peuvent créer des clés liées à un certain niveau de démarrage. Par exemple, si vous créez une clé pour le niveau de démarrage 10, elle ne peut être utilisée que lorsque l'appareil est au niveau de démarrage 10.

odsign utilise le niveau de démarrage 30, et la clé de signature qu'il crée est liée à ce niveau de démarrage. Avant d'utiliser une clé pour signer des artefacts, odsign vérifie qu'elle est liée au niveau de démarrage 30.

Cela empêche les deux attaques décrites précédemment dans cette section :

  • Les pirates ne peuvent pas utiliser la clé générée, car au moment où ils ont la possibilité d'exécuter du code malveillant, le niveau de démarrage a dépassé 30 et Keystore refuse les opérations qui utilisent la clé.
  • Les pirates ne peuvent pas créer de clé, car au moment où ils ont la possibilité d'exécuter du code malveillant, le niveau de démarrage a dépassé 30 et Keystore refuse de créer une clé avec ce niveau de démarrage. Si un pirate crée une clé qui n'est pas liée au niveau de démarrage 30, odsign la rejette.

Keystore s'assure que le niveau de démarrage est correctement appliqué. Les sections suivantes expliquent plus en détail comment cela est effectué pour différentes versions de KeyMint (anciennement Keymaster).

Implémentation de Keymaster 4.0

Différentes versions de Keymaster gèrent l'implémentation des clés d'étape de démarrage de différentes manières. Sur les appareils équipés d'un TEE/StrongBox Keymaster 4.0, Keymaster gère l'implémentation comme suit :

  1. Au premier démarrage, Keystore crée une clé symétrique K0 avec le tag MAX_USES_PER_BOOT défini sur 1. Cela signifie que la clé ne peut être utilisée qu'une seule fois par démarrage.
  2. Pendant le démarrage, si le niveau de démarrage est augmenté, une nouvelle clé pour ce niveau de démarrage peut être générée à partir de K0 à l'aide d'une fonction HKDF : Ki+i=HKDF(Ki, "some_fixed_string"). Par exemple, si vous passez du niveau de démarrage 0 au niveau de démarrage 10, le HKDF est appelé 10 fois pour dériver K10 de K0.
  3. Lorsque le niveau de démarrage change, la clé du niveau de démarrage précédent est effacée de la mémoire, et les clés associées aux niveaux de démarrage précédents ne sont plus disponibles.

    La clé K0 est une clé MAX_USES_PER_BOOT=1. Cela signifie qu'il est également impossible d'utiliser cette clé plus tard au démarrage, car au moins une transition de niveau de démarrage (vers le niveau de démarrage final) se produit toujours.

Lorsqu'un client Keystore tel que odsign demande la création d'une clé au niveau de démarrage i, son blob est chiffré avec la clé Ki. Comme Ki n'est pas disponible après le niveau de démarrage i, cette clé ne peut pas être créée ni déchiffrée lors des étapes de démarrage ultérieures.

Implémentation de Keymaster 4.1 et KeyMint 1.0

Les implémentations de Keymaster 4.1 et KeyMint 1.0 sont en grande partie identiques à l'implémentation de Keymaster 4.0. La principale différence est que K0 n'est pas une clé MAX_USES_PER_BOOT, mais une clé EARLY_BOOT_ONLY, introduite dans Keymaster 4.1. Une clé EARLY_BOOT_ONLY ne peut être utilisée que lors des premières phases de démarrage, lorsqu'aucun code non approuvé n'est en cours d'exécution. Cela offre un niveau de protection supplémentaire : dans l'implémentation de Keymaster 4.0, un pirate qui compromet le système de fichiers et SELinux peut modifier la base de données Keystore pour créer sa propre clé MAX_USES_PER_BOOT=1 afin de signer des artefacts. Une telle attaque est impossible avec les implémentations de Keymaster 4.1 et KeyMint 1.0, car les clés EARLY_BOOT_ONLY ne peuvent être créées qu'au début du démarrage.

Composant public des clés de signature approuvées

odsign récupère le composant de clé publique de la clé de signature à partir de Keystore. Toutefois, Keystore ne récupère pas cette clé publique à partir du TEE/SE qui contient la clé privée correspondante. Au lieu de cela, il récupère la clé publique à partir de sa propre base de données sur disque. Cela signifie qu'un pirate qui compromet le système de fichiers peut modifier la base de données Keystore pour qu'elle contienne une clé publique qui fait partie d'une paire de clés publique/privée sous son contrôle.

Pour éviter cette attaque, odsign crée une clé HMAC supplémentaire avec le même niveau de démarrage que la clé de signature. Ensuite, lors de la création de la clé de signature, odsign utilise cette clé HMAC pour créer une signature de la clé publique et la stocke sur le disque. Lors des démarrages suivants, lors de la récupération de la clé publique de la clé de signature, il utilise la clé HMAC pour vérifier que la signature sur disque correspond à la signature de la clé publique récupérée. Si elles correspondent, la clé publique est fiable, car la clé HMAC ne peut être utilisée qu'aux premiers niveaux de démarrage et ne peut donc pas avoir été créée par un pirate.