
Credenciales WebAuthn portátiles respaldadas por hardware utilizando TPM 2.0. Una clave principal determinista derivada de una semilla maestra permite la portabilidad de credenciales entre dispositivos. Las claves de firma privadas nunca abandonan el TPM. Incluye extensión de navegador y CLI.
⚠️ Prueba de concepto temprana. Este proyecto no ha sido probado o auditado a fondo. No lo uses para nada más allá de experimentación.
Credenciales WebAuthn/passkey portátiles respaldadas por hardware que funcionan en múltiples dispositivos usando TPM 2.0.
Las credenciales TPM tradicionales están bloqueadas al dispositivo que las creó. Este proyecto las hace portátiles importando una clave padre determinista (derivada de una semilla maestra) en el TPM de cada dispositivo. Los blobs de credenciales cifrados por un TPM pueden ser cargados y usados por cualquier otro TPM aprovisionado con la misma semilla. Las claves de firma privadas son generadas aleatoriamente por el TPM para cada credencial y nunca existen en texto plano fuera del hardware.
La semilla maestra solo se necesita una vez por dispositivo durante el aprovisionamiento. Después de eso, todas las operaciones criptográficas ocurren completamente dentro del TPM.
Una extensión del navegador sobrescribe navigator.credentials y enruta las llamadas WebAuthn a través de mensajería nativa a un backend Python que se comunica directamente con el TPM. Al registrarse, el TPM crea una nueva clave de firma bajo el padre portátil y devuelve un blob cifrado. Al autenticarse, carga el blob de nuevo, lo descifra internamente y firma el desafío.
Linux (Debian/Ubuntu):
sudo apt install tpm2-tools python3-tpm2-pytss python3-cryptography
Windows:
pip install cryptography
Windows se comunica con el TPM a través de TBS (TPM Base Services) mediante ctypes, por lo que no se necesitan paquetes nativos adicionales.
La extensión del navegador se comunica con native_host.py a través de mensajería nativa. Necesitas registrar un manifiesto que le indique a Firefox dónde encontrar el host.
Crea el archivo ~/.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]"
]
}
Reemplaza path con la ruta absoluta a native_host.py. Asegúrate de que sea ejecutable (chmod +x native_host.py).
En Windows, el manifiesto de mensajería nativa se registra a través del Registro de Windows. Consulta la documentación de mensajería nativa de Firefox para más detalles.
cd extension
npm install
npm run build
Luego en Firefox:
about:debugging#/runtime/this-firefoxextension/dist (por ejemplo, manifest.json)Abre la ventana emergente de la extensión y pega una semilla existente o haz clic en "Generar" para crear una nueva, luego haz clic en "Aprovisionar". Si generas una nueva semilla, guárdala en un lugar seguro. La necesitarás para aprovisionar dispositivos adicionales, y perderla significa perder la capacidad de configurar nuevos dispositivos (las credenciales existentes en dispositivos ya aprovisionados seguirán funcionando).
El aprovisionamiento también se puede hacer desde la CLI:
./webauthn_cli.py provision --generate
# o con una semilla existente:
./webauthn_cli.py provision <seed_hex>
./webauthn_cli.py test
Esto crea una credencial, firma un desafío y verifica la firma.
webauthn_cli.py [--backend=BACKEND] <comando> [args]
Comandos:
Backends (seleccionados con --backend o la variable de entorno WEBAUTHN_BACKEND):
| Backend | Descripción |
|---|---|
tpm | TPM multiplataforma mediante comandos sin procesar (predeterminado) |
linux | Solo Linux, usa la biblioteca tpm2-pytss |
soft | Puramente software, no requiere TPM (para pruebas) |
Las claves de firma de las credenciales se generan dentro del TPM y nunca lo abandonan en texto plano. El blob cifrado en el ID de la credencial es inútil sin acceso a un TPM aprovisionado. A diferencia de los almacenes de credenciales basados en software, las claves privadas nunca están presentes en la memoria del host durante la autenticación, lo que protege contra ataques de arranque en frío y extracción de claves por malware.
TPM2_Duplicate (que teóricamente podría exportar claves) está bloqueado porque las credenciales se crean con un authPolicy vacío, lo que hace imposible la duplicación incluso con acceso completo al sistema.
El malware que se ejecuta en un sistema aprovisionado puede pedirle al TPM que firme desafíos, ya que no hay verificación de usuario (sin pulsación de botón ni biometría). No puede extraer las claves, pero puede usarlas mientras esté activo. Esta es una superficie de ataque más reducida que los almacenes de credenciales basados en software, donde el malware puede robar las claves directamente.
La semilla maestra es la raíz de confianza. Si se ve comprometida, un atacante puede aprovisionar su propio TPM y usar cualquier blob de credencial que obtenga. Si se pierde y todos los dispositivos aprovisionados dejan de estar disponibles, las credenciales son irrecuperables. Almacénala como lo harías con una frase de recuperación de una billetera de hardware: fuera de línea, en un lugar seguro, idealmente con redundancia (por ejemplo, dividida en múltiples ubicaciones).
El proyecto incluye tres backends intercambiables:
webauthn_tpm_portable.py es el backend principal. Construye comandos TPM a nivel de bytes y funciona tanto en Linux (/dev/tpmrm0) como en Windows (API TBS mediante ctypes).
webauthn_tpm_linux.py usa la biblioteca Python tpm2-pytss y solo funciona en Linux.
webauthn_soft.py es una implementación puramente software que emula el mismo formato de credencial sin ningún TPM. Útil para pruebas y desarrollo, pero no proporciona protección de hardware.
"Permiso denegado" en /dev/tpmrm0:
Agrega tu usuario al grupo tss y vuelve a iniciar sesión: sudo usermod -aG tss $USER
Errores de importación de tpm2-pytss:
Prueba sudo apt install python3-tpm2-pytss o pip install --upgrade tpm2-pytss --break-system-packages.
La extensión no se conecta al host nativo:
Verifica que la path en el manifiesto de mensajería nativa sea una ruta absoluta que apunte a native_host.py. Abre la Consola del Navegador en Firefox (Ctrl+Shift+J) para comprobar si hay errores de la extensión.
MIT
| Comando | Descripción |
|---|
status | Verificar si el TPM está aprovisionado |
provision --generate | Generar una semilla aleatoria y aprovisionar |
provision <seed_hex> | Aprovisionar con una semilla existente |
create <rp_id> | Crear una credencial para un party confiable |
sign <cred_id> <rp_id> <desafío> | Firmar un desafío |
verify <cred_id> <rp_id> <desafío> <sig> | Verificar una firma |
clear | Eliminar la clave padre portátil del TPM |
test | Ejecutar un ciclo completo de creación/firma/verificación |