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 AIDLIGateKeeperService, com base em uma implementação deIGatekeeperespecí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:
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
enrollusa um blob de senha, o assina e retorna a assinatura como um identificador. O blob retornado (de uma chamada paraenroll) precisa ter a estrutura mostrada emsystem/gatekeeper/include/gatekeeper/password_handle.h. - A função
verifyprecisa 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 emHardwareAuthToken.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).
- Acordo de secret compartilhado: o Gatekeeper pode participar da
negociação por inicialização da chave HMAC implementando a
HAL
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.