A disponibilidade de um ambiente de execução confiável (TEE, na sigla em inglês) em um sistema em um chip
(SoC, na sigla em inglês) oferece uma oportunidade para que os dispositivos Android forneçam serviços de segurança robustos 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 Java Cryptography Architecture padrão,
consulte
KeyGenParameterSpec).
Glossário
Confira uma visão geral rápida dos componentes do Keystore e das relações deles.
AndroidKeyStore- A API e o componente do framework do Android usados
por apps para acessar a funcionalidade do Keystore. É uma implementação das
APIs Java Cryptography Architecture padrão, 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.
AndroidKeyStoreatende às solicitações de comportamento do Keystore encaminhando-as ao daemon do Keystore. - daemon do Keystore
- Um daemon do sistema Android que fornece acesso a toda a funcionalidade do Keystore por meio de 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 ou revelar.
- Serviço HAL do KeyMint
- Um servidor AIDL que implementa
a
IKeyMintDeviceHAL, fornecendo acesso ao TA do KeyMint subjacente. - App confiável do KeyMint (TA)
- 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 da 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 sido autenticado.
LockSettingsServiceinterage com o TA do Gatekeeper e o TA de impressão digital 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 executado no ambiente seguro que é responsável por autenticar senhas de usuários e gerar tokens de autenticação usados para comprovar ao TA do KeyMint que uma autenticação foi feita para um usuário específico em um determinado momento.
- TA de impressão digital
- O componente executado no ambiente seguro que é responsável por autenticar impressões digitais de usuários e gerar tokens de autenticação usados para comprovar ao TA do 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 do KeyMint subjacente fornecem um conjunto básico, mas adequado, de primitivas criptográficas 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 com suporte de 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 ou mesmo no espaço do kernel. Em vez disso, o serviço HAL do KeyMint executado no Android delega operações sensíveis a um TA executado em algum tipo de ambiente seguro, normalmente organizando e desorganizando solicitações em algum formato de fio definido pela implementação.
A arquitetura resultante é assim:
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 fornece 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 criou a chave.
Domínios do 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, juntamente com 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 desambiguar chaves de diferentes apps, impedindo que um app acesse as chaves de outro.
Internamente, o código de 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 para a 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 um app diferente (conforme identificado pelo UID). Essa operação de concessão retorna um identificador exclusivo, que é usado como identificador para descritores de chave no domínio GRANT. Novamente, o controle de acesso ainda é realizado: mesmo que um terceiro app descubra o ID de concessão para a chave de um beneficiário, ele não poderá usá-lo.
O Keystore também oferece suporte a outros dois domínios para descritores de chave, que são usados para outros componentes do sistema e não estão disponíveis para chaves criadas por apps:
- O domínio
BLOBindica que não há identificador para a chave no descritor de chave. Em vez disso, o descritor de chave contém o próprio keyblob e o cliente processa o armazenamento do keyblob. Isso é usado por clientes (por exemplo,vold) que precisam acessar o Keystore antes que a partição de dados seja montada. - O domínio
SELINUXpermite que os componentes do sistema compartilhem chaves, com acesso regido por um identificador numérico que corresponde a um rótulo SELinux (consulte a política SELinux para keystore_key).
Política SELinux para keystore_key
Os valores de identificador usados para descritores de chave Domain::SELINUX são configurados no arquivo de política SELinux keystore2_key_context.
Cada linha nesses arquivos mapeia um número para um rótulo 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 o ID 102 no domínio SELINUX precisa ter a política 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:
| Código do namespace | Rótulo SEPolicy | UID | Descrição |
|---|---|---|---|
| 0 | su_key |
N/A | Chave de superusuário. Usada 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 shell. Usado principalmente para testes, mas também pode ser usado em builds de usuário 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 uma chave. As keystore2_key
permissões são descritas no
arquivo KeyPermission.aidl.
Permissões do sistema
Além dos controles de acesso por chave descritos na política SELinux para keystore_key, a seguinte tabela descreve outras permissões 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 o Gatekeeper ou BiometricManager. |
clear_ns
|
Necessá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 que o sistema enumere 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 as 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 o padrão de fábrica, excluindo todas as chaves que não são essenciais 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 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 digital, além da geração e importação de pares de chaves de assinatura assimétricas. Isso já está implementado em muitos dispositivos, mas há muitos objetivos de segurança que não podem ser alcançados facilmente apenas com uma API de assinatura. O Android 6.0 estendeu a API Keystore para fornecer uma gama mais ampla de recursos.
Android 6.0
No Android 6.0, o Keymaster 1.0 adicionou primitivas criptográficas simétricas, AES e HMAC, e um sistema de controle de acesso para chaves com suporte de hardware. Os controles de acesso são especificados durante a geração de chaves e aplicados durante o ciclo de vida da chave. As chaves podem ser restritas para serem usadas somente depois que o usuário for autenticado 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 permitir que o uso de chaves seja limitado, para mitigar o risco de comprometimento de segurança devido ao uso indevido de chaves
- Um esquema de controle de acesso para permitir a restrição de chaves a usuários, clientes e um período definido
Android 7.0
No Android 7.0, o Keymaster 2 adicionou suporte para atestado de chave 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.
A vinculação de versão vincula chaves ao sistema operacional e à versão do nível de patch. Isso garante que um invasor que descobre uma vulnerabilidade 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 o dispositivo, mas qualquer reversão do dispositivo 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 a partir de uma definição na nova linguagem de definição de interface de hardware (HIDL, na sigla em inglês). Como parte da mudança, muitos dos tipos de argumentos foram alterados, embora os tipos e métodos tenham uma correspondência um para um com os tipos antigos e os métodos de struct 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. O atestado de ID fornece um mecanismo limitado e opcional para atestar fortemente identificadores de hardware, como número de série do dispositivo, nome do produto e ID do telefone (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íram:
- Atualização para o 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.imgesystem.imgtenham 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 nos estágios de inicialização antecipada
- Suporte opcional para chaves de armazenamento encapsuladas por hardware
- Suporte opcional para atestado exclusivo do dispositivo no StrongBox
Android 12
O Android 12 introduziu a nova HAL do KeyMint, que substitui a HAL do Keymaster, mas oferece funcionalidades semelhantes. Além de todos os recursos acima, a HAL do KeyMint também inclui:
- Suporte para acordo 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 do KeyMint, que inclui suporte ao Curve25519 para assinatura e acordo de chave.