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
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
Returns
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
alternativesDcqlCredentialQuery[]At least two Credential Queries with distinct ids.
Returns
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
Returns
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
docTypestringThe mdoc document type, which becomes
meta.doctype_value.claimsIReadOnlyList<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.claimSetsstring[][]Each entry is a list of Id values, and ORDER IS THE PREFERENCE. Pass none to request every claim.
Returns
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
credentialsIReadOnlyList<DcqlCredentialQuery>The Credential Queries, at least one, each with an id no other carries.
credentialSetsDcqlCredentialSet[]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
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
vctValuesIReadOnlyList<string>claimsstring[]
Returns
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
Returns
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
vctValuesIReadOnlyList<string>Credential types to accept. At least one, any of which matches.
claimsIReadOnlyList<DcqlClaim>Every claim the query may ask for, each addressed by path.
claimSetsstring[][]Each entry is a list of Id values, and ORDER IS THE PREFERENCE. Pass none to request every claim.
Returns
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
dcqlQueryJsonstringA DCQL query, from one of the other builders or written by hand.
trustedIssuerCertificatesIReadOnlyList<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
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.