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 chamadores podem criar chaves 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 semelhantes não devem 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 entropia fornecida pelo
chamador 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 combinação precisa ser processada para que um invasor com 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 principais, 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, eles são vinculados criptograficamente ao
keyblob. Assim, se os valores corretos não forem fornecidos quando a chave for
usada, o uso vai falhar. Da mesma forma, Tag::ROOT_OF_TRUST
é vinculado criptograficamente à chave, mas não pode ser especificado durante a criação ou importação da chave 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 poderá ser usada.
As implementações do KeyMint retornam o material da chave gerada ou importada para o chamador como um keyblob, um formato criptografado e autenticado. Quando o Keystore exclui o keyblob, a chave desaparece, mas um invasor que conseguiu recuperar o material da chave pode restaurá-lo no dispositivo.
Uma chave é resistente a rollback se o hardware seguro garantir que as chaves excluídas não possam ser restauradas posteriormente. 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 é o RPMB (replay protected memory blocks). Como o número de chaves que podem ser criadas é essencialmente ilimitado e o armazenamento confiável usado para resistência a rollback pode ter tamanho limitado, a implementação pode falhar em solicitações para criar chaves resistentes a rollback 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 um para o vold
usar na criptografia de
senhas. 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 usada há menos tempo 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 esse 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á cancelada e o objeto Binder da operação será invalidado. Qualquer uso futuro do objeto
retorna ErrorCode::INVALID_OPERATION_HANDLE
.
Aplicação da autorização
A aplicação da autorização de chave é feita principalmente
em begin()
. A única exceção é quando a chave tem um ou mais valores de Tag::USER_SECURE_ID
, mas não tem um valor de 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 "challenge".
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 de update()
e finish()
. A implementação só pode validar o token uma vez.