Liaison de version

Dans Keymaster 1, toutes les clés Keymaster étaient liées de manière cryptographique à la racine de confiance de l'appareil ou à la clé de démarrage validé. Dans Keymaster 2 et 3, toutes les clés sont également liées au système d'exploitation et au niveau du correctif de l'image système. Cela garantit qu'un pirate informatique qui découvre une faille dans une ancienne version du système ou du logiciel TEE ne peut pas faire revenir un appareil à la version vulnérable et utiliser les clés créées avec la version plus récente. De plus, lorsqu'une clé avec une version et un niveau de correctif donnés est utilisée sur un appareil qui a été mis à niveau vers une version ou un niveau de correctif plus récents, la clé est mise à niveau avant de pouvoir être utilisée, et la version précédente de la clé est invalidée. Ainsi, à mesure que l'appareil est mis à niveau, les clés *progressent* avec l'appareil, mais toute réversion de l'appareil vers une version précédente rend les clés inutilisables.

Pour prendre en charge la structure modulaire de Treble et dissocier la liaison de system.img à boot.img, Keymaster 4 a modifié le modèle de liaison de version de clé pour disposer de niveaux de correctifs distincts pour chaque partition. Cela permet de mettre à jour chaque partition indépendamment, tout en offrant une protection contre le rollback.

Dans Android 9, les partitions boot, system et vendor ont chacune leur propre niveau de correctif.

  • Les appareils équipés d'Android Verified Boot (AVB) peuvent placer tous les niveaux de correctifs et la version du système dans vbmeta, afin que le bootloader puisse les fournir à Keymaster. Pour les partitions en chaîne, les informations de version de la partition se trouvent dans le vbmeta en chaîne. En général, les informations de version doivent se trouver dans le vbmeta struct contenant les données de validation (hachage ou arbre de hachage) d'une partition donnée.
  • Sur les appareils sans AVB :
    • Les implémentations du démarrage validé doivent fournir un hachage des métadonnées de version au bootloader, afin que le bootloader puisse fournir le hachage à Keymaster.
    • boot.img peut continuer à stocker le niveau de correctif dans l'en-tête
    • system.img peut continuer à stocker le niveau de correctif et la version du système d'exploitation dans des propriétés en lecture seule
    • vendor.img stocke le niveau du correctif dans la propriété en lecture seule ro.vendor.build.version.security_patch.
    • Le bootloader peut fournir un hachage de toutes les données validées par le démarrage validé à keymaster.
  • Dans Android 9, utilisez les balises suivantes pour fournir des informations de version pour les partitions suivantes :
    • VENDOR_PATCH_LEVEL: partition vendor
    • BOOT_PATCH_LEVEL: partition boot
    • OS_PATCH_LEVEL et OS_VERSION : partition system. (OS_VERSION est supprimé de l'en-tête boot.img.
  • Les implémentations Keymaster doivent traiter tous les niveaux de correctifs indépendamment. Les clés sont utilisables si toutes les informations de version correspondent aux valeurs associées à une clé, et IKeymaster::upgradeDevice() passe à un niveau de correctif supérieur si nécessaire.

Modifications apportées à HAL

Pour prendre en charge la liaison de version et l'attestation de version, Android 7.1 a ajouté les balises Tag::OS_VERSION et Tag::OS_PATCHLEVEL, ainsi que les méthodes configure et upgradeKey. Les tags de version sont automatiquement ajoutés par les implémentations Keymaster 2 ou version ultérieure à toutes les clés nouvellement générées (ou mises à jour). De plus, toute tentative d'utilisation d'une clé dont la version ou le niveau de correctif du système d'exploitation ne correspond pas respectivement à la version ou au niveau de correctif du système d'exploitation actuel est rejetée avec ErrorCode::KEY_REQUIRES_UPGRADE.

Tag::OS_VERSION est une valeur UINT qui représente les parties majeure, mineure et de correction d'une version du système Android sous la forme MMmmss, où MM correspond à la version majeure, mm à la version mineure et ss à la version de correction. Par exemple, 6.1.2 est représenté par 060102.

Tag::OS_PATCHLEVEL est une valeur UINT qui représente l'année et le mois de la dernière mise à jour du système au format AAAAMM, où AAAA correspond à l'année à quatre chiffres et MM au mois à deux chiffres. Par exemple, mars 2016 est représenté par 201603.

UpgradeKey

Pour permettre la mise à niveau des clés vers la nouvelle version de l'OS et le nouveau niveau de correctif de l'image système, Android 7.1 a ajouté la méthode upgradeKey au HAL:

Keymaster 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Keymaster 2

keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
    const keymaster_key_blob_t* key_to_upgrade,
    const keymaster_key_param_set_t* upgrade_params,
    keymaster_key_blob_t* upgraded_key);
  • dev est la structure de l'appareil
  • keyBlobToUpgrade est la clé à mettre à niveau.
  • upgradeParams sont des paramètres nécessaires pour mettre à niveau la clé. Cela inclut Tag::APPLICATION_ID et Tag::APPLICATION_DATA, qui sont nécessaires pour déchiffrer le blob de clé, s'ils ont été fournis lors de la génération.
  • upgradedKeyBlob est le paramètre de sortie, utilisé pour renvoyer le nouveau blob de clé.

Si upgradeKey est appelé avec un blob de clé qui ne peut pas être analysé ou qui n'est pas valide, il renvoie ErrorCode::INVALID_KEY_BLOB. S'il est appelé avec une clé dont le niveau de correctif est supérieur à la valeur système actuelle, il renvoie ErrorCode::INVALID_ARGUMENT. S'il est appelé avec une clé dont la version de l'OS est supérieure à la valeur système actuelle et que la valeur système est non nulle, il renvoie ErrorCode::INVALID_ARGUMENT. Les mises à niveau de version d'OS de non nul à zéro sont autorisées. En cas d'erreurs de communication avec le monde sécurisé, il renvoie une valeur d'erreur appropriée (par exemple, ErrorCode::SECURE_HW_ACCESS_DENIED, ErrorCode::SECURE_HW_BUSY). Sinon, il renvoie ErrorCode::OK et renvoie un nouveau blob de clé dans upgradedKeyBlob.

keyBlobToUpgrade reste valide après l'appel upgradeKey et pourrait théoriquement être réutilisé si l'appareil était rétrogradé. En pratique, le keystore appelle généralement deleteKey sur le blob keyBlobToUpgrade peu de temps après l'appel de upgradeKey. Si keyBlobToUpgrade avait la balise Tag::ROLLBACK_RESISTANT, upgradedKeyBlob doit également l'avoir (et être résistant au rollback).

Configuration sécurisée

Pour implémenter la liaison de version, le TA keymaster doit disposer d'un moyen de recevoir de manière sécurisée la version actuelle de l'OS et le niveau du correctif (informations de version), et de s'assurer que les informations qu'il reçoit correspondent étroitement aux informations sur le système en cours d'exécution.

Pour permettre la diffusion sécurisée des informations de version au TA, un champ OS_VERSION a été ajouté à l'en-tête de l'image de démarrage. Le script de compilation de l'image de démarrage renseigne automatiquement ce champ. Les OEM et les implémentateurs de TA Keymaster doivent travailler ensemble pour modifier les bootloaders de l'appareil afin d'extraire les informations de version de l'image de démarrage et de les transmettre au TA avant le démarrage du système non sécurisé. Cela garantit que les pirates informatiques ne peuvent pas interférer avec le provisionnement des informations de version vers le TA.

Vous devez également vous assurer que l'image système contient les mêmes informations de version que l'image de démarrage. À cette fin, la méthode de configuration a été ajoutée à la HAL Keymaster:

keymaster_error_t (*configure)(const struct keymaster2_device* dev,
  const keymaster_key_param_set_t* params);

L'argument params contient Tag::OS_VERSION et Tag::OS_PATCHLEVEL. Cette méthode est appelée par les clients keymaster2 après l'ouverture du HAL, mais avant d'appeler d'autres méthodes. Si une autre méthode est appelée avant la configuration, le TA renvoie ErrorCode::KEYMASTER_NOT_CONFIGURED.

La première fois que configure est appelé après le démarrage de l'appareil, il doit vérifier que les informations de version fournies correspondent à celles fournies par le bootloader. Si les informations de version ne correspondent pas, configure renvoie ErrorCode::INVALID_ARGUMENT, et toutes les autres méthodes Keymaster continuent de renvoyer ErrorCode::KEYMASTER_NOT_CONFIGURED. Si les informations correspondent, configure renvoie ErrorCode::OK, et les autres méthodes Keymaster commencent à fonctionner normalement.

Les appels suivants à configure renvoient la même valeur que le premier appel et ne modifient pas l'état de Keymaster.

Étant donné que configure est appelé par le système dont le contenu est destiné à être validé, un pirate informatique dispose d'une fenêtre d'opportunité étroite pour compromettre l'image système et la forcer à fournir des informations de version correspondant à l'image de démarrage, mais qui ne sont pas la version réelle du système. La combinaison de la validation de l'image de démarrage, de la validation dm-verity du contenu de l'image système et du fait que configure est appelé très tôt au démarrage du système devrait rendre cette fenêtre d'opportunité difficile à exploiter.