Journal Utilisation d’un TPM pour l’authentification SSH

Posté par  (site web personnel) . Licence CC By‑SA.
41
25
mai
2020
Ce journal a été promu en dépêche : Utilisation d’un TPM pour l’authentification SSH.

Sommaire

J’ai récemment fait l’acquisition d’un nouveau PC portable équipé entre autres choses d’un Trusted Platform Module (TPM) — comme la plupart des PC portables de nos jours, puisqu’à ce qu’il me semble la présence d’un TPM est un pré-requis pour vendre un PC avec une version récente de Windows). Je n’ai pas encore étudié tout ce qu’il serait possible de faire avec ce TPM, mais dans ce journal je vais décrire comment l’utiliser pour s’authentifier auprès d’un serveur SSH.

Support noyau

Vérifions d’abord à quel matériel j’ai affaire et s’il est bien reconnu par le noyau :

# dmesg | grep tpm
[   16.880645] tpm_tis IFX0783:00: 2.0 TPM (device-id 0x1B, rev-id 22)

C’est donc une puce Infineon (IFX), gérée par le module tpm_tis (et les modules associés tpm_tis_core, tpm_crb, tpm).

Si vous êtes de ceux qui compilent leur propre noyau, assurez-vous que toutes les options CONFIG_TCG_*, dans Devices Drivers > Characters devices > TPM Hardware Support, sont activées.

La pile logicielle

Ensuite, il nous faut un ensemble de bibliothèques et d’outils en espace utilisateur, ce que le Trusted Computing Group appelle la pile logicielle TPM (TPM Software Stack ou TSS). On aura pris soin de noter plus haut, dans la sortie de dmesg, que la puce TPM de ce portable est un TPM 2.0 ; cela signifie notamment qu’il est inutile d’essayer TrouSerS, qui est une pile logicielle TPM pour GNU/Linux ne supportant que les TPM ≤ 1.2 — c’est dommage, car la plupart des documents disponibles sur le Net concernant l’utilisation d’un TPM sous GNU/Linux ne parlent que de TrouSerS.

À la place de TrouSerS, il y a deux piles logicielles TPM 2.0 disponibles : une provenant d’IBM (IBM TPM 2.0 TSS), et une provenant de la “communauté logicielle tpm2” (principalement poussée par Intel). J’ai choisi cette dernière, qui semble fournir davantage d’outils pour l’intégration dans un système GNU/Linux — par exemple un moteur OpenSSL et surtout une interface PKCS#11, dont on reparlera plus bas.1

La pile de base

Installons donc le cœur de la pile Intel, la bibliothèque tpm2-tss et les outils associés. La bibliothèque est peut-être déjà disponible dans les dépôts de votre distribution (c’est le cas sous Debian), sinon, use the source, Luke :

$ wget https://github.com/tpm2-software/tpm2-tss/releases/download/2.4.1/tpm2-tss-2.4.1.tar.gz
$ tar xf tpm2-tss-2.4.1.tar.gz
$ cd tpm2-tss-2.4.1
$ ./configure --with-udevrulesdir=/lib/udev/rules.d \
    --with-udevrulesprefix=50- \
    --localstatedir=/var \
    --sysconfdir=/etc \
    --disable-weakcrypto
$ make
# make install-strip

Dans le reste de ce journal, nous installerons systématiquement tout à partir des sources. Il vous appartiendra de vérifier préalablement si des paquets sont disponibles pour votre distribution de prédilection et de privilégier cette voie le cas échéant. À l’heure où ces lignes sont écrites, Debian Buster par exemple fournit tpm2-tss, tpm2-tools, et tpm2-abrmd, mais tpm2-pkcs11 n’est disponible que dans Sid et tpm2-tss-engine n’est disponible dans aucune version.

Pour les utilisateurs de Slackware, je fournis des SlackBuilds pour tous les projets mentionnés ici : tpm2-tss, tpm2-tools, tpm2-abrmd, tpm2-pkcs11, et tpm2-tss-engine.

Installons ensuite les outils permettant de manipuler le TPM. Pour ce qu’on veut faire, on ne les utilisera pas directement, mais l’interface PKCS#11 que nous installerons plus en aura besoin.

$ wget https://github.com/tpm2-software/tpm2-tools/releases/download/4.2/tpm2-tools-4.2.tar.gz
$ tar xf tpm2-tools-4.2.tar.gz
$ cd tpm2-tools-4.2
$ ./configure
$ make
# make install-strip

Il faut ensuite décider de la méthode d’accès au TPM pour les utilisateurs de la machine, sachant qu’il y a trois options :

  • Laisser les utilisateurs accéder au périphérique /dev/tpm0 directement ; ce n’est pas recommandé par les développeurs et je confirme en effet que sur ma machine, ça ne marche pas quand on veut utiliser l’interface PKCS#11 comme on le fera plus loin.
  • Laisser les utilisateurs accéder au périphérique /dev/tpmrm0 directement ; il s’agit du gestionnaire de ressources (resources manager) du TPM fourni par le noyau.
  • Utiliser un gestionnaire de ressources en espace utilisateur, le TPM Access Broker and Resource Manager daemon (TABRMD) ; seul le démon utilisera le TPM directement, les autres programmes interagiront avec le démon. C’est l’approche recommandée.

Nous utiliserons le démon, donc installons le projet tpm2-abrmd.

$ wget https://github.com/tpm2-software/tpm2-abrmd/releases/download/2.3.2/tpm2-abrmd-2.3.2.tar.gz
$ tar xf tpm2-abrmd-2.3.2.tar.gz
$ cd tpm2-abrmd-2.3.2
$ ./configure --with-systemdsystemunitdir=/usr/lib/systemd/system \
    --with-systemdpresetdir=/usr/lib/systemd/system-preset \
    --sysconfdir=/etc \
    --localstatedir=/var
$ make
# make install-strip

Le démon a besoin d’un compte utilisateur dédié avec un accès en lecture/écriture au périphérique /dev/tpm0. Si vous l’avez installé depuis les dépôts de votre distribution, l’auteur du paquet a probablement déjà fait le nécessaire et vous pouvez sauter le reste de cette section ; sinon, lisez ce qui suit.

Le projet tpm2-tss est fourni avec une règle Udev donnant accès au TPM à un compte utilisateur appelé tss ; assurez-vous qu’un tel compte existe, donnez-lui les droits sur les dossiers dont aura besoin le démon (ces dossiers sont normalement créés lors du make install de tpm2-tss) puis rechargez et appliquez les règles Udev :

# groupadd --system tss
# useradd --system --comment "TPM2 Software Stack" --home-dir /var/lib/tpm2-tss --gid tss tss
# chown -R tss:tss /var/lib/tpm2-tss /var/run/tpm2-tss
# chmod 755 /var/lib/tpm2-tss /var/run/tpm2-tss
# udevadm control --reload-rules
# udevadm trigger

Le projet tpm2-abrmd est fourni avec une « unité » systemd ; si votre distribution utilise systemd, vous ne devriez pas avoir besoin de faire quoi que ce soit (à part peut-être un systemctl daemon-reload pour être sûr que la nouvelle unité est prise en compte). Dans le cas contraire, il vous appartient d’élaborer un script de démarrage qui convienne au système d’initialisation de votre distribution, quel qu’il soit. Prenez garde que tabrmd fait partie de cette nouvelle génération de démons qui ne connaissent rien d’autre que systemd : le démon considère comme acquis qu’il est géré par systemd et du coup ne prend pas la peine d’écrire son PID quelque part ou même de se détacher du terminal, votre script de démarrage devra se charger de ça.

L’interface PKCS#11

L’interface PKCS#11, fournie par le projet tpm2-pkcs11, est une couche qui permet d’utiliser le TPM comme si c’était un jeton cryptographique compatible avec la spécification PKCS#11. Elle rend rend le TPM utilisable par n’importe quel programme capable d’interagir avec un tel jeton, comme OpenSSH par exemple.

$ wget https://github.com/tpm2-software/tpm2-pkcs11/releases/download/1.0/tpm2-pkcs11-1.2.0.tar.gz
$ tar xf tpm2-pkcs11-1.2.0.tar.xf
$ cd tpm2-pkcs11-1.2.0
$ ./configure
$ make
# make install-strip

L’interface OpenSSL

Dernier composant de la pile Intel que nous installerons, le projet tpm2-tss-engine fournit un « moteur » OpenSSL, exposant les fonctions cryptographiques du TPM à travers OpenSSL. Elle n’est pas nécessaire pour SSH, mais je l’installe quand même puisqu’au-delà de SSH, le but de tout ceci est d’explorer ce que je peux faire de mon TPM.

$ wget https://github.com/tpm2-software/tpm2-tss-engine/releases/download/v1.0.1/tpm2-tss-engine-1.0.1.tar.gz
$ tar xf tpm2-tss-engine-1.0.1.tar.gz
$ cd tpm2-tss-engine-1.0.1
$ ./configure --sysconfdir=/etc
$ make
# make install-strip

Configurer l’accès au TPM pour les différents composants

Comme nous avons décidé plus haut d’accéder au TPM par l’intermédiaire du gestionnaire de ressources en espace utilisateur (TABRMD), nous devons définir les variables d’environnement suivantes :

export TPM2TOOLS_TCTI=tabrmd:
export TPM2_PKCS11_TCTI=tabrmd:
export TPM2TSSENGINE_TCTI=tabrmd:

Cela indiquera respectivement à tpm2-tools, tpm2-pkcs11, et tpm2-tss-engine de ne pas chercher à accéder au TPM directement mais de passer par le gestionnaire de ressources (TCTI signifie TPM Control Transmission Interface) ; sans cela, les différents outils ne contacteraient le gestionnaire de ressources qu’après avoir bruyamment échoué à ouvrir le périphérique /dev/tpm0 eux-mêmes. Ces variables ne sont pas strictement nécessaires, mais les définir permet d’éviter de polluer la console avec des messages d’erreur inutiles.

Pour information, la syntaxe de la valeur attendue par toutes ces variables est méthode:paramètres, où méthode peut être :

  • device, pour accéder au TPM directement ; dans ce cas paramètres indique le chemin d’accès au périphérique (exemple : device:/dev/tpm0) ;
  • tabrmd, pour accéder au TPM via le gestionnaire de ressources ; paramètres peut alors contenir l’adresse IP et le numéro de port où ledit gestionnaire attend ses clients (exemple : tabrmd:host=127.0.0.1,port=555), ou bien rester vide pour utiliser les valeurs par défaut ;
  • mssim, pour accéder à un émulateur logiciel de TPM comme ibmswtpm2 (pratique pour apprendre à utiliser un TPM ou développer et tester des logiciels faisant usage d’un TPM) ; paramètres peut alors contenir l’adresse IP et le numéro de port de l’émulateur, comme pour la méthode tabrmd.

Utilisation avec SSH

Créer un jeton PKCS#11

OpenSSH est nativement capable d’utiliser un jeton PKCS#11, nous utiliserons donc l’interface tpm2-pkcs11 installée plus haut. Il nous faut pour ça commencer par créer le dossier où tpm2-pkcs11 stockera la clef et les autres données dont il a besoin :

$ mkdir ~./tpm2_pkcs11
$ tpm2_ptool init
action: Created
id: 1

En effet, et de manière quelque peu contre-intuitive, la clef privée que nous allons créer ne sera pas stockée dans le TPM. À la place, la clef sera stockée dans un fichier SQLite dans le dossier .tpm2_pkcs11, chiffrée de telle sorte qu’elle ne peut être déchiffré que par le TPM. Chaque fois que la clef privée sera requise (par exemple pour s’authentifier auprès d’un serveur SSH), la bibliothèque tpm2-pkcs11 enverra la clef chiffré au TPM en même temps que les données à signer ; le TPM déchiffrera la clef et l’utilisera immédiatement pour signer les données, puis renverra à tpm2-pkcs11 le résultat de l’opération de signature.

Ce mode de fonctionnement a été conçu ainsi pour permettre d’utiliser un nombre illimité de clefs différentes avec un TPM dont la capacité de stockage est très réduite.

Nous pouvons maintenant créer un (pseudo) jeton PKCS#11 :

$ tpm2_ptool addtoken --pid=1 --label=mylabel --sopin=XXXX --userpin=YYYY

La valeur de --pid doit correspondre à l’identifiant de l’objet primaire renvoyé par la commande init un peu plus haut (id: 1). Le label peut être choisi librement, mais doit être unique parmi tous les jetons que vous créez (si jamais vous en créez plusieurs). Enfin, sopin et userpin sont respectivement le PIN administrateur du jeton (Security Officer PIN) et le PIN utilisateur.

Maintenant que nous avons un jeton, on peut y créer une clef, par exemple une clef ECC basée sur la courbe NIST P-256 :

$ tpm2_ptool addkey --label=mylabel --userpin=YYYY --algorithm=ecc256

Utiliser le jeton avec SSH

Il nous faut obtenir la partie publique de la clef que nous venons de créer, afin d’autoriser cette clef sur le serveur SSH auquel on veut se connecter. On utilise pour ça la commande ssh-keygen standard de OpenSSH, en lui indiquant d’obtenir la clef depuis notre jeton PKCS#11:

$ ssh-keygen -D /usr/local/lib/pkcs11/libtpm2_pkscs11.so > key.pub

Ajustez le chemin d’accès au module libtpm2_pkcs11.so en fonction de votre système et de la manière dont vous avez installé le projet tpm2-pkcs11.

Ajoutez le contenu du fichier key.pub au fichier ~/.ssh/authorized_key de votre compte utilisateur sur le serveur SSH. Vous pouvez maintenant tenter de vous connecter à ce serveur en utilisant le jeton :

$ ssh -I /usr/local/lib/pkcs11/libtpm2-pkcs11.so myserver.example.org
Enter PIN for 'myabel': YYYY

Pour éviter d’avoir à spécifier le chemin vers le module libtpm2-pkcs11.so à chaque appel, vous pouvez utiliser l’option PKCS11Provider dans le fichier de configuration de SSH (globalement ou pour un hôte donné). Si vous utilisez en parallèle d’autres clefs SSH que vous chargez normalement dans un agent SSH, vous devez aussi désactiver l’utilisation de l’agent pour les hôtes pour lesquels vous comptez utiliser le jeton TPM (sinon SSH contactera systématiquement l’agent sans jamais essayer le jeton):

Host myserver.example.org
  PKCS11Provider /usr/local/lib/pkcs11/libtpm2-pkcs11.so
  IdentityAgent none

Utilisation avec OpenSSL

Maintenant qu’on peut utiliser le TPM pour SSH, ce qui était l’objectif premier, voyons rapidement comment on peut aussi l’utiliser avec OpenSSL.

Confirmons d’abord que l’interface OpenSSL (tpm2-tss-engine) a été installée correctement et profitons-en pour voir les fonctions du TPM que cette interface rend disponible, en demandant à OpenSSL les capacités du moteur tpm2tss :

$ openssl engine -c tpm2tss
(tpm2tss) TPM2-TSS engine for OpenSSL
 [RSA, RAND]

Le moteur est donc effectivement bien installé, et donne accès aux fonctions relatives à RSA ainsi qu’au générateur de nombres aléatoires.

J’ignore pourquoi les fonctions ECDSA ne sont pas disponibles, alors que mon TPM les prend en charge (et que tpm2-pkcs11 les utilise sans problèmes). Il s’agit sans doute d’une limitation, voire d’un bug, de tpm2-tss-engine.

On pourra donc obtenir du TPM, par exemple, 20 octets aléatoires (encodés en base64) via la commande suivante :

$ openssl rand -engine tpm2tss -base64 20
engine "tpm2tss" set.
cO1eoOMocHPlvUxFB9tTDzOwZyE=

Générons une clef RSA à présent :

$ tpm2tss-genkey -a rsa -s 2048 -p XXXXXXXX tpmkey.pem

La commande produit un fichier tpmkey.pem contenant la clef générée. Elle est sous forme chiffrée et ne peut être déchiffrée et utilisée que par le TPM ; XXXXXXXX est le mot de passe à présenter au TPM pour le déchiffrement.

L’utilisation de la clef passe par les commandes OpenSSL classiques, auxquelles on précise d’utiliser le moteur tpm2tss. Par exemple, pour chiffrer puis déchiffrer un fichier, on commence par extraire la partie publique de la clef :

$ openssl rsa -engine tpm2tss -inform engine -in tpmkey.pem -pubout -outform pem -out publickey.pem
engine "tpm2tss" set.
Enter password for user key: XXXXXXXX
writing RSA key

Le moteur tpm2tss envoie la clef chiffrée contenue dans le fichier tpmkey.pem vers le TPM, celui-ci la déchiffre (si l’utilisateur fournit le bon mot de passe) et renvoie à OpenSSL la partie publique. Utilisons cette dernière pour chiffrer un fichier (le TPM n’est pas impliqué ici, le chiffrement ne faisant appel qu’à la clef publique) :

$ openssl pkeyutl -pubin -inkey publickey.pem -in cleartext.txt -encrypt -out ciphertext.dat

Pour déchiffrer, on utilise à nouveau le moteur tpm2tss :

$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey tpmkey.pem -decrypt -in ciphertext.dat -out deciphered.txt
engine "tpm2tss" set.
Enter password for user key: XXXXXXXX

Le moteur envoie au TPM à la fois la clef chiffrée tpmkey.pem et le fichier à déchiffrer ciphertext.dat. Le TPM commence par déchiffrer la clef elle-même (encore une fois sous réserve que l’utilisateur saississe le bon mot de passe) puis l’utilise pour déchiffrer le fichier et renvoie le texte clair correspondant à OpenSSL.


  1. Une autre raison pour ne pas s’attarder sur le code d’IBM est que le fait que ledit code est fourni sous la forme d’une tar bomb… C’est con, mais je n’ai aucune envie d’utiliser un code écrit par quelqu’un qui ne sait pas utiliser tar correctement. 

  • # Super intéressant

    Posté par  . Évalué à 8.

    Merci pour ton article c'est super intéressant

    Le moteur est donc effectivement bien installé, et donne accès aux fonctions relatives à RSA ainsi qu’au générateur de nombres aléatoires.

    Il est pris automatique comme source d'entropie par le noyau ? Est-ce qu'il lui fait particulièrement confiance ?

    Je ne connais pas trop TPM, j'ai lu que souvent c'était implémenté dans les CPU en firmware, mais mon nouveau CPU dernier cris de chez AMD ne semble rien avoir pour ça.

    Utilisons cette dernière pour chiffrer un fichier (le TPM n’est pas impliqué ici, le chiffrement ne faisant appel qu’à la clef publique) :

    J'imagine que pour cet usage, il faut faire attention car, je présume qu'il n'est impossible de sortir la clef privée. Donc le document chiffré est indéchiffrable ailleurs. C'est ça ?

    https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

    • [^] # Re: Super intéressant

      Posté par  . Évalué à 1.

      On peut lire et écrire dans la mémoire du TPM : https://wiki.archlinux.org/index.php/User:Diabonas/Trusted_Platform_Module#Using_TPM_2.0

      Cependant, selon les modalités d'écriture de la clef dans le TPM, je ne suis pas certain qu'il soit possible de l'extraire.

    • [^] # Re: Super intéressant

      Posté par  (site web personnel) . Évalué à 2. Dernière modification le 25 mai 2020 à 11:09.

      Il est pris automatique comme source d'entropie par le noyau ?

      Pas à ma connaissance. Par contre, c’est une des sources d’entropie possible pour alimenter le périphérique /dev/hwrng, comme on peut le voir dans /sys/class/misc/hw_random :

      # cat /sys/class/misc/hw_random/rng_available
      tpm-rng-0 via

      Et sur ma machine c’est la source actuellement utilisée :

      # cat /sys/class/misc/hw_random/rng_current
      tpm-rng-0

      Donc lire depuis /dev/hwrng va directement taper dans le TPM, sans avoir besoin de passer par OpenSSL.

      Si on veut utiliser cette source pour alimenter le pool d’entropie du noyau (celui qui est derrière les périphériques /dev/(u)random ou l’appel getrandom(2)), on peut utiliser des outils comme rngd(8).

      je présume qu'il n'est impossible de sortir la clef privée. Donc le document chiffré est indéchiffrable ailleurs.

      Oui, c’est tout le but.

  • # <noob>A quoi ça sert ?</noob>

    Posté par  . Évalué à 2.

    Ca serait pas mal de dire quelle est l'utilité en introduction ?

    Est-ce que ça permet de s'authentifier avec un jeton ? (non)

    Ou d'utiliser l'authentif biométrique du PC ? Ou de faire du SSO ?

    Merci

    • [^] # Re: <noob>A quoi ça sert ?</noob>

      Posté par  . Évalué à 7.

      Cela permet de stocker la clef dans une puce dédiée à cela qui permet (en théorie) d'empêcher que quelqu'un puisse lire la clef.

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

    • [^] # Re: <noob>A quoi ça sert ?</noob>

      Posté par  . Évalué à 4.

      C'est une unité de calcul dédiée à la sécurité. Il implémente différentes fonction de sécurité. L'intérêt c'est qu'il est possible de séparer physiquement (quand il s'agit d'un véritable circuit) les données sensibles du reste. Dans l'exemple décrit la clef privée déchiffrée ne sort jamais du TPM. En cela ça se rapproche d'un HSM (il en est peut être un d'ailleurs ?).

      https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

      • [^] # Re: <noob>A quoi ça sert ?</noob>

        Posté par  . Évalué à 4.

        À ma connaissance, il n'y a pas de définition formelle d'un HSM. Ce n'est pas un HSM bancaire, mais il s'agit bien d'un composant hardware dédié au stockage et l'utilisation de clefs cryptographiques. Il peut être intégré à un firmware, par exemple chez Intel : Intel firmware-based TPM (fTPM), mais c'est généralement un composant dédié (le ST sur base ST33 est très répandu).

        Mais les capacité d'un TPM sont très limitées, même si c'est mieux depuis TPMv2, essentiellement pour limiter leurs coûts, ils ne peuvent stocker en interne que très peu de clefs (généralement quelques clefs symétriques), et supportent un nombre très faible d'algos pour les calculs.

    • [^] # Re: <noob>A quoi ça sert ?</noob>

      Posté par  . Évalué à 4.

      Pour compléter les autres commentaires1 : l’intérêt du TPM c’est que tu peux donner des conditions pour l’accès aux données. Tu peux par exemple n’autoriser l’accès que si secure boot est activé et que tu démarre sur un kernel spécifique ou ce genre de chose. C’est à ma connaissance ce que fait Bitlocker dans Windows pour le chiffrement des disques.

      Dans l’exemple du journal (la manière dont il stocke la clef), je ne sais pas si tu pourrais y accéder en démarrant un live USB (si oui, ça limite fortement l’intérêt).


      1. Note que je ne suis pas expert et qu’il s’agit seulement de ma compréhension du système après avoir discuter avec des gens bien meilleur que moi. 

      • [^] # Re: <noob>A quoi ça sert ?</noob>

        Posté par  (site web personnel) . Évalué à 4.

        Tu peux par exemple n’autoriser l’accès que si

        Et si tu supposes l'intégrité de Intel.

        Adhérer à l'April, ça vous tente ?

        • [^] # Re: <noob>A quoi ça sert ?</noob>

          Posté par  . Évalué à 3.

          Et si tu supposes l'intégrité de Intel.

          Et si tu supposes l'intégrité des différents constructeurs de la chaîne de boot, ça marche avec AMD, un constructeur ARM, un fabricant TPM…

          « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

  • # Using TPM 2.0 As a Secure Keystore on your Laptop

    Posté par  . Évalué à 5.

    Il y a eu plusieurs conférence sur TPM au FOSDEM ces dernières années qui peuvent être intéressantes pour découvrir ou approfondir le sujet, et notamment Using TPM 2.0 As a Secure Keystore on your Laptop.

  • # tar bomb

    Posté par  . Évalué à 1.

    https://xkcd.com/1168/ -> pas sûr toutefois que cela éclaire la note de bas de page

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.