Onboarding-Leitfaden für Verifier Registrars

Übersicht

In diesem Abschnitt wird der schrittweise Prozess für die Registrierung von Verifier-Registrars beim Google Wallet Identitätsdienst beschrieben.

Als Verifier-Registrar (z. B. ein IDV-Unternehmen, das im Namen anderer Rechtssubjekte Bestätigungen durchführt) fungieren Sie als eigene Zertifizierungsstelle (Certificate Authority, CA) und signieren Identitätsanfragen für die nachgelagerten End Relying Parties (RPs), die Sie verwalten.

Onboarding-Prozess

Schritt 1: Aufnahmeformular und Root-Zertifikate einreichen und Nutzungsbedingungen akzeptieren

Füllen Sie das Aufnahmeformular für das Onboarding von Verifier-Registrars aus und reichen Sie es ein. In diesem Formular geben Sie sowohl Ihre Sandbox- als auch Ihre Produktions-Root-Zertifikate an. Mit dem Einreichen dieses Aufnahmeformulars für das Onboarding akzeptieren Sie auch offiziell die Nutzungsbedingungen für Verifier-Registrars von Google Wallet.

Schritt 2: Sandbox-Vertrauen und ‑Tests

Nachdem Sie das Aufnahmeformular eingereicht haben, fügt Google Ihr Sandbox-Root-Zertifikat dem Google Wallet Sandbox Trust Store hinzu und benachrichtigt Sie. Anschließend können Sie mit dem Testen Ihrer Integration in der Sandbox mit Zertifikaten beginnen, die von Ihrem Sandbox-Root signiert wurden.

Schritt 3: E2E-Videodemonstration aufzeichnen

Nach Abschluss der Sandbox-Tests zeichnen Sie E2E-Videodemonstrationen des Bestätigungsablaufs für Ihre erste Relying Party auf und reichen Sie sie bei Google ein.

  • Videoanforderungen:
    • Zeichnen Sie Demonstrationen für sowohl Verifier-gehostete (selbst gehostete) als auch Händler-gehostete (RP-gehostete) Abläufe auf.
    • Verwenden Sie in den Videos tatsächliche Händler-Display-Assets (Name, Logo, URL der Nutzungsbedingungen) und Aggregator-Display-Assets.
    • Demonstrieren Sie deutlich die Benutzeroberfläche und die Bildschirme, die den Bestätigungsablauf starten.

Schritt 4: Genehmigung und Vertrauenswürdigkeit des Produktions-Roots

Nachdem Google Ihre E2E-Videodemonstrationen erhalten hat, wird der Videoprüfungs- und ‑genehmigungsprozess ausgelöst. Parallel dazu wird der Prozess zur Vertrauenswürdigkeit des Produktions-Root-Zertifikats gestartet. Nachdem beide Prozesse abgeschlossen und genehmigt wurden, können Sie mit der Einführung des Dienstes für Ihre nachgelagerten End-RPs beginnen.

Schritt 5: Laufendes Onboarding von End-RPs

Für jede End-RP, für die Sie signieren, müssen Sie Folgendes tun:

  • Google informieren: Verwenden Sie das Aufnahmeformular für Verifier-Registrar-Clients, um Google über die neue RP und den beabsichtigten Anwendungsfall zu informieren.
  • Metadaten konfigurieren: Füllen Sie die Anzeigeinformationen der RP (Name, Logo, URL der Datenschutzerklärung) aus und legen Sie in ihrem Zertifikat einen global eindeutigen Distinguished Name (Subject) fest.

Technische Spezifikationen

A. Zertifikatsprofil

Anfragen müssen mit standardmäßigen X.509 v3-Zertifikaten signiert werden, die mit P-256 / ECDSA generiert wurden und eine benutzerdefinierte Google-Erweiterung enthalten:

  • Benutzerdefinierte Erweiterungs-OID: 1.3.6.1.4.1.11129.10.1
  • Wichtigkeit: Nicht kritisch.
  • Inhalt: Ein SHA256-Hash von RelyingPartyMetadataBytes, codiert in einem ASN.1 OCTET STRING.

B. Metadatenschema (CBOR)

Metadaten müssen im CBOR-Format codiert sein.

; in CDDL for CBOR encoding
; schemaVersion = "v1"

RelyingPartyMetadataBytes = #6.24(bstr .cbor RelyingPartyMetadata)


RelyingPartyMetadata = {
  "schema_version": tstr,
  "display": DisplayInfo,
  "aggregator_info": DisplayInfo  ; Optional: include to show your branding alongside the RP
}

DisplayInfo = {
  "display_name": tstr,
  "logo_uri": tstr,             ; See brand guidelines link in following paragraph
  "privacy_policy_uri": tstr
}

Die logo_uri muss den Markenrichtlinien für Google Wallet entsprechen.

C. OpenID4VP-Integration

Wenn Sie Ihre signierte OpenID4VP-Anfrage für Anmeldedaten formatieren, fügen Sie die Base64URL-codierten Metadaten im Feld gw_rp_metadata_bytes im Objekt client_metadata ein (wie im Beispielcode für die Anfrage im folgenden Abschnitt gezeigt).

Compliance und Widerruf

  • Missbrauchsüberwachung: Google überwacht böswillige RP-Aktivitäten und benachrichtigt Sie über jeden erkannten Missbrauch.
  • Sofortiger Widerruf: Sie müssen Zertifikate für missbräuchliche RPs umgehend widerrufen und eine aktualisierte Zertifikatssperrliste (Certificate Revocation List, CRL) veröffentlichen.
  • Auditierung: Google führt anonymisierte Logs, um sicherzustellen, dass RP-Anfragen mit den registrierten Anwendungsfällen übereinstimmen.

Nächste Schritte

Wenn Sie mit dem Onboarding als Verifier-Registrar beginnen möchten, füllen Sie das Aufnahmeformular für das Onboarding von Verifier-Registrars aus und reichen Sie es ein. Für das Onboarding nachfolgender nachgelagerter Kunden verwenden Sie das Aufnahmeformular für Verifier-Registrar-Clients.

Antworten auf häufig gestellte Fragen zum Onboarding und zur Integration finden Sie in den FAQ zu digitaler Identität und Anmeldedaten.

Details zur Integration von Verifier-Registrars

Im folgenden Abschnitt werden die technischen Details zur Integration für Verifier-Registrars beschrieben, die in die Digital Credentials API eingebunden werden (einschließlich Anfrageformatierung, Anfrageverschlüsselung, Auslösen der API, Validieren von Antworten und Implementieren von Zero-Knowledge-Proofs).

Unterstützte Formate und Funktionen

Google Wallet unterstützt ISO-mdoc basierte digitale Ausweise.

Anfrage formatieren

Wenn Sie Anmeldedaten von einem Wallet anfordern möchten, müssen Sie Ihre Anfrage mit OpenID4VP formatieren. Sie können bestimmte Anmeldedaten oder mehrere Anmeldedaten in einem einzigen dcql_query-Objekt anfordern.

JSON-Beispiel für eine Anfrage

Hier sehen Sie ein Beispiel für eine requestJson-Anfrage für mdoc, um Anmeldedaten von einem beliebigen Wallet auf einem Android-Gerät oder im Web abzurufen.

{
      "requests" : [
        {
          "protocol": "openid4vp-v1-signed",
          "data": {<signed_credential_request>} // This is an object, shouldn't be a string.
        }
      ]
}

Anfrageverschlüsselung

Die client_metadata enthält den öffentlichen Verschlüsselungsschlüssel für jede Anfrage. Sie müssen private Schlüssel für jede Anfrage speichern und damit das Token authentifizieren und autorisieren, das Sie von der Wallet-App erhalten.

Integrierte OpenID4VP-Metadaten

Wenn Sie Ihre Anfrage für Anmeldedaten formatieren, müssen Sie das Feld gw_rp_metadata_bytes im Objekt client_metadata einfügen (wie im Beispielcode für die Anfrage unten gezeigt). Dieses Feld enthält die Base64URL-codierten Metadaten der Relying Party, die von Google Wallet benötigt werden, um Ihre Identität zu bestätigen und Ihr Branding dem Nutzer zu präsentieren.

Der Parameter credential_request in requestJson enthält die folgenden Felder.

Bestimmte Anmeldedaten

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "cred1",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"  // this is for mDL. Use com.google.wallet.idcard.1 for ID pass
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
  },
  "client_metadata": {
    "jwks": {
      "keys": [ // sample request encryption key
        {
          "kty": "EC",
          "crv": "P-256",
          "x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
          "y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
          "use": "enc",
          "kid" : "1",  // This is required
          "alg" : "ECDH-ES",  // This is required
        }
      ]
    },
    "vp_formats_supported": {
      "mso_mdoc": {
        "deviceauth_alg_values": [
          -7
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Alle infrage kommenden Anmeldedaten

Hier sehen Sie die Beispielanfrage für sowohl mDL als auch digitalen Identitätsnachweis. Der Nutzer kann mit beiden fortfahren.

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "mdl-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      },
      {  // Credential type 2
        "id": "id_pass-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "com.google.wallet.idcard.1"
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
    credential_sets : [
      {
        "options": [
          [ "mdl-request" ],
          [ "id_pass-request" ]
        ]
      }
    ]
  },
  "client_metadata": {
    "jwks": {
      "keys": [ // sample request encryption key
        {
          "kty": "EC",
          "crv": "P-256",
          "x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
          "y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
          "use": "enc",
          "kid" : "1",  // This is required
          "alg" : "ECDH-ES",  // This is required
        }
      ]
    },
    "vp_formats_supported": {
      "mso_mdoc": {
        "deviceauth_alg_values": [
          -7
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Sie können eine beliebige Anzahl unterstützter Attribute von allen in Google Wallet gespeicherten Anmeldedaten anfordern.

Signierte Anfragen

Signierte Anfragen (JWT-gesicherte Autorisierungsanfragen) kapseln Ihre überprüfbare Präsentationsanfrage in einem kryptografisch signierten JSON Web Token (JWT) mit Ihrer PKI-Infrastruktur ein. So wird die Integrität der Anfrage sichergestellt und Ihre Identität gegenüber Google Wallet nachgewiesen.

Vorbereitung

Bevor Sie die Codeänderungen für signierte Anfragen implementieren, müssen Sie Folgendes haben:

  • Privater Schlüssel: Sie benötigen einen privaten Schlüssel (z.B. Elliptic Curve ES256), um die Anfrage zu signieren, die auf Ihrem Server verwaltet wird.
  • Zertifikat: Sie benötigen ein standardmäßiges X.509-Zertifikat, das von Ihrem Schlüsselpaar abgeleitet wurde.
  • Registrierung: Ihr öffentliches Zertifikat muss bei Google Wallet registriert sein.

Logik für die Erstellung von Anfragen

Um eine Anfrage zu erstellen, müssen Sie Ihren privaten Schlüssel verwenden und die Nutzlast in ein JWS einfügen.

def construct_openid4vp_request(
    doctypes: list[str],
    requested_fields: list[dict],
    nonce_base64: str,
    jwe_encryption_public_jwk: jwk.JWK,
    is_zkp_request: bool,
    is_signed_request: bool,
    state: dict,
    origin: str
) -> dict:

    # ... [Existing logic to build 'presentation_definition' and basic 'request_payload'] ...

    # ------------------------------------------------------------------
    # SIGNED REQUEST IMPLEMENTATION (JAR)
    # ------------------------------------------------------------------
    if is_signed_request:
        try:
            # 1. Load the Verifier's Certificate
            # We must load the PEM string into a cryptography x509 object
            verifier_cert_obj = x509.load_pem_x509_certificate(
                CERTIFICATE.encode('utf-8'),
                backend=default_backend()
            )

            # 2. Calculate Client ID (x509_hash)
            # We calculate the SHA-256 hash of the DER-encoded certificate.
            cert_der = verifier_cert_obj.public_bytes(serialization.Encoding.DER)
            verifier_fingerprint_bytes = hashlib.sha256(cert_der).digest()

            # Create a URL-safe Base64 hash (removing padding '=')
            verifier_fingerprint_b64 = base64.urlsafe_b64encode(verifier_fingerprint_bytes).decode('utf-8').rstrip("=")

            # Format the client_id as required by the spec
            client_id = f'x509_hash:{verifier_fingerprint_b64}'

            # 3. Update Request Payload with JAR specific fields
            request_payload["client_id"] = client_id

            # Explicitly set expected origins to prevent relay attacks
            # Format for android origin: origin = android:apk-key-hash:<base64SHA256_ofAppSigningCert>
            # Format for web origin: origin = <origin_url>
            if origin:
                request_payload["expected_origins"] = [origin]

            # 4. Create Signed JWT (JWS)
            # Load the signing private key
            signing_key = jwk.JWK.from_pem(PRIVATE_KEY.encode('utf-8'))

            # Initialize JWS with the JSON payload
            jws_token = jws.JWS(json.dumps(request_payload).encode('utf-8'))

            # Construct the JOSE Header
            # 'x5c' (X.509 Certificate Chain) is critical: it allows the wallet
            # to validate your key against the one registered in the console.
            x5c_value = base64.b64encode(cert_der).decode('utf-8')

            protected_header = {
                "alg": "ES256",                 # Algorithm (e.g., ES256 or RS256)
                "typ": "oauth-authz-req+jwt",   # Standard type for JAR
                "kid": "1",                     # Key ID
                "x5c": [x5c_value]              # Embed the certificate
            }

            # Sign the token
            jws_token.add_signature(
                key=signing_key,
                alg=None,
                protected=json_encode(protected_header)
            )

            # 5. Return the Request Object
            # Instead of returning the raw JSON, we return the signed JWT string
            # under the 'request' key.
            return {"request": jws_token.serialize(compact=True)}

        except Exception as e:
            print(f"Error signing OpenID4VP request: {e}")
            return None

    # ... [Fallback for unsigned requests] ...
    return request_payload

API auslösen

Die gesamte API-Anfrage sollte serverseitig generiert werden. Je nach Plattform übergeben Sie das generierte JSON an die Plattform-APIs.

In-App (Android)

So fordern Sie Anmeldedaten von Ihren Android-Apps an:

Abhängigkeiten aktualisieren

Aktualisieren Sie in der Datei „build.gradle“ Ihres Projekts die Abhängigkeiten, um den Credential Manager (Beta) zu verwenden:

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}

Credential Manager konfigurieren

Fügen Sie eine Logik ähnlich der folgenden hinzu, um ein CredentialManager-Objekt zu konfigurieren und zu initialisieren:

// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)

Attribute zur Identität anfordern

Anstatt einzelne Parameter für Identitätsanfragen anzugeben, werden sie von der App alle zusammen als JSON-String in CredentialOption bereitgestellt. Der Credential Manager übergibt diesen JSON-String an die verfügbaren digitalen Wallets, ohne den Inhalt zu prüfen. Jedes Wallet ist dann für Folgendes verantwortlich: - JSON-String parsen, um die Identitätsanfrage zu verstehen. - Festlegen, welche der gespeicherten Anmeldedaten die Anfrage erfüllen.

Wir empfehlen Partnern, ihre Anfragen auf dem Server zu erstellen, auch für Android-App-Integrationen.

Verwenden Sie requestJson aus Anfrageformat als request im Funktionsaufruf GetDigitalCredentialOption().

// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
    GetDigitalCredentialOption(requestJson = requestJson)

// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
    listOf(digitalCredentialOption)
)

coroutineScope.launch {
    try {
        val result = credentialManager.getCredential(
            context = activityContext,
            request = getCredRequest
        )
        verifyResult(result)
    } catch (e : GetCredentialException) {
        handleFailure(e)
    }
}

Antwort auf Anmeldedaten verarbeiten

Sobald Sie eine Antwort vom Wallet erhalten, prüfen Sie, ob die Antwort erfolgreich war und die credentialJson-Antwort enthält.

// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is DigitalCredential -> {
            val responseJson = credential.credentialJson
            validateResponseOnServer(responseJson) // make a server call to validate the response
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential ${credential.type}")
        }
    }
}

// Handle failure.
fun handleFailure(e: GetCredentialException) {
  when (e) {
        is GetCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to share the credential.
        }
        is GetCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is NoCredentialException -> {
            // No credential was available.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}

Die credentialJson-Antwort enthält ein verschlüsseltes identityToken (JWT), das vom W3C definiert wurde. Die Wallet-App ist für die Erstellung dieser Antwort verantwortlich.

Beispiel:

{
  "protocol" : "openid4vp-v1-signed",
  "data" : {
    <encrpted_response>
  }
}

Sie übergeben diese Antwort zur Überprüfung der Authentizität an den Server zurück. Hier finden Sie die Schritte zum Validieren der Antwort auf Anmeldedaten.

Web

Wenn Sie Anmeldedaten mit der Digital Credentials API in Chrome oder anderen unterstützten Browsern anfordern möchten, stellen Sie die folgende Anfrage.

const credentialResponse = await navigator.credentials.get({
          digital : {
          requests : [
            {
              protocol: "openid4vp-v1-signed",
              data: {<credential_request>} // This is an object, shouldn't be a string.
            }
          ]
        }
      })

Senden Sie die Antwort von dieser API zurück an Ihren Server, um die Antwort auf Anmeldedaten zu validieren.

Antwort validieren

Sobald das Wallet das verschlüsselte identityToken (JWT) zurückgibt, müssen Sie eine strenge serverseitige Validierung durchführen, bevor Sie den Daten vertrauen.

Antwort entschlüsseln

Verwenden Sie den privaten Schlüssel, der dem öffentlichen Schlüssel entspricht, der in den client_metadata der Anfrage gesendet wurde, um das JWE zu entschlüsseln. Dadurch erhalten Sie ein vp_token.

Beispiel für Python:

  from jwcrypto import jwe, jwk

  # Retrieve the Private Key from Datastore
  reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str)
  # Save public key thumbprint for session transcript
  encryption_public_jwk_thumbprint = reader_private_jwk.thumbprint()


  # Decrypt the JWE encrypted response from Google Wallet
  jwe_object = jwe.JWE()
  jwe_object.deserialize(encrypted_jwe_response_from_wallet)
  jwe_object.decrypt(reader_private_jwk)
  decrypted_payload_bytes = jwe_object.payload
  decrypted_data = json.loads(decrypted_payload_bytes)

decrypted_data führt zu einem vp_token-JSON, das die Anmeldedaten enthält.

  {
    "vp_token":
    {
      "cred1": ["<base64UrlNoPadding_encoded_credential>"] // This applies to OpenID4VP 1.0 spec.
    }
  }
  1. Sitzungsprotokoll erstellen

    Im nächsten Schritt erstellen Sie das SessionTranscript aus ISO/IEC 18013-5:2021 mit einer Android- oder webspezifischen Übergabestruktur:

    SessionTranscript = [
      null,                // DeviceEngagementBytes not available
      null,                // EReaderKeyBytes not available
      [
        "OpenID4VPDCAPIHandover",
        AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
      ]
    ]
    

    Für Android- und Web-Übergaben müssen Sie dieselbe Nonce verwenden, die Sie zum Generieren von credential_request verwendet haben.

    Android-Übergabe

        AndroidHandoverData = [
          origin,             // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>",
          nonce,           // nonce that was used to generate credential request,
          encryption_public_jwk_thumbprint,  // Encryption public key (JWK) Thumbprint
        ]
    
        AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
        

    Browserübergabe

        BrowserHandoverData =[
          origin,               // Origin URL
          nonce,               //  nonce that was used to generate credential request
          encryption_public_jwk_thumbprint,  // Encryption public key (JWK) Thumbprint
        ]
    
        BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
        

    Mit dem SessionTranscript muss die Geräteantwort gemäß ISO/IEC 18013-5:2021, Abschnitt 9 validiert werden.

    Diese Validierung umfasst mehrere Schritte:

  2. Ausstellerzertifikat prüfen: Extrahieren Sie die Signaturzertifikatskette des Ausstellers aus issuerAuth und validieren Sie sie anhand der vertrauenswürdigen IACA-Root-Zertifikate. Informationen zu den unterstützten IACA-Zertifikaten des Ausstellers

  3. MSO-Signatur überprüfen (18013-5, Abschnitt 9.1.2)

  4. ValueDigests für Datenelemente berechnen und prüfen (18013-5, Abschnitt 9.1.2)

  5. deviceSignature-Signatur überprüfen (18013-5, Abschnitt 9.1.3)

{
  "version": "1.0",
  "documents": [
    {
      "docType": "org.iso.18013.5.1.mDL",
      "issuerSigned": {
        "nameSpaces": {...}, // contains data elements
        "issuerAuth": [...]  // COSE_Sign1 w/ issuer PK, mso + sig
      },
      "deviceSigned": {
        "nameSpaces": 24(<< {} >>), // empty
        "deviceAuth": {
          "deviceSignature": [...] // COSE_Sign1 w/ device signature
        }
      }
    }
  ],
  "status": 0
}

Datenschutzfreundliche Altersüberprüfung (Zero-Knowledge-Proof)

Wenn Sie Zero-Knowledge-Proofs unterstützen möchten (z.B. um zu überprüfen, ob ein Nutzer über 18 Jahre alt ist, ohne sein genaues Geburtsdatum zu sehen), ändern Sie das Anfrageformat in mso_mdoc_zk und geben Sie die erforderliche zk_system_type-Konfiguration an.

Eine allgemeine Übersicht über Zero-Knowledge-Proofs und ihre Funktionen finden Sie in den FAQ.

  ...
  "dcql_query": {
    "credentials": [{
      "id": "cred1",
      "format": "mso_mdoc_zk",
      "meta": {
        "doctype_value": "org.iso.18013.5.1.mDL"
        "zk_system_type": [
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "f88a39e561ec0be02bb3dfe38fb609ad154e98decbbe632887d850fc612fea6f", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 5,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "137e5a75ce72735a37c8a72da1a8a0a5df8d13365c2ae3d2c2bd6a0e7197c7c6", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 6,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

Sie erhalten einen verschlüsselten Zero-Knowledge-Proof vom Wallet zurück. Sie können diesen Proof mit den IACA-Zertifikaten der Aussteller mithilfe der Longfellow-zk-Bibliothek von Google validieren.

Der Verifier-Dienst enthält einen einsatzbereiten, Docker-basierten Server, mit dem Sie die Antwort anhand bestimmter IACA-Zertifikate des Ausstellers validieren können.

Sie können die Datei „certs.pem“ ändern, um IACA-Ausstellerzertifikate zu verwalten, denen Sie vertrauen möchten.

Ressourcen und Support