O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Keystore com suporte de hardware

A disponibilidade de um ambiente de execução confiável em um sistema em um chip (SoC) oferece uma oportunidade para os dispositivos Android fornecerem serviços de segurança robustos com suporte de hardware para o sistema operacional Android, para serviços de plataforma e até mesmo para aplicativos de terceiros. Desenvolvedores que buscam as extensões específicas do Android deve ir para android.security.keystore .

Antes do Android 6.0, o Android já tinha uma API simples de serviços de criptografia apoiada por hardware, fornecida pelas versões 0.2 e 0.3 do Keymaster Hardware Abstraction Layer (HAL). A Keystore fornecia operações de assinatura e verificação digital, além de 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 com apenas uma API de assinatura. Keystore no Android 6.0 estende a API Keystore para fornecer uma gama mais ampla de recursos.

No Android 6.0, Keystore acrescentou primitivas simétricas criptografia , AES e HMAC, e um sistema de controle de acesso para as chaves lastreados em hardware. Os controles de acesso são especificados durante a geração da chave e aplicados durante o tempo de vida da chave. As chaves podem ser restritas para uso somente após a autenticação do usuário e apenas para propósitos específicos ou com parâmetros criptográficos especificados. Para mais informações, consulte os autorização Tags Porta e Funções páginas.

Além de expandir a gama de primitivas criptográficas, o Keystore no Android 6.0 adiciona o seguinte:

  • Um esquema de controle de uso para permitir que o uso de chaves seja limitado, para mitigar o risco de comprometimento da segurança devido ao uso indevido de chaves
  • Um esquema de controle de acesso para permitir a restrição de chaves para usuários e clientes especificados e um intervalo de tempo definido

No Android 7.0, o Keymaster 2 adicionou suporte para atestado de chave e vinculação de versão. Atestado Key fornece certificados de chaves públicas que contêm uma descrição detalhada da chave e seus controles de acesso, para tornar a existência da chave em hardware seguro e sua configuração remotamente verificável.

Vinculativo versão chaves liga-se ao sistema operacional e versão do nível de patch. Isso garante que um invasor que descobrir uma fraqueza em uma versão antiga do sistema ou software TEE não possa reverter um dispositivo para a versão vulnerável e usar as 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. Conforme o dispositivo é atualizado, as chaves "movem-se" para frente junto com o dispositivo, mas qualquer reversão do dispositivo para uma versão anterior faz com que as teclas fiquem inutilizáveis.

No Android 8.0, o Keymaster 3 fez a transição da antiga estrutura C Hardware Abstraction Layer (HAL) para a interface C ++ HAL gerada a partir de uma definição na nova Hardware Interface Definition Language (HIDL). Como parte da mudança, muitos dos tipos de argumento mudaram, embora os tipos e métodos tenham uma correspondência um a um com os tipos antigos e os métodos de estrutura HAL. Veja o Funções página para mais detalhes.

Além desta revisão interface, Android 8.0 estende recurso atestado de Keymaster 2 para suporte atestado ID . O atestado de ID fornece um mecanismo limitado e opcional para atestar fortemente os identificadores de hardware, como número de série do dispositivo, nome do produto e ID do telefone (IMEI / MEID). Para implementar essa adição, altere o esquema de atestado ASN.1 para adicionar 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.

No Android 9, as atualizações incluem:

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

Glossário

Aqui está uma visão geral rápida dos componentes do Keystore e seus relacionamentos.

AndroidKeystore é a API Framework Android e componente usado por aplicativos para acessar a funcionalidade Keystore. Ele é implementado como uma extensão das APIs de arquitetura de criptografia Java padrão e consiste em código Java executado no próprio espaço de processo do aplicativo. AndroidKeystore cumpre as solicitações de aplicativos para o comportamento do armazenamento de chaves, encaminhando-os para o daemon de armazenamento de chaves.

O daemon de armazenamento de chaves é um daemon do sistema Android que fornece acesso a todas as funcionalidades Keystore através de uma API Binder . É responsável por armazenar "key blobs", que contêm o material da chave secreta real, criptografado para que o Keystore possa armazená-lo, mas não usá-lo ou revelá-lo.

keymasterd é um servidor HIDL que fornece acesso ao Keymaster TA. (Este nome não é padronizado e serve para fins conceituais.)

Keymaster TA (aplicativo confiável) é o software executado em um contexto seguro, na maioria das vezes em TrustZone em um ARM SoC, que fornece todas as operações do armazenamento de chaves seguras, tem acesso ao material de chave cru, valida todas as condições de controle de acesso em chaves etc.

LockSettingsService é o componente do sistema Android responsável pela autenticação de usuário, tanto senha e impressão digital. Não faz parte do Keystore, mas é relevante porque muitas operações de chave do Keystore exigem autenticação do usuário. LockSettingsService interage com o gatekeeper e TA TA impressão digital para obter sinais de autenticação, o qual fornece para o daemon armazenamento de chave, e que em última análise são consumidas pela aplicação Keymaster TA.

Gatekeeper TA (aplicação de confiança) é outra componente que funciona no contexto de segurança, que é responsável pela autenticação do utilizador e palavras-passe geração de autenticação fichas usado para provar ao Keymaster TA que uma autenticação foi feito por um utilizador em particular num ponto particular no tempo.

Impressão digital TA (aplicação de confiança) é outra componente que funciona no contexto seguro, que é responsável pela autenticação do utilizador e gerar impressões digitais de autenticação fichas usado para provar ao Keymaster TA que uma autenticação foi feito por um utilizador em particular num ponto particular no tempo.

Arquitetura

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

O Keymaster HAL é uma biblioteca fornecida por OEM, carregável dinamicamente, usada pelo serviço Keystore para fornecer serviços criptográficos suportados por hardware. Para manter as coisas seguras, as implementações HAL não executam nenhuma operação sensível no espaço do usuário, ou mesmo no espaço do kernel. As operações confidenciais são delegadas a um processador seguro alcançado por meio de alguma interface do kernel. A arquitetura resultante é semelhante a esta:

Acesso ao Keymaster

Figura 1. Acesso à Keymaster

Em um dispositivo Android, o "cliente" do Keymaster HAL consiste em várias camadas (por exemplo, aplicativo, estrutura, daemon de armazenamento de chave), mas isso pode ser ignorado para os fins deste documento. Isso significa que a API Keymaster HAL descrita é de baixo nível, usada por componentes internos da plataforma e não é exposta a desenvolvedores de aplicativos. A API de nível superior é descrito no site do desenvolvedor Android .

O objetivo do Keymaster HAL não é implementar os algoritmos sensíveis à segurança, mas apenas para empacotar e desempacotar solicitações para o mundo seguro. O formato do fio é definido pela implementação.

Compatibilidade com versões anteriores

O Keymaster 1 HAL é completamente incompatível com os HALs lançados anteriormente, por exemplo, Keymaster 0.2 e 0.3. Para facilitar a interoperabilidade em dispositivos com Android 5.0 e anteriores lançados com os HALs Keymaster mais antigos, o Keystore fornece um adaptador que implementa o HAL Keymaster 1 com chamadas para a biblioteca de hardware existente. O resultado não pode fornecer toda a gama de funcionalidades do Keymaster 1 HAL. Em particular, ele suporta apenas algoritmos RSA e ECDSA, e toda a aplicação de autorização de chave é executada pelo adaptador, no mundo não seguro.

Keymaster 2 simplificada ainda mais a interface de HAL, removendo os get_supported_* métodos e permitindo que o finish() método para aceitar a entrada. Isso reduz o número de viagens de ida e volta ao TEE nos casos em que a entrada está disponível de uma só vez e simplifica a implementação da descriptografia AEAD.

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). A implementação HAL novo estilo é criado por subclasse o gerado IKeymasterDevice classe e da implementação dos métodos virtuais puros. Como parte da mudança, muitos dos tipos de argumento foram alterados, embora os tipos e métodos tenham uma correspondência um-para-um com os tipos antigos e os métodos de estrutura HAL.

Visão geral do HIDL

O Hardware Interface Definition Language (HIDL) fornece um mecanismo independente de linguagem de implementação para especificar interfaces de hardware. O conjunto de ferramentas HIDL atualmente oferece suporte à geração de interfaces C ++ e Java. Espera-se que a maioria dos implementadores de Trusted Execution Environment (TEE) ache o conjunto de ferramentas C ++ mais conveniente, portanto, este documento discute apenas a representação C ++.

As interfaces HIDL consistem em um conjunto de métodos, expressos como:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Existem vários tipos predefinidos e os HALs podem definir novos tipos enumerados e de estrutura. Para mais detalhes sobre HIDL, consulte a seção de referência .

Um exemplo de método do Keymaster 3 IKeymasterDevice.hal é:

generateKey(vec<KeyParameter> keyParams)
        generates(ErrorCode error, vec<uint8_t> keyBlob,
                  KeyCharacteristics keyCharacteristics);

Isso é o equivalente ao seguinte do HAL keymaster2:

keymaster_error_t (*generate_key)(
        const struct keymaster2_device* dev,
        const keymaster_key_param_set_t* params,
        keymaster_key_blob_t* key_blob,
        keymaster_key_characteristics_t* characteristics);

Na versão HIDL, o dev argumento é removido, porque é implícito. O params argumento já não é uma estrutura que contém um apontador fazendo referência a um conjunto de key_parameter_t objectos, mas um vec (vector) contendo KeyParameter objectos. Os valores de retorno são listadas no " generates " cláusula, incluindo um vector de uint8_t valores para o blob chave.

O método virtual C ++ gerado pelo compilador HIDL é:

Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                         generateKey_cb _hidl_cb) override;

Onde generate_cb é um ponteiro de função definida como:

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                   const KeyCharacteristics& keyCharacteristics)>

Ou seja, generate_cb é uma função que recebe os valores de retorno listados na cláusula gerar. A classe de implementação HAL substitui essa generateKey método e chama o generate_cb ponteiro de função para retornar o resultado da operação para o chamador. Observe a chamada ponteiro de função é síncrono. O chamador chama generateKey e generateKey chama o ponteiro de função fornecido, que executa até a conclusão, retornando o controle para o generateKey implementação, que então retorna para o chamador.

Para um exemplo detalhado, consulte a implementação padrão em hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . A implementação padrão fornece compatibilidade com versões anteriores para dispositivos com HALS keymaster0, keymaster1 ou keymaster2 de estilo antigo.

Controle de acesso

A regra mais básica do controle de acesso do Keystore é que cada aplicativo tem seu próprio namespace. Mas para cada regra existe uma exceção. O Keystore possui alguns mapas codificados que permitem que certos componentes do sistema acessem certos outros espaços de nomes. Este é um instrumento muito simples, pois dá a um componente controle total sobre outro namespace. E depois há a questão dos componentes do fornecedor como clientes da Keystore. Atualmente, não temos como estabelecer um namespace para os componentes de um fornecedor, por exemplo, suplicante WPA.

Para acomodar os componentes do fornecedor e generalizar o controle de acesso sem exceções embutidas em código, o Keystore 2.0 introduz domínios e namespaces selinux.

Domínios de armazenamento de chaves

Com os domínios Keystore, podemos desacoplar os namespaces dos uids. Os clientes que acessam uma chave no armazenamento de chaves precisam especificar o domínio, o namespace e o alias que desejam acessar. Com base nessa tupla e na identidade do chamador, podemos determinar qual chave o chamador deseja acessar e se tem as permissões apropriadas.

Apresentamos cinco parâmetros de domínio que controlam como as chaves podem ser acessadas. Eles controlam a semântica do parâmetro de namespace do descritor de chave e como o controle de acesso é executado.

  • DOMAIN_APP : O domínio de aplicativo abrange o comportamento legado. O Java Keystore SPI usa esse domínio por padrão. Quando este domínio é usado, o argumento do namespace é ignorado e o uid do chamador é usado em seu lugar. O acesso a esse domínio é controlado pelo rótulo de armazenamento de chaves para a classe keystore_key na política do SELinux.
  • DOMAIN_SELINUX : Este domínio indica que o namespace tem uma etiqueta na política do SELinux. O parâmetro namespace é procurado e traduzido em um contexto de destino, e uma verificação de permissão é realizada para o chamando contexto SELinux para o keystore_key classe. Quando a permissão foi estabelecida para a operação fornecida, a tupla completa é usada para a pesquisa da chave.
  • DOMAIN_GRANT : O domínio concessão indica que o parâmetro namespace é um identificador de concessão. O parâmetro alias é ignorado. As verificações Selinux são realizadas quando a concessão é criada. O controle de acesso adicional verifica apenas se o uid do chamador corresponde ao uid dos beneficiários da concessão solicitada.
  • DOMAIN_KEY_ID : Este domínio indica que o parâmetro namespace é um ID de chave única. A chave em si pode ter sido criado com DOMAIN_APP ou DOMAIN_SELINUX . A verificação de permissão é realizada após o domain eo namespace foram carregados a partir do banco de dados chave da mesma forma como se o blob foi carregado pelo domínio, namespace, e tuple alias. A justificativa para o domínio de ID de chave é a continuidade. Ao acessar uma chave por apelido, as chamadas subsequentes podem operar em chaves diferentes, porque uma nova chave pode ter sido gerada ou importada e vinculada a este apelido. A identificação da chave, entretanto, nunca muda. Portanto, ao usar uma chave por id de chave após ter sido carregada do banco de dados de armazenamento de chaves usando o alias uma vez, pode-se ter certeza de que é a mesma chave, desde que a id de chave ainda exista. Essa funcionalidade não é exposta a desenvolvedores de aplicativos, em vez disso, é usada dentro do Android Keystore SPI para fornecer uma experiência mais consistente, mesmo quando usada simultaneamente de maneira insegura.
  • DOMAIN_BLOB : O domínio blob indica que o chamador administra o blob por si só. Isso é usado para clientes que precisam acessar o Keystore antes que a partição de dados seja montada. O blob de chave está incluído no blob campo do descritor de chave.

Usando o domínio SELinux, podemos fornecer aos componentes do fornecedor acesso a namespaces de armazenamento de chaves muito específicos que podem ser compartilhados por componentes do sistema, como a caixa de diálogo de configurações.

Política SELinux para keystore_key

Etiquetas de namespace são configurados usando o keystore2_key_context arquivo.
Cada linha nesses arquivos mapeia um ID de namespace numérico 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

Depois de configurar um novo namespace de chave dessa maneira, podemos dar acesso a ele adicionando uma política apropriada. Por exemplo, para permitir que wpa_supplicant para obter e utilizar as teclas no novo namespace poderíamos acrescentar a seguinte linha ao hal_wifi_supplicant.te :

allow hal_wifi_supplicant wifi_keys:keystore2_key { get, use };

Depois de configurar o novo namespace, o AndroidKeyStore pode ser usado quase como de costume. A única diferença é que o ID do namespace deve ser especificado. Para carregar e importar chaves de e para armazenamento de chaves, o ID de namespace é especificado usando o AndroidKeyStoreLoadStoreParameter . Por exemplo,

import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import java.security.KeyStore;

KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(new AndroidKeyStoreLoadStoreParameter(102));

Para gerar uma chave em um determinado espaço de nomes, o ID de namespace deve ser dada utilizando KeyGenParameterSpec.Builder#setNamespace():

import android.security.keystore.KeyGenParameterSpec;
KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder();
specBuilder.setNamespace(102);

Os seguintes arquivos de contexto podem ser usados ​​para configurar os namespaces do Keystore 2.0 SELinux. Cada partição tem um intervalo reservado diferente de 10.000 IDs de namespace para evitar colisões.

Partição Alcance 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
produtos 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

O cliente solicita a chave, solicitando o domínio SELinux eo namespace virtual desejado, aqui "wifi_keys" , pela sua identificação numérica.

Acima disso, os seguintes namespaces foram definidos. Onde eles substituem regras especiais, a tabela a seguir indica o UID ao qual eles costumavam corresponder.

ID do namespace Etiqueta SEPolicy UID Descrição
0 su_key N / D Chave de superusuário. Usado apenas para teste em builds userdebug e eng. Não é relevante nas compilações do usuário.
1 shell_key N / D Espaço de nomes disponível para shell. Principalmente usado para teste, mas também pode ser usado em compilações de usuário a partir da linha de comando.
100 vold_key N / D Destinado ao uso por Vold.
101 odsing_key N / D Usado pelo daemon de assinatura no dispositivo.
102 wfi_key AID_WIFI (1010) Usado pelo sistema wi-fi do Android, incluindo wpa_supplicant.
120 resume_on_reboot_key AID_SYSTEM (1000) Usado pelo servidor do sistema Android para dar suporte à retomada na reinicialização.

Vetores de acesso

A classe SELinux keystore_key envelheceu um pouco e algumas das permissões, tais como verify ou sign ter perdido seu significado. Aqui está o novo conjunto de permissões, keystore2_key , que Keystore 2.0 irá aplicar.

Permissão Significado
delete Verificado ao remover chaves do Keystore.
get_info Verificado quando os metadados de uma chave são solicitados.
grant O chamador precisa dessa permissão para criar uma concessão para a chave no contexto de destino.
manage_blob O chamador pode usar DOMAIN_BLOB sobre o dado namespace SELinux, gerindo assim blobs por si só. Isso é especialmente útil para Vold.
rebind Essa permissão controla se um alias pode ser religado para uma nova chave. Isso é necessário para a inserção e implica que a chave vinculada anteriormente será excluída. É basicamente uma permissão de inserção, mas captura melhor a semântica do armazenamento de chaves.
req_forced_op Os clientes com essa permissão podem criar operações não executáveis ​​e a criação da operação nunca falha, a menos que todos os slots de operação sejam ocupados por operações não executáveis.
update Necessário para atualizar o subcomponente de uma chave.
use Verificado ao criar uma operação Keymint que usa o material da chave, por exemplo, para assinatura, en / descriptografia.
use_dev_id Obrigatório ao gerar informações de identificação do dispositivo, como atestado de identificação do dispositivo.

Além disso, nós dividir um conjunto de permissões específicas de armazenamento de chaves não-chave na classe de segurança SELinux keystore2 :

Permissão Significado
add_auth Requerido pelo provedor de autenticação, como Gatekeeper ou BiometricsManager, para adicionar tokens de autenticação.
clear_ns Anteriormente, clear_uid, essa permissão permite que um não proprietário de um namespace exclua todas as chaves desse namespace.
list Requerido pelo sistema para enumerar chaves por várias propriedades, como propriedade ou limite de autenticação. Essa permissão não é exigida por chamadores que enumeram seus próprios namespaces. Isto é coberto pelo get_info permissão.
lock Essa permissão permite bloquear o Keystore, ou seja, despejar a chave mestra, de forma que as chaves de autenticação se tornem inutilizáveis ​​e não-criativas.
reset Esta permissão permite redefinir o Keystore para o padrão de fábrica, excluindo todas as chaves que não são vitais para o funcionamento do sistema operacional Android
unlock Esta permissão é necessária para tentar desbloquear a chave mestra para as chaves de autenticação.