Table of Contents

Class Dcql

Namespace
Tessio.Verifier.OpenId4Vp
Assembly
Tessio.Verifier.OpenId4Vp.dll

Builders for OpenID4VP DCQL (Digital Credentials Query Language) queries, producing the JSON string expected by DcqlQueryJson.

public static class Dcql
Inheritance
Dcql
Inherited Members

Remarks

Two levels of builder, and the difference is how a claim is ADDRESSED, not how many credential types a query accepts. The params string[] overloads name claims, which assumes every claim sits at the top level of its credential. The DcqlClaim overloads address claims by PATH and accept claim sets, which is what a nested claim or a preference order over alternatives needs. Both levels can name several credential types in one query.

This used to tell callers to hand-write the JSON for a nested path or a claim set. A builder that covers only the easy shape does not prevent the hard one, it only decides where the hard one gets written: in a caller, where the path the query asks for sits apart from the code that reads the answer back, and nothing compares the two. Still hand-written, because nothing asks for it yet: claim value constraints.

Several Credential Queries in one query, offered as alternatives or required together, are built by Query(IReadOnlyList<DcqlCredentialQuery>, params DcqlCredentialSet[]) and AnyOf(params DcqlCredentialQuery[]) from DcqlCredentialQuery entries.

Fields

DefaultCredentialId

The credential id this builder puts on a single-credential query.

public const string DefaultCredentialId = "credential"

Field Value

string

Remarks

Nothing on the verify side REQUIRES this value. WalletResponseParser.ExtractCredentials enumerates every property of the vp_token object whatever its key, per OpenID4VP 1.0 section 8.1, so a query using other ids parses fine. Said the other way because the previous wording said the pipeline "expects" it, which reads as a constraint that is not there.

Methods

AgeOver(int, string)

Convenience for the common age check: a single SD-JWT VC credential of type vct requesting the boolean age_over_{age} claim.

public static string AgeOver(int age, string vct)

Parameters

age int
vct string

Returns

string

AnyOf(params DcqlCredentialQuery[])

A query asking for one of alternatives, whichever the wallet holds: for example a PID as an mdoc or as an SD-JWT VC. One credential set lists each Credential Query as an option of its own.

public static string AnyOf(params DcqlCredentialQuery[] alternatives)

Parameters

alternatives DcqlCredentialQuery[]

At least two Credential Queries with distinct ids.

Returns

string

Remarks

SPEC: OpenID4VP 1.0 section 6.2: each option is "a list of Credential Query identifiers representing one set of Credentials that satisfies the use case", and section 6.4.2 has the wallet "return presentations of a set of Credentials that match to one of the options". The specification gives the order of options no meaning: a preference order is stated only for claim_sets (section 6.4.1), and section 6.4.3 expects the wallet to let its user choose when several options can be satisfied.

One query rather than one request per credential, because some wallets answer only one request of several handed to a single Digital Credentials API call. The answer verifies in the format of the Credential Query its vp_token key names, and the verification result reports that id.

Exceptions

ArgumentException

Fewer than two alternatives are given, or two share an id.

Mdoc(string, string, params string[])

A query for a single mdoc credential of document type docType, requesting each of elements from nameSpace (mdoc DCQL paths are [namespace, element]).

public static string Mdoc(string docType, string nameSpace, params string[] elements)

Parameters

docType string
nameSpace string
elements string[]

Returns

string

MdocByPath(string, IReadOnlyList<DcqlClaim>, params string[][])

A query for a single mdoc credential of document type docType, requesting claims by path, optionally preferring one combination of them over another.

public static string MdocByPath(string docType, IReadOnlyList<DcqlClaim> claims, params string[][] claimSets)

Parameters

docType string

The mdoc document type, which becomes meta.doctype_value.

claims IReadOnlyList<DcqlClaim>

Every claim the query may ask for. Each path is the full [namespace, element] of §7.2, because a caller spanning two namespaces cannot say so through a single namespace parameter. Mdoc(string, string, params string[]) keeps that parameter and builds these paths for you, since a caller naming elements in one namespace cannot have that problem.

claimSets string[][]

Each entry is a list of Id values, and ORDER IS THE PREFERENCE. Pass none to request every claim.

Returns

string

Query(IReadOnlyList<DcqlCredentialQuery>, params DcqlCredentialSet[])

A query asking for credentials, with credentialSets saying which combinations of them answer it. With no credential sets every Credential Query is requested.

public static string Query(IReadOnlyList<DcqlCredentialQuery> credentials, params DcqlCredentialSet[] credentialSets)

Parameters

credentials IReadOnlyList<DcqlCredentialQuery>

The Credential Queries, at least one, each with an id no other carries.

credentialSets DcqlCredentialSet[]

The credential sets. Each set's options are lists of Credential Query ids; the wallet answers a set with every credential of one option. A set is required unless Required is false.

Returns

string

Remarks

SPEC: OpenID4VP 1.0 section 6.4.2: "If credential_sets is not provided, the Verifier requests presentations for all Credentials in credentials to be returned. Otherwise, the Verifier requests presentations of Credentials to be returned satisfying all of the Credential Set Queries in the credential_sets array where the required attribute is true or omitted, and optionally, any of the other Credential Set Queries."

A Credential Query that no option names is refused. That is this library's rule, inferred from section 6.4.2 rather than stated there, by the reasoning that refuses a claim no claim set names: with credential sets present the verifier requests only what they list, so such an entry is never asked for, and nothing about the JSON would show it.

Exceptions

ArgumentException

No credential is given, two share an id, a credential set or option is empty or names an id no Credential Query carries, or a Credential Query is in no option.

SdJwtVc(IReadOnlyList<string>, params string[])

A query for a single SD-JWT VC credential of ANY of vctValues, requesting each of claims by selective disclosure. Use this where one credential entry should accept several types, for example a base PID type and a member state's own.

public static string SdJwtVc(IReadOnlyList<string> vctValues, params string[] claims)

Parameters

vctValues IReadOnlyList<string>
claims string[]

Returns

string

Remarks

SPEC: OpenID4VP 1.0 §B.3.5 defines vct_values as "A non-empty array of strings that specifies allowed values for the type of the requested Verifiable Credential", so an empty list is refused here rather than emitted. The verifier accepts a credential whose vct is any member of the array it sent.

SdJwtVc(string, params string[])

A query for a single SD-JWT VC credential of type vct, requesting each of claims by selective disclosure. Each entry is a top-level claim name.

public static string SdJwtVc(string vct, params string[] claims)

Parameters

vct string
claims string[]

Returns

string

SdJwtVcByPath(IReadOnlyList<string>, IReadOnlyList<DcqlClaim>, params string[][])

A query for a single SD-JWT VC credential of ANY of vctValues, requesting claims by path, optionally preferring one combination of them over another.

public static string SdJwtVcByPath(IReadOnlyList<string> vctValues, IReadOnlyList<DcqlClaim> claims, params string[][] claimSets)

Parameters

vctValues IReadOnlyList<string>

Credential types to accept. At least one, any of which matches.

claims IReadOnlyList<DcqlClaim>

Every claim the query may ask for, each addressed by path.

claimSets string[][]

Each entry is a list of Id values, and ORDER IS THE PREFERENCE. Pass none to request every claim.

Returns

string

Remarks

SPEC: OpenID4VP 1.0 section 6.4.1. With both claims and claim_sets present the verifier requests ONE combination, the wallet SHOULD return the first option it can satisfy, and if it can satisfy none it MUST NOT return any claims. That is what expresses "this claim, or failing that this one", which no list of claims alone can say.

WithTrustedAuthorities(string, IReadOnlyList<X509Certificate2>)

dcqlQueryJson with every credential in it asking for credentials issued under trustedIssuerCertificates, as an aki Trusted Authorities Query.

public static string WithTrustedAuthorities(string dcqlQueryJson, IReadOnlyList<X509Certificate2> trustedIssuerCertificates)

Parameters

dcqlQueryJson string

A DCQL query, from one of the other builders or written by hand.

trustedIssuerCertificates IReadOnlyList<X509Certificate2>

The certificates your trust list names for the trusted issuers: CA certificates such as an IACA, signing certificates such as a Document Signer, or both. A certificate whose BasicConstraints marks it a CA contributes its Subject Key Identifier, which RFC 5280 section 4.2.1.2 makes, "in conforming CA certificates", the Authority Key Identifier of every certificate it issues. Any other certificate contributes its own Authority Key Identifier, the value it carries in the credential's chain.

Returns

string

Remarks

SPEC: HAIP 1.0 section 5: "The Authority Key Identifier (aki)-based Trusted Authority Query (trusted_authorities) for DCQL, as defined in section 6.1.1.1 of [OIDF.OID4VP], MUST be supported." It says how the values are built: "by collecting the relevant X.509 certificates for the trusted Issuers and including the encoded Key Identifiers from the certificates in the aki array". OpenID4VP 1.0 section 6.1.1.1 says the value is base64url, and that its raw bytes "MUST match with the AuthorityKeyIdentifier element" of a certificate in the credential's chain.

The filter can be wider than the trust list. A signing certificate's value names the CA that issued it, so the wallet may offer any credential signed under that CA; a root names only what the root itself issued, which a credential carrying part of its chain (section 6.1.1.1) may not include. Leave out issuers trusted through metadata rather than a certificate chain, and any certificate this refuses, and ask for their credentials in a query without trusted authorities. Build the query from the same issuers as the trust list, so the two do not drift apart.

A filter for the wallet, not a check. Section 6.1 says the wallet SHOULD return only credentials that match, and that verifiers must still verify the issuer's trust themselves: a response is verified against the trust list as before, whatever this query asked for.

Exceptions

ArgumentException

The query has no credentials, a credential is not an object or already names trusted authorities, no certificate is given, or a certificate is null, lacks the key identifier it would contribute, carries an empty one, or repeats an extension.

JsonException

The query is not JSON.