Gatekeeper

O subsistema Gatekeeper realiza a autenticação de padrão/senha do dispositivo em um ambiente de execução confiável (TEE, na sigla em inglês). O Gatekeeper registra e verifica senhas usando uma chave secreta com suporte de hardware. Além disso, o Gatekeeper limita as tentativas de verificação com falha consecutivas e precisa recusar solicitações de serviço com base em um determinado tempo limite e em um determinado número de tentativas com falha 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 de hardware. Ou seja, um token de autenticação do Gatekeeper notifica o Keystore de que as 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 do Gatekeeper): um serviço do Binder em C++ no Android que contém uma lógica independente de plataforma que implementa a interface AIDL IGateKeeperService, com base em uma implementação de IGatekeeper específica do fornecedor.
  • 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 de HAL é executado no Android, mas a funcionalidade principal do Gatekeeper precisa ser executada em um ambiente seguro. Por isso, ele geralmente se comunica com o TA do Gatekeeper.
  • Aplicativo confiável (TA, na sigla em inglês) do Gatekeeper: 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 (pelo Binder) que chega ao daemon gatekeeperd no SO Android. O daemon gatekeeperd faz uma solicitação ao serviço HAL IGatekeeper, que, por sua vez, chega ao Gatekeeper TA correspondente no TEE:

Fluxo do assistente

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

O daemon gatekeeperd dá às APIs do framework do Android acesso à HAL e participa da geração 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 a HAL IGatekeeper para interagir com o TA do Gatekeeper para autenticação de senha. A implementação da TA do Gatekeeper precisa ser capaz de assinar (registrar) e verificar blobs. Todas as implementações precisam seguir o 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 da HAL IGatekeeper precisam implementar as funções enroll e verify:

  • O método enroll usa 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 registrar e verificar nunca pode mudar e precisa ser rederivável em cada inicialização do dispositivo.

Trusty e outras implementações

O sistema operacional Trusty é o SO 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 protegida por hardware persistente e a um relógio monotônico seguro que funcione em suspensão.

O Trusty usa um sistema de IPC interno para comunicar uma chave secreta compartilhada diretamente entre o KeyMint (anteriormente Keymaster) e a implementação do Trusty do Gatekeeper (o Trusty Gatekeeper). Esse secret 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 requer 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 de TEE com código específico do dispositivo para seu 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:

  • Aderência à HAL de 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 ser capaz de compartilhar uma chave HMAC com o KeyMint usando uma das seguintes opções:
    • Acordo de secret compartilhado: o Gatekeeper pode participar da negociação por inicialização da chave HMAC implementando a HAL ISharedSecret. Isso exige que o Gatekeeper e o KeyMint tenham acesso a um segredo pré-compartilhado comum.
    • Acesso direto: o Gatekeeper pode recuperar a chave HMAC do KeyMint usando um mecanismo de comunicação entre processos interno do TEE, sob demanda ou no primeiro uso (armazenado em cache depois disso).

IDs seguros de usuário (SIDs)

Um SID de 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 um novo registro não confiável e normalmente só acontece quando um usuário define uma senha ou um padrão pela primeira vez.

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

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

Os SIDs do usuário são incluídos no HardwareAuthToken retornado pela função verify() e associados 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, ela inutiliza as chaves vinculadas a essa senha. 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, a HAL permite retornar um tempo limite em milissegundos. O tempo limite informa ao cliente que ele não deve chamar o Gatekeeper novamente até que o tempo limite tenha decorrido. O Gatekeeper não deve atender a solicitações se houver um tempo limite pendente.

O Gatekeeper precisa gravar um contador de falhas antes de verificar uma senha de usuário. Se a verificação de senha for bem-sucedida, o contador de falhas será apagado. Isso evita ataques que impedem a limitação desativando o MMC incorporado (eMMC) depois de emitir uma chamada verify. A função enroll também verifica a senha do usuário (se fornecida) e precisa ser limitada da mesma maneira.

Se houver suporte no dispositivo, é altamente recomendável que o contador de falhas seja gravado no armazenamento seguro. Se o dispositivo não for compatível com criptografia baseada em arquivos ou se o armazenamento seguro for muito lento, as implementações poderão usar o Replay Protected Memory Block (RPMB) diretamente.