Documentation
¶
Overview ¶
Package dcql implements the OpenID4VP 1.0 Digital Credentials Query Language (§6) and claims path pointers (§7): model, strict parsing, validation, matching of already-verified credentials, and TS5 registered-scope checks. No crypto lives here.
Index ¶
- Constants
- Variables
- func Resolve(format string, claims map[string]any, path ClaimPath) ([]any, error)
- type AuthorityRef
- type Candidate
- type ClaimPath
- type ClaimsQuery
- type CredentialQuery
- type CredentialSetQuery
- type MatchResult
- type Meta
- type PathElement
- type PathKind
- type Query
- type RegisteredCredential
- type TrustedAuthority
- type Unmet
- type UnmetReason
- type ValidationError
Constants ¶
const ( FormatMdoc = "mso_mdoc" // OID4VP Annex B.2 FormatSDJWT = "dc+sd-jwt" // OID4VP Annex B.3 )
Credential format identifiers profiled by HAIP 1.0.
const ( AuthorityTypeAKI = "aki" AuthorityTypeETSITL = "etsi_tl" AuthorityTypeOpenIDFederation = "openid_federation" )
Trusted-authority query types (OID4VP §6.1.1).
Variables ¶
var ( // ErrParse wraps syntactic failures of Parse (malformed JSON, unknown // members, bad path elements). Services map it to err:credential:parse // or a 400 at the management boundary. ErrParse = errors.New("dcql: parse") // ErrInvalid wraps semantic failures of Validate; every joined entry is // a *ValidationError with a position. // Resolve also wraps structural misuse (e.g. malformed mdoc paths, // unsupported formats) in ErrInvalid, without positions. ErrInvalid = errors.New("dcql: invalid query") )
Functions ¶
func Resolve ¶
Resolve applies a claims path pointer to the claims of one credential. SD-JWT VC: full JSON traversal per OID4VP §7.1/§7.3 — a component that selects nothing resolves the whole path to no claims (empty result, nil error). mdoc: exactly [namespace, element] per §7.2 — any other shape is ErrInvalid (structural misuse, distinct from "not disclosed").
Types ¶
type AuthorityRef ¶
type AuthorityRef struct {
AKIs []string // base64url KeyIdentifier values of chain certs (aki)
TrustedListURIs []string // ETSI TS 119 612 trusted list(s) of the anchor (etsi_tl)
FederationIDs []string // OpenID Federation Entity Identifiers (openid_federation)
}
AuthorityRef carries trust references of the candidate's verified issuer chain, supplied by the pipeline; compared against trusted_authorities queries (OID4VP §6.1.1, matching logic in T-05.5).
type Candidate ¶
type Candidate struct {
QueryCredID string // vp_token key: which credential query it answers (OID4VP §8.1)
Format string // mso_mdoc | dc+sd-jwt
DoctypeOrVCT string // mdoc doctype or SD-JWT VC vct
Claims map[string]any // mdoc: namespace → element → value; sd-jwt: claims object
HolderBound bool // cryptographic holder binding verified (pipeline step 6)
IssuerAuthority AuthorityRef
}
Candidate is one already-verified credential presented for a credential query (pipeline steps 3–6 done). WP-05 decision: the matcher operates post-verification only — no crypto here; the pipeline enforces that no unverified candidate enters.
type ClaimPath ¶
type ClaimPath []PathElement
ClaimPath is an OID4VP §7 claims path pointer: a non-empty array whose elements select object keys (string), array indices (non-negative integer), or all elements of an array (null).
func NewPath ¶
func NewPath(elems ...PathElement) ClaimPath
NewPath constructs a ClaimPath from path elements.
func (ClaimPath) MarshalJSON ¶
MarshalJSON encodes the path as a JSON array.
func (ClaimPath) String ¶
String renders the path in its JSON form — the canonical representation used in MatchResult.ByCredential, Unmet.Paths, and scope offenses.
func (*ClaimPath) UnmarshalJSON ¶
UnmarshalJSON enforces §7 syntax: string | non-negative integer | null.
type ClaimsQuery ¶
type ClaimsQuery struct {
ID string `json:"id,omitempty"` // required when claim_sets present (§6.3)
Path ClaimPath `json:"path"`
Values []any `json:"values,omitempty"` // strings, integers, booleans (§6.3)
}
ClaimsQuery per OID4VP §6.3.
type CredentialQuery ¶
type CredentialQuery struct {
ID string `json:"id"`
Format string `json:"format"`
Multiple bool `json:"multiple,omitempty"` // §6.1: default false
Meta *Meta `json:"meta,omitempty"` // §6.1: REQUIRED — enforced by Validate
TrustedAuthorities []TrustedAuthority `json:"trusted_authorities,omitempty"`
RequireCryptographicHolderBinding *bool `json:"require_cryptographic_holder_binding,omitempty"` // §6.1: default true
Claims []ClaimsQuery `json:"claims,omitempty"`
ClaimSets [][]string `json:"claim_sets,omitempty"`
}
CredentialQuery per OID4VP §6.1.
func (*CredentialQuery) HolderBindingRequired ¶
func (c *CredentialQuery) HolderBindingRequired() bool
HolderBindingRequired resolves the §6.1 default (true).
type CredentialSetQuery ¶
type CredentialSetQuery struct {
Options [][]string `json:"options"`
Required *bool `json:"required,omitempty"` // §6.2: default true
}
CredentialSetQuery per OID4VP §6.2.
func (*CredentialSetQuery) IsRequired ¶
func (s *CredentialSetQuery) IsRequired() bool
IsRequired resolves the §6.2 default (true).
type MatchResult ¶
type MatchResult struct {
Satisfied bool
ByCredential map[string][]string // credential query id → claim paths actually used
Unmet []Unmet
}
MatchResult reports the outcome. Unmet may be non-empty even when Satisfied is true: it also lists optional queries/sets that did not match.
type Meta ¶
type Meta struct {
VCTValues []string `json:"vct_values,omitempty"` // dc+sd-jwt
DoctypeValue string `json:"doctype_value,omitempty"` // mso_mdoc
}
Meta carries the format-specific parameters (OID4VP Annex B.2.3 / B.3.5). Exactly one side is populated, matching Format — enforced by Validate.
type PathElement ¶
type PathElement struct {
Key string // set when Kind == KindKey
Index int // set when Kind == KindIndex
Kind PathKind
}
PathElement is one component of a ClaimPath.
type Query ¶
type Query struct {
Credentials []CredentialQuery `json:"credentials"`
CredentialSets []CredentialSetQuery `json:"credential_sets,omitempty"`
}
Query is a DCQL query — faithful OID4VP §6 model, json tags exact.
func Parse ¶
Parse parses raw into a Query. Strict at every level: unknown members are rejected (WP-05 decision — this is the query-AUTHORING boundary; a member we don't understand could silently widen disclosure. OID4VP §6's "ignore unknown properties" targets consumers of foreign queries, i.e. wallets.) Numbers are kept as json.Number so claim values survive untouched.
func PresetMDLDrivingPrivileges ¶
func PresetMDLDrivingPrivileges() *Query
PresetMDLDrivingPrivileges requests the driving_privileges element of an ISO/IEC 18013-5 mobile driving licence.
func PresetPIDAgeOver18 ¶
func PresetPIDAgeOver18() *Query
PresetPIDAgeOver18 requests proof of being over 18 from a PID, accepting the mdoc or the SD-JWT VC encoding via one required credential_set with two options (OID4VP §6.2).
Withdrawal caveat: the upstream PID Rulebook (eudi-doc-attestation-rulebooks- catalog, rulebooks/pid/pid-rulebook.md, current as of 2026-07-03) removed age_over_18 (and all age-verification attributes) from the PID attribute catalog in v1.1 (4 Sep 2025) "following CIR 2024/2977"; the current version (v1.6, 1 Jul 2026) and the CIR (EU) 2024/2977 Annex itself list no age attribute at all. PresetPIDAgeOver18 is kept using age_over_18 per this task's brief — no replacement identifier exists in the current PID schema to substitute — but callers should treat it as targeting a deprecated/withdrawn attribute pending a dedicated Age Verification attestation rulebook upstream. See SOURCE.md for exact citations.
func PresetPIDFull ¶
func PresetPIDFull() *Query
PresetPIDFull requests a PID with its mandatory-to-present claims: the claims member is deliberately absent (OID4VP §6.4.1 — the wallet returns the claims mandatory to present), so no claim names are hardcoded here.
func (*Query) Match ¶
func (q *Query) Match(cands []Candidate) MatchResult
Match decides whether the verified candidates satisfy the query (OID4VP §6.4). Precondition: q passed Validate(). Fail closed: a candidate answering an unknown credential query id (over-disclosure, pipeline step 8) makes the whole result unsatisfied.
func (*Query) Validate ¶
Validate checks the semantic rules of OID4VP §6/§7 and returns all violations joined; each entry is a *ValidationError with a position.
func (*Query) WithinScope ¶
func (q *Query) WithinScope(registered []RegisteredCredential) (bool, []string)
WithinScope checks that every claim the query COULD request (union over claims, regardless of claim_sets choice) lies within the registered intended use. Drives err:client:scope-exceeded at the management boundary. Offense strings carry positions and paths — never claim values. The query must have passed Validate(); on unvalidated queries the check fails closed per-credential but individual guarantees are weaker. A claim is in scope when ANY covering registration lists it (union across registrations).
type RegisteredCredential ¶
type RegisteredCredential struct {
Format string
DoctypesOrVCTs []string // registered doctype(s) (mdoc) or vct value(s) (sd-jwt)
AllClaims bool // registration covers every claim of the credential
Claims []ClaimPath // registered claim paths when AllClaims is false
}
RegisteredCredential mirrors one Credential entry of the client's TS5 registered intended use (ETSI TS5 v1.3 §2.4.1/2.4.4 — WP-05 spec refs).
type TrustedAuthority ¶
TrustedAuthority per OID4VP §6.1.1.
type Unmet ¶
type Unmet struct {
CredentialID string // credential query id; "" for set-level entries
SetIndex int // index into credential_sets; -1 otherwise
Reason UnmetReason
Paths []string
}
Unmet explains one failed query or set. Paths only — never claim values (hard rule 3; safe for the verification report).
type UnmetReason ¶
type UnmetReason string
UnmetReason categorizes why a credential query or credential set could not be satisfied.
const ( UnmetNoCandidate UnmetReason = "no-candidate" UnmetFormat UnmetReason = "format-mismatch" UnmetMeta UnmetReason = "meta-mismatch" UnmetClaims UnmetReason = "claims-unsatisfied" UnmetHolderBinding UnmetReason = "holder-binding-missing" UnmetAuthority UnmetReason = "authority-mismatch" UnmetMultiple UnmetReason = "multiple-not-allowed" UnmetSet UnmetReason = "credential-set-unsatisfied" UnmetUnknownQuery UnmetReason = "unknown-credential-query" )
Reasons a credential query or credential set can go unmet.
type ValidationError ¶
ValidationError pinpoints one violation, e.g. Pos "credentials[0].claims[1].path". Never contains claim values (hard rule 3).
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) Is ¶
func (e *ValidationError) Is(target error) bool
Is reports whether this error wraps ErrInvalid.