
Identifiants WebAuthn portables et adossés au matériel utilisant TPM 2.0. Une clé parente déterministe dérivée d'une graine maîtresse permet la portabilité des identifiants entre appareils. Les clés de signature privées ne quittent jamais le TPM. Inclut une extension de navigateur et une CLI.
⚠️ Preuve de concept précoce. Ce projet n'a pas été rigoureusement testé ni audité. Ne l'utilisez pas pour autre chose que de l'expérimentation.
Credentials WebAuthn/passkey portables, sécurisés par matériel, fonctionnant sur plusieurs appareils via TPM 2.0.
Les credentials TPM traditionnels sont verrouillés sur l'appareil qui les a créés. Ce projet les rend portables en important une clé parent déterministe (dérivée d'une graine maîtresse) dans le TPM de chaque appareil. Les blobs de credentials chiffrés par un TPM peuvent ensuite être chargés et utilisés par tout autre TPM provisionné avec la même graine. Les clés de signature privées sont générées aléatoirement par le TPM pour chaque credential et n'existent jamais en clair en dehors du matériel.
La graine maîtresse n'est nécessaire qu'une fois par appareil lors du provisionnement. Ensuite, toutes les opérations cryptographiques se déroulent entièrement à l'intérieur du TPM.
Une extension de navigateur remplace navigator.credentials et achemine les appels WebAuthn via la messagerie native vers un backend Python qui communique directement avec le TPM. Lors de l'enregistrement, le TPM crée une nouvelle clé de signature sous la clé parent portable et renvoie un blob chiffré. Lors de l'authentification, il recharge le blob, le déchiffre en interne, et signe le défi.
Linux (Debian/Ubuntu) :
sudo apt install tpm2-tools python3-tpm2-pytss python3-cryptography
Windows :
pip install cryptography
Windows communique avec le TPM via TBS (TPM Base Services) via ctypes, donc aucun paquet natif supplémentaire n'est nécessaire.
L'extension de navigateur communique avec native_host.py via la messagerie native. Vous devez enregistrer un manifeste qui indique à Firefox où trouver l'hôte.
Créez le fichier ~/.mozilla/native-messaging-hosts/webauthn_tpm_portable.json :
{
"name": "webauthn_tpm_portable",
"description": "WebAuthn TPM Portable Credentials Backend",
"path": "/absolute/path/to/native_host.py",
"type": "stdio",
"allowed_extensions": [
"[email protected]"
]
}
Remplacez path par le chemin absolu vers native_host.py. Assurez-vous qu'il est exécutable (chmod +x native_host.py).
Sous Windows, le manifeste de messagerie native est enregistré via le Registre Windows. Consultez la documentation sur la messagerie native de Firefox pour plus de détails.
cd extension
npm install
npm run build
Ensuite, dans Firefox :
about:debugging#/runtime/this-firefoxextension/dist (par exemple manifest.json)Ouvrez la popup de l'extension et soit collez une graine existante, soit cliquez sur "Générer" pour en créer une nouvelle, puis cliquez sur "Provisionner". Si vous générez une nouvelle graine, sauvegardez-la dans un endroit sûr. Vous en aurez besoin pour provisionner d'autres appareils, et la perdre signifie perdre la capacité de configurer de nouveaux appareils (les credentials existants sur les appareils déjà provisionnés continueront de fonctionner).
Le provisionnement peut également être effectué depuis la CLI :
./webauthn_cli.py provision --generate
# or with an existing seed:
./webauthn_cli.py provision <seed_hex>
./webauthn_cli.py test
Ceci crée un credential, signe un défi et vérifie la signature.
webauthn_cli.py [--backend=BACKEND] <command> [args]
Commandes :
| Commande | Description |
|---|---|
status | Vérifier si le TPM est provisionné |
provision --generate | Générer une graine aléatoire et provisionner |
provision <seed_hex> | Provisionner avec une graine existante |
create <rp_id> | Créer un credential pour une partie de confiance |
sign <cred_id> <rp_id> <challenge> | Signer un défi |
verify <cred_id> <rp_id> <challenge> <sig> | Vérifier une signature |
clear | Supprimer la clé parent portable du TPM |
test | Exécuter un cycle complet de création/signature/vérification |
Backends (sélectionnés avec --backend ou la variable d'environnement WEBAUTHN_BACKEND) :
| Backend | Description |
|---|---|
tpm | TPM multiplateforme via commandes brutes (par défaut) |
linux | Linux uniquement, utilise la bibliothèque tpm2-pytss |
soft | Uniquement logiciel, aucun TPM requis (pour les tests) |
Les clés de signature des credentials sont générées à l'intérieur du TPM et ne le quittent jamais en clair. Le blob chiffré dans l'ID du credential est inutile sans accès à un TPM provisionné. Contrairement aux magasins de credentials logiciels, les clés privées ne sont jamais présentes dans la mémoire de l'hôte lors de l'authentification, ce qui protège contre les attaques par démarrage à froid et l'extraction de clés par malware.
TPM2_Duplicate (qui pourrait théoriquement exporter des clés) est bloqué parce que les credentials sont créés avec un authPolicy vide, rendant la duplication impossible même avec un accès complet au système.
Un malware s'exécutant sur un système provisionné peut demander au TPM de signer des défis, car il n'y a pas de vérification utilisateur (pas de pression de bouton ni de biométrie). Il ne peut pas extraire les clés, mais peut les utiliser tant qu'il est actif. Il s'agit d'une surface d'attaque plus restreinte que les magasins de credentials logiciels où un malware peut voler les clés directement.
La graine maîtresse est la racine de confiance. Si elle est compromise, un attaquant peut provisionner son propre TPM et utiliser tous les blobs de credentials qu'il obtient. Si elle est perdue et que tous les appareils provisionnés deviennent indisponibles, les credentials sont irrécupérables. Stockez-la comme vous le feriez pour une phrase de récupération de portefeuille matériel : hors ligne, dans un endroit sécurisé, idéalement avec redondance (par exemple répartie sur plusieurs emplacements).
Le projet inclut trois backends interchangeables :
webauthn_tpm_portable.py est le backend principal. Il construit les commandes TPM au niveau octet et fonctionne à la fois sur Linux (/dev/tpmrm0) et Windows (API TBS via ctypes).
webauthn_tpm_linux.py utilise la bibliothèque Python tpm2-pytss et ne fonctionne que sous Linux.
webauthn_soft.py est une implémentation purement logicielle qui émule le même format de credential sans TPM. Utile pour les tests et le développement, mais n'offre aucune protection matérielle.
"Permission refusée" sur /dev/tpmrm0 :
Ajoutez votre utilisateur au groupe tss et reconnectez-vous : sudo usermod -aG tss $USER
Erreurs d'import de tpm2-pytss :
Essayez sudo apt install python3-tpm2-pytss ou pip install --upgrade tpm2-pytss --break-system-packages.
L'extension ne se connecte pas à l'hôte natif :
Vérifiez que le path dans le manifeste de messagerie native est un chemin absolu pointant vers native_host.py. Ouvrez la Console du navigateur dans Firefox (Ctrl+Maj+J) pour vérifier les erreurs de l'extension.
MIT