
Credenciais WebAuthn portáteis e protegidas por hardware usando TPM 2.0. Uma chave pai determinística derivada de uma semente mestre permite a portabilidade de credenciais entre dispositivos. As chaves de assinatura privadas nunca saem do TPM. Inclui extensão de navegador e CLI.
⚠️ Prova de conceito inicial. Este projeto não foi exaustivamente testado ou auditado. Não o utilize para nada além de experimentação.
Credenciais WebAuthn/passkey portáteis e com suporte de hardware que funcionam em múltiplos dispositivos usando TPM 2.0.
As credenciais TPM tradicionais estão bloqueadas ao dispositivo que as criou. Este projeto torna-as portáteis ao importar uma chave-mãe determinística (derivada de uma semente-mestra) no TPM de cada dispositivo. Blobos de credenciais encriptados por um TPM podem então ser carregados e usados por qualquer outro TPM provisionado com a mesma semente. As chaves de assinatura privadas são geradas aleatoriamente pelo TPM para cada credencial e nunca existem em texto simples fora do hardware.
A semente-mestra é necessária apenas uma vez por dispositivo durante o provisionamento. Depois disso, todas as operações criptográficas ocorrem inteiramente dentro do TPM.
Uma extensão do navegador substitui navigator.credentials e encaminha chamadas WebAuthn através de mensagens nativas para um backend Python que comunica diretamente com o TPM. No registo, o TPM cria uma nova chave de assinatura sob a chave-mãe portátil e retorna um blob encriptado. Na autenticação, carrega o blob de volta, descodifica-o internamente e assina o desafio.
Linux (Debian/Ubuntu):
sudo apt install tpm2-tools python3-tpm2-pytss python3-cryptography
Windows:
pip install cryptography
O Windows comunica com o TPM através de TBS (TPM Base Services) via ctypes, pelo que não são necessários pacotes nativos extras.
A extensão do navegador comunica com native_host.py através de mensagens nativas. Precisa de registar um manifesto que informe o Firefox onde encontrar o host.
Crie o ficheiro ~/.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]"
]
}
Substitua path pelo caminho absoluto para native_host.py. Certifique-se de que é executável (chmod +x native_host.py).
No Windows, o manifesto de mensagens nativas é registado através do Registo do Windows. Consulte a documentação de mensagens nativas do Firefox para mais detalhes.
cd extension
npm install
npm run build
Depois no Firefox:
about:debugging#/runtime/this-firefoxextension/dist (por exemplo, manifest.json)Abra o popup da extensão e cole uma semente existente ou clique em "Generate" para criar uma nova, depois clique em "Provision". Se gerar uma nova semente, guarde-a num local seguro. Vai precisar dela para provisionar dispositivos adicionais, e perdê-la significa perder a capacidade de configurar novos dispositivos (as credenciais existentes em dispositivos já provisionados continuarão a funcionar).
O provisionamento também pode ser feito a partir da CLI:
./webauthn_cli.py provision --generate
# or with an existing seed:
./webauthn_cli.py provision <seed_hex>
./webauthn_cli.py test
Isto cria uma credencial, assina um desafio e verifica a assinatura.
webauthn_cli.py [--backend=BACKEND] <command> [args]
Comandos:
Backends (selecionados com --backend ou variável de ambiente WEBAUTHN_BACKEND):
| Backend | Descrição |
|---|---|
tpm | TPM multi-plataforma através de comandos brutos (padrão) |
linux | Apenas Linux, usa a biblioteca tpm2-pytss |
soft | Software puro, sem necessidade de TPM (para testes) |
As chaves de assinatura de credenciais são geradas dentro do TPM e nunca saem dele em texto simples. O blob encriptado no ID da credencial é inútil sem acesso a um TPM provisionado. Ao contrário dos armazenamentos de credenciais baseados em software, as chaves privadas nunca estão presentes na memória do anfitrião durante a autenticação, o que protege contra ataques de arranque a frio e extração de chaves por malware.
TPM2_Duplicate (que poderia teoricamente exportar chaves) está bloqueado porque as credenciais são criadas com um authPolicy vazio, tornando a duplicação impossível mesmo com acesso total ao sistema.
Malware a executar num sistema provisionado pode pedir ao TPM para assinar desafios, uma vez que não há verificação do utilizador (sem pressionar botão ou biometria). Não consegue extrair as chaves, mas pode usá-las enquanto estiver ativo. Esta é uma superfície de ataque mais reduzida do que nos armazenamentos de credenciais baseados em software, onde o malware pode roubar chaves diretamente.
A semente-mestra é a raiz da confiança. Se for comprometida, um atacante pode provisionar o seu próprio TPM e usar quaisquer blobs de credenciais que obtenha. Se for perdida e todos os dispositivos provisionados se tornarem indisponíveis, as credenciais são irrecuperáveis. Guarde-a como guardaria uma frase de recuperação de carteira de hardware: offline, num local seguro, idealmente com redundância (por exemplo, dividida em vários locais).
O projeto inclui três backends intercambiáveis:
webauthn_tpm_portable.py é o backend principal. Constrói comandos TPM ao nível dos bytes e funciona tanto no Linux (/dev/tpmrm0) como no Windows (API TBS via ctypes).
webauthn_tpm_linux.py usa a biblioteca Python tpm2-pytss e funciona apenas no Linux.
webauthn_soft.py é uma implementação puramente de software que emula o mesmo formato de credencial sem qualquer TPM. Útil para testes e desenvolvimento, mas não fornece proteção de hardware.
"Permission denied" em /dev/tpmrm0:
Adicione o seu utilizador ao grupo tss e faça login novamente: sudo usermod -aG tss $USER
Erros de importação do tpm2-pytss:
Tente sudo apt install python3-tpm2-pytss ou pip install --upgrade tpm2-pytss --break-system-packages.
Extensão não está a ligar ao host nativo:
Verifique que o path no manifesto de mensagens nativas é um caminho absoluto a apontar para native_host.py. Abra a Consola do Navegador no Firefox (Ctrl+Shift+J) para verificar os erros da extensão.
MIT
| Comando | Descrição |
|---|
status | Verificar se o TPM está provisionado |
provision --generate | Gerar uma semente aleatória e provisionar |
provision <seed_hex> | Provisionar com uma semente existente |
create <rp_id> | Criar uma credencial para uma parte confiável |
sign <cred_id> <rp_id> <challenge> | Assinar um desafio |
verify <cred_id> <rp_id> <challenge> <sig> | Verificar uma assinatura |
clear | Remover a chave-mãe portátil do TPM |
test | Executar um ciclo completo de criação/assinatura/verificação |