Implementar atestado com suporte de hardware para credenciais digitais

Em um fluxo típico de emissão de credenciais digitais usando a especificação OpenID for Verifiable Credential Issuance (OpenID4VCI), um emissor precisa saber se a chave na credencial a ser assinada está armazenada em um local seguro. O tipo de prova android_keystore_attestation, um formato para uso com o OpenID4VCI, fornece um relatório assinado por hardware do Android Keystore, garantindo que a chave esteja bloqueada em um ambiente de execução confiável (TEE, na sigla em inglês) ou StrongBox e não possa ser exportada ou clonada.

Visão geral do atestado de hardware

Quando uma chave é gerada no Android Keystore, o sistema pode gerar um certificado de atestado. Esse certificado é assinado por uma chave protegida pelo hardware do dispositivo, que é encadeada a uma raiz de confiança mantida pelo Google.

A prova android_keystore_attestation é uma matriz de cadeias de certificados X.509. Cada cadeia representa uma única chave de autenticação e é estruturada por um certificado de folha seguido por certificados intermediários.

  • Certificado de folha: contém a chave e uma extensão de atestado específica do Android.
  • Certificados intermediários: conectam a folha à raiz do Android.

Etapas de verificação

Os emissores precisam realizar várias validações no atestado.

  • Encontre o certificado na cadeia que contém a extensão de atestado do Android (normalmente o certificado de folha). Esse certificado contém os dados de atestado da chave criada pelo Android Keystore.
  • Verifique se o campo attestationChallenge na extensão corresponde ao c_nonce fornecido pelo protocolo para evitar ataques de repetição.
  • Verifique o valor de todas as declarações nas extensões de seu interesse.
  • Realize uma verificação de revogação nos certificados do Android Keystore.

Os valores na prova de atestado vêm de várias fontes:

  • Emissor: vários valores são fornecidos pelo emissor, e os mais comuns são colocados no formato de metadados do emissor para permitir a filtragem na apresentação.
  • Titular:valores como o nome e a assinatura do pacote vêm do titular. Eles não são compartilhados por procedimentos de emissão padrão e precisam ser obtidos de forma independente do titular.
  • Protocolo:valores como o nonce com attestationChallenge vêm do protocolo.

Para instruções mais completas sobre como validar os dados de atestado, consulte os seguintes recursos:

Formato de prova de atestado

Em uma solicitação de credencial, a prova android_keystore_attestation é incluída no exemplo a seguir:

{
  "type": "array",
  "description": "An array of certificate chains. Each chain attests a single key.",
  "items": {
    "type": "array",
    "description": "An X.509 certificate chain. Each certificate is a Base64-encoded string. The first element in the chain is the leaf certificate with the extension, the last is the Android Keystore root certificate.",
    "items": {
      "type": "string",
      "description": "A single X.509 certificate (Base64-NoWrap padded DER encoded)."
    },
    "minItems": 1
  },
  "minItems": 1
}

Em seguida, ela é armazenada no objeto proofs de uma solicitação de credencial.

{
  "credential_configuration_id": "org.iso.18013.5.1.mDL",
  "proofs": {
    "android_keystore_attestation": [
      [
        "MII...", // Leaf certificate (contains Keystore extension)
        "MII...", // Intermediate certificate
        "MII..."  // Android Root certificate
      ],
      [ "MII...", "MII...", "MII..." ] // second proof
    ]
  }
}

Formato de metadados do emissor

Um emissor indica os tipos de prova que ele oferece suporte incluindo o objeto android_keystore_attestation no objeto proof_types_supported para uma determinada configuração de credencial.

Confira um exemplo do objeto android_keystore_attestation para emissores:

{
  "type": "object",
  "properties": {
    "proof_signing_alg_values_supported": {
      "type": "array",
      "description": "REQUIRED. As defined in OpenID4VCI 1.0 Section 12.2.4.",
      "items": {
        "type": "string",
        "description": "Cryptographic algorithm identifiers used in the proof_signing_alg_values_supported Credential Issuer metadata parameter for this proof type are case sensitive strings and SHOULD be one of those defined in [IANA.JOSE]."
      },
      "minItems": 1
    },
    "key_attestations_required": {
      "type": "object",
      "description": "OPTIONAL. Specifies the minimum attestation requirements.",
      "properties": {
        "key_mint_security_level": {
          "type": "string",
          "description": "OPTIONAL. Minimum accepted keyMintSecurityLevel. Values defined in https://source.android.com/docs/security/features/keystore/attestation#securitylevel-values.",
          "enum": ["Software", "TrustedEnvironment", "StrongBox"],
          "default": "TrustedEnvironment"
        },
        "user_auth_types": {
          "type": "array",
          "description": "OPTIONAL. A list of authentication types which can authorize the use of the key. If empty, no authentication is required. If multiple, any are allowed.",
          "items": {
            "type": "string",
            "description": "Allowed values are 'LSKF' and 'BIOMETRIC'. These values are meant to mimic the values used during the key generation process here.",
            "enum": ["LSKF", "BIOMETRIC"]
          },
          "default": []
        }
      }
    }
  },
  "required": ["proof_signing_alg_values_supported"]
}

Confira um exemplo do objeto proof_types_supported externo:

{
  "credential_configurations_supported": {
    "org.iso.18013.5.1.mDL": {
      "format": "mso_mdoc",
      "doctype": "org.iso.18013.5.1.mDL",
      "cryptographic_binding_methods_supported": [
        "cose_key"
      ],
      "credential_signing_alg_values_supported": [
        -7, -9
      ],
      "proof_types_supported": {
        "android_keystore_attestation": {
          "proof_signing_alg_values_supported": [
            "ES256" // ecdsaWithSHA256
          ],
          "key_attestations_required" : {
            // OPTIONAL String - Representing the minimum accepted value for keyMintSecurityLevel values
            // defined here ("Software"|"TrustedEnvironment"|"StrongBox"). Default value: "TrustedEnvironment"
            "key_mint_security_level": "TrustedEnvironment",
            // OPTIONAL List of Strings - Representing all allowed values for userAuthType values defined here.
            // [] value will represent noAuthRequired. Default value: [].
            "user_auth_types": ["LSKF", "BIOMETRIC"]
          }
        }
      }
    }
  }
}

Como mapear declarações de atestado de VCI para o Android Keystore

Esta tabela fornece um mapeamento informativo para ajudar entidades familiarizadas com o tipo de prova de atestado OpenID4VCI padrão a entender onde conceitos semelhantes estão localizados no atestado do Android Keystore.

Declaração de atestado de VCI

Localização de android_keystore_attestation

Localização do valor esperado

iss

Chave pública do certificado raiz do Keystore

N/A

iat

Valor creationDateTime na extensão de atestado

N/A

exp

Campo validUntil no certificado de folha

N/A

attested_keys

Chave pública contida no certificado de folha de cada cadeia

N/A

key_storage

Valor keyMintSecurityLevel na extensão de atestado

Emissor selecionado: campo key_mint_security_level nos metadados do emissor

user_authentication

Valores userAuthType e noAuthRequired na extensão de atestado

Emissor selecionado: campo user_auth_types nos metadados do emissor

nonce

Valor attestationChallenge na extensão de atestado

Do protocolo: valor c_nonce do endpoint nonce descrito no VCI

certification

N/A

N/A

status

N/A

N/A