Funções do KeyMint

Esta página fornece mais detalhes e diretrizes para ajudar os implementadores da camada de abstração de hardware (HAL) do KeyMint. A documentação principal do HAL é a especificação da interface AIDL.

Uso indevido da API

Os autores de chamadas podem criar chaves KeyMint com autorizações válidas como parâmetros de API, mas que tornam as chaves resultantes não seguras ou inutilizáveis. As implementações do KeyMint não precisam falhar nesses casos ou emitir um diagnóstico. O uso de chaves muito pequenas, a especificação de parâmetros de entrada irrelevantes, a reutilização de IVs ou valores de uso único, a geração de chaves sem propósito (ou seja, inúteis) e assim por diante não podem ser diagnosticados por implementações.

É responsabilidade dos apps, do framework e do Android Keystore garantir que as chamadas para módulos KeyMint sejam sensatas e úteis.

Ponto de entrada addRngEntropy

O ponto de entrada addRngEntropy adiciona a entropia fornecida pelo autor da chamada ao pool usado pela implementação do KeyMint para gerar números aleatórios, chaves e IVs.

As implementações do KeyMint precisam misturar com segurança a entropia fornecida no pool, que também precisa conter entropia gerada internamente de um gerador de números aleatórios de hardware. A mistura precisa ser processada para que um invasor que tenha controle total dos bits fornecidos por addRngEntropy ou dos gerados por hardware (mas não ambos) não tenha uma vantagem significativa na previsão dos bits gerados pelo pool de entropia.

Principais características

Cada um dos mecanismos (generateKey, importKey e importWrappedKey) que criam chaves KeyMint retorna as características da chave recém-criada, divididas adequadamente nos níveis de segurança que aplicam cada característica. As características retornadas incluem todos os parâmetros especificados para a criação de chaves, exceto Tag::APPLICATION_ID e Tag::APPLICATION_DATA. Se essas tags forem incluídas nos parâmetros de chave, elas serão removidas das características retornadas para que não seja possível encontrar os valores delas analisando o keyblob retornado. No entanto, eles são criptograficamente vinculados ao blob de chave. Se os valores corretos não forem fornecidos quando a chave for usada, o uso falhará. Da mesma forma, Tag::ROOT_OF_TRUST é vinculado criptograficamente à chave, mas não pode ser especificado durante a criação ou importação de chaves e nunca é retornado.

Além das tags fornecidas, a implementação do KeyMint também adiciona Tag::ORIGIN, indicando a maneira como a chave foi criada (KeyOrigin::GENERATED, KeyOrigin::IMPORTED ou KeyOrigin::SECURELY_IMPORTED).

Resistência a reversão

A resistência a reversão é indicada por Tag::ROLLBACK_RESISTANCE e significa que, depois que uma chave é excluída com deleteKey ou deleteAllKeys, o hardware seguro garante que ela nunca mais será usada.

As implementações do KeyMint retornam o material de chave gerado ou importado para o autor da chamada como um keyblob, um formulário criptografado e autenticado. Quando o Keystore exclui o keyblob, a chave é excluída, mas um invasor que conseguiu recuperar o material principal pode restaurá-lo no dispositivo.

Uma chave é resistente a reversão se o hardware seguro garante que as chaves excluídas não possam ser restauradas mais tarde. Isso geralmente é feito armazenando metadados de chave adicionais em um local confiável que não pode ser manipulado por um invasor. Em dispositivos móveis, o mecanismo usado para isso geralmente é blocos de memória protegidos contra repetição (RPMB, na sigla em inglês). Como o número de chaves que podem ser criadas é essencialmente ilimitado e o armazenamento confiável usado para a resistência à reversão pode ser limitado em tamanho, a implementação pode falhar nas solicitações para criar chaves resistentes à reversão quando o armazenamento estiver cheio.

begin

O ponto de entrada begin() inicia uma operação criptográfica usando a chave especificada, para a finalidade especificada, com os parâmetros especificados (conforme apropriado). Ele retorna um novo objeto Binder IKeyMintOperation usado para concluir a operação. Além disso, um valor de desafio é retornado e usado como parte do token de autenticação em operações autenticadas.

Uma implementação do KeyMint oferece suporte a pelo menos 16 operações simultâneas. O keystore usa até 15, deixando uma para vold usar para criptografia de senha. Quando o Keystore tem 15 operações em andamento (begin() foi chamado, mas finish ou abort não foram chamados) e recebe uma solicitação para iniciar a 16ª, ele chama abort() na operação menos usada recentemente para reduzir o número de operações ativas para 14 antes de chamar begin() para iniciar a operação recém-solicitada.

Se Tag::APPLICATION_ID ou Tag::APPLICATION_DATA foram especificados durante a geração ou importação de chaves, as chamadas para begin() precisam incluir essas tags com os valores especificados originalmente no argumento params para este método.

Tratamento de erros

Se um método em um IKeyMintOperation retornar um código de erro diferente de ErrorCode::OK, a operação será abortada e o objeto Binder da operação será invalidado. Qualquer uso futuro do objeto retorna ErrorCode::INVALID_OPERATION_HANDLE.

Aplicação de autorização

A aplicação de autorização de chave é realizada principalmente em begin(). A única exceção é o caso em que a chave tem um ou mais valores Tag::USER_SECURE_ID e não tem um valor Tag::AUTH_TIMEOUT.

Nesse caso, a chave exige uma autorização por operação, e os métodos update() ou finish() recebem um token de autenticação no argumento authToken. Para garantir que o token seja válido, a implementação do KeyMint:

  • Verifica a assinatura HMAC no token de autenticação.
  • Verifica se o token contém um ID de usuário seguro que corresponde a um associado à chave.
  • Verifica se o tipo de autenticação do token corresponde ao Tag::USER_AUTH_TYPE da chave.
  • Verifica se o token contém o valor do desafio para a operação atual no campo de desafio.

Se essas condições não forem atendidas, o KeyMint vai retornar ErrorCode::KEY_USER_NOT_AUTHENTICATED.

O autor da chamada fornece o token de autenticação para cada chamada para update() e finish(). A implementação só pode validar o token uma vez.