Keystore protegido por hardware

A disponibilidade de um ambiente de execução confiável em um sistema em um chip (SoC) oferece aos dispositivos Android a oportunidade de oferecer serviços de segurança avançados para o SO Android, para serviços de plataforma e até e apps de terceiros. Os desenvolvedores que buscam as extensões específicas do Android devem para android.security.keystore.

Antes do Android 6.0, o Android já tinha uma criptografia simples com suporte de hardware API de serviços, fornecida pelas versões 0.2 e 0.3 do Keymaster Hardware camada de abstração (HAL). Verificação e assinatura digital fornecidas pelo keystore operações, além da geração e importação de pares de chaves de assinatura assimétrica. Isso é já implementada em muitos dispositivos, mas há muitas metas de segurança que pode ser alcançado facilmente com apenas uma API de assinatura. Keystore no Android 6.0 estendemos a API Keystore para oferecer uma gama mais ampla de recursos.

No Android 6.0, o Keystore foi adicionado primitivas criptográficas simétricas (link em inglês), AES e HMAC, além de um sistema de controle de acesso para chaves protegidas por hardware. Acesso são especificados durante a geração de chaves e aplicados durante o ciclo de vida a chave. As chaves podem ser restritas para uso somente após o usuário ser autenticados e somente para fins específicos ou com configurações parâmetros. Para mais informações, consulte a Tags de autorização e Funções.

Além de expandir a gama de primitivas criptográficas, o Keystore na O Android 6.0 adicionou o seguinte:

  • Um esquema de controle de uso para permitir que o uso da chave seja limitado, para reduzir o risco de comprometimento da segurança devido ao uso indevido de chaves
  • Um esquema de controle de acesso para ativar a restrição de chaves a usuários específicos clientes e um período definido

No Android 7.0, o Keymaster 2 adicionou suporte a atestados de chaves e versões vinculação. Atestado de chaves fornece certificados de chave pública que contêm uma descrição detalhada da e os controles de acesso dela, para tornar a existência da chave em hardware seguro e que sua configuração possa ser verificada remotamente.

Vinculação de versões vincula as chaves ao sistema operacional e à versão em nível de patch. Isso garante que um invasor que descobre uma fraqueza em uma versão antiga do sistema ou O software TEE não pode reverter um dispositivo para a versão vulnerável e usar chaves criado com a versão mais recente. Além disso, quando uma chave com determinada versão e o nível do patch é usado em um dispositivo que foi atualizado para uma versão mais recente. ou de patch, a chave será atualizada antes de ser usada, e a versão anterior versão da chave invalidada. À medida que o dispositivo é atualizado, as teclas fazem uma "catraca" com o dispositivo, mas qualquer reversão do dispositivo para uma versão inutilizável faz com que as chaves não possam ser usadas.

No Android 8.0, o Keymaster 3 fez a transição do hardware de estrutura C tradicional. Camada de abstração (HAL) para a interface HAL do C++ gerada a partir 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 mudaram, embora os tipos e métodos tenham uma relação correspondência com os tipos antigos e os métodos struct da HAL. Consulte a Funções para mais informações detalhes.

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

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

  • Atualizar para Keymaster 4 (link em inglês)
  • Suporte para elementos de segurança incorporados
  • Suporte à importação de chaves seguras
  • Suporte à criptografia 3DES
  • Mudanças na vinculação de versões para que boot.img e system.img tenham defina versões separadamente para permitir atualizações independentes

Glossário

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

AndroidKeystore é a API Android Framework e o componente usado. por apps para acessar a funcionalidade do keystore. Ele é implementado como uma extensão da APIs padrão de arquitetura de criptografia Java e consiste em código Java que é executada no próprio espaço de processo do app. AndroidKeystore atende aos requisitos do app solicitações para o comportamento do keystore encaminhando-as para o daemon do keystore.

O daemon do keystore é um daemon do sistema Android que fornece acesso a toda a funcionalidade do Keystore por uma API Binder. Ele é responsável por armazenar "blobs de chaves", que contêm o material real da chave secreta, criptografado para que o Keystore possa armazená-lo, mas usar ou revelar.

keymasterd é um servidor HIDL que fornece acesso à Keymaster TA. Esse nome não foi padronizado e tem fins conceituais.

O Keymaster TA (aplicativo confiável) é o software executado em um contexto seguro, geralmente no TrustZone em um SoC ARM, que fornece todos os operações seguras de Keystore, tem acesso à matéria bruta da chave, valida todas as condições de controle de acesso nas chaves etc.

LockSettingsService é o componente do sistema Android responsável para autenticação de usuário, com senha e impressão digital. Não faz parte Keystore, mas relevante porque muitas operações de chaves do Keystore exigem que o usuário autenticação. LockSettingsService interage com a recepção TA e Impressão digital para obter tokens de autenticação, que são fornecidos ao e que são consumidos pelo Keymaster TA para o aplicativo.

O Gatekeeper TA (aplicativo confiável) é outro componente. em execução no contexto seguro, que é responsável por autenticar usuários senhas e gerar tokens de autenticação usados para comprovar ao Keymaster TA que uma autenticação foi feita para um determinado usuário em um ponto específico no tempo de resposta.

O impressão digital TA (aplicativo confiável) é outro componente em execução no contexto seguro, responsável por autenticar usuários impressões digitais e gerar tokens de autenticação usados para comprovar para o Keymaster TA de que uma autenticação foi feita para um determinado usuário em um ponto específico com o tempo.

Arquitetura

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

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

Acesso ao Keymaster

Figura 1. Acesso ao Keymaster

Em um dispositivo Android, o "cliente" da HAL do Keymaster consiste em várias camadas (por exemplo, app, framework, daemon do Keystore), mas que podem ser ignoradas para os fins deste documento. Isso significa que a HAL do Keymaster descrita A API é de baixo nível, usada por componentes internos da plataforma e não é exposta ao app desenvolvedores de aplicativos. A API de nível superior é descrita no site para desenvolvedores Android.

O objetivo da HAL do Keymaster não é implementar os recursos algoritmos, mas apenas para ordenar e desempacotar solicitações para o mundo seguro. A wire é definido pela implementação.

Compatibilidade com versões anteriores versões

A HAL do Keymaster 1 é completamente incompatível com a HALs lançadas anteriormente, por exemplo, Keymaster 0.2 e 0.3. Para facilitar interoperabilidade em dispositivos com o Android 5.0 e anteriores lançados com as HALs mais antigas do Keymaster, o Keystore fornece um adaptador que implementa a HAL do Keymaster 1 com chamadas para a biblioteca de hardware existente. O resultado não pode oferecem todas as funcionalidades da Keymaster 1 HAL. Especificamente, Ele é compatível apenas com algoritmos RSA e ECDSA e todas as chaves de autorização aplicação é realizada pelo adaptador em um mundo não seguro.

O Keymaster 2 simplificou ainda mais a interface HAL removendo a get_supported_* e permitindo que o finish() para aceitar a entrada. Isso reduz o número de idas e voltas ao TEE em casos em que a entrada é disponibilizada de uma só vez, e simplifica a implementação de Descriptografia AEAD.

No Android 8.0, o Keymaster 3 fez a transição da estrutura C antiga. HAL para a interface HAL C++ gerada por uma definição no novo Linguagem de definição de interface de hardware (HIDL, na sigla em inglês). Uma HAL com novo estilo é criada com a subclassificação a classe IKeymasterDevice e implementar a VM pura métodos. Como parte da mudança, muitos dos tipos de argumento mudaram, embora os tipos e métodos tenham uma correspondência um para um com o e os métodos de struct da HAL.

Visão geral do HIDL

A linguagem de definição de interface de hardware (HIDL) oferece uma implementação mecanismo independente de linguagem para especificar interfaces de hardware. O HIDL atualmente oferece suporte à geração de interfaces C++ e Java. É esperado que a maioria dos implementadores de ambiente de execução confiável (TEE) encontrarão a interface C++ ferramentas mais convenientes, por isso, 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 as HALs podem definir novos tipos tipos de estrutura física. Para mais detalhes sobre o HIDL, consulte a seção "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);

Ele é o equivalente ao seguinte da 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 argumento dev é removido, porque é implícita. O argumento params não é mais um struct contendo uma que faz referência a uma matriz de objetos key_parameter_t, mas um vec (vetor) contendo objetos KeyParameter. A valores retornados estão listados no campo "generates" , incluindo uma cláusula vetor de valores uint8_t para o blob de chave.

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

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

Em que generateKey_cb é um ponteiro de função definido como:

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

Ou seja, generateKey_cb é uma função que usa os valores de retorno listados na cláusula generate. A classe de implementação de HAL substitui essa o método generateKey e chama a função generateKey_cb; ponteiro para retornar o resultado da operação ao autor da chamada. Observe a função chamada de ponteiro é síncrona. O autor da chamada liga generateKey e generateKey chamam os objetos ponteiro de função, que é executado até a conclusão, retornando o controle ao Implementação de generateKey, que retorna ao autor da chamada.

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

Controle de acesso

A regra mais básica do controle de acesso do Keystore é que cada app tem uma próprio namespace. Mas toda regra tem uma exceção. O keystore tem alguns mapas codificados que permitem que certos componentes do sistema acessem outros os namespaces. Este é um instrumento muito contundente, pois fornece a um componente controle total sobre outro namespace. E também há a questão do fornecimento como clientes para o Keystore. No momento, não temos como estabelecer uma para componentes do fornecedor, como o suplicante de WPA.

Para acomodar componentes do fornecedor e generalizar o controle de acesso sem exceções codificadas, o Keystore 2.0 introduz domínios e o SELinux os namespaces.

Domínios de keystore

Com domínios de keystore, é possível desacoplar namespaces de UIDs. Clientes que acessam uma chave no Keystore têm que especificar o domínio, o namespace e o alias que eles querem acessar. Com base nessa tupla e na identidade do autor da chamada, pode determinar qual chave o autor da chamada quer acessar e se ela tem permissões.

Introduzimos cinco parâmetros de domínio que regem 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 é realizado.

  • DOMAIN_APP: o domínio do app abrange os comportamento legado. O SPI do Java Keystore usa esse domínio por padrão. Quando isso domínio é usado, o argumento do namespace é ignorado e o UID do autor da chamada é é usado no lugar dele. O acesso a esse domínio é controlado pelo rótulo Keystore para o classe keystore_key na política do SELinux.
  • DOMAIN_SELINUX: esse domínio indica que o tem um rótulo na política do SELinux. O parâmetro de namespace é analisado e traduzida em um contexto alvo, e uma verificação de permissão é realizada para o contexto do SELinux de chamada para a classe keystore_key. Quando o foi estabelecida para a operação em questão, a tupla completa é usada para a pesquisa de chaves.
  • DOMAIN_GRANT: o domínio de concessão indica que o parâmetro de namespace é um identificador de concessão. O parâmetro alias é ignorado. As verificações do SELinux são realizadas quando a concessão é criada. Controle de acesso avançado verifica somente se o UID do autor da chamada corresponde ao UID dos beneficiários da concessão solicitada.
  • DOMAIN_KEY_ID: esse domínio indica que o namespace é um ID de chave exclusivo. A própria chave pode ter sido criada com DOMAIN_APP ou DOMAIN_SELINUX. A permissão é realizada depois que domain e namespace foram carregados do banco de dados de chaves da mesma forma que se o blob fosse carregado pelo domínio, namespace e tupla de alias. A lógica do domínio de ID da chave é continuidade. Ao acessar uma tecla por alias, as chamadas subsequentes podem operar em chaves diferentes, porque uma nova chave pode ter sido gerada ou importada e vinculada para este alias. No entanto, o ID da chave nunca muda. Portanto, ao usar uma chave por ID de chave, depois de ter sido carregado do banco de dados Keystore usando o alias uma vez, um podemos ter certeza de que é a mesma chave, desde que ainda exista a ID da chave. Isso a funcionalidade do app não é exposta aos desenvolvedores de apps. Em vez disso, ele é usado SPI do Android Keystore para oferecer uma experiência mais consistente, mesmo quando usado concomitantemente de maneira não segura.
  • DOMAIN_BLOB: o domínio blob indica que o autor da chamada gerencia o blob sozinho. Isso é usado para clientes que precisam acessar o keystore antes que a partição de dados seja montada. O blob de chave é incluída no campo blob do descritor de chave.

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

Política SELinux para keystore_key

Os rótulos de namespace são configurados usando o keystore2_key_context .
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 forma, podemos dar acesso a ele adicionando uma política apropriada. Por exemplo, para permitir wpa_supplicant para receber e usar chaves no novo namespace que faríamos adicione a seguinte linha a hal_wifi_supplicant.te:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Depois de configurar o novo namespace, o AndroidKeyStore pode ser usado quase de costume. A única diferença é que o ID do namespace precisa ser especificado. Para carregando e importando chaves de e para o Keystore, o ID do 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 namespace, o ID do namespace precisa ser fornecido usando KeyGenParameterSpec.Builder#setNamespace():

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

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

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

O cliente solicita a chave solicitando o domínio SELinux e a namespace virtual, neste caso, "wifi_key", pelo ID numérico.

Acima disso, os seguintes namespaces foram definidos. Se eles substituirem regras especiais, a tabela a seguir indica o UID usado para corresponder

ID do namespace Marcador da política SE UID Descrição
0 su_chave N/A Chave de superusuário. Usado apenas para testes em builds userdebug e eng. Não relevantes para builds do usuário.
1 chave_do_shell N/A Namespace disponível para o shell. Usado principalmente para testes, mas pode ser usado em com base na linha de comando.
100 chave_vold N/A Destinado ao uso pelo vold.
101 chave_odsing N/A Usado pelo daemon de assinatura no dispositivo.
102 chave_Wi-Fi AID_WIFI(1010) Usado pelo sybsystem Wi-Fi do Android, incluindo o wpa_supplicant.
120 retomar_na_chave_reinicializar AID_SYSTEM(1000) Usado pelo servidor do sistema Android para oferecer suporte à retomada na reinicialização.

Vetores de acesso

A classe SELinux keystore_key envelheceu bastante, e algumas se as permissões, como verify ou sign, foram perdidas e o significado delas. Este é o novo conjunto de permissões, keystore2_key, que o Keystore 2.0 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 autor da chamada precisa dessa permissão para criar uma concessão para a chave no destino contexto.
manage_blob O autor da chamada pode usar DOMAIN_BLOB no namespace do SELinux fornecido, gerenciando os blobs sozinhos. Isso é útil especificamente para vold.
rebind Essa permissão controla se um alias pode ser vinculado a uma nova chave. Isso é necessária para a inserção e implica que a chave previamente vinculada excluída. É basicamente uma permissão de inserção, mas captura a semântica do keystore.
req_forced_op Clientes com essa permissão podem criar operações que não podem ser podadas, e a criação da operação nunca falha, a menos que todos os slots de operação sejam ocupados as operações não podá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 e descriptografia.
use_dev_id Obrigatório ao gerar informações de identificação do dispositivo, como o ID do dispositivo atestado.

Além disso, dividimos um conjunto de permissões de keystore não específicas de chaves em a classe de segurança do SELinux keystore2:

Permissão Significado
add_auth Exigido pelo provedor de autenticação, como Gatekeeper ou BiometricsManager para adicionar tokens de autorização.
clear_ns Anteriormente Clear_uid, esta permissão possibilita que um não proprietário de um namespace ou excluir todas as chaves nesse namespace.
list Exigido pelo sistema para enumerar chaves por várias propriedades, como propriedade ou limitação de autenticação. Esta permissão não é exigida pelos autores das chamadas e numerar os próprios namespaces. Isso é abordado pela get_info.
lock Essa permissão autoriza o bloqueio do Keystore, ou seja, remove a chave mestra, como que as chaves vinculadas à autenticação se tornem inutilizáveis e não cracionáveis.
reset Essa permissão autoriza a redefinição do Keystore para o padrão de fábrica, excluindo todos os chaves que não são vitais para o funcionamento do SO Android.
unlock Essa permissão é necessária para tentar desbloquear a chave mestra para autenticação. com chaves vinculadas.