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 da HAL é a especificação da interface AIDL .
Uso indevido da API
Os autores de chamadas podem criar chaves do KeyMint com autorizações válidas como parâmetros de API, mas que tornam as chaves resultantes inseguras ou inutilizáveis. As implementações do KeyMint não precisam falhar nesses casos nem 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 nonces, a geração de chaves sem finalidades (portanto, inúteis) e outros casos semelhantes não devem ser diagnosticados por implementações.
É responsabilidade dos apps, da estrutura e do Android Keystore garantir que as chamadas para módulos do 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, para 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 por 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 bits 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 do 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 da chave, elas serão removidas das características retornadas para que não seja possível encontrar os valores delas examinando o keyblob retornado. No entanto, elas estão criptograficamente vinculadas ao keyblob. Portanto, se os valores corretos não forem fornecidos quando a chave for usada, o uso vai falhar. Da mesma forma, Tag::ROOT_OF_TRUST está criptograficamente vinculada à chave, mas não pode ser especificada durante a criação ou importação da chave e nunca é retornada.
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 possa ser usada.
As implementações do KeyMint retornam o material da chave gerada ou importada para o autor da chamada como um keyblob, um formulário criptografado e autenticado. Quando o Keystore exclui o keyblob, a chave desaparece, mas um invasor que já conseguiu recuperar o material da chave pode restaurá-la no dispositivo.
Uma chave é resistente a reversão se o hardware seguro garantir que as chaves excluídas não possam ser restauradas mais tarde. Isso geralmente é feito armazenando metadados de chave adicionais em um local de confiança 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 resistência a reversão pode ter um tamanho limitado, a implementação pode falhar em solicitações para criar chaves resistentes a reversão quando o armazenamento estiver cheio.
início
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 um 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 uma 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 da chave, as chamadas para begin() precisam incluir essas tags com os valores originalmente especificados no argumento params desse 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á interrompida 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 da 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_TYPEda chave. - Verifica se o token contém o valor de desafio para a operação atual no campo de desafio.
Se essas condições não forem atendidas, o KeyMint 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 pode validar o token apenas uma vez.