Keystore protegido por hardware

A disponibilidade de um ambiente de execução confiável (TEE) em um sistema em um chip (SoC) oferece aos dispositivos Android a oportunidade de fornecer serviços de segurança fortes e com suporte de hardware para o SO Android, serviços de plataforma e até mesmo apps de terceiros (na forma de extensões específicas do Android para a arquitetura de criptografia Java padrão. Consulte KeyGenParameterSpec).

Glossário

Confira uma visão geral rápida dos componentes do Keystore e das relações entre eles.

AndroidKeyStore
A API e o componente do framework Android usados por apps para acessar a funcionalidade Keystore. É uma implementação das APIs padrão da Java Cryptography Architecture, mas também adiciona extensões específicas do Android e consiste em código Java executado no próprio espaço de processo do app. O AndroidKeyStore atende às solicitações de comportamento do keystore encaminhando-as para o daemon do keystore.
daemon keystore
Um daemon do sistema Android que fornece acesso a todas as funcionalidades do Keystore por uma API Binder. Esse daemon é responsável por armazenar keyblobs criados pela implementação do KeyMint (ou Keymaster) subjacente, que contêm o material da chave secreta, criptografado para que o Keystore possa armazená-los, mas não usar nem revelar.
Serviço HAL do KeyMint
Um servidor AIDL que implementa a HAL IKeyMintDevice e fornece acesso à TA do KeyMint.
App confiável (TA) do KeyMint
Software executado em um contexto seguro, geralmente no TrustZone em um SoC ARM, que fornece todas as operações criptográficas seguras. Esse app tem acesso ao material de chave bruta e valida todas as condições de controle de acesso nas chaves antes de permitir o uso delas.
LockSettingsService
O componente do sistema Android responsável pela autenticação do usuário, tanto por senha quanto por impressão digital. Ele não faz parte do Keystore, mas é relevante porque o Keystore oferece suporte ao conceito de chaves vinculadas à autenticação: chaves que só podem ser usadas se o usuário tiver feito a autenticação. O LockSettingsService interage com o TA do Gatekeeper e do Fingerprint para receber tokens de autenticação, que ele fornece ao daemon do keystore e que são consumidos pelo TA do KeyMint.
TA do Gatekeeper
O componente em execução no ambiente seguro responsável por autenticar senhas de usuários e gerar tokens de autenticação usados para provar à TA KeyMint que uma autenticação foi feita para um usuário específico em um determinado momento.
TA de impressão digital
O componente em execução no ambiente seguro responsável por autenticar impressões digitais do usuário e gerar tokens de autenticação usados para provar à TA KeyMint que uma autenticação foi feita para um usuário específico em um determinado momento.

Arquitetura

A API Android Keystore e a HAL KeyMint subjacente fornecem um conjunto básico, mas adequado, de primitivos criptográficos para permitir a implementação de protocolos usando chaves controladas por acesso e com suporte de hardware.

A HAL do KeyMint é um serviço fornecido pelo OEM usado pelo serviço Keystore para fornecer serviços criptográficos protegidos por hardware. Para manter o material da chave privada seguro, as implementações de HAL não realizam operações sensíveis no espaço do usuário nem no espaço do kernel. Em vez disso, o serviço KeyMint HAL em execução no Android delega operações sensíveis a uma TA em execução em algum tipo de ambiente seguro, normalmente organizando e desorganizando solicitações em algum formato de transmissão definido pela implementação.

A arquitetura resultante é assim:

Acesso ao KeyMint

Figura 1. Acesso ao KeyMint.

A API HAL do KeyMint é de baixo nível, usada por componentes internos da plataforma e não exposta a desenvolvedores de apps. A API Java de nível superior disponível para apps é descrita no site de desenvolvedores Android.

Controle de acesso

O Android Keystore oferece um componente central para o armazenamento e uso de chaves criptográficas com suporte de hardware, tanto para apps quanto para outros componentes do sistema. Assim, o acesso a qualquer chave individual é normalmente limitado ao app ou componente do sistema que a criou.

Domínios de keystore

Para oferecer suporte a esse controle de acesso, as chaves são identificadas no Keystore com um descritor de chave. Esse descritor de chave indica um domínio a que o descritor pertence, além de uma identidade dentro desse domínio.

Os apps Android acessam o Keystore usando a Java Cryptography Architecture padrão, que identifica chaves com um alias de string. Esse método de identificação é mapeado internamente para o domínio APP do Keystore. O UID do autor da chamada também é incluído para diferenciar chaves de diferentes apps, impedindo que um app acesse as chaves de outro.

Internamente, o código dos frameworks também recebe um ID de chave numérico exclusivo depois que uma chave é carregada. Esse ID numérico é usado como identificador para descritores de chave no domínio KEY_ID. No entanto, o controle de acesso ainda é realizado: mesmo que um app descubra um ID de chave de outro app, ele não poderá usá-lo em circunstâncias normais.

No entanto, é possível que um app conceda o uso de uma chave a outro app (identificado por UID). Essa operação de concessão retorna um identificador exclusivo, que é usado como identificador para descritores de chave no domínio GRANT. O controle de acesso ainda é realizado: mesmo que um app de terceiros descubra o ID de concessão de uma chave do beneficiário, ele não poderá usá-lo.

O keystore também oferece suporte a dois outros domínios para descritores de chaves, que são usados para outros componentes do sistema e não estão disponíveis para chaves criadas por apps:

  • O domínio BLOB indica que não há um identificador para a chave no descritor de chave. Em vez disso, o descritor contém o keyblob e o cliente processa o armazenamento dele. Usado por clientes (por exemplo, vold) que precisam acessar o Keystore antes que a partição de dados seja montada.
  • O domínio SELINUX permite que componentes do sistema compartilhem chaves, com acesso controlado por um identificador numérico que corresponde a um rótulo do SELinux (consulte Política do SELinux para keystore_key).

Política do SELinux para keystore_key

Os valores de identificador usados para descritores de chave Domain::SELINUX são configurados no arquivo de política do SELinux keystore2_key_context. Cada linha nesses arquivos mapeia um número para um rótulo do SELinux. Por exemplo:

# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and
# Settings to share Keystore keys.
102            u:object_r:wifi_key:s0

Um componente que precisa de acesso à chave com ID 102 no domínio SELINUX precisa ter a política do SELinux correspondente. Por exemplo, para permitir que wpa_supplicant receba e use essas chaves, adicione a seguinte linha a hal_wifi_supplicant.te:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Os identificadores numéricos para chaves Domain::SELINUX são divididos em intervalos para oferecer suporte a diferentes partições sem colisões:

Partição Intervalo Arquivos de configuração
Sistema 0 ... 9.999 /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Sistema estendido 10.000 ... 19.999 /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
Produto 20.000 ... 29.999 /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
Fornecedor 30.000 ... 39.999 /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

Os seguintes valores específicos foram definidos para a partição do sistema:

ID do namespace Rótulo SEPolicy UID Descrição
0 su_key N/A Chave de superusuário. Usado apenas para testes em builds userdebug e eng. Não relevante em builds de usuário.
1 shell_key N/A Namespace disponível para o shell. Usado principalmente para testes, mas também pode ser usado em builds de usuários na linha de comando.
100 vold_key N/A Destinado ao uso pelo vold.
101 odsign_key N/A Usado pelo daemon de assinatura no dispositivo.
102 wifi_key AID_WIFI(1010) Usado pelo subsistema Wi-Fi do Android, incluindo wpa_supplicant.
103 locksettings_key N/A Usado por LockSettingsService
120 resume_on_reboot_key AID_SYSTEM(1000) Usado pelo servidor do sistema Android para oferecer suporte à retomada na reinicialização.

Vetores de acesso

O Keystore permite controlar quais operações podem ser realizadas em uma chave, além de controlar o acesso geral a ela. As permissões keystore2_key estão descritas no arquivo KeyPermission.aidl.

Permissões do sistema

Além dos controles de acesso por chave descritos em Política do SELinux para keystore_key, a tabela a seguir descreve outras permissões do SELinux necessárias para realizar várias operações de sistema e manutenção:

Permissão Significado
add_auth Necessário para adicionar tokens de autenticação ao Keystore. Usado por provedores de autenticação, como Gatekeeper ou BiometricManager.
clear_ns Obrigatório para excluir todas as chaves em um namespace específico. Usado como uma operação de manutenção quando os apps são desinstalados.
list Necessário para o sistema enumerar chaves por várias propriedades, como propriedade ou se elas estão vinculadas à autenticação. Essa permissão não é necessária para autores de chamadas que enumeram os próprios namespaces (cobertos pela permissão get_info).
lock Necessário para notificar o keystore de que o dispositivo foi bloqueado, o que, por sua vez, remove superchaves para garantir que as chaves vinculadas à autenticação não estejam disponíveis.
unlock Necessário para notificar o keystore de que o dispositivo foi desbloqueado, restaurando o acesso às superchaves que protegem as chaves vinculadas à autenticação.
reset Necessário para redefinir o Keystore para a configuração original, excluindo todas as chaves que não são vitais para o funcionamento do SO Android.

Histórico

No Android 5 e versões anteriores, o Android tinha uma API de serviços criptográficos simples e com suporte de hardware, fornecida pelas versões 0.2 e 0.3 da camada de abstração de hardware (HAL, na sigla em inglês) do Keymaster. O keystore forneceu operações de assinatura e verificação digitais, além da geração e importação de pares de chaves de assinatura assimétricas. Isso já foi implementado em muitos dispositivos, mas há muitas metas de segurança que não podem ser facilmente alcançadas apenas com uma API de assinatura. O Android 6.0 estendeu a API Keystore para oferecer uma gama mais ampla de recursos.

Android 6.0

No Android 6.0, o Keymaster 1.0 adicionou primitivos criptográficas simétricas, AES e HMAC, além de um sistema de controle de acesso para chaves com suporte de hardware. Os controles de acesso são especificados durante a geração da chave e aplicados durante todo o ciclo de vida dela. As chaves podem ser restritas para serem usadas somente após a autenticação do usuário e apenas para fins especificados ou com parâmetros criptográficos especificados.

Além de expandir o intervalo de primitivas criptográficas, o Keystore no Android 6.0 adicionou o seguinte:

  • Um esquema de controle de uso para limitar o uso de chaves e reduzir o risco de comprometimento da segurança devido ao uso indevido de chaves.
  • Um esquema de controle de acesso para restringir chaves a usuários, clientes e um período definidos.

Android 7.0

No Android 7.0, o Keymaster 2 adicionou suporte para atestado de chaves e vinculação de versão.

O atestado de chave fornece certificados de chave pública que contêm uma descrição detalhada da chave e dos controles de acesso dela, para tornar a existência da chave em hardware seguro e a configuração dela verificáveis remotamente.

O vínculo de versão vincula chaves ao sistema operacional e à versão do nível de patch. Isso garante que um invasor que descobrir uma falha em uma versão antiga do sistema ou do software TEE não possa reverter um dispositivo para a versão vulnerável e usar chaves criadas com a versão mais recente. Além disso, quando uma chave com uma determinada versão e nível de patch é usada em um dispositivo que foi atualizado para uma versão ou nível de patch mais recente, a chave é atualizada antes de poder ser usada, e a versão anterior da chave é invalidada. À medida que o dispositivo é atualizado, as chaves avançam junto com ele, mas qualquer reversão para uma versão anterior faz com que as chaves fiquem inutilizáveis.

Android 8.0

No Android 8.0, o Keymaster 3 fez a transição da HAL de estrutura C de estilo antigo para a interface HAL C++ gerada de uma definição na nova linguagem de definição de interface de hardware (HIDL). Como parte da mudança, muitos dos tipos de argumento foram alterados, embora os tipos e métodos tenham uma correspondência individual com os tipos antigos e os métodos de estrutura HAL.

Além dessa revisão de interface, o Android 8.0 estendeu o recurso de atestado do Keymaster 2 para oferecer suporte ao atestado de ID. A declaração de ID oferece um mecanismo limitado e opcional para declarar identificadores de hardware, como número de série do dispositivo, nome do produto e ID do smartphone (IMEI ou MEID). Para implementar essa adição, o Android 8.0 mudou o esquema de atestado ASN.1 para adicionar o atestado de ID. As implementações do Keymaster precisam encontrar uma maneira segura de recuperar os itens de dados relevantes, bem como definir um mecanismo para desativar o recurso de forma segura e permanente.

Android 9

No Android 9, as atualizações incluíam:

  • Atualização para Keymaster 4
  • Suporte para elementos seguros incorporados
  • Suporte para importação de chave segura
  • Suporte para criptografia 3DES
  • Mudanças na vinculação de versão para que boot.img e system.img tenham versões definidas separadamente para permitir atualizações independentes

Android 10

O Android 10 introduziu a versão 4.1 da HAL do Keymaster, que adicionou:

  • Suporte para chaves que só podem ser usadas quando o dispositivo está desbloqueado
  • Suporte para chaves que só podem ser usadas nas primeiras etapas de inicialização
  • Suporte opcional para chaves de armazenamento encapsuladas em hardware
  • Suporte opcional para atestado exclusivo do dispositivo no StrongBox

Android 12

O Android 12 introduziu a nova HAL KeyMint, que substitui a HAL Keymaster mas oferece funcionalidade semelhante. Além de todos os recursos acima, a HAL KeyMint também inclui:

  • Suporte para contrato de chave ECDH
  • Suporte para chaves de atestado especificadas pelo usuário
  • Suporte para chaves com um número limitado de usos

O Android 12 também inclui uma nova versão do daemon do sistema keystore, reescrita em Rust e conhecida como keystore2

Android 13

O Android 13 adicionou a v2 da HAL KeyMint, que inclui suporte para Curve25519 para assinatura e acordo de chaves.