@openeudi/openid4vp 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -1
- package/dist/index.cjs +124 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -3
- package/dist/index.d.ts +55 -3
- package/dist/index.js +123 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,6 +119,73 @@ Supported formats: `dc+sd-jwt` and `mso_mdoc`. Other formats (e.g., `jwt_vc_json
|
|
|
119
119
|
|
|
120
120
|
Known EUDI doctypes auto-namespace their claim paths (e.g., `org.iso.18013.5.1.mDL` → claims under `org.iso.18013.5.1`). Unknown doctypes use the full doctype string as the namespace.
|
|
121
121
|
|
|
122
|
+
### Offering the wallet a choice (`credential_sets`)
|
|
123
|
+
|
|
124
|
+
Some questions can be answered by more than one credential. The clearest case is
|
|
125
|
+
proof of age: a wallet may hold a **Proof-of-Age attestation** (`mso_mdoc`, with
|
|
126
|
+
`age_over_18` in namespace `eu.europa.ec.av.1`) or only a **PID** (`dc+sd-jwt`,
|
|
127
|
+
carrying `birth_date` — the PID has no age attribute, so the verifier computes the
|
|
128
|
+
threshold). Asking for both in one request avoids a second wallet interaction:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { buildCredentialSetQuery } from "@openeudi/openid4vp";
|
|
132
|
+
|
|
133
|
+
const query = buildCredentialSetQuery({
|
|
134
|
+
options: [
|
|
135
|
+
// Most-preferred first — discloses only a boolean.
|
|
136
|
+
{
|
|
137
|
+
credentialId: "age-attestation",
|
|
138
|
+
format: "mso_mdoc",
|
|
139
|
+
doctypeValue: "eu.europa.ec.av.1",
|
|
140
|
+
claims: ["age_over_18"],
|
|
141
|
+
},
|
|
142
|
+
// Fallback — the verifier computes the threshold from birth_date.
|
|
143
|
+
{
|
|
144
|
+
credentialId: "pid",
|
|
145
|
+
format: "dc+sd-jwt",
|
|
146
|
+
vctValues: ["urn:eu.europa.ec.eudi:pid:1"],
|
|
147
|
+
claims: ["birth_date"],
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The wallet satisfies **one** option and returns **one** presentation;
|
|
154
|
+
`verifyAuthorizationResponse` resolves it by the id the wallet keyed `vp_token`
|
|
155
|
+
with. Option order is a privacy preference signal, not a constraint — wallets are
|
|
156
|
+
not obliged to honour it.
|
|
157
|
+
|
|
158
|
+
Validate a hand-built disjunction with `validateCredentialSetQuery`. Note this is
|
|
159
|
+
deliberately **not** HAIP-minimal: `validateHaipQuery` rejects `credential_sets`
|
|
160
|
+
and `isHaipQuery` returns `false` for these queries.
|
|
161
|
+
|
|
162
|
+
> **`match.unmatched` is non-empty on success here.** A disjunction is satisfied
|
|
163
|
+
> when the wallet takes **one** option, so the option it did *not* take is
|
|
164
|
+
> reported as unmatched — typically with `format_mismatch` or `vct_mismatch`
|
|
165
|
+
> against the credential the wallet never held. That is the expected result, not
|
|
166
|
+
> a failure:
|
|
167
|
+
>
|
|
168
|
+
> ```ts
|
|
169
|
+
> // Wallet presented the PID; the attestation option was not taken.
|
|
170
|
+
> result.valid // true
|
|
171
|
+
> result.match.satisfied // true
|
|
172
|
+
> result.match.matches // [{ queryId: "pid", ... }]
|
|
173
|
+
> result.match.unmatched // [{ queryId: "age-attestation", reason: "format_mismatch" }]
|
|
174
|
+
> ```
|
|
175
|
+
>
|
|
176
|
+
> Gate on `result.valid` (or `match.satisfied`), **never** on
|
|
177
|
+
> `match.unmatched.length === 0`. The latter is the correct test only for a query
|
|
178
|
+
> without `credential_sets`, and silently rejects every valid disjunction
|
|
179
|
+
> response. If you log `unmatched` as "mismatch reasons" (as the verification
|
|
180
|
+
> example below does), expect a benign entry per successful disjunction and
|
|
181
|
+
> filter accordingly so it does not trip alerting.
|
|
182
|
+
|
|
183
|
+
> **Not ZKP.** This is the plain `mso_mdoc` attestation path. The AV technical
|
|
184
|
+
> specification's preferred mechanism — a Zero-Knowledge Proof — is not supported
|
|
185
|
+
> over OpenID4VP (no standardised DCQL query for it exists); it rides only the W3C
|
|
186
|
+
> Digital Credentials API. Plain mDoc is the profile's designated fallback for this
|
|
187
|
+
> transport.
|
|
188
|
+
|
|
122
189
|
## Verifying presentations against a query
|
|
123
190
|
|
|
124
191
|
Use `verifyPresentation` to combine crypto/structural verification with DCQL matching in a single call:
|
|
@@ -143,6 +210,11 @@ if (result.valid) {
|
|
|
143
210
|
|
|
144
211
|
Mismatches return `valid: false` — they do not throw. Only crypto/structural failures (malformed VP tokens, invalid signatures, expired credentials) and malformed DCQL queries throw exceptions.
|
|
145
212
|
|
|
213
|
+
The `else` branch above is the right place to read `unmatched` for an ordinary
|
|
214
|
+
query. For a **`credential_sets` disjunction** it is not the whole story: the
|
|
215
|
+
option the wallet did not take is reported as unmatched even when `valid` is
|
|
216
|
+
`true`. See [Offering the wallet a choice](#offering-the-wallet-a-choice-credential_sets).
|
|
217
|
+
|
|
146
218
|
> **Privacy — diagnostics are verifier-internal.** `match.unmatched[].reason` and `detail` (including `value_mismatch`) are intended for verifier-side logging, debugging, and admin UIs. OpenID4VP §11 warns that per-claim verification outcomes can reveal wallet contents to observers. Do NOT echo these diagnostics into the OpenID4VP wire response sent back to the wallet, into end-user-visible error messages that another party could correlate, or into public analytics/third-party logs. The protocol's own error codes are the public interface; these fields are your internal instrumentation.
|
|
147
219
|
|
|
148
220
|
## Signed authorization requests (x509_san_dns, x509_hash)
|
|
@@ -318,6 +390,21 @@ Both `parsePresentation` and `verifyPresentation` accept:
|
|
|
318
390
|
- `verifierEncryptionJwk?` — *(`VerifyAuthorizationResponseOptions` only)* the verifier's response-encryption public JWK. Required on the encrypted path when `sessionTranscriptProfile: 'openid4vp-1.0'` is used, to derive the handover's JWK thumbprint; ignored for the `'iso-18013-7'` profile.
|
|
319
391
|
- `trustedCertificates` (required when `trustStore` is unset) — DER-encoded issuer leaf certificates for the 0.4.x byte-equality trust check. Deprecated since 0.5.0 — pass an empty array and supply `trustStore` for production deployments.
|
|
320
392
|
- `trustStore?` — `TrustStore` instance for full RFC 5280 chain validation (e.g. `LotlTrustStore`, `StaticTrustStore`, or `CompositeTrustStore`). When set, takes precedence over `trustedCertificates`.
|
|
393
|
+
|
|
394
|
+
> **`LotlTrustStore` requires an `xmldsigjs` crypto engine.** Trusted lists are
|
|
395
|
+
> verified as signed XML, and this library does not pick a WebCrypto provider on
|
|
396
|
+
> your behalf. Register one **once at startup**, before any trusted-list fetch:
|
|
397
|
+
>
|
|
398
|
+
> ```ts
|
|
399
|
+
> import * as xmldsig from "xmldsigjs";
|
|
400
|
+
> import { Crypto } from "@peculiar/webcrypto";
|
|
401
|
+
>
|
|
402
|
+
> xmldsig.Application.setEngine("NodeJS", new Crypto());
|
|
403
|
+
> ```
|
|
404
|
+
>
|
|
405
|
+
> Omit it and `LotlTrustStore` throws `LotlConfigurationError` on first use,
|
|
406
|
+
> naming this as the cause. `StaticTrustStore` is unaffected.
|
|
407
|
+
|
|
321
408
|
- `revocationPolicy?` — `'skip'` (default) | `'prefer'` | `'require'`. Controls whether the chain validator consults OCSP / CRL.
|
|
322
409
|
- `fetcher?` — HTTP transport for CRL/OCSP/LOTL fetches. Defaults to `globalThis.fetch`.
|
|
323
410
|
- `cache?` — cache for CRL/OCSP/LOTL artefacts. Defaults to `new InMemoryCache()`.
|
|
@@ -405,6 +492,7 @@ class MyCustomParser implements ICredentialParser {
|
|
|
405
492
|
| `MalformedCredentialError` | Credential structure is malformed | Token cannot be decoded or is structurally invalid |
|
|
406
493
|
| `NonceValidationError` | Nonce does not match expected value | Key binding JWT nonce does not match |
|
|
407
494
|
| `HaipValidationError` | HAIP query constraint violated | DCQL query fails `validateHaipQuery` |
|
|
495
|
+
| `LotlConfigurationError` | No xmldsigjs crypto engine registered | `LotlTrustStore` used without `Application.setEngine` |
|
|
408
496
|
|
|
409
497
|
```ts
|
|
410
498
|
import { MalformedCredentialError, ExpiredCredentialError } from "@openeudi/openid4vp";
|
|
@@ -427,7 +515,7 @@ This library implements the **verifier side** of OpenID4VP for SD-JWT VC and mDO
|
|
|
427
515
|
- **SD-JWT VC** — full cryptographic verification (issuer JWT signature via `x5c`, transitive disclosure-hash check, key binding JWT signature + `sd_hash`, nonce check). Holder binding (KB-JWT) is **mandatory and fails closed** whenever the issuer JWT carries a `cnf` claim; `requireKeyBinding` extends the requirement to credentials without `cnf`. Optional `trustedIssuerJwks` alternate trust path for VCs without `x5c`.
|
|
428
516
|
- **mDOC / ISO 18013-5** `mso_mdoc` format — CBOR decoding, claim extraction, COSE_Sign1 signature verification, MobileSecurityObject validity enforcement, IssuerSignedItem digest verification. Device authentication (ISO 18013-5 §9.1.3) is **mandatory and fails closed**: the `DeviceSignature` (COSE_Sign1) over `DeviceAuthentication`/`SessionTranscript` is verified against the MSO-committed device key. `DeviceMac` (COSE_Mac0) is **not supported and is rejected**.
|
|
429
517
|
- **DCQL** — authorization request builder with DCQL query, matching via [@openeudi/dcql](https://www.npmjs.com/package/@openeudi/dcql), `verifyPresentation` for combined crypto + match.
|
|
430
|
-
- **HAIP** — `buildHaipQuery` / `validateHaipQuery` helpers for the High Assurance Interoperability Profile.
|
|
518
|
+
- **HAIP** — `buildHaipQuery` / `validateHaipQuery` helpers for the High Assurance Interoperability Profile, plus `buildCredentialSetQuery` / `validateCredentialSetQuery` for `credential_sets` disjunctions.
|
|
431
519
|
- **Signed authorization requests (JAR)** — `createSignedAuthorizationRequest` per RFC 9101 / OpenID4VP 1.0 §5.10 with `x509_san_dns` or `x509_hash` client-id binding. Emits the OpenID4VP 1.0 Final `client_metadata` shape. Self-signed verifier leaf certificates are rejected by default per HAIP 1.0 Final.
|
|
432
520
|
- **Encrypted responses** — `decryptAuthorizationResponse` for `direct_post.jwt` (ECDH-ES + A128GCM/A256GCM), `verifyAuthorizationResponse` for the 1.0 §8.1 object-keyed `vp_token` envelope.
|
|
433
521
|
- **X.509 chain validation** — RFC 5280 chain building including `nameConstraints`, `StaticTrustStore`, `CompositeTrustStore`.
|
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,7 @@ var init_reflect_polyfill = __esm({
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
// src/errors.ts
|
|
48
|
-
exports.InvalidSignatureError = void 0; exports.ExpiredCredentialError = void 0; exports.UnsupportedFormatError = void 0; exports.MalformedCredentialError = void 0; exports.NonceValidationError = void 0; exports.HaipValidationError = void 0; exports.OpenID4VPError = void 0; exports.TrustAnchorNotFoundError = void 0; exports.CertificateChainError = void 0; exports.RevokedCertificateError = void 0; exports.RevocationCheckFailedError = void 0; exports.LotlFetchError = void 0; exports.LotlSignatureError = void 0; exports.SignedRequestBuildError = void 0; exports.UnsupportedJweError = void 0; exports.DecryptionFailedError = void 0; exports.MissingDecryptionKeyError = void 0; exports.MissingVerifierEncryptionKeyError = void 0; exports.MultipleCredentialsNotSupportedError = void 0;
|
|
48
|
+
exports.InvalidSignatureError = void 0; exports.ExpiredCredentialError = void 0; exports.UnsupportedFormatError = void 0; exports.MalformedCredentialError = void 0; exports.NonceValidationError = void 0; exports.HaipValidationError = void 0; exports.OpenID4VPError = void 0; exports.TrustAnchorNotFoundError = void 0; exports.CertificateChainError = void 0; exports.RevokedCertificateError = void 0; exports.RevocationCheckFailedError = void 0; exports.LotlFetchError = void 0; exports.LotlSignatureError = void 0; exports.LotlConfigurationError = void 0; exports.SignedRequestBuildError = void 0; exports.UnsupportedJweError = void 0; exports.DecryptionFailedError = void 0; exports.MissingDecryptionKeyError = void 0; exports.MissingVerifierEncryptionKeyError = void 0; exports.MultipleCredentialsNotSupportedError = void 0;
|
|
49
49
|
var init_errors = __esm({
|
|
50
50
|
"src/errors.ts"() {
|
|
51
51
|
init_reflect_polyfill();
|
|
@@ -142,6 +142,9 @@ var init_errors = __esm({
|
|
|
142
142
|
exports.LotlSignatureError = class extends exports.OpenID4VPError {
|
|
143
143
|
code = "lotl_signature_invalid";
|
|
144
144
|
};
|
|
145
|
+
exports.LotlConfigurationError = class extends exports.OpenID4VPError {
|
|
146
|
+
code = "lotl_configuration_invalid";
|
|
147
|
+
};
|
|
145
148
|
exports.SignedRequestBuildError = class extends exports.OpenID4VPError {
|
|
146
149
|
code;
|
|
147
150
|
constructor(code, message) {
|
|
@@ -8443,6 +8446,33 @@ function buildHaipQuery(input) {
|
|
|
8443
8446
|
}
|
|
8444
8447
|
return { credentials: [credential] };
|
|
8445
8448
|
}
|
|
8449
|
+
function buildCredentialSetQuery(input) {
|
|
8450
|
+
if (input.options.length === 0) {
|
|
8451
|
+
throw new exports.HaipValidationError(
|
|
8452
|
+
"EMPTY_OPTIONS",
|
|
8453
|
+
"a credential set must offer at least one option"
|
|
8454
|
+
);
|
|
8455
|
+
}
|
|
8456
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8457
|
+
for (const option of input.options) {
|
|
8458
|
+
if (seen.has(option.credentialId)) {
|
|
8459
|
+
throw new exports.HaipValidationError(
|
|
8460
|
+
"DUPLICATE_CREDENTIAL_ID",
|
|
8461
|
+
`credential '${option.credentialId}' is declared by more than one option; credential ids must be unique for credential_sets to reference them`,
|
|
8462
|
+
option.credentialId
|
|
8463
|
+
);
|
|
8464
|
+
}
|
|
8465
|
+
seen.add(option.credentialId);
|
|
8466
|
+
}
|
|
8467
|
+
const credentials = input.options.map((option) => buildHaipQuery(option).credentials[0]);
|
|
8468
|
+
const credentialSet = {
|
|
8469
|
+
options: input.options.map((option) => [option.credentialId])
|
|
8470
|
+
};
|
|
8471
|
+
if (input.required === false) {
|
|
8472
|
+
credentialSet.required = false;
|
|
8473
|
+
}
|
|
8474
|
+
return { credentials, credential_sets: [credentialSet] };
|
|
8475
|
+
}
|
|
8446
8476
|
var HAIP_FORMATS = /* @__PURE__ */ new Set(["dc+sd-jwt", "mso_mdoc"]);
|
|
8447
8477
|
function validateHaipQuery(query) {
|
|
8448
8478
|
if (!query.credentials || query.credentials.length === 0) {
|
|
@@ -8458,46 +8488,86 @@ function validateHaipQuery(query) {
|
|
|
8458
8488
|
);
|
|
8459
8489
|
}
|
|
8460
8490
|
for (const credential of query.credentials) {
|
|
8461
|
-
|
|
8491
|
+
validateCredential(credential);
|
|
8492
|
+
}
|
|
8493
|
+
}
|
|
8494
|
+
function validateCredential(credential) {
|
|
8495
|
+
if (!HAIP_FORMATS.has(credential.format)) {
|
|
8496
|
+
throw new exports.HaipValidationError(
|
|
8497
|
+
"UNSUPPORTED_FORMAT",
|
|
8498
|
+
`credential '${credential.id}' uses unsupported format '${credential.format}' (allowed: dc+sd-jwt, mso_mdoc)`,
|
|
8499
|
+
credential.id
|
|
8500
|
+
);
|
|
8501
|
+
}
|
|
8502
|
+
if (credential.format === "dc+sd-jwt") {
|
|
8503
|
+
const vctValues = credential.meta?.vct_values;
|
|
8504
|
+
if (!vctValues || vctValues.length === 0) {
|
|
8462
8505
|
throw new exports.HaipValidationError(
|
|
8463
|
-
"
|
|
8464
|
-
`credential '${credential.id}'
|
|
8506
|
+
"MISSING_SDJWT_META",
|
|
8507
|
+
`credential '${credential.id}' with format 'dc+sd-jwt' must set meta.vct_values`,
|
|
8465
8508
|
credential.id
|
|
8466
8509
|
);
|
|
8467
8510
|
}
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
throw new exports.HaipValidationError(
|
|
8472
|
-
"MISSING_SDJWT_META",
|
|
8473
|
-
`credential '${credential.id}' with format 'dc+sd-jwt' must set meta.vct_values`,
|
|
8474
|
-
credential.id
|
|
8475
|
-
);
|
|
8476
|
-
}
|
|
8477
|
-
}
|
|
8478
|
-
if (credential.format === "mso_mdoc") {
|
|
8479
|
-
if (typeof credential.meta?.doctype_value !== "string") {
|
|
8480
|
-
throw new exports.HaipValidationError(
|
|
8481
|
-
"MISSING_MDOC_META",
|
|
8482
|
-
`credential '${credential.id}' with format 'mso_mdoc' must set meta.doctype_value`,
|
|
8483
|
-
credential.id
|
|
8484
|
-
);
|
|
8485
|
-
}
|
|
8486
|
-
}
|
|
8487
|
-
if (!credential.claims || credential.claims.length === 0) {
|
|
8511
|
+
}
|
|
8512
|
+
if (credential.format === "mso_mdoc") {
|
|
8513
|
+
if (typeof credential.meta?.doctype_value !== "string") {
|
|
8488
8514
|
throw new exports.HaipValidationError(
|
|
8489
|
-
"
|
|
8490
|
-
`credential '${credential.id}'
|
|
8515
|
+
"MISSING_MDOC_META",
|
|
8516
|
+
`credential '${credential.id}' with format 'mso_mdoc' must set meta.doctype_value`,
|
|
8491
8517
|
credential.id
|
|
8492
8518
|
);
|
|
8493
8519
|
}
|
|
8494
|
-
|
|
8520
|
+
}
|
|
8521
|
+
if (!credential.claims || credential.claims.length === 0) {
|
|
8522
|
+
throw new exports.HaipValidationError(
|
|
8523
|
+
"NO_CLAIMS",
|
|
8524
|
+
`credential '${credential.id}' must declare at least one claim`,
|
|
8525
|
+
credential.id
|
|
8526
|
+
);
|
|
8527
|
+
}
|
|
8528
|
+
if (credential.claim_sets !== void 0) {
|
|
8529
|
+
throw new exports.HaipValidationError(
|
|
8530
|
+
"CLAIM_SETS_DISALLOWED",
|
|
8531
|
+
`credential '${credential.id}' uses claim_sets, not permitted in HAIP-minimal`,
|
|
8532
|
+
credential.id
|
|
8533
|
+
);
|
|
8534
|
+
}
|
|
8535
|
+
}
|
|
8536
|
+
function validateCredentialSetQuery(query) {
|
|
8537
|
+
if (!query.credentials || query.credentials.length === 0) {
|
|
8538
|
+
throw new exports.HaipValidationError(
|
|
8539
|
+
"EMPTY_QUERY",
|
|
8540
|
+
"query.credentials must have at least one entry"
|
|
8541
|
+
);
|
|
8542
|
+
}
|
|
8543
|
+
if (!query.credential_sets || query.credential_sets.length === 0) {
|
|
8544
|
+
throw new exports.HaipValidationError(
|
|
8545
|
+
"MISSING_CREDENTIAL_SETS",
|
|
8546
|
+
"a credential-set query must declare at least one credential_sets entry"
|
|
8547
|
+
);
|
|
8548
|
+
}
|
|
8549
|
+
for (const credential of query.credentials) {
|
|
8550
|
+
validateCredential(credential);
|
|
8551
|
+
}
|
|
8552
|
+
const declaredIds = new Set(query.credentials.map((c) => c.id));
|
|
8553
|
+
for (const credentialSet of query.credential_sets) {
|
|
8554
|
+
if (!credentialSet.options || credentialSet.options.length === 0) {
|
|
8495
8555
|
throw new exports.HaipValidationError(
|
|
8496
|
-
"
|
|
8497
|
-
|
|
8498
|
-
credential.id
|
|
8556
|
+
"EMPTY_OPTIONS",
|
|
8557
|
+
"a credential set must offer at least one option"
|
|
8499
8558
|
);
|
|
8500
8559
|
}
|
|
8560
|
+
for (const option of credentialSet.options) {
|
|
8561
|
+
for (const id of option) {
|
|
8562
|
+
if (!declaredIds.has(id)) {
|
|
8563
|
+
throw new exports.HaipValidationError(
|
|
8564
|
+
"UNKNOWN_OPTION_REFERENCE",
|
|
8565
|
+
`credential_sets option references '${id}', which is not declared in query.credentials`,
|
|
8566
|
+
id
|
|
8567
|
+
);
|
|
8568
|
+
}
|
|
8569
|
+
}
|
|
8570
|
+
}
|
|
8501
8571
|
}
|
|
8502
8572
|
}
|
|
8503
8573
|
function isHaipQuery(query) {
|
|
@@ -9967,6 +10037,7 @@ function bytesToHex3(bytes) {
|
|
|
9967
10037
|
|
|
9968
10038
|
// src/trust/LotlTrustStore.ts
|
|
9969
10039
|
init_reflect_polyfill();
|
|
10040
|
+
init_errors();
|
|
9970
10041
|
|
|
9971
10042
|
// src/trust/lotl-signing-anchors.ts
|
|
9972
10043
|
init_reflect_polyfill();
|
|
@@ -10035,6 +10106,7 @@ var LotlFetcher = class {
|
|
|
10035
10106
|
this.fetcher = opts.fetcher ?? globalThis.fetch.bind(globalThis);
|
|
10036
10107
|
}
|
|
10037
10108
|
async fetchSigned(url, signingAnchors) {
|
|
10109
|
+
assertCryptoEngineRegistered();
|
|
10038
10110
|
let xmlText;
|
|
10039
10111
|
try {
|
|
10040
10112
|
const response = await this.fetcher(url, { method: "GET" });
|
|
@@ -10087,6 +10159,22 @@ var LotlFetcher = class {
|
|
|
10087
10159
|
);
|
|
10088
10160
|
}
|
|
10089
10161
|
};
|
|
10162
|
+
function assertCryptoEngineRegistered() {
|
|
10163
|
+
let engine;
|
|
10164
|
+
try {
|
|
10165
|
+
engine = xmldsig__namespace.Application.crypto;
|
|
10166
|
+
} catch (err) {
|
|
10167
|
+
throw new exports.LotlConfigurationError(
|
|
10168
|
+
`no xmldsigjs crypto engine registered \u2014 trusted-list signatures cannot be verified. Call xmldsig.Application.setEngine('NodeJS', new Crypto()) (e.g. from @peculiar/webcrypto) once at startup, before using LotlTrustStore. Underlying error: ${err instanceof Error ? err.message : String(err)}`,
|
|
10169
|
+
{ cause: err instanceof Error ? err : void 0 }
|
|
10170
|
+
);
|
|
10171
|
+
}
|
|
10172
|
+
if (!engine) {
|
|
10173
|
+
throw new exports.LotlConfigurationError(
|
|
10174
|
+
"no xmldsigjs crypto engine registered \u2014 trusted-list signatures cannot be verified. Call xmldsig.Application.setEngine('NodeJS', new Crypto()) (e.g. from @peculiar/webcrypto) once at startup, before using LotlTrustStore."
|
|
10175
|
+
);
|
|
10176
|
+
}
|
|
10177
|
+
}
|
|
10090
10178
|
async function verifyAgainst(doc, sigEl, anchor) {
|
|
10091
10179
|
try {
|
|
10092
10180
|
const signed = new xmldsig__namespace.SignedXml(doc);
|
|
@@ -10234,6 +10322,7 @@ function parsePointer(el) {
|
|
|
10234
10322
|
|
|
10235
10323
|
// src/trust/NationalTlResolver.ts
|
|
10236
10324
|
init_reflect_polyfill();
|
|
10325
|
+
init_errors();
|
|
10237
10326
|
var TSL_NS2 = "http://uri.etsi.org/02231/v2#";
|
|
10238
10327
|
var NationalTlResolver = class {
|
|
10239
10328
|
constructor(opts) {
|
|
@@ -10249,6 +10338,7 @@ var NationalTlResolver = class {
|
|
|
10249
10338
|
);
|
|
10250
10339
|
return parseNationalTl(doc, pointer.country);
|
|
10251
10340
|
} catch (err) {
|
|
10341
|
+
if (err instanceof exports.LotlConfigurationError) throw err;
|
|
10252
10342
|
console.warn(
|
|
10253
10343
|
`[openid4vp] national TL for ${pointer.country} failed: ${err.message}`
|
|
10254
10344
|
);
|
|
@@ -10427,6 +10517,7 @@ var LotlTrustStore = class {
|
|
|
10427
10517
|
};
|
|
10428
10518
|
return this.snapshot;
|
|
10429
10519
|
} catch (err) {
|
|
10520
|
+
if (err instanceof exports.LotlConfigurationError) throw err;
|
|
10430
10521
|
if (this.snapshot) {
|
|
10431
10522
|
console.warn(
|
|
10432
10523
|
`[openid4vp] LOTL refresh failed; serving cached snapshot (${err.message})`
|
|
@@ -10474,7 +10565,7 @@ function equalBytes(a, b) {
|
|
|
10474
10565
|
|
|
10475
10566
|
// src/index.ts
|
|
10476
10567
|
init_errors();
|
|
10477
|
-
var VERSION = "0.
|
|
10568
|
+
var VERSION = "0.12.0";
|
|
10478
10569
|
/*! Bundled license information:
|
|
10479
10570
|
|
|
10480
10571
|
pvtsutils/build/index.es.js:
|
|
@@ -10560,6 +10651,7 @@ exports.MdocParser = MdocParser;
|
|
|
10560
10651
|
exports.SdJwtParser = SdJwtParser;
|
|
10561
10652
|
exports.StaticTrustStore = StaticTrustStore;
|
|
10562
10653
|
exports.VERSION = VERSION;
|
|
10654
|
+
exports.buildCredentialSetQuery = buildCredentialSetQuery;
|
|
10563
10655
|
exports.buildHaipQuery = buildHaipQuery;
|
|
10564
10656
|
exports.buildOid4vpSessionTranscript = buildOid4vpSessionTranscript;
|
|
10565
10657
|
exports.buildOpenID4VPHandoverSessionTranscript = buildOpenID4VPHandoverSessionTranscript;
|
|
@@ -10568,6 +10660,7 @@ exports.createSignedAuthorizationRequest = createSignedAuthorizationRequest;
|
|
|
10568
10660
|
exports.decryptAuthorizationResponse = decryptAuthorizationResponse;
|
|
10569
10661
|
exports.isHaipQuery = isHaipQuery;
|
|
10570
10662
|
exports.parsePresentation = parsePresentation;
|
|
10663
|
+
exports.validateCredentialSetQuery = validateCredentialSetQuery;
|
|
10571
10664
|
exports.validateHaipQuery = validateHaipQuery;
|
|
10572
10665
|
exports.verifyAuthorizationResponse = verifyAuthorizationResponse;
|
|
10573
10666
|
exports.verifyPresentation = verifyPresentation;
|