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 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 tempo limite e um 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 de Binder em C++ no Android que contém uma lógica independente da plataforma que implementa a IGateKeeperService interface AIDL, 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 geralmente se comunica com o TA do Gatekeeper.
  • Aplicativo confiável (TA) 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 do serviço HAL IGatekeeper, que, por sua vez, chega ao TA do Gatekeeper correspondente no TEE:

Fluxo de gatekeeper

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

O daemon gatekeeperd oferece às APIs do framework do Android acesso ao HAL e participa da geração de relatórios de autenticações de dispositivos para o Keystore. O daemon gatekeeperd é executado no próprio processo e é separado do servidor do sistema.

Implementação de HAL

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

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

  • O método enroll usa um blob de senha, 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 muda e precisa ser derivada novamente 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 um relógio seguro e monotônico que funcione em suspensão.

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

A chave HMAC usada para registrar e verificar senhas é derivada e mantida apenas 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 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 compatível incluem:

  • Adesão ao HAL IGatekeeper.
  • Os tokens de autenticação retornados precisam ser formatados de acordo com a HardwareAuthToken especificação (descrita em Autenticação).
  • O Gatekeeper TEE precisa ser capaz de compartilhar uma chave HMAC com o KeyMint, solicitando a chave por um IPC TEE sob demanda ou mantendo um cache válido do valor em todos os momentos.

IDs seguros do usuário (SIDs)

Um SID do usuário é a representação de um usuário no TEE (sem conexão forte com um ID de usuário do Android). O SID é gerado com um gerador de números pseudoaleatórios criptográficos (PRNG) 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 acontece apenas quando um usuário define uma senha ou padrão pela primeira vez.

Um novo registro 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 no HardwareAuthToken retornado pela verify() função e associados a todas as chaves do Keystore vinculadas à autenticação. Para mais 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 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. Conforme mostrado em GatekeeperVerifyResponse.aidl, o HAL permite retornar um tempo limite em milissegundos. O tempo limite informa ao cliente para não chamar o Gatekeeper novamente até que o tempo limite tenha expirado. O Gatekeeper não deve atender 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 evita ataques que impedem a limitação desativando o MMC incorporado (eMMC) 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 maneira.

Se o dispositivo for compatível, é altamente recomendável que o contador de falhas seja gravado no armazenamento seguro. Se o dispositivo não for compatível com a criptografia baseada em arquivo ou se o armazenamento seguro for muito lento, as implementações poderão usar o bloco de memória protegido contra repetição (RPMB) diretamente.