Gatekeeper

O subsistema Gatekeeper realiza a autenticação de padrão/senha do dispositivo em um ambiente de execução confiável (TEE). O gatekeeper registra e verifica senhas usando uma chave secreta protegida por hardware. Além disso, o Gatekeeper limita as tentativas de verificação falhadas consecutivas e precisa recusar as solicitações de serviço com base em um tempo limite e um número de tentativas falhadas consecutivas.

Quando os usuários verificam as senhas, o Gatekeeper emite um token de autenticação assinado com uma chave HMAC por inicialização que está disponível apenas para componentes seguros. Esse token é enviado para o Keystore com suporte a hardware. Ou seja, um token de autenticação do Gatekeeper notifica o Keystore de que chaves vinculadas à autenticação (por exemplo, chaves criadas por apps) podem ser usadas por apps.

Arquitetura

O Gatekeeper envolve três componentes principais:

  • gatekeeperd (daemon gatekeeper) — um serviço de vinculação C++ no Android que contém uma lógica independente de plataforma que implementa a interface AIDL IGateKeeperService, com base em uma implementação específica do fornecedor de IGatekeeper.
  • Serviço da camada de abstração de hardware (HAL) do gatekeeper: uma implementação específica do fornecedor da interface AIDL IGatekeeper. Esse serviço HAL é executado no Android, mas a funcionalidade principal do Gatekeeper precisa ser executada em um ambiente seguro. Por isso, ele normalmente se comunica com o TA do Gatekeeper.
  • Aplicativo de confiança do gatekeeper (TA): uma implementação específica do fornecedor que é executada no TEE e realiza a verificação real de senha ou padrão.

O LockSettingsService faz uma solicitação (por meio do Binder) que alcança o daemon gatekeeperd no SO Android. O daemon gatekeeperd faz uma solicitação do serviço HAL IGatekeeper, que, por sua vez, alcança a TA Gatekeeper correspondente no TEE:

Fluxo do gatekeeper

Figura 1. Fluxo de dados de alto nível para autenticação pelo GateKeeper.

O daemon gatekeeperd dá às APIs do framework Android acesso ao HAL e participa do envio de relatórios de autenticações do dispositivo para o keystore. O daemon gatekeeperd é executado no próprio processo e é separado do servidor do sistema.

Implementação da HAL

O daemon gatekeeperd usa o HAL IGatekeeper para interagir com o TA do Gatekeeper subjacente para autenticação de senha. A implementação da TA do gatekeeper precisa ser capaz de assinar (inscrição) e verificar blobs. Todas as implementações precisam aderir ao formato padrão do token de autenticação (HardwareAuthToken) gerado em cada verificação de senha bem-sucedida. Para detalhes sobre o conteúdo e a semântica do HardwareAuthToken, consulte a definição de HardwareAuthToken.aidl.

As implementações do fornecedor do HAL IGatekeeper precisam implementar as funções enroll e verify:

  • O método enroll recebe um blob de senha, o assina e retorna a assinatura como um identificador. O blob retornado (de uma chamada para enroll) precisa ter a estrutura mostrada em system/gatekeeper/include/gatekeeper/password_handle.h.
  • A função verify precisa comparar a assinatura produzida pela senha fornecida e garantir que ela corresponda ao identificador de senha registrado.

A chave usada para registro e verificação nunca pode mudar e precisa ser rederivável em cada inicialização do dispositivo.

Trusty e outras implementações

O sistema operacional Trusty é o sistema operacional confiável de código aberto do Google para ambientes TEE e contém uma implementação aprovada do Gatekeeper. No entanto, qualquer SO TEE pode implementar o Gatekeeper, desde que o TEE tenha acesso a uma chave persistente com suporte de hardware e um relógio monótono e seguro que marque na suspensão.

O Trusty usa um sistema IPC interno para comunicar uma chave secreta compartilhada diretamente entre o KeyMint e a implementação do Trusty do Gatekeeper (o Trusty Gatekeeper). Esse segredo compartilhado é usado para assinar tokens de autenticação enviados ao Keystore para fornecer atestados de verificação de senha. O Trusty Gatekeeper solicita a chave do KeyMint para cada uso e não persiste nem armazena em cache o valor. As implementações podem compartilhar esse secret de qualquer maneira que não comprometa a segurança.

A chave HMAC usada para registrar e verificar senhas é derivada e mantida exclusivamente no Gatekeeper.

O Android oferece uma implementação genérica do Gatekeeper em C++, que exige apenas a adição de rotinas específicas do dispositivo para ser concluída. A implementação do Trusty é baseada nisso. Para implementar um gatekeeper do TEE com código específico do dispositivo para o TEE, consulte as funções e os comentários em system/gatekeeper/include/gatekeeper/gatekeeper.h. As principais responsabilidades de uma implementação em conformidade incluem:

  • Adesão ao HAL IGatekeeper.
  • Os tokens de autenticação retornados precisam ser formatados de acordo com a especificação HardwareAuthToken (descrita em HardwareAuthToken.aidl).
  • O gatekeeper do TEE precisa compartilhar uma chave HMAC com o KeyMint usando uma das seguintes opções:
    • Acordo secreto compartilhado:o gatekeeper pode participar da negociação por inicialização da chave HMAC implementando o HAL ISharedSecret. Isso exige que o Gatekeeper e o KeyMint tenham acesso a um segredo compartilhado comum.
    • Acesso direto:o Gatekeeper pode recuperar a chave HMAC do KeyMint usando um mecanismo de comunicação interprocesso interno do TEE, sob demanda ou no primeiro uso (armazenado em cache depois).

IDs seguros do usuário (SIDs)

Um SID do usuário é a representação do TEE de um usuário (sem conexão forte com um ID do usuário do Android). O SID é gerado com um gerador de números pseudoaleatórios criptográficos (PRNG, na sigla em inglês) sempre que um usuário registra uma nova senha sem fornecer uma anterior. Isso é conhecido como uma nova inscrição não confiável e normalmente acontece apenas quando um usuário define uma senha ou um padrão pela primeira vez.

Uma rematrícula confiável ocorre quando um usuário fornece uma senha anterior válida, como ao mudar a senha. Nesse caso, o SID do usuário é migrado para o novo identificador de senha, conservando as chaves vinculadas a ele.

O SID do usuário é incluído na autenticação HMAC com a senha no identificador de senha quando a senha é registrada.

Os SIDs do usuário são incluídos na HardwareAuthToken retornada pela função verify() e associadas a todas as chaves do Keystore vinculadas à autenticação. Para detalhes sobre o formato HardwareAuthToken e o Keystore, consulte Autenticação.

Como uma chamada não confiável para a função enroll() muda o SID do usuário, a chamada torna as chaves vinculadas a essa senha inúteis. Os invasores podem mudar a senha do dispositivo se controlarem o SO Android, mas eles destroem chaves sensíveis protegidas por raiz no processo.

Limitação de solicitações

O gatekeeper precisa ser capaz de limitar com segurança as tentativas de força bruta em uma credencial de usuário. Como mostrado em GatekeeperVerifyResponse.aidl, o HAL fornece um tempo limite em milissegundos. O tempo limite informa ao cliente para não chamar o Gatekeeper novamente até que o tempo limite expire. O Gatekeeper não deve atender às solicitações se houver um tempo limite pendente.

O gatekeeper precisa gravar um contador de falhas antes de verificar a senha de um usuário. Se a verificação de senha for bem-sucedida, o contador de falhas será limpo. Isso impede ataques que impedem o estrangulamento desativando o MMC (eMMC) integrado após emitir uma chamada verify. A função enroll também verifica a senha do usuário (se fornecida) e precisa ser limitada da mesma forma.

Se o dispositivo oferecer suporte, é altamente recomendável que o contador de falhas seja gravado no armazenamento seguro. Se o dispositivo não oferecer suporte à criptografia baseada em arquivos ou se o armazenamento seguro for muito lento, as implementações poderão usar o bloco de memória protegida contra repetição (RPMB, na sigla em inglês) diretamente.