Implémenter l'attestation intégrée au matériel pour les identifiants numériques

Dans un flux d'émission d'identifiants numériques typique utilisant la spécification OpenID for Verifiable Credential Issuance (OpenID4VCI), un émetteur doit savoir que la clé de l'identifiant à signer est stockée dans un emplacement sécurisé. Le type de preuve android_keystore_attestation (format à utiliser avec OpenID4VCI) fournit un rapport signé par le matériel à partir de l'Android Keystore, ce qui garantit que la clé est verrouillée dans un environnement d'exécution sécurisé (TEE) ou StrongBox, et qu'elle ne peut pas être exportée ni clonée.

Présentation de l'attestation matérielle

Lorsqu'une clé est générée dans Android Keystore, le système peut générer un certificat d'attestation. Ce certificat est signé par une clé protégée par le matériel de l'appareil, qui renvoie à une racine de confiance détenue par Google.

La preuve android_keystore_attestation est un tableau de chaînes de certificats X.509. Chaque chaîne représente une seule clé d'authentification et est structurée par un certificat feuille suivi de certificats intermédiaires.

  • Certificat feuille : contient la clé et une extension d'attestation spécifique à Android.
  • Certificats intermédiaires : connectent la feuille à la racine Android.

Étapes de validation

Les émetteurs doivent effectuer plusieurs validations sur l'attestation.

  • Recherchez le certificat de la chaîne qui contient l'extension d'attestation Android (généralement le certificat feuille). Ce certificat contient les données d'attestation de la clé générée par Android Keystore.
  • Vérifiez que le champ attestationChallenge de l'extension correspond au c_nonce fourni par le protocole pour éviter les attaques par relecture.
  • Vérifiez la valeur de toutes les assertions dans les extensions qui vous intéressent.
  • Effectuez une vérification de la révocation par rapport aux certificats Android Keystore.

Les valeurs de la preuve d'attestation proviennent de plusieurs sources :

  • Émetteur : différentes valeurs sont fournies par l'émetteur. Les plus courantes sont placées au format de métadonnées de l'émetteur pour permettre le filtrage lors de la présentation.
  • Titulaire : les valeurs telles que le nom du package et la signature proviennent du titulaire. Elles ne sont pas partagées via les procédures d'émission standards et doivent être obtenues indépendamment du titulaire.
  • Protocole : les valeurs telles que le nonce avec attestationChallenge proviennent du protocole.

Pour obtenir des instructions plus complètes sur la validation des données d'attestation, consultez les ressources suivantes :

Format de la preuve d'attestation

Dans une demande d'identifiant, la preuve android_keystore_attestation est incluse dans l'exemple suivant :

{
  "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
}

Elle est ensuite stockée dans l'objet proofs d'une demande d'identifiant.

{
  "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
    ]
  }
}

Format des métadonnées de l'émetteur

Un émetteur indique les types de preuves qu'il accepte en incluant l'objet android_keystore_attestation dans l'objet proof_types_supported pour une configuration d'identifiant donnée.

Voici un exemple de l'objet android_keystore_attestation pour les émetteurs :

{
  "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"]
}

Voici un exemple de l'objet externe proof_types_supported :

{
  "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"]
          }
        }
      }
    }
  }
}

Mapper les revendications d'attestation VCI à Android Keystore

Ce tableau fournit un mappage informatif pour aider les entités familiarisées avec le type de preuve d'attestation OpenID4VCI standard à comprendre où des concepts similaires se trouvent dans l'attestation Android Keystore.

Revendication d'attestation VCI

Emplacement android_keystore_attestation

Emplacement de la valeur attendue

iss

Clé publique du certificat racine Keystore

N/A

iat

Valeur creationDateTime dans l'extension d'attestation

N/A

exp

Champ validUntil dans le certificat feuille

N/A

attested_keys

Clé publique contenue dans le certificat feuille de chaque chaîne

N/A

key_storage

Valeur keyMintSecurityLevel dans l'extension d'attestation

Émetteur sélectionné : champ key_mint_security_level dans les métadonnées de l'émetteur

user_authentication

Valeurs userAuthType et noAuthRequired dans l'extension d'attestation

Émetteur sélectionné : champ user_auth_types dans les métadonnées de l'émetteur

nonce

Valeur attestationChallenge dans l'extension d'attestation

À partir du protocole : valeur c_nonce du point de terminaison nonce décrit dans VCI

certification

N/A

N/A

état

N/A

N/A