Keystore intégré au matériel

Disponibilité d'un environnement d'exécution sécurisé dans un système sur puce (SoC) permet aux appareils Android de fournir des composants de solides services de sécurité à l'OS Android, aux services de plateforme et même des applications tierces. Les développeurs à la recherche d'extensions spécifiques à Android doivent se tourner vers par android.security.keystore.

Avant la version 6.0 d'Android, Android disposait déjà d'une solution de cryptomonnaie simple et intégrée au matériel. API Services, fournie par les versions 0.2 et 0.3 du matériel Keymaster Couche d'abstraction (HAL). Signature et validation numériques fournies par le keystore des opérations, ainsi que la génération et l'importation de paires de clés de signature asymétriques. C'est déjà implémentée sur de nombreux appareils, mais de nombreux objectifs de sécurité n'est pas facile à réaliser avec une seule API de signature. Keystore dans Android 6.0 étendu l'API Keystore pour offrir un plus large éventail de fonctionnalités.

Dans Android 6.0, Keystore a été ajouté primitives cryptographiques symétriques AES et HMAC, ainsi qu'un système de contrôle des accès pour les clés intégrées au matériel. Accès sont spécifiés lors de la génération de la clé et appliqués pendant toute la durée de vie la clé. Les clés ne peuvent être utilisées qu'après avoir été authentifiés, et uniquement à des fins spécifiées ou avec une clé cryptographique paramètres. Pour en savoir plus, consultez les Balises d'autorisation et Pages Fonctions.

En plus d'étendre la gamme de primitives cryptographiques, Keystore dans Android 6.0 a ajouté les éléments suivants:

  • Un schéma de contrôle de l'utilisation permettant de limiter l'utilisation des clés afin d'atténuer risque de compromission de sécurité en raison d'un usage abusif des clés
  • Un schéma de contrôle d'accès pour permettre la restriction des clés à des utilisateurs spécifiés les clients et une période définie

Dans Android 7.0, Keymaster 2 prend en charge l'attestation de clé et la version. liée. Attestation de clé fournit des certificats de clé publique contenant une description détaillée de la clé et ses contrôles d'accès, pour garantir la présence de la clé sur du matériel sécurisé et vérifiable à distance.

Liaison de version qui lie des clés au système d'exploitation et à la version au niveau du correctif. Cela garantit que un attaquant qui découvre une faiblesse dans une ancienne version du système ou le Le logiciel TEE ne peut pas effectuer le rollback d'un appareil vers la version vulnérable et utiliser des clés créé avec la nouvelle version. De plus, lorsqu'une clé avec une version donnée et le niveau de correctif est utilisé sur un appareil qui a été mis à niveau vers une version plus récente ou du correctif, la clé est mise à niveau avant de pouvoir être utilisée, et la clé précédente version de la clé invalidée. À mesure que l'appareil est mis à niveau, les clés "à cliquet" avec l'appareil, mais tout retour à une version précédente rend les clés inutilisables.

Dans Android 8.0, Keymaster 3 est passé de l'ancien matériel à structure C. Couche d'abstraction (HAL) vers l'interface HAL C++ générée à partir d'une définition dans le nouveau langage HIDL (Hardware Interface Definition Language). Dans le cadre de ce changement, de nombreux types d'arguments ont changé, bien que les types et les méthodes aient un caractère avec les anciens types et les méthodes de structure HAL. Consultez le Fonctions pour en savoir plus plus de détails.

En plus de cette révision de l'interface, Android 8.0 a étendu l'API Keymaster 2 d'attestation afin de prendre en charge Attestation d'identité. L'attestation d'ID fournit un mécanisme limité et facultatif pour confirmer aux identifiants matériels, comme le numéro de série de l'appareil, le nom du produit Identifiant (IMEI / MEID). Pour implémenter cet ajout, Android 8.0 a modifié le numéro ASN.1 d'attestation pour ajouter une attestation d'ID. Les implémentations de Keymaster doivent trouver un moyen sécurisé de récupérer les éléments de données pertinents un mécanisme pour désactiver la fonction de manière sécurisée et permanente.

Sous Android 9, les mises à jour incluaient les éléments suivants:

  • Remplacer par Keymaster 4
  • Compatibilité avec les composants sécurisés intégrés
  • Compatibilité avec l'importation de clés sécurisées
  • Compatibilité avec le chiffrement 3DES
  • Modifications apportées à la liaison de version de sorte que boot.img et system.img aient définir des versions séparément pour permettre des mises à jour indépendantes

Glossaire

Voici une présentation rapide des composants Keystore et de leurs relations.

AndroidKeystore est l'API et le composant Android Framework utilisé. par les applications pour accéder à la fonctionnalité Keystore. Il est implémenté en tant qu'extension les API Java Cryptography Architecture standards et se compose de code Java qui s'exécute dans le propre espace de processus de l'application. AndroidKeystore traite l'application les requêtes de comportement du keystore en les transférant au daemon keystore.

Le démon keystore est un daemon du système Android qui fournit l'accès à toutes les fonctionnalités Keystore via une API Binder. Il est responsable du stockage des « blobs de clé », qui contenant le matériel réel de la clé secrète, chiffrée afin que Keystore puisse les stocker, mais ne pas les utiliser ni les révéler.

keymasterd est un serveur HIDL qui permet d'accéder aux Keymaster TA. (Ce nom n'est pas standardisé et est utilisé à des fins conceptuelles.)

Keymaster TA (application de confiance) est le logiciel qui s'exécute dans un un contexte sécurisé, le plus souvent dans TrustZone sur un SoC ARM, qui fournit toutes les des opérations Keystore sécurisées, a accès au matériel de clé brut, valide l'ensemble les conditions de contrôle d'accès sur les touches, etc.

LockSettingsService est le composant système Android responsable pour l'authentification des utilisateurs, à la fois par mot de passe et par empreinte digitale. Il ne fait pas partie de Keystore, mais pertinente car de nombreuses opérations de clés Keystore nécessitent l'authentification unique. LockSettingsService interagit avec le gardien. TA et Fingerprint TA pour obtenir des jetons d'authentification, qu'il fournit au keystore daemon et qui sont finalement utilisés par le Keymaster TA application.

Gatekeeper TA (application de confiance) est un autre composant. s'exécutant dans un contexte sécurisé, chargé d'authentifier l'utilisateur mots de passe et génération de jetons d’authentification utilisés pour prouver à l’TA Keymaster qu'une authentification a été effectuée pour un utilisateur particulier à un moment donné en temps réel.

Fingerprint TA (application de confiance) est un autre composant. s'exécutant dans un contexte sécurisé chargé d'authentifier l'utilisateur les empreintes digitales et la génération de jetons d'authentification utilisés pour prouver au Keymaster qu'une authentification a été effectuée pour un utilisateur particulier à un moment donné à temps.

Architecture

L'API Android Keystore et le HAL Keymaster sous-jacent fournir un ensemble de primitives cryptographiques de base, la mise en œuvre de protocoles à l’aide de clés à contrôle d’accès et intégrées au matériel.

Keymaster HAL est une bibliothèque à chargement dynamique fournie par l'OEM et utilisée par le service Keystore pour fournir des services cryptographiques avec support matériel. Pour conserver la sécurité des éléments, les implémentations HAL n'effectuent aucune opération sensible un espace utilisateur ou même un noyau. Les opérations sensibles sont déléguées un processeur sécurisé accessible via une interface de noyau. L'architecture obtenue se présente comme suit:

Accès à Keymaster

Figure 1 : Accès à Keymaster

Sur un appareil Android, le "client" du HAL Keymaster se compose plusieurs couches (par exemple, l'application, le framework ou le daemon Keystore), mais qui peuvent être ignorées aux fins du présent document. Cela signifie que le HAL Keymaster décrit L'API de bas niveau est utilisée par les composants internes de la plate-forme et n'est pas exposée à l'application. développeurs. L'API de niveau supérieur est décrite sur le site des développeurs Android.

L'objectif du HAL Keymaster n'est pas d'implémenter les fonctionnalités des algorithmes, mais uniquement pour marshaler et réduire les requêtes vers le monde sécurisé. La de communication est défini par l'implémentation.

Compatibilité avec les versions précédentes versions

Le HAL de Keymaster 1 est totalement incompatible avec des HAL précédemment publiées, par exemple Keymaster 0.2 et 0.3. Pour faciliter sur les appareils équipés d'Android 5.0 ou version antérieure, ainsi que sur les appareils des anciens HAL Keymaster, Keystore fournit un adaptateur qui implémente le HAL Keymaster 1 avec appels à la bibliothèque matérielle existante. Le résultat ne peut pas fournissent l'ensemble des fonctionnalités de Keymaster 1 HAL. En particulier, Il n'est compatible qu'avec les algorithmes RSA et ECDSA, et toutes les clés d'autorisation l'application est effectuée par l'adaptateur, dans un environnement non sécurisé.

Keymaster 2 a encore plus simplifié l'interface HAL en supprimant le Méthodes get_supported_* et autorisation de finish() pour accepter la saisie. Cela réduit le nombre d'aller-retours vers le TEE dans dans les cas où l'entrée est disponible en une seule fois et simplifie l'implémentation Déchiffrement AEAD.

Dans Android 8.0, Keymaster 3 est passé de l'ancienne structure C. HAL vers l'interface HAL C++ générée à partir d'une définition dans le nouveau Langage HIDL (Hardware Interface Definition Language) Un HAL au nouveau design est créée en sous-classant les éléments IKeymasterDevice et implémenter la classe virtuelle pure méthodes. Dans le cadre de ce changement, de nombreux types d'arguments ont changé, bien que les types et les méthodes aient une correspondance un à un et les méthodes de structure HAL.

Présentation de HIDL

Le langage HIDL (Hardware Interface Definition Language) fournit une implémentation mécanisme indépendant du langage pour spécifier les interfaces matérielles. The HIDL est actuellement compatible avec la génération d'interfaces C++ et Java. Il est normal que la plupart des développeurs d'environnements d'exécution sécurisés (TEE) trouveront le C++ plus pratiques. Ce document ne traite donc que de la représentation C++.

Les interfaces HIDL sont constituées d'un ensemble de méthodes, exprimées comme suit:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Il existe différents types prédéfinis, et les HAL peuvent définir de nouvelles valeurs types de structure. Pour en savoir plus sur HIDL, consultez la section de référence.

Voici un exemple de méthode du IKeymasterDevice.hal Keymaster 3:

generateKey(vec<KeyParameter> keyParams)
        generates(ErrorCode error, vec<uint8_t> keyBlob,
                  KeyCharacteristics keyCharacteristics);

Il s'agit de l'équivalent du code suivant issu du HAL de keymaster2:

keymaster_error_t (*generate_key)(
        const struct keymaster2_device* dev,
        const keymaster_key_param_set_t* params,
        keymaster_key_blob_t* key_blob,
        keymaster_key_characteristics_t* characteristics);

Dans la version HIDL, l'argument dev est supprimé, car il est implicite. L'argument params n'est plus un struct contenant un pointant vers un tableau d'objets key_parameter_t, mais vec (vecteur) contenant des objets KeyParameter. La les valeurs renvoyées sont listées dans "generates" , y compris une clause vecteur de valeurs uint8_t pour le blob de clé.

La méthode virtuelle C++ générée par le compilateur HIDL est la suivante:

Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                         generateKey_cb _hidl_cb) override;

generateKey_cb est un pointeur de fonction défini comme suit:

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                   const KeyCharacteristics& keyCharacteristics)>

Autrement dit, generateKey_cb est une fonction qui prend les valeurs renvoyées dans la clause "generate". La classe d'implémentation HAL remplace generateKey et appelle la fonction generateKey_cb pointeur pour renvoyer le résultat de l'opération à l'appelant. Notez la fonction que l'appel de pointeur est synchrone. L'appelant appelle generateKey et generateKey appelle la méthode un pointeur de fonction, qui s'exécute jusqu'à la fin et restitue le contrôle au generateKey, qui est ensuite renvoyée à l'appelant.

Pour obtenir un exemple détaillé, consultez l'implémentation par défaut dans hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp L'implémentation par défaut assure la rétrocompatibilité pour les appareils avec keymaster0, keymaster1 ou HALS à l'ancienne.

Contrôle des accès

La règle la plus simple du contrôle des accès au keystore est que chaque application votre propre espace de noms. Mais il existe une exception pour chaque règle. Keystore contient des les cartes codées en dur qui permettent à certains composants du système d'accéder à d'autres et plusieurs espaces de noms. Il s'agit d'un instrument très contondant, un contrôle total sur un autre espace de noms. Ensuite, il y a la question du fournisseur en tant que clients de Keystore. Nous n'avons actuellement aucun moyen d'établir un espace de noms pour les composants du fournisseur, par exemple, un demandeur WPA.

Pour s'adapter aux composants des fournisseurs et généraliser le contrôle des accès sans exceptions codées en dur, Keystore 2.0 introduit les domaines et SELinux et plusieurs espaces de noms.

Domaines du keystore

Avec les domaines Keystore, nous pouvons dissocier les espaces de noms des UID. Clients qui accèdent à une clé dans Keystore doivent spécifier le domaine, l'espace de noms et l'alias auxquelles ils souhaitent accéder. D'après ce tuple et l'identité de l'appelant que nous peut déterminer à quelle touche l'appelant souhaite accéder et si la clé autorisations.

Nous introduisons cinq paramètres de domaine qui régissent l'accès aux clés. Ils contrôlent la sémantique du paramètre d'espace de noms du descripteur de clé. le contrôle des accès.

  • DOMAIN_APP: le domaine de l'application couvre les l'ancien comportement. La SPI Java Keystore utilise ce domaine par défaut. Lorsque cette domaine est utilisé, l'argument d'espace de noms est ignoré et l'UID de l'appelant est utilisé à la place. L'accès à ce domaine est contrôlé par le libellé Keystore keystore_key dans la règle SELinux.
  • DOMAIN_SELINUX: ce domaine indique que le a une étiquette dans la règle SELinux. Le paramètre d'espace de noms est examiné et traduit dans un contexte cible, et une vérification des autorisations est effectuée pour le contexte SELinux appelant pour la classe keystore_key. Lorsque a été établie pour l'opération donnée, le tuple complet est utilisé pour la recherche de clé.
  • DOMAIN_GRANT: le domaine d'octroi indique que le paramètre d'espace de noms est un identifiant d'octroi. Le paramètre d'alias est ignoré. Les vérifications SELinux sont effectuées lors de la création de l'autorisation. Contrôle des accès renforcé vérifie uniquement si l'UID de l'appelant correspond à celui des bénéficiaires de l'autorisation demandée.
  • DOMAIN_KEY_ID: ce domaine indique que le est un ID de clé unique. La clé elle-même a peut-être été créée avec DOMAIN_APP ou DOMAIN_SELINUX. L'autorisation est effectuée après domain et namespace. ont été chargés depuis la base de données de clés de la même manière que si le blob était chargé par le tuple domaine, espace de noms et alias. Raison pour laquelle le domaine d'ID de clé est utilisé est la continuité. Lors de l’accès à une clé par alias, les appels suivants peuvent fonctionner sur différentes clés, car une nouvelle clé peut avoir été générée ou importée et liée à cet alias. Cependant, l'ID de clé ne change jamais. Lorsque vous utilisez une clé par ID de clé, après son chargement à partir de la base de données Keystore à l'aide de l'alias, peut être certain qu'il s'agit de la même clé tant que l'ID de clé existe toujours. Ce les fonctionnalités ne sont pas accessibles aux développeurs d'applications. Il est utilisé dans la SPI Android Keystore pour offrir une expérience plus cohérente même lorsqu'elle est utilisée simultanément et de manière non sécurisée.
  • DOMAIN_BLOB: le domaine de l'objet blob indique que l'appelant gère le blob tout seul. Il est utilisé pour les clients qui doivent accéder au keystore avant le montage de la partition de données. Le blob de clé est inclus dans le champ blob du descripteur de clé.

Le domaine SELinux nous permet d'accorder aux composants du fournisseur un accès Keystore spécifiques, qui peuvent être partagés par des composants système tels que dans la boîte de dialogue des paramètres.

Règles SELinux pour keystore_key

Les étiquettes d'espace de noms sont configurées à l'aide de keystore2_key_context .
Chaque ligne de ces fichiers mappe un identifiant d'espace de noms numérique à une étiquette SELinux. Par exemple :

# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and
# Settings to share keystore keys.
102            u:object_r:wifi_key:s0

Après avoir configuré un nouvel espace de noms de clé de cette façon, nous pouvons lui donner accès en ajoutant une stratégie appropriée. Par exemple, pour autoriser wpa_supplicant pour obtenir et utiliser des clés dans le nouvel espace de noms. Ajoutez la ligne suivante à hal_wifi_supplicant.te:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Après la configuration du nouvel espace de noms, AndroidKeyStore peut être utilisé presque d'habitude. La seule différence réside dans le fait que l'ID de l'espace de noms doit être spécifié. Pour lors du chargement et de l'importation de clés depuis et dans le keystore, l'ID d'espace de noms est spécifié à l'aide de AndroidKeyStoreLoadStoreParameter. Par exemple :

import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import java.security.KeyStore;

KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(new AndroidKeyStoreLoadStoreParameter(102));

Pour générer une clé dans un espace de noms donné, l'ID de l'espace de noms doit être indiqué avec KeyGenParameterSpec.Builder#setNamespace():

import android.security.keystore.KeyGenParameterSpec;
KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder();
specBuilder.setNamespace(102);

Les fichiers de contexte suivants peuvent être utilisés pour configurer Keystore 2.0 SELinux et plusieurs espaces de noms. Chaque partition a une plage réservée différente de 10 000 espaces de noms pour éviter les conflits.

Partition Plage Fichiers de configuration
Système 0 ... 9 999
/system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Système étendu 10 000 ... 19 999
/system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
Produit 20 000 ... 29 999
/product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
Fournisseur 30 000 ... 39 999
/vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

Le client demande la clé en demandant le domaine SELinux et les identifiants espace de noms virtuel, dans ce cas "wifi_key", par son ID numérique.

Au-dessus, les espaces de noms suivants ont été définis. S'ils remplacent règles spéciales, le tableau suivant indique l'UID auquel elles correspondent auxquelles vous souhaitez vous connecter.

ID de l'espace de noms Libellé SEPolicy UID Description
0 Clé Su N/A Clé de super-utilisateur. Utilisé uniquement pour les tests sur les builds userdebug et eng. Non pertinentes pour les compilations utilisateur.
1 clé_shell N/A Espace de noms disponible pour l'interface système. Principalement utilisée à des fins de test, mais peut être utilisée sur les compilations utilisateur aussi à partir de la ligne de commande.
100 clé_vold N/A Destiné à être utilisé par vold.
101 clé_odsing N/A Utilisé par le daemon de signature sur l'appareil.
102 clé_Wi-Fi WI-FI_AID(1010) Utilisé par le système Wi-Fi d'Android, y compris wpa_supplicant.
120 CV_on_reboot_key SYSTÈME_AID(1000) Utilisé par le serveur système Android pour permettre la reprise au redémarrage.

Vecteurs d'accès

La classe SELinux keystore_key a beaucoup vieilli et certaines des les autorisations, comme verify ou sign, ont été perdues leur signification. Voici le nouvel ensemble d'autorisations, keystore2_key, que Keystore 2.0 appliquera.

Autorisation Signification
delete Vérifié lors de la suppression de clés du keystore.
get_info Vérifié lorsque les métadonnées d'une clé sont demandées.
grant L'appelant a besoin de cette autorisation pour créer une autorisation pour la clé dans la cible. le contexte.
manage_blob L'appelant peut utiliser DOMAIN_BLOB sur l'espace de noms SELinux donné, et de gérer les blobs par lui-même. Ceci est particulièrement utile pour Vold
rebind Cette autorisation permet de contrôler si un alias peut être associé à une nouvelle clé. C'est requise pour l'insertion et implique que la clé précédemment liée supprimés. Il s'agit essentiellement d'une autorisation d'insertion, mais elle capture la sémantique de keystore.
req_forced_op Les clients disposant de cette autorisation peuvent créer des opérations irréalisables. la création d'opération n'échoue jamais, sauf si tous les emplacements d'opération sont occupés par qui ne peuvent pas être éliminées.
update Obligatoire pour mettre à jour le sous-composant d'une clé.
use Cochée lors de la création d'une opération Keymint qui utilise le matériel de clé, par exemple, pour la signature, l'en/déchiffrement.
use_dev_id Obligatoire lors de la génération d'informations permettant d'identifier l'appareil, telles que son ID attestation.

De plus, nous avons divisé un ensemble d'autorisations keystore non spécifiques la classe de sécurité SELinux keystore2:

Autorisation Signification
add_auth Requis par un fournisseur d'authentification tel que Gatekeeper ou BiometricsManager permettant d'ajouter des jetons d'authentification.
clear_ns Anciennement clear_uid, cette autorisation permet à un utilisateur qui n'est pas propriétaire d'un espace de noms de supprimer toutes les clés de cet espace de noms.
list Requis par le système pour énumérer les clés selon différentes propriétés, comme des limites de propriété ou d'authentification. Cette autorisation n'est pas requise par les appelants à énumérer leurs propres espaces de noms. Ce point est abordé dans le Autorisation get_info.
lock Cette autorisation permet de verrouiller le keystore, c'est-à-dire d'évincer la clé principale, que les clés liées à l'authentification deviennent inutilisables et incrédules.
reset Cette autorisation permet de rétablir la configuration d'usine du keystore et de supprimer clés qui ne sont pas essentielles au fonctionnement de l'OS Android.
unlock Cette autorisation est requise pour tenter de déverrouiller la clé principale pour l'authentification liées.