Magasin de clés basé sur le matériel

La disponibilité d'un environnement d'exécution fiable dans un système sur puce (SoC) offre aux appareils Android la possibilité de fournir des services de sécurité solides et soutenus par le matériel au système d'exploitation Android, aux services de plate-forme et même aux applications tierces. Les développeurs qui cherchent les extensions spécifiques Android doivent aller à android.security.keystore .

Avant Android 6.0, Android disposait déjà d'une API de services de chiffrement simple et matérielle, fournie par les versions 0.2 et 0.3 de Keymaster Hardware Abstraction Layer (HAL). Keystore a fourni des opérations de signature et de vérification numériques, ainsi que la génération et l'importation de paires de clés de signature asymétrique. Ceci est déjà implémenté sur de nombreux appareils, mais il existe de nombreux objectifs de sécurité qui ne peuvent pas être facilement atteints avec uniquement une API de signature. Keystore dans Android 6.0 a étendu l'API Keystore pour fournir un plus large éventail de fonctionnalités.

Dans Android 6.0, Keystore ajouté primitives cryptographiques symétriques , AES et HMAC, et un système de contrôle d'accès pour les clés matérielles soutenues. Les contrôles d'accès sont spécifiés lors de la génération de la clé et appliqués pour la durée de vie de la clé. Les clés peuvent être restreintes pour être utilisables uniquement après que l'utilisateur a été authentifié, et uniquement à des fins spécifiées ou avec des paramètres cryptographiques spécifiés. Pour plus d' informations, consultez les autorisations Balises et fonctions pages.

En plus d'étendre la gamme de primitives cryptographiques, Keystore dans Android 6.0 a ajouté ce qui suit :

  • Un schéma de contrôle d'utilisation permettant de limiter l'utilisation des clés, afin d'atténuer le risque de compromission de la sécurité dû à une mauvaise utilisation des clés
  • Un schéma de contrôle d'accès pour permettre la restriction des clés à des utilisateurs spécifiés, des clients et une plage de temps définie

Dans Android 7.0, Keymaster 2 a ajouté la prise en charge de l'attestation de clé et de la liaison de version. Attestation clé fournit des certificats de clé publique qui contiennent une description détaillée de la clé et ses contrôles d'accès, pour rendre l'existence de la clé dans le matériel sécurisé et sa configuration à distance vérifiable.

Version de liaison Lié clés du système d'exploitation et la version du niveau de patch. Cela garantit qu'un attaquant qui découvre une faiblesse dans une ancienne version du système ou du logiciel TEE ne peut pas restaurer un périphérique vers la version vulnérable et utiliser les clés créées avec la version la 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écent, la clé est mise à niveau avant de pouvoir être utilisée et la version précédente de la clé est invalidée. Au fur et à mesure que l'appareil est mis à niveau, les clés « cliquet » vers l'avant avec l'appareil, mais toute réversion de l'appareil vers une version précédente rend les clés inutilisables.

Dans Android 8.0, Keymaster 3 est passé de l'ancienne couche d'abstraction matérielle (HAL) à structure C à l'interface C++ HAL générée à partir d'une définition dans le nouveau langage de définition d'interface matérielle (HIDL). Dans le cadre du changement, de nombreux types d'arguments ont changé, bien que les types et les méthodes aient une correspondance un à un avec les anciens types et les méthodes de structure HAL. Voir la Functions page pour plus de détails.

En plus de cette révision de l' interface, Android 8.0 a étendu la fonction d'attestation de Keymaster 2 à l' appui attestation d'identité . L'attestation d'ID fournit un mécanisme limité et facultatif pour attester fortement des identifiants matériels, tels que le numéro de série de l'appareil, le nom du produit et l'ID de téléphone (IMEI / MEID). Pour implémenter cet ajout, Android 8.0 a modifié le schéma d'attestation ASN.1 pour ajouter l'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, ainsi que de définir un mécanisme pour désactiver de manière sécurisée et permanente la fonctionnalité.

Dans Android 9, les mises à jour comprenaient :

  • Mise à jour à Keymaster 4
  • Prise en charge des éléments sécurisés intégrés
  • Prise en charge de l'importation de clé sécurisée
  • Prise en charge du cryptage 3DES
  • Modifications de la liaison de version afin que boot.img et system.img aient des versions définies séparément pour permettre des mises à jour indépendantes

Glossaire

Voici un aperçu rapide des composants Keystore et de leurs relations.

AndroidKeystore est l'API Android et Framework composant utilisé par les applications pour accéder aux fonctionnalités Keystore. Il est implémenté en tant qu'extension des API d'architecture de cryptographie Java standard et se compose de code Java qui s'exécute dans le propre espace de processus de l'application. AndroidKeystore répond aux demandes d'application pour le comportement Keystore en les transférant au démon keystore.

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

keymasterd est un serveur de HIDL qui donne accès à la Keymaster TA. (Ce nom n'est pas standardisé et est à des fins conceptuelles.)

Keymaster TA (application de confiance) est le logiciel en cours d' exécution dans un contexte sécurisé, le plus souvent dans TrustZone sur un ARM SoC, qui fournit toutes les opérations magasins de clefs sécurisées, a accès à la matière clé brute, valide toutes les conditions de contrôle d'accès sur les clés , etc.

LockSettingsService est le composant système Android responsable de l' authentification des utilisateurs, à la fois le mot de passe et d' empreintes digitales. Cela ne fait pas partie de Keystore, mais est pertinent car de nombreuses opérations de clés Keystore nécessitent une authentification de l'utilisateur. LockSettingsService interagit avec le Gatekeeper TA et TA d' empreintes digitales pour obtenir des jetons d'authentification, qu'il fournit au démon keystore, et qui sont finalement consommés par l'application Keymaster TA.

Gatekeeper TA (application de confiance) est un autre élément en cours d' exécution dans le contexte sécurisé, qui est responsable de l' authentification des mots de passe de l' utilisateur et de générer des jetons d' authentification utilisé pour prouver au TA Keymaster qu'une authentification a été effectuée pour un utilisateur particulier à un moment donné dans le temps.

Fingerprint TA (application de confiance) est un autre composant en cours d' exécution dans le contexte sécurisé qui est responsable de l' authentification des empreintes digitales de l' utilisateur et pour générer des jetons d' authentification utilisé pour prouver à la TA Keymaster qu'une authentification a été effectuée pour un utilisateur particulier à un moment particulier dans le temps.

Architecture

L'API Android Keystore et le Keymaster HAL sous-jacent fournissent un ensemble basique mais adéquat de primitives cryptographiques pour permettre la mise en œuvre de protocoles utilisant des clés matérielles à accès contrôlé.

Keymaster HAL est une bibliothèque fournie par l'OEM et chargeable dynamiquement utilisée par le service Keystore pour fournir des services cryptographiques basés sur le matériel. Pour assurer la sécurité, les implémentations HAL n'effectuent aucune opération sensible dans l'espace utilisateur, ni même dans l'espace noyau. Les opérations sensibles sont déléguées à un processeur sécurisé accessible via une interface noyau. L'architecture résultante ressemble à ceci :

Accès à Keymaster

Figure 1. L' accès à Keymaster

Au sein d'un appareil Android, le « client » de Keymaster HAL se compose de plusieurs couches (par exemple, application, framework, démon Keystore), mais qui peuvent être ignorées pour les besoins de ce document. Cela signifie que l'API Keymaster HAL décrite est de bas niveau, utilisée par les composants internes de la plate-forme et non exposée aux développeurs d'applications. L'API de niveau supérieur est décrit sur le site des développeurs Android .

Le but de Keymaster HAL n'est pas d'implémenter les algorithmes sensibles à la sécurité, mais uniquement de rassembler et de désorganiser les demandes vers le monde sécurisé. Le format de fil est défini par l'implémentation.

Compatibilité avec les versions précédentes

Le Keymaster 1 HAL est totalement incompatible avec les HAL précédemment publiés, par exemple Keymaster 0.2 et 0.3. Pour faciliter l'interopérabilité sur les appareils exécutant Android 5.0 et versions antérieures lancés avec les anciennes HAL Keymaster, Keystore fournit un adaptateur qui implémente la HAL Keymaster 1 avec des appels à la bibliothèque matérielle existante. Le résultat ne peut pas fournir la gamme complète de fonctionnalités dans le Keymaster 1 HAL. En particulier, il ne prend en charge que les algorithmes RSA et ECDSA, et toute l'application de l'autorisation de clé est effectuée par l'adaptateur, dans le monde non sécurisé.

2 Keymaster encore simplifié l'interface HAL en enlevant les get_supported_* méthodes et permettant à la finish() méthode pour accepter l' entrée. Cela réduit le nombre d'allers-retours vers le TEE dans les cas où l'entrée est disponible en une seule fois, et simplifie la mise en œuvre du déchiffrement AEAD.

Dans Android 8.0, Keymaster 3 est passé de l'ancien style HAL à structure C à l'interface C++ HAL générée à partir d'une définition dans le nouveau langage de définition d'interface matérielle (HIDL). Un nouveau style de mise en œuvre HAL est créée par la sous - classement généré IKeymasterDevice classe et mise en œuvre des méthodes virtuelles pures. Dans le cadre du changement, de nombreux types d'arguments ont changé, bien que les types et les méthodes aient une correspondance un à un avec les anciens types et les méthodes de structure HAL.

Présentation de l'HIDL

Le Hardware Interface Definition Language (HIDL) fournit un mécanisme indépendant du langage de mise en œuvre pour spécifier les interfaces matérielles. L'outillage HIDL prend actuellement en charge la génération d'interfaces C++ et Java. On s'attend à ce que la plupart des implémenteurs de Trusted Execution Environment (TEE) trouvent les outils C++ plus pratiques, donc ce document ne traite que de la représentation C++.

Les interfaces HIDL consistent en un ensemble de méthodes, exprimées sous la forme :

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Il existe différents types prédéfinis et les HAL peuvent définir de nouveaux types énumérés et structurés. Pour plus de détails sur HIDL, consultez la section de référence .

Un exemple de procédé de la Keymaster 3 IKeymasterDevice.hal est:

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

C'est l'équivalent de ce qui suit de keymaster2 HAL :

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, le dev argument est supprimé, car il est implicite. Le params argument ne soit plus une structure contenant un pointeur référençant un tableau de key_parameter_t objets, mais un vec (vecteur) contenant KeyParameter objets. Les valeurs de retour sont répertoriés dans le « generates la clause », y compris un vecteur de uint8_t valeurs pour la clé blob.

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

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

generate_cb est un pointeur de fonction définie comme:

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

Autrement dit, generate_cb est une fonction qui prend les valeurs de retour figurant dans la clause générer. La classe d'implémentation HAL remplace cette generateKey méthode et appelle le generate_cb pointeur de fonction pour retourner le résultat de l'opération à l'appelant. Notez l'appel de pointeur de fonction est synchrone. L'appelant appelle generateKey et generateKey appelle le pointeur de fonction fournie, qui exécute à son terme, le contrôle de retour à la generateKey mise en œuvre, qui retourne ensuite à l'appelant.

Pour un exemple détaillé, voir l'implémentation par défaut dans le hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . L'implémentation par défaut fournit une compatibilité descendante pour les appareils avec l'ancien style keymaster0, keymaster1 ou keymaster2 HALS.

Contrôle d'accès

La règle la plus basique du contrôle d'accès Keystore est que chaque application a son propre espace de noms. Mais pour chaque règle, il y a une exception. Keystore a des cartes codées en dur qui permettent à certains composants du système d'accéder à certains autres espaces de noms. Il s'agit d'un instrument très brutal en ce sens qu'il donne à un composant un contrôle total sur un autre espace de noms. Et puis il y a la question des composants 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, le demandeur WPA.

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

Domaines de magasin de clés

Avec les domaines Keystore, nous pouvons découpler les espaces de noms des UID. Les clients accédant à une clé dans Keystore doivent spécifier le domaine, l'espace de noms et l'alias auxquels ils souhaitent accéder. Sur la base de ce tuple et de l'identité de l'appelant, nous pouvons déterminer à quelle clé l'appelant souhaite accéder et s'il dispose des autorisations appropriées.

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é et la manière dont le contrôle d'accès est effectué.

  • DOMAIN_APP : Le domaine de l' application couvre le comportement de l' héritage. Le Java Keystore SPI utilise ce domaine par défaut. Lorsque ce domaine est utilisé, l'argument namespace est ignoré et l'UID de l'appelant est utilisé à la place. L' accès à ce domaine est contrôlé par l'étiquette Keystore à la classe keystore_key dans la politique SELinux.
  • DOMAIN_SELINUX : Ce domaine indique que l'espace de noms a une étiquette dans la politique SELinux. Le paramètre d'espace de noms est recherché et traduit dans un contexte cible, et une vérification d'autorisation est effectuée pour l'appelant contexte SELinux pour la keystore_key classe. Lorsque l'autorisation a été établie pour l'opération donnée, le tuple complet est utilisé pour la recherche de clé.
  • DOMAIN_GRANT : Le domaine de subvention indique que le paramètre d'espace de noms est un identifiant de subvention. Le paramètre alias est ignoré. Les contrôles SELinux sont effectués lors de la création de l'octroi. Un contrôle d'accès supplémentaire vérifie uniquement si l'UID de l'appelant correspond à l'UID des bénéficiaires de la subvention demandée.
  • DOMAIN_KEY_ID : Ce domaine indique que le paramètre d'espace de noms est un identifiant de clé unique. La clé elle - même peut avoir été créé avec DOMAIN_APP ou DOMAIN_SELINUX . Le contrôle de l' autorisation est effectuée après le domain et l' namespace de namespace ont été chargés à partir de la base de données clé de la même manière que si le blob a été chargé par le domaine, espace de noms et tuple alias. La raison d'être du domaine d'identification de clé est la continuité. Lors de l'accès à une clé par alias, les appels suivants peuvent opérer sur des clés différentes, car une nouvelle clé peut avoir été générée ou importée et liée à cet alias. L'identifiant de la clé, cependant, ne change jamais. Ainsi, lorsque vous utilisez une clé par identifiant de clé après qu'elle a été chargée à partir de la base de données du magasin de clés en utilisant l'alias une fois, on peut être certain qu'il s'agit de la même clé tant que l'identifiant de clé existe toujours. Cette fonctionnalité n'est pas exposée aux développeurs d'applications. Au lieu de cela, il est utilisé dans Android Keystore SPI pour offrir une expérience plus cohérente, même lorsqu'il est utilisé simultanément de manière dangereuse.
  • DOMAIN_BLOB : Le domaine blob indique que l'appelant gère le blob par lui - même. Ceci est utilisé pour les clients qui doivent accéder au magasin de clés avant le montage de la partition de données. La clé blob est inclus dans le blob champ du descripteur clé.

En utilisant le domaine SELinux, nous pouvons donner aux composants du fournisseur l'accès à des espaces de noms de magasin de clés très spécifiques qui peuvent être partagés par des composants système tels que la boîte de dialogue des paramètres.

Politique SELinux pour keystore_key

Des étiquettes d'espaces de noms sont configurés à l' aide du keystore2_key_context fichier.
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 nom de clé de cette manière, nous pouvons y donner accès en ajoutant une politique appropriée. Par exemple, pour permettre wpa_supplicant pour obtenir et utiliser les touches dans le nouvel espace de noms , nous ajouterons la ligne suivante à hal_wifi_supplicant.te :

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Après avoir configuré le nouvel espace de noms, AndroidKeyStore peut être utilisé presque comme d'habitude. La seule différence est que l'ID d'espace de noms doit être spécifié. Pour les clés du chargement et l' importation à partir et en Keystore, l'identifiant d'espace de noms est spécifié à l' aide du 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 nom donné, l'identifiant d'espace de nom doit être donné en utilisant 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 les espaces de noms Keystore 2.0 SELinux. Chaque partition a une plage réservée différente de 10 000 identifiants d'espace de noms pour éviter les collisions.

Cloison Varier 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
Vendeur 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 l'espace de noms virtuel souhaité, dans ce cas "wifi_key" , par son identifiant numérique.

Au-dessus de cela, les espaces de noms suivants ont été définis. Si elles remplacent des règles spéciales, le tableau suivant indique l'UID auquel elles correspondaient.

ID d'espace de noms Étiquette SEPolicy UID La description
0 su_key N / A Clé super utilisateur. Utilisé uniquement pour les tests sur les builds userdebug et eng. Non pertinent sur les builds des utilisateurs.
1 shell_key N / A Espace de noms disponible pour le shell. Principalement utilisé pour les tests, mais peut également être utilisé sur les versions utilisateur à partir de la ligne de commande.
100 clé_vold N / A Destiné à être utilisé par vold.
101 odsing_key N / A Utilisé par le démon de signature sur l'appareil.
102 clé_wifi AID_WIFI (1010) Utilisé par le sybsystem Wifi d'Android, y compris wpa_supplicant.
120 resume_on_reboot_key AID_SYSTEM(1000) Utilisé par le serveur système d'Android pour prendre en charge la reprise au redémarrage.

Accéder aux vecteurs

La classe SELinux keystore_key a vieilli tout à fait un peu et certaines des autorisations, comme verify ou sign ont perdu leur sens. Voici la nouvelle série d'autorisations, keystore2_key , que Keystore 2.0 va appliquer.

Autorisation Sens
delete Vérifié lors de la suppression des clés de 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 un octroi à la clé dans le contexte cible.
manage_blob L'appelant peut utiliser DOMAIN_BLOB sur l'espace de noms SELinux donné, de manière à gérer blobs par lui - même. Ceci est particulièrement utile pour vold.
rebind Cette autorisation contrôle si un alias peut être lié à une nouvelle clé. Ceci est requis pour l'insertion et implique que la clé précédemment liée sera supprimée. Il s'agit essentiellement d'une autorisation d'insertion, mais elle capture mieux la sémantique du magasin de clés.
req_forced_op Les clients disposant de cette autorisation peuvent créer des opérations non prunables, et la création d'opérations n'échoue jamais à moins que tous les emplacements d'opération ne soient pris par des opérations non prunables.
update Obligatoire pour mettre à jour le sous-composant d'une clé.
use Coché 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 d'identification de l'appareil, telles que l'attestation d'identification de l'appareil.

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

Autorisation Sens
add_auth Requis par le fournisseur d'authentification tel que Gatekeeper ou BiometricsManager pour l'ajout de jetons d'authentification.
clear_ns Anciennement clear_uid, cette autorisation permet à un non 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 diverses propriétés, telles que la propriété ou la limite d'authentification. Cette autorisation n'est pas requise par les appelants énumérant leurs propres espaces de noms. Ceci est couvert par la get_info permission.
lock Cette autorisation permet de verrouiller le magasin de clés, c'est-à-dire d'expulser la clé principale, de sorte que les clés liées à l'authentification deviennent inutilisables et impossibles à créer.
reset Cette autorisation permet de réinitialiser Keystore aux paramètres d'usine par défaut, en supprimant toutes les clés qui ne sont pas vitales pour le fonctionnement du système d'exploitation Android.
unlock Cette autorisation est requise pour tenter de déverrouiller la clé principale pour les clés liées à l'authentification.