DCQL pe înțeles: cum cere un verificator unui portofel exact ce îi trebuie
Digital Credentials Query Language, DCQL, este formatul de interogare JSON pe care OpenID4VP îl folosește într-o cerere de prezentare. Permite unei părți care se bazează să descrie ce credențiale și ce atribute din acestea dorește să vadă, într-un mod pe care orice portofel conform îl poate interpreta fără o integrare personalizată.
Problema pe care o rezolvă DCQL
Un portofel de afaceri poate stoca credențiale în mai multe formate: o înregistrare a companiei ca SD-JWT VC, o calificare profesională codificată în mdoc, un credențial verificabil W3C dintr-un proiect pilot anterior. Un verificator care trebuie doar să confirme un număr de înregistrare și o denumire legală nu are o modalitate portabilă de a cere exact acest lucru, indiferent de format, fără a accepta întregul credențial sau a programa manual o cerere separată pentru fiecare format și fiecare furnizor de portofel.
DCQL rezolvă partea de cerere a acestei probleme. Este un singur obiect JSON, inclus în cererea de autorizare OpenID4VP, care specifică una sau mai multe interogări de credențiale, fiecare legată de un format și de un set de căi de atribute. Portofelul evaluează interogarea față de credențialele stocate, stabilește care corespund și abia apoi îi cere titularului să aprobe divulgarea acelor atribute concrete. Verificatorul primește o structură previzibilă de procesat, indiferent de portofelul folosit de titular.
1. Verificator
Trimite o cerere OpenID4VP cu un dcql_query
2. Portofel
Compară interogarea cu credențialele stocate
3. Titular
Aprobă divulgarea doar a atributelor solicitate
4. Verificator
Primește o prezentare pentru fiecare id de interogare
Structura unei interogări DCQL
O interogare DCQL este un obiect JSON cu un array credentials și, opțional, un array credential_sets. Fiecare intrare din credentials este o interogare de credențial. Câmpurile marcate cu M sunt obligatorii în acea interogare.
dcql_query
credentials[ ]
O interogare pentru fiecare credențial necesar
id + format
Ce credențial, în ce format
meta
Filtru de tip, de exemplu vct_values
claims[ ]
Căile atributelor de divulgat
claim_sets[ ]
Combinații de atribute acceptate
credential_sets[ ]
Opțional: ce combinații de interogări de credențiale satisfac cererea
| Câmp | Tip | Obligatoriu |
|---|---|---|
| id | string | M |
| format | enum: dc+sd-jwt | mso_mdoc | jwt_vc_json | ldp_vc | M |
| meta | obiect, structura depinde de format | |
| claims | array de interogări de atribute | |
| claim_sets | array de array-uri de id-uri de atribute | |
| trusted_authorities | array de obiecte cu un type și values |
Fiecare intrare din claims este la rândul ei un obiect: un id folosit pentru a o referi din claim_sets, un path, adică un array care localizează atributul în credențial (de exemplu ["legal_name"] pentru un atribut SD-JWT de nivel superior sau ["org", "registration_number"] pentru unul imbricat) și, opțional, values, o listă de valori cu care atributul trebuie să corespundă.
Exemplu practic: verificarea înregistrării unei companii
Înregistrarea companiei
dc+sd-jwtVerificatorul spune: asta vreau să primesc
- ✓ Număr de înregistrarereg_nopath: ["registration_number"]
- ✓ Denumire legalălegal_namepath: ["legal_name"]
- ✓ Țara de înregistrarereg_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"] }
]
}
]
}Exemplu de răspuns al portofelului
Portofelul răspunde cu un obiect vp_token indexat după id-ul interogării de credențial. Fiecare valoare este un array de prezentări. Pentru dc+sd-jwt, o prezentare este JWT-ul semnat de emitent, câte o disclosure pentru fiecare atribut divulgat și un JWT de key binding care o leagă de nonce-ul și clientul acestei cereri.
Ce trimite portofelul
{
"vp_token": {
"company_registration": [
"<issuer-signed JWT>~<disclosure: registration_number>~<disclosure: legal_name>~<disclosure: registration_country>~<key binding JWT>"
]
}
}Atributele pe care le vede verificatorul după validare
{
"vct": "urn:eudi:business:company-registration:1",
"registration_number": "12345678",
"legal_name": "Example Logistics B.V.",
"registration_country": "NL"
}Solicitarea unei alternative: claim_sets
claim_sets enumeră grupuri de id-uri de atribute, în ordinea preferinței. Portofelul returnează primul grup pe care îl poate satisface integral din ceea ce deține efectiv titularul, astfel încât verificatorul nu mai trebuie să trimită două cereri separate, una pentru cazul precis și una pentru cazul alternativ.
Exemplu practic: număr de înregistrare sau, ca alternativă, doar denumirea legală
1. Preferat
Returnat când credențialul conține ambele atribute
2. Alternativă
Returnat doar când primul set nu poate fi satisfăcut
{
"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"]
]
}
]
}Aici verificatorul preferă un număr de înregistrare împreună cu denumirea legală, dar acceptă doar denumirea legală dacă credențialul titularului nu conține un atribut cu numărul de înregistrare.
Exemplu de răspuns: a fost folosită alternativa
Ce trimite portofelul
{
"vp_token": {
"company_registration": [
"<issuer-signed JWT>~<disclosure: legal_name>~<key binding JWT>"
]
}
}Atributele pe care le vede verificatorul după validare
{
"vct": "urn:eudi:business:company-registration:1",
"legal_name": "Example Logistics B.V."
}Credențialul titularului nu are număr de înregistrare, așa că portofelul a satisfăcut al doilea set de atribute și a trimis o singură disclosure. Răspunsul nu indică ce set a fost folosit: verificatorul deduce acest lucru din atributele primite.
Combinarea credențialelor: credential_sets
credential_sets funcționează cu un nivel deasupra claim_sets. Fiecare intrare enumeră options, unde fiecare opțiune este un grup de id-uri de interogări de credențiale. Portofelul trebuie să satisfacă o opțiune din fiecare intrare obligatorie, ceea ce îi oferă verificatorului logică AND și OR între credențiale într-o singură cerere.
Obligatoriu
Înregistrarea companiei
Unul dintre
Înregistrare în scopuri de TVA
Unul dintre
Atestare de cont bancar
"credential_sets": [
{ "options": [["company_registration"]] },
{ "options": [["vat_registration"], ["bank_account"]] }
]Exemplu de răspuns: înregistrare plus cont bancar
Ce trimite portofelul
{
"vp_token": {
"company_registration": [
"<issuer-signed JWT>~<disclosures>~<key binding JWT>"
],
"bank_account": [
"<issuer-signed JWT>~<disclosures>~<key binding JWT>"
]
}
}Atributele pe care le vede verificatorul după validare
{
"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."
}
}Titularul nu are un credențial de înregistrare în scopuri de TVA, așa că portofelul a ales a doua opțiune din al doilea set. Id-urile de interogare nefolosite, aici vat_registration, pur și simplu lipsesc din vp_token.
Doar emitenți de încredere: trusted_authorities
trusted_authorities restrânge o interogare la credențialele al căror emitent este susținut de o autoritate în care verificatorul are încredere. Fiecare intrare are un type și o listă de values: aki pentru un identificator de cheie al autorității (authority key identifier), etsi_tl pentru o listă de încredere ETSI sau openid_federation pentru o ancoră de încredere a unei federații. Portofelul oferă doar credențialele care corespund.
Exemplu practic: o înregistrare de la un emitent listat
Verificatorul spune: doar de la emitenți din această listă de încredere
https://ec.europa.eu/tools/lotl/eu-lotl.xml
Credențial de înregistrare de la un emitent listat
emitentul se află pe lista de încredere
✓ Corespunde interogării
Credențial de înregistrare de la un emitent nelistat
emitentul nu se află pe lista de încredere
✗ Nu corespunde, nu este oferit titularului
{
"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"] }
]
}
]
}Exemplu de răspuns: doar credențialul emitentului listat
Ce trimite portofelul
{
"vp_token": {
"company_registration": [
"<issuer-signed JWT>~<disclosure: registration_number>~<disclosure: legal_name>~<key binding JWT>"
]
}
}Atributele pe care le vede verificatorul după validare
{
"vct": "urn:eudi:business:company-registration:1",
"registration_number": "12345678",
"legal_name": "Example Logistics B.V."
}Titularul avea și un credențial de înregistrare de la un emitent nelistat, dar portofelul nu l-a oferit. trusted_authorities este un filtru pentru portofel, nu o garanție: verificatorul verifică în continuare el însuși emitentul în lista de încredere atunci când validează prezentarea.
Potrivirea unei valori: claims.values
O interogare de atribut poate conține values, o listă de șiruri de caractere, numere întregi sau valori booleene. Portofelul returnează atributul doar când tipul și valoarea sa corespund exact uneia dintre ele, astfel încât un verificator poate verifica o condiție fără a cere mai întâi altceva.
Exemplu practic: doar companii înregistrate în Țările de Jos sau în Belgia
Verificatorul spune: doar o companie înregistrată într-una dintre aceste țări
Companie olandeză
registration_country: "NL"
✓ Corespunde interogării
Companie germană
registration_country: "DE"
✗ Nu corespunde, nu este oferit titularului
{
"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"]
}
]
}
]
}Exemplu de răspuns: o companie olandeză
Ce trimite portofelul
{
"vp_token": {
"company_registration": [
"<issuer-signed JWT>~<disclosure: legal_name>~<disclosure: registration_country>~<key binding JWT>"
]
}
}Atributele pe care le vede verificatorul după validare
{
"vct": "urn:eudi:business:company-registration:1",
"legal_name": "Example Logistics B.V.",
"registration_country": "NL"
}Credențialul unei companii germane are registration_country "DE", deci nu satisface interogarea, iar portofelul nu are nimic de returnat pentru acesta. Verificatorul ar trebui totuși să verifice valoarea în atributele validate, în loc să se bazeze pe filtrarea făcută de portofel.
Constrângeri specifice formatului în meta
SD-JWT VC: vct_values
Pentru dc+sd-jwt, meta.vct_values enumeră identificatorii de tip de credențial pe care verificatorul îi acceptă. O interogare corespunde doar unui credențial stocat al cărui vct este una dintre valorile enumerate, astfel încât un verificator care are încredere doar în tipul de credențial de înregistrare al unui singur emitent enumeră exact acel identificator.
mso_mdoc: doctype_value și namespace
Pentru mso_mdoc, meta.doctype_value fixează DocType-ul ISO 18013-5, iar fiecare cale de atribut începe cu namespace-ul mdoc căruia îi aparține atributul, nu cu un simplu nume de câmp, deoarece mdoc grupează atributele pe namespace-uri în loc de un obiect plat.
Stadiul actual al DCQL
- DCQL este definit în cadrul specificației OpenID4VP, nu ca document separat, și face parte din draft de când mecanismul a fost introdus pentru a înlocui o dependență anterioară de DIF Presentation Exchange în cererile OpenID4VP.
- EUDI Wallet Architecture and Reference Framework specifică OpenID4VP ca protocol de prezentare și, odată cu acesta, DCQL ca mecanism de interogare pe care părțile care se bazează și portofelele din ecosistem sunt așteptate să îl suporte.
- Implementările de referință pentru portofele și verificatori din programul EUDI Wallet Reference Implementation au convergit spre DCQL, așa că noile integrări de portofele de afaceri construite astăzi pe OpenID4VP ar trebui să considere DCQL, nu Presentation Exchange, drept format de interogare pentru cererile de prezentare.
Termeni înrudiți
Întrebări frecvente
Prin ce diferă DCQL de DIF Presentation Exchange?
Ambele descriu ce dorește un verificator de la un portofel, dar DCQL este limitat la OpenID4VP și definit direct în acea specificație, în timp ce Presentation Exchange este o specificație DIF separată, care acoperă și alte protocoale. DCQL este intenționat mai restrâns: nu are grupuri de input descriptors sau submission requirements și exprimă constrângerile specifice formatului, cum ar fi un doctype mdoc sau un tip SD-JWT VC, direct într-un obiect de interogare, nu printr-un filtru JSON Schema generic. Ecosistemul EUDI Wallet a adoptat DCQL ca standard pentru prezentările OpenID4VP.
Poate o singură interogare DCQL să solicite mai multe credențiale?
Da. Array-ul credentials poate conține mai multe interogări de credențiale, fiecare cu propriul id. Un portofel care deține potriviri pentru toate intrările returnează o prezentare pentru fiecare intrare. Obiectul opțional credential_sets poate impune, în plus, anumite combinații, de exemplu să accepte fie doar un credențial de înregistrare a companiei, fie un credențial de înregistrare a companiei împreună cu o declarație UBO, fără a-l întreba pe titular de două ori.
Ce problemă rezolvă claim_sets în cadrul unei singure interogări de credențial?
Un credențial nu conține întotdeauna toate atributele pe care și le-ar dori un verificator. claim_sets enumeră grupuri alternative de id-uri de atribute, fiecare suficient pe cont propriu pentru a satisface cererea, ordonate de la cel mai preferat la cel mai puțin preferat. Portofelul alege primul grup pe care îl poate satisface integral cu atributele pe care titularul le deține efectiv, astfel încât un verificator poate solicita un număr de identificare precis, acolo unde există, și poate recurge la o verificare mai generală, cum ar fi un indicator de peste 18 ani, fără a trimite două cereri separate.
Este DCQL specific EUDI Wallet?
Nu. DCQL face parte din specificația de bază OpenID4VP și orice implementare OpenID4VP îl poate folosi. Ecosistemul EUDI Wallet este un adoptator important: Architecture and Reference Framework specifică OpenID4VP cu DCQL ca mecanism de prezentare pe care părțile care se bazează trebuie să îl suporte, motiv pentru care contează în mod special pentru portofelele și verificatorii dezvoltați pentru piața europeană.
Realizează DCQL în sine divulgarea selectivă?
Nu. DCQL descrie doar ceea ce se solicită. Dacă portofelul poate dezvălui exact acele atribute și nimic altceva depinde de formatul credențialului: atât un SD-JWT VC, cât și un ISO mdoc permit divulgarea unui subset al atributelor, astfel încât un array claims din DCQL se sprijină pe această capacitate. DCQL aplicat unui format fără divulgare selectivă ar funcționa în continuare, dar titularul ar trebui să divulge întregul credențial pentru a satisface chiar și o interogare pentru un singur atribut.
Surse
Această pagină are caracter informativ și nu constituie consultanță juridică. Pentru îndrumări oficiale, consultați direct OpenID Foundation și Comisia Europeană.