A confirmação de chaves dá a você a confiança de que as chaves usadas no seu aplicativo sejam armazenadas em um armazenamento de chaves protegido por hardware de um dispositivo. As seções a seguir descrevem como verificar as propriedades de chaves protegidas por hardware e como interpretar o esquema dos dados de extensão do certificado de confirmação.
Observação: Poucos dispositivos que executam o Android 7.0 (nível de API 24) oferecem suporte à confirmação de chaves no nível do hardware; todos os demais dispositivos que executam o Android 7.0 usam a confirmação de chaves no nível do software. Antes de verificar as propriedades das chaves protegidas por hardware de um dispositivo em um ambiente de produção, certifique-se de que o dispositivo ofereça suporte à confirmação de chaves no nível do hardware. Para isso, verifique se a cadeia de certificados de confirmação contém um certificado raiz assinado pela chave raiz de confirmação do Google e que o elemento attestationSecurityLevel na estrutura de dados de descriptografia de chaves seja definido para o nível de segurança TrustedEnvironment.
Recuperar e verificar um par de chaves protegido por hardware
Durante a confirmação de chaves, você especifica o alias de um par de chaves. Por sua vez, a ferramenta de confirmação fornece uma cadeia de certificados, que você pode usar para verificar as propriedades desse par de chaves.
Se o dispositivo oferecer suporte à confirmação de chaves no nível o hardware, o certificado raiz nessa cadeia será assinado usando uma chave raiz de confirmação, que o fabricante do dispositivo injeta no armazenamento de chaves protegido por hardware do dispositivo na fábrica.
Observação: Em dispositivos que incluem a confirmação de chaves no nível do hardware, o Android 7.0 (nível de API 24) e o Google Play Services, o certificado raiz é assinado pela chave raiz de confirmação do Google. Você deve verificar se esse certificado raiz aparece na lista de certificados raiz do Google.
Para implementar a confirmação de chaves, siga as seguintes etapas:
-
Use o método
getCertificateChain()de um objetoKeyStorepara obter uma referência à cadeia de certificados X.509 associada ao armazenamento de chaves protegido por hardware. -
Verifique a validez de cada certificado usando um método
isRevoked()de um objetoCRL.Atenção: Apesar de ser possível realizar esse processo diretamente no seu aplicativo, é mais seguro verificar as listas de revogação dos certificados em um servidor de confiança separado.
-
Crie um objeto
Attestation, passando o primeiro elemento da cadeia de certificados como um argumento:// "certificates" contains the certificate chain associated with a specific key // pair in the device's hardware-backed keystore. X509Certificate attestationCert = (X509Certificate) certificates[0]; Attestation hardwareKeyAttestation = new Attestation(attestationCert);
Um objeto de confirmação extrai os dados de extensão nesse certificado e armazena essas informações em um formato mais acessível. Para saber mais sobre o esquema dos dados de extensão, consulte Esquema de dados de extensão de certificado.
-
Use os métodos de acesso na classe
Attestationpara recuperar os dados de extensão do certificado. Esses métodos usam os mesmos nomes e a hierarquia de estrutura do esquema de dados de extensão de certificado.Por exemplo, para visualizar a chave de inicialização verificada do TEE do dispositivo, use a seguinte sequência de métodos:
// "hardwareKeyAttestation" contains the first element of the attestation // certificate chain. AuthorizationList teeAuthList = hardwareKeyAttestation.getTeeEnforced(); RootOfTrust teeRootOfTrust = teeAuthList.getRootOfTrust(); byte[] teeVerifiedBootKey = teeRootOfTrust.getVerifiedBootKey();
-
Compare os dados de extensão do objeto
Attestationcom o conjunto de valores que você espera que a chave protegida por hardware contenha.Atenção: Apesar de ser possível realizar esse processo diretamente no seu aplicativo, é mais seguro verificar os dados de extensão do certificado em um servidor de confiança separado.
Esquema de dados de extensão de certificado
A confirmação de chaves verifica os dados de extensão que aparecem no primeiro certificado da cadeia de um armazenamento de chaves protegido por hardware de um dispositivo. O certificado armazena as informações de acordo com o seguinte esquema ASN.1:
KeyDescription ::= SEQUENCE {
attestationVersion INTEGER,
attestationSecurityLevel SecurityLevel,
keymasterVersion INTEGER,
keymasterSecurityLevel SecurityLevel,
attestationChallenge OCTET_STRING,
reserved OCTET_STRING,
softwareEnforced AuthorizationList,
teeEnforced AuthorizationList,
}
SecurityLevel ::= ENUMERATED {
Software (0),
TrustedEnvironment (1),
}
AuthorizationList ::= SEQUENCE {
purpose [1] EXPLICIT SET OF INTEGER OPTIONAL,
algorithm [2] EXPLICIT INTEGER OPTIONAL,
keySize [3] EXPLICIT INTEGER OPTIONAL,
digest [5] EXPLICIT SET OF INTEGER OPTIONAL,
padding [6] EXPLICIT SET OF INTEGER OPTIONAL,
ecCurve [10] EXPLICIT INTEGER OPTIONAL,
rsaPublicExponent [200] EXPLICIT INTEGER OPTIONAL,
activeDateTime [400] EXPLICIT INTEGER OPTIONAL,
originationExpireDateTime [401] EXPLICIT INTEGER OPTIONAL,
usageExpireDateTime [402] EXPLICIT INTEGER OPTIONAL,
noAuthRequired [503] EXPLICIT NULL OPTIONAL,
userAuthType [504] EXPLICIT INTEGER OPTIONAL,
authTimeout [505] EXPLICIT INTEGER OPTIONAL,
allowWhileOnBody [506] EXPLICIT NULL OPTIONAL,
allApplications [600] EXPLICIT NULL OPTIONAL,
applicationId [601] EXPLICIT OCTET_STRING OPTIONAL,
creationDateTime [701] EXPLICIT INTEGER OPTIONAL,
origin [702] EXPLICIT INTEGER OPTIONAL,
rollbackResistant [703] EXPLICIT NULL OPTIONAL,
rootOfTrust [704] EXPLICIT RootOfTrust OPTIONAL,
osVersion [705] EXPLICIT INTEGER OPTIONAL,
osPatchLevel [706] EXPLICIT INTEGER OPTIONAL,
attestationChallenge [708] EXPLICIT INTEGER OPTIONAL,
attestationApplicationId [709] EXPLICIT OCTET_STRING OPTIONAL,
}
RootOfTrust ::= SEQUENCE {
verifiedBootKey OCTET_STRING,
deviceLocked BOOLEAN,
verifiedBootState VerifiedBootState,
}
VerifiedBootState ::= ENUMERATED {
Verified (0),
SelfSigned (1),
Unverified (2),
Failed (3),
}
A lista a seguir apresenta uma descrição de cada elemento do esquema:
KeyDescription
Essa sequência de valores apresenta informações gerais sobre o par de chaves sendo verificado por meio da confirmação de chaves e oferece acesso fácil a detalhes adicionais.
-
attestationVersion - A versão do recurso de confirmação de chaves. Deve ser definido como 1.
-
attestationSecurityLevel -
O nível de segurança da confirmação.
Aviso: Apesar de ser possível confirmar chaves armazenadas no sistema Android — ou seja, se o valor de
attestationSecurityLevelestiver definido como Software — você não poderá confiar nessas confirmações se o sistema Android for comprometido. -
keymasterVersion - A versão da camada de abstração de hardware (HAL) do Keymaster. Use 0 para representar a versão 0.2 ou 0.3, 1 para representar a versão 1.0 e 2 para representar a versão 2.0.
-
keymasterSecurityLevel - O nível de segurança da implementação do Keymaster.
-
attestationChallenge - A string de desafio associada a um par de chaves verificado usando a confirmação de chaves.
-
reserved - Somente aplicativos de sistema usam esse valor. Em todos os demais aplicativos, esse valor fica vazio.
-
softwareEnforced - Opcional. A lista de autorização do Keymaster que é aplicada pelo sistema Android, não pelo TEE do dispositivo.
-
teeEnforced - Opcional. A lista de autorização do Keymaster que é aplicada pelo TEE do dispositivo.
SecurityLevel
Essa estrutura de dados indica até onde um recurso de software, como um par de chaves, é protegido com base em sua localização no dispositivo.
Como a estrutura de dados é uma enumeração, ela aceita um dos seguintes valores:
- Software
- A lógica para criar e gerenciar o recurso é implementada no sistema Android. Para os fins de criar e armazenar pares de chaves, essa localização é menos segura do que o TEE, mas mais segura do que o espaço de processamento do aplicativo.
- TrustedEnvironment
- A lógica para criar e gerenciar o recurso é implementada em um hardware protegido, como o TEE. Para os fins de criar e armazenar pares de chaves, essa localização é mais segura pois um hardware protegido é altamente resistente ao comprometimento remoto.
AuthorizationList
Essa estrutura de dados contém as propriedades do par de chaves, conforme são definidas na camada de abstração de hardware (HAL) do Keymaster. Você compara esses valores ao estado atual do dispositivo ou a um conjunto de valores esperados para verificar se um par de chaves ainda é válido para uso no seu aplicativo.
Cada nome de campo corresponde a uma tag do Keymaster com nome similar. Por exemplo, o campo keySize em uma lista de autorização corresponde à tag KM_TAG_KEY_SIZE do Keymaster.
Cada campo da lista a seguir é opcional:
-
purpose -
Corresponde à tag
KM_TAG_PURPOSEdo Keymaster, que usa um valor de código de tag de 1. -
algorithm -
Corresponde à tag
KM_TAG_ALGORITHMdo Keymaster, que usa um valor de código de tag de 2.Quando um objeto
AuthorizationListé associado à confirmação de chaves, esse valor é sempreKM_ALGORITHM_RSAouKM_ALGORITHM_EC. -
keySize -
Corresponde à tag
KM_TAG_KEY_SIZEdo Keymaster, que usa um valor de código de tag de 3. -
digest -
Corresponde à tag
KM_TAG_DIGESTdo Keymaster, que usa um valor de código de tag de 5. -
padding -
Corresponde à tag
KM_TAG_PADDINGdo Keymaster, que usa um valor de código de tag de 6. -
ecCurve -
Corresponde à tag
KM_TAG_EC_CURVEdo Keymaster, que usa um valor de código de tag de 10.O conjunto de parâmetros usados para criar um par de chaves de curva elíptica (EC), que usa ECDSA para assinaturas e verificações, no armazenamento de chaves do sistema Android.
-
rsaPublicExponent -
Corresponde à tag
KM_TAG_RSA_PUBLIC_EXPONENTdo Keymaster, que usa um valor de código de tag de 200. -
activeDateTime -
Corresponde à tag
KM_TAG_ACTIVE_DATETIMEdo Keymaster, que usa um valor de código de tag de 400. -
originationExpireDateTime -
Corresponde à tag
KM_TAG_ORIGINATION_EXPIRE_DATETIMEdo Keymaster, que usa um valor de código de tag de 401. -
usageExpireDateTime -
Corresponde à tag
KM_TAG_USAGE_EXPIRE_DATETIMEdo Keymaster, que usa um valor de código de tag de 402. -
noAuthRequired -
Corresponde à tag
KM_TAG_NO_AUTH_REQUIREDdo Keymaster, que usa um valor de código de tag de 503.Quando um objeto
AuthorizationListé associado à confirmação de chaves, esse valor é sempre true. -
userAuthType -
Corresponde à tag
KM_TAG_USER_AUTH_TYPEdo Keymaster, que usa um valor de código de tag de 504. -
authTimeout -
Corresponde à tag
KM_TAG_AUTH_TIMEOUTdo Keymaster, que usa um valor de código de tag de 505. -
allowWhileOnBody -
Corresponde à tag
KM_TAG_ALLOW_WHILE_ON_BODYdo Keymaster, que usa um valor de código de tag de 506.Permite que a chave seja usada após seu tempo limite de autenticação se o usuário ainda estiver usando o dispositivo vestível. Observe que um sensor corporal seguro determina se o dispositivo está sendo usado pelo usuário.
Quando um objeto
AuthorizationListé associado à confirmação de chaves, esse valor é sempre true. -
allApplications -
Corresponde à tag
KM_TAG_ALL_APPLICATIONSdo Keymaster, que usa um valor de código de tag de 600.Indica se todos os aplicativos de um dispositivo podem acessar o par de chaves.
Quando um objeto
AuthorizationListé associado à confirmação de chaves, esse valor é sempre true. -
applicationId -
Corresponde à tag
KM_TAG_APPLICATION_IDdo Keymaster, que usa um valor de código de tag de 601. -
creationDateTime -
Corresponde à tag
KM_TAG_CREATION_DATETIMEdo Keymaster, que usa um valor de código de tag de 701. -
origin -
Corresponde à tag
KM_TAG_ORIGINdo Keymaster, que usa um valor de código de tag de 702.Quando um objeto
AuthorizationListé associado à confirmação de chaves, esse valor é geralmente definido comoKM_ORIGIN_GENERATED. Entretanto, se a confirmação usar o Keymaster versão 0.2 ou 0.3, a origem poderá ser definida comoKM_ORIGIN_UNKNOWN. -
rollbackResistant -
Corresponde à tag
KM_TAG_ROLLBACK_RESISTANTdo Keymaster, que usa um valor de código de tag de 703. -
rootOfTrust -
Corresponde à tag
KM_TAG_ROOT_OF_TRUSTdo Keymaster, que usa um valor de código de tag de 704.Para saber mais, consulte a seção que descreve a estrutura de dados
RootOfTrust. -
osVersion -
Corresponde à tag
KM_TAG_OS_VERSIONdo Keymaster, que usa um valor de código de tag de 705.A versão do sistema operacional Android associado ao Keymaster, especificada como um número inteiro de seis dígitos. Por exemplo, a versão 6.0.1 é representada como 060001.
Somente o Keymaster versão 1.0 ou superior inclui esse valor na lista de autorizações.
-
osPatchLevel -
Corresponde à tag
KM_TAG_PATCHLEVELdo Keymaster, que usa um valor de código de tag de 706.O mês e o ano associados com o patch de segurança sendo usado no Keymaster, especificados como um número inteiro de seis dígitos. Por exemplo, o patch de junho de 2016 é representado como 201606.
Somente o Keymaster versão 1.0 ou superior inclui esse valor na lista de autorizações.
-
attestationChallenge -
Corresponde à tag
KM_TAG_ATTESTATION_CHALLENGEdo Keymaster, que usa um valor de código de tag de 708.A string de desafio associada ao par de chaves definido no Keymaster.
-
attestationApplicationId -
Corresponde à tag
KM_TAG_ATTESTATION_APPLICATION_IDdo Keymaster, que usa um valor de código de tag de 709.O código exclusivo do certificado de confirmação que assinou o par de chaves que está no Keymaster.
RootOfTrust
Esse conjunto de valores define informações essenciais sobre o status do dispositivo.
Cada campo da lista a seguir é obrigatório:
-
verifiedBootKey -
Um hash seguro da chave que verifica a imagem do sistema. Recomenda-se o uso do algoritmo SHA-256 para esse hash.
-
deviceLocked - True se o bootloader do dispositivo estiver bloqueado, o que ativa a verificação da inicialização verificada e impede que uma imagem de dispositivo não assinada seja reproduzida no dispositivo. Para saber mais sobre esse recurso, consulte a documentação Verificar inicialização.
-
verifiedBootState - O estado de inicialização do dispositivo, de acordo com o recurso de inicialização verificada.
-
osVersion - A versão atual do sistema operacional Android no dispositivo, especificada como um número inteiro de seis dígitos. Por exemplo, a versão 6.0.1 é representada como 060001.
-
patchMonthYear - O mês e o ano associados ao patch de segurança atualmente instalado no dispositivo, especificados como um número inteiro de seis dígitos. Por exemplo, o patch de agosto de 2016 é representado como 201608.
VerifiedBootState
Essa estrutura de dados fornece o estado de inicialização atual do dispositivo, que representa o nível de proteção fornecido ao usuário e aos aplicativos após a conclusão da inicialização do dispositivo. Para saber mais sobre esse recurso, consulte a seção Estado de inicialização da documentação Verificar inicialização.
Essa estrutura de dados é uma enumeração, portanto, ela aceita um dos seguintes valores:
- Verified
-
Indica uma cadeia completa de confiança, que inclui o bootloader, a partição de inicialização e todas as partições verificadas.
Quando o dispositivo se encontra nesse estado de inicialização, o
verifiedBootKeyé o hash do certificado incorporado ao dispositivo, que é adicionado pelo fabricante à ROM do dispositivo na fábrica. - SelfSigned
-
Indica que o certificado incorporado ao dispositivo verificou a partição de inicialização do dispositivo e que a assinatura é válida.
Quando o dispositivo se encontra nesse estado de inicialização, o
verifiedBootKeyé o hash do certificado instalado pelo usuário, que assina uma partição de inicialização que o usuário adiciona ao dispositivo no lugar da partição de inicialização original fornecida pelo fabricante. - Unverified
- Indica que o usuário pode modificar o dispositivo livremente. Portanto, o usuário é responsável por verificar a integridade do dispositivo.
- Failed
-
Indica que a verificação do dispositivo falhou. O certificado de conformação nunca deve usar esse valor para
VerifiedBootState.