Zum Hauptinhalt springen

DCQL erklärt: wie ein Verifier eine Wallet um genau das bittet, was er braucht

Die Digital Credentials Query Language, DCQL, ist das JSON-Abfrageformat, das OpenID4VP innerhalb einer Präsentationsanfrage verwendet. Damit beschreibt eine Relying Party, welche Credentials und welche Claims darin sie sehen möchte, und zwar so, dass jede konforme Wallet die Abfrage ohne individuelle Integration verarbeiten kann.

Das Problem, das DCQL löst

Eine Business Wallet kann Credentials in mehreren Formaten enthalten: einen Handelsregistereintrag als SD-JWT VC, eine berufliche Qualifikation als mdoc, ein W3C Verifiable Credential aus einem früheren Pilotprojekt. Ein Verifier, der nur eine Registernummer und einen Firmennamen bestätigen muss, hat keinen formatübergreifenden, portablen Weg, genau das anzufordern. Er muss entweder das gesamte Credential akzeptieren oder für jedes Format und jeden Wallet-Anbieter eine eigene Anfrage programmieren.

DCQL schließt diese Lücke auf der Anfrageseite. Es ist ein einzelnes JSON-Objekt, eingebettet in die OpenID4VP-Autorisierungsanfrage, das eine oder mehrere Credential Queries benennt, jeweils festgelegt auf ein Format und eine Menge von Claim-Pfaden. Die Wallet wertet die Abfrage gegen ihre gespeicherten Credentials aus, ermittelt die passenden und bittet erst dann den Inhaber, die Freigabe genau dieser Claims zu bestätigen. Der Verifier erhält eine vorhersehbare Struktur, unabhängig davon, welche Wallet der Inhaber nutzt.

1. Verifier

Sendet eine OpenID4VP-Anfrage mit einer dcql_query

2. Wallet

Gleicht die Abfrage mit gespeicherten Credentials ab

3. Inhaber

Gibt nur die angefragten Claims frei

4. Verifier

Erhält eine Präsentation pro Credential-Query-id

Der Aufbau einer DCQL-Abfrage

Eine DCQL-Abfrage ist ein JSON-Objekt mit einem credentials-Array und optional einem credential_sets-Array. Jeder Eintrag in credentials ist eine Credential Query. Mit M gekennzeichnete Felder sind in dieser Query Pflicht.

dcql_query

credentials[ ]

Eine Credential Query pro benötigtem Credential

id + format

Welches Credential, in welchem Format

meta

Typfilter, etwa vct_values

claims[ ]

Pfade der offenzulegenden Claims

claim_sets[ ]

Zulässige Claim-Kombinationen

credential_sets[ ]

Optional: welche Kombinationen von Credential Queries die Anfrage erfüllen

FeldTypPflicht
idstringM
formatenum: dc+sd-jwt | mso_mdoc | jwt_vc_json | ldp_vcM
metaObjekt, Aufbau abhängig von format
claimsArray von Claim Queries
claim_setsArray von Arrays mit Claim-ids
trusted_authoritiesArray von Objekten mit type und values

Jeder Eintrag in claims ist selbst ein Objekt: eine id, über die claim_sets darauf verweist, ein path, also ein Array, das den Claim im Credential verortet (zum Beispiel ["legal_name"] für einen SD-JWT-Claim auf oberster Ebene oder ["org", "registration_number"] für einen verschachtelten), und optional values, eine Liste von Werten, denen der Claim entsprechen muss.

Praxisbeispiel: Prüfung eines Handelsregistereintrags

Handelsregistereintrag

dc+sd-jwt

Der Verifier sagt: Das möchte ich erhalten

  • ✓ Registernummerreg_nopath: ["registration_number"]
  • ✓ Firmennamelegal_namepath: ["legal_name"]
  • ✓ Registrierungslandreg_countrypath: ["registration_country"]
{
  "credentials": [
    {
      "id": "company_registration",
      "format": "dc+sd-jwt",
      "meta": {
        "vct_values": ["urn:eudi:business:company-registration:1"]
      },
      "claims": [
        { "id": "reg_no", "path": ["registration_number"] },
        { "id": "legal_name", "path": ["legal_name"] },
        { "id": "reg_country", "path": ["registration_country"] }
      ]
    }
  ]
}

Beispielantwort der Wallet

Die Wallet antwortet mit einem vp_token-Objekt, dessen Schlüssel die Credential-Query-ids sind. Jeder Wert ist ein Array von Präsentationen. Bei dc+sd-jwt besteht eine Präsentation aus dem vom Aussteller signierten JWT, einer Disclosure pro freigegebenem Claim und einem Key Binding JWT, der sie an die Nonce und den Client dieser Anfrage bindet.

Was die Wallet sendet

{
  "vp_token": {
    "company_registration": [
      "<issuer-signed JWT>~<disclosure: registration_number>~<disclosure: legal_name>~<disclosure: registration_country>~<key binding JWT>"
    ]
  }
}

Claims, die der Verifier nach der Validierung sieht

{
  "vct": "urn:eudi:business:company-registration:1",
  "registration_number": "12345678",
  "legal_name": "Example Logistics B.V.",
  "registration_country": "NL"
}

Einen Fallback anfordern: claim_sets

claim_sets listet Gruppen von Claim-ids in der Reihenfolge der Präferenz. Die Wallet liefert die erste Gruppe, die sie mit dem, was der Inhaber tatsächlich besitzt, vollständig erfüllen kann. Der Verifier muss also keine zwei getrennten Anfragen für den genauen Fall und den Fallback senden.

Praxisbeispiel: Registernummer oder als Fallback nur der Firmenname

1. Bevorzugt

reg_nolegal_name

Wird geliefert, wenn das Credential beide Claims enthält

2. Fallback

legal_name

Wird nur geliefert, wenn das erste Set nicht erfüllbar ist

{
  "credentials": [
    {
      "id": "company_registration",
      "format": "dc+sd-jwt",
      "meta": { "vct_values": ["urn:eudi:business:company-registration:1"] },
      "claims": [
        { "id": "reg_no", "path": ["registration_number"] },
        { "id": "legal_name", "path": ["legal_name"] }
      ],
      "claim_sets": [
        ["reg_no", "legal_name"],
        ["legal_name"]
      ]
    }
  ]
}

Hier bevorzugt der Verifier eine Registernummer plus Firmenname, akzeptiert aber auch nur den Firmennamen, wenn das Credential des Inhabers keinen Claim mit Registernummer enthält.

Beispielantwort: Der Fallback wurde genutzt

Was die Wallet sendet

{
  "vp_token": {
    "company_registration": [
      "<issuer-signed JWT>~<disclosure: legal_name>~<key binding JWT>"
    ]
  }
}

Claims, die der Verifier nach der Validierung sieht

{
  "vct": "urn:eudi:business:company-registration:1",
  "legal_name": "Example Logistics B.V."
}

Das Credential des Inhabers hat keine Registernummer, daher hat die Wallet das zweite Claim-Set erfüllt und eine einzige Disclosure freigegeben. Die Antwort sagt nicht, welches Set verwendet wurde: Der Verifier erkennt das an den Claims, die er erhält.

Credentials kombinieren: credential_sets

credential_sets arbeitet eine Ebene über claim_sets. Jeder Eintrag listet options, wobei jede Option eine Gruppe von Credential-Query-ids ist. Die Wallet muss eine Option jedes erforderlichen Eintrags erfüllen. So erhält ein Verifier UND- und ODER-Logik über mehrere Credentials in einer einzigen Anfrage.

Erforderlich

Handelsregistereintrag

AND

Eines von

USt-Registrierung

OR

Eines von

Bankkontonachweis

"credential_sets": [
  { "options": [["company_registration"]] },
  { "options": [["vat_registration"], ["bank_account"]] }
]

Beispielantwort: Registrierung plus Bankkonto

Was die Wallet sendet

{
  "vp_token": {
    "company_registration": [
      "<issuer-signed JWT>~<disclosures>~<key binding JWT>"
    ],
    "bank_account": [
      "<issuer-signed JWT>~<disclosures>~<key binding JWT>"
    ]
  }
}

Claims, die der Verifier nach der Validierung sieht

{
  "company_registration": {
    "vct": "urn:eudi:business:company-registration:1",
    "registration_number": "12345678",
    "legal_name": "Example Logistics B.V."
  },
  "bank_account": {
    "vct": "urn:eudi:business:bank-account:1",
    "iban": "NL91ABNA0417164300",
    "account_holder": "Example Logistics B.V."
  }
}

Der Inhaber hat kein Credential zur USt-Registrierung, daher hat die Wallet die zweite Option des zweiten Sets gewählt. Nicht verwendete Query-ids, hier vat_registration, fehlen in vp_token einfach.

Nur vertrauenswürdige Aussteller: trusted_authorities

trusted_authorities schränkt eine Credential Query auf Credentials ein, deren Aussteller von einer Autorität gestützt wird, der der Verifier vertraut. Jeder Eintrag hat einen type und eine Liste von values: aki für einen Authority Key Identifier, etsi_tl für eine ETSI Trusted List oder openid_federation für einen Trust Anchor einer Föderation. Die Wallet bietet nur passende Credentials an.

Praxisbeispiel: eine Registrierung von einem gelisteten Aussteller

Der Verifier sagt: nur von Ausstellern auf dieser Vertrauensliste

type: etsi_tl

https://ec.europa.eu/tools/lotl/eu-lotl.xml

Registrierungs-Credential eines gelisteten Ausstellers

Aussteller steht auf der Vertrauensliste

✓ Erfüllt die Abfrage

Registrierungs-Credential eines nicht gelisteten Ausstellers

Aussteller steht nicht auf der Vertrauensliste

✗ Erfüllt sie nicht, wird dem Inhaber nicht angeboten

{
  "credentials": [
    {
      "id": "company_registration",
      "format": "dc+sd-jwt",
      "meta": { "vct_values": ["urn:eudi:business:company-registration:1"] },
      "trusted_authorities": [
        {
          "type": "etsi_tl",
          "values": ["https://ec.europa.eu/tools/lotl/eu-lotl.xml"]
        }
      ],
      "claims": [
        { "id": "reg_no", "path": ["registration_number"] },
        { "id": "legal_name", "path": ["legal_name"] }
      ]
    }
  ]
}

Beispielantwort: nur das Credential des gelisteten Ausstellers

Was die Wallet sendet

{
  "vp_token": {
    "company_registration": [
      "<issuer-signed JWT>~<disclosure: registration_number>~<disclosure: legal_name>~<key binding JWT>"
    ]
  }
}

Claims, die der Verifier nach der Validierung sieht

{
  "vct": "urn:eudi:business:company-registration:1",
  "registration_number": "12345678",
  "legal_name": "Example Logistics B.V."
}

Der Inhaber hatte auch ein Registrierungs-Credential eines nicht gelisteten Ausstellers, doch die Wallet hat es nicht angeboten. trusted_authorities ist ein Filter für die Wallet, keine Garantie: Der Verifier prüft den Aussteller bei der Validierung der Präsentation trotzdem selbst gegen die Vertrauensliste.

Einen Wert abgleichen: claims.values

Eine Claim Query kann values enthalten, eine Liste von Strings, Integern oder Booleans. Die Wallet liefert den Claim nur, wenn Typ und Wert exakt einem davon entsprechen. So kann ein Verifier eine Bedingung prüfen, ohne vorher etwas anderes anzufordern.

Praxisbeispiel: nur in den Niederlanden oder Belgien registrierte Unternehmen

Der Verifier sagt: nur ein Unternehmen, das in einem dieser Länder registriert ist

reg_countryvalues:"NL""BE"

Niederländisches Unternehmen

registration_country: "NL"

✓ Erfüllt die Abfrage

Deutsches Unternehmen

registration_country: "DE"

✗ Erfüllt sie nicht, wird dem Inhaber nicht angeboten

{
  "credentials": [
    {
      "id": "company_registration",
      "format": "dc+sd-jwt",
      "meta": { "vct_values": ["urn:eudi:business:company-registration:1"] },
      "claims": [
        { "id": "legal_name", "path": ["legal_name"] },
        {
          "id": "reg_country",
          "path": ["registration_country"],
          "values": ["NL", "BE"]
        }
      ]
    }
  ]
}

Beispielantwort: ein niederländisches Unternehmen

Was die Wallet sendet

{
  "vp_token": {
    "company_registration": [
      "<issuer-signed JWT>~<disclosure: legal_name>~<disclosure: registration_country>~<key binding JWT>"
    ]
  }
}

Claims, die der Verifier nach der Validierung sieht

{
  "vct": "urn:eudi:business:company-registration:1",
  "legal_name": "Example Logistics B.V.",
  "registration_country": "NL"
}

Das Credential eines deutschen Unternehmens hat registration_country "DE", erfüllt die Abfrage also nicht, und die Wallet hat dafür nichts zurückzugeben. Der Verifier sollte den Wert dennoch in den validierten Claims prüfen, statt sich auf die Filterung der Wallet zu verlassen.

Formatspezifische Einschränkungen in meta

SD-JWT VC: vct_values

Bei dc+sd-jwt listet meta.vct_values die Credential-Typkennungen auf, die der Verifier akzeptiert. Eine Query passt nur auf ein gespeichertes Credential, dessen vct einem der gelisteten Werte entspricht. Ein Verifier, der nur dem Registrierungs-Credential-Typ eines bestimmten Ausstellers vertraut, listet also genau diese Kennung.

mso_mdoc: doctype_value und Namespace

Bei mso_mdoc legt meta.doctype_value den ISO 18013-5 DocType fest, und jeder Claim-Pfad beginnt mit dem mdoc-Namespace, zu dem der Claim gehört, statt mit einem einfachen Feldnamen, da mdoc Claims nach Namespace gruppiert statt in einem flachen Objekt.

Wo DCQL heute steht

  • DCQL ist innerhalb der OpenID4VP-Spezifikation selbst definiert, nicht als separates Dokument, und ist Teil des Entwurfs, seit der Mechanismus eingeführt wurde, um eine frühere Abhängigkeit von DIF Presentation Exchange für OpenID4VP-Anfragen abzulösen.
  • Das EUDI Wallet Architecture and Reference Framework legt OpenID4VP als Präsentationsprotokoll fest und damit DCQL als den Abfragemechanismus, den Relying Parties und Wallets im Ökosystem unterstützen sollen.
  • Die Referenzimplementierungen für Wallets und Verifier im EUDI Wallet Reference Implementation-Programm setzen inzwischen einheitlich auf DCQL. Neue Business-Wallet-Integrationen, die heute auf OpenID4VP aufbauen, sollten daher DCQL und nicht Presentation Exchange als Abfrageformat für Präsentationsanfragen voraussetzen.

Verwandte Begriffe

Häufig gestellte Fragen

Worin unterscheidet sich DCQL von DIF Presentation Exchange?

Beide beschreiben, was ein Verifier von einer Wallet möchte. DCQL ist jedoch auf OpenID4VP beschränkt und direkt in dieser Spezifikation definiert, während Presentation Exchange eine eigenständige DIF-Spezifikation ist, die auch andere Protokolle abdeckt. DCQL ist bewusst schlanker: Es kennt keine Input Descriptor Groups oder Submission Requirements und drückt formatspezifische Einschränkungen, etwa einen mdoc-Doctype oder einen SD-JWT VC-Typ, direkt in einem Query-Objekt aus statt über einen generischen JSON-Schema-Filter. Das EUDI Wallet-Ökosystem hat sich für OpenID4VP-Präsentationen auf DCQL als Standard festgelegt.

Kann eine DCQL-Abfrage mehr als ein Credential anfordern?

Ja. Das credentials-Array kann mehrere Credential Queries enthalten, jede mit eigener id. Eine Wallet, die für jeden Eintrag ein passendes Credential hat, liefert pro Eintrag eine Präsentation. Das optionale credential_sets-Objekt kann darüber hinaus bestimmte Kombinationen verlangen, zum Beispiel entweder nur ein Handelsregister-Credential oder ein Handelsregister-Credential zusammen mit einer UBO-Erklärung, ohne den Inhaber zweimal zu fragen.

Welches Problem löst claim_sets innerhalb einer einzelnen Credential Query?

Ein Credential enthält nicht immer jeden Claim, den ein Verifier gern hätte. claim_sets listet alternative Gruppen von Claim-ids auf, von denen jede für sich die Anfrage erfüllen würde, sortiert von der meistgewünschten zur am wenigsten gewünschten. Die Wallet wählt die erste Gruppe, die sie mit den tatsächlich vorhandenen Claims des Inhabers vollständig erfüllen kann. So kann ein Verifier eine genaue Ausweisnummer anfordern, wo verfügbar, und auf eine gröbere Prüfung wie ein Volljährigkeitsmerkmal ausweichen, ohne zwei getrennte Anfragen zu senden.

Ist DCQL spezifisch für die EUDI Wallet?

Nein. DCQL ist Teil der OpenID4VP-Kernspezifikation und kann von jeder OpenID4VP-Implementierung genutzt werden. Das EUDI Wallet-Ökosystem ist ein prominenter Anwender: Das Architecture and Reference Framework legt OpenID4VP mit DCQL als Präsentationsmechanismus fest, den Relying Parties unterstützen müssen. Deshalb ist es besonders für Wallets und Verifier relevant, die für den europäischen Markt entwickelt werden.

Übernimmt DCQL selbst die Selective Disclosure?

Nein. DCQL beschreibt nur, was angefragt wird. Ob die Wallet genau diese Claims und nichts anderes offenlegen kann, hängt vom Credential-Format ab: Sowohl ein SD-JWT VC als auch ein ISO mdoc unterstützen die Offenlegung eines Teils ihrer Claims, und ein DCQL-claims-Array setzt auf dieser Fähigkeit auf. DCQL funktioniert auch mit einem Format ohne Selective Disclosure, dann müsste der Inhaber jedoch selbst für eine Abfrage nach nur einem Claim das vollständige Credential freigeben.

Quellen

  1. OpenID for Verifiable Presentations 1.0, Abschnitt Digital Credentials Query Language (DCQL)
  2. EUDI Wallet Architecture and Reference Framework
  3. Spezifikation DIF Presentation Exchange 2.0.0

Diese Seite dient nur der Information und stellt keine Rechtsberatung dar. Verbindliche Auskünfte erhalten Sie direkt bei der OpenID Foundation und der Europäischen Kommission.

Sprechen Sie mit uns über die Integration der EUDI Wallet