@openeudi/openid4vp 0.11.1 → 0.13.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 +140 -4
- package/dist/index.cjs +742 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -8
- package/dist/index.d.ts +165 -8
- package/dist/index.js +741 -115
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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,8 +390,36 @@ 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
|
+
The signer certificate (`x5c[0]` / `x5chain[0]`) is trusted when it **is** an anchor (byte-identical DER) or **chains to** one through verified signatures; the remaining `x5c` / `x5chain` entries are untrusted path candidates and never anchors. A list longer than 10 certificates, signer included, is rejected as malformed before any entry is parsed. Anchors may therefore be roots — such as the IACA certificates an ETSI TS 119 602 PID-providers list publishes — or the document-signer certificate itself:
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
import { StaticTrustStore } from "@openeudi/openid4vp";
|
|
398
|
+
|
|
399
|
+
// DER bytes of every certificate listed for the PID providers you accept:
|
|
400
|
+
// IACA roots and directly-listed signer certificates alike.
|
|
401
|
+
const trustStore = new StaticTrustStore(listedCertificates);
|
|
402
|
+
await parsePresentation(vpToken, { trustedCertificates: [], trustStore, nonce, mdocSessionTranscript });
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Each link's signature, validity now **and** at issuance time (MSO `signed` / SD-JWT `iat`), `basicConstraints` cA + `keyUsage` keyCertSign on every CA, `digitalSignature` on the signer, `pathLenConstraint`, `nameConstraints` and a 5-certificate maximum are enforced. For `mso_mdoc`, built chains must also follow the ISO 18013-5 Annex B profile: the document signer carries EKU `1.0.18013.5.1.2` (`reason: 'extended_key_usage'` otherwise) and `keyUsage` is mandatory. A signer that is itself the listed anchor is trusted by presence and exempt from that profile. Anchors are never matched by Subject DN alone.
|
|
406
|
+
|
|
407
|
+
> **`LotlTrustStore` requires an `xmldsigjs` crypto engine.** Trusted lists are
|
|
408
|
+
> verified as signed XML, and this library does not pick a WebCrypto provider on
|
|
409
|
+
> your behalf. Register one **once at startup**, before any trusted-list fetch:
|
|
410
|
+
>
|
|
411
|
+
> ```ts
|
|
412
|
+
> import * as xmldsig from "xmldsigjs";
|
|
413
|
+
> import { Crypto } from "@peculiar/webcrypto";
|
|
414
|
+
>
|
|
415
|
+
> xmldsig.Application.setEngine("NodeJS", new Crypto());
|
|
416
|
+
> ```
|
|
417
|
+
>
|
|
418
|
+
> Omit it and `LotlTrustStore` throws `LotlConfigurationError` on first use,
|
|
419
|
+
> naming this as the cause. `StaticTrustStore` is unaffected.
|
|
420
|
+
|
|
321
421
|
- `revocationPolicy?` — `'skip'` (default) | `'prefer'` | `'require'`. Controls whether the chain validator consults OCSP / CRL.
|
|
322
|
-
- `fetcher?` — HTTP transport for CRL/OCSP/LOTL fetches. Defaults to `
|
|
422
|
+
- `fetcher?` — HTTP transport for CRL/OCSP/LOTL fetches. Defaults to a guarded fetcher — see [Network access](#network-access). A fetcher you supply **replaces** the guards; wrap it with `createGuardedFetcher({ fetch: yourFetcher })` to keep them.
|
|
323
423
|
- `cache?` — cache for CRL/OCSP/LOTL artefacts. Defaults to `new InMemoryCache()`.
|
|
324
424
|
- `clockSkewTolerance?` — seconds of slack applied to certificate validity checks. Default 60.
|
|
325
425
|
- `trustedIssuerJwks?` — opt-in alternate trust path for SD-JWT VCs whose issuer JWT lacks an `x5c` header. The library matches by `kid` (or iterates the array when no `kid` is present) and skips chain validation entirely. Intended for harness setups (e.g. OIDF conformance suite) where the wallet signs without `x5c` and the verifier knows the signing key out-of-band. **Not recommended for production verifiers** — `trustStore` is the secure path.
|
|
@@ -327,6 +427,38 @@ Both `parsePresentation` and `verifyPresentation` accept:
|
|
|
327
427
|
- `allowedAlgorithms?` — restrict signature algorithms. Defaults to `['ES256','ES384','ES512']`.
|
|
328
428
|
- `skipTrustCheck?` — skip trust checks entirely (dev/test only).
|
|
329
429
|
- `expectedDocType?` — for mDOC verification, lock the credential `docType` (or SD-JWT `vct`).
|
|
430
|
+
- `allowLegacyVcSdJwtTyp?` — **deprecated**. Also accept the legacy `vc+sd-jwt` issuer-JWT `typ`, which draft-ietf-oauth-sd-jwt-vc-19 removed. Default `false`; only for interoperating with wallets that have not migrated yet. Removed in 1.0.0.
|
|
431
|
+
|
|
432
|
+
### Network access
|
|
433
|
+
|
|
434
|
+
The library dereferences URLs only inside the trust module, and only when you opt into it:
|
|
435
|
+
|
|
436
|
+
| Fetch | When | Method |
|
|
437
|
+
|---|---|---|
|
|
438
|
+
| EU LOTL + national trusted lists | `LotlTrustStore` | GET |
|
|
439
|
+
| CRL distribution points | `revocationPolicy` `'prefer'`/`'require'` | GET |
|
|
440
|
+
| OCSP responders (AIA) | `revocationPolicy` `'prefer'`/`'require'` | POST |
|
|
441
|
+
|
|
442
|
+
It does **not** fetch SD-JWT VC issuer metadata (`/.well-known/jwt-vc-issuer`), `jwks_uri`, Type Metadata (`vct` resolution), Token Status Lists, or `x5u`. Issuer keys come from `x5c` or `trustedIssuerJwks`. **If your application dereferences any of those itself, it is responsible for applying the SD-JWT VC draft-19 HTTP retrieval rules** — `createGuardedFetcher()` (HTTPS-only by default) is exported for exactly that.
|
|
443
|
+
|
|
444
|
+
All library fetches go through `createGuardedFetcher({ allowHttp: true })` unless you pass `fetcher`. It enforces:
|
|
445
|
+
|
|
446
|
+
- `https:` only by default (`allowHttp: true` for the trust module: RFC 5280 CRLs and RFC 6960 OCSP are conventionally plain HTTP and every artefact is signature-verified); never an `https` → `http` redirect downgrade.
|
|
447
|
+
- No loopback, RFC 1918, CGNAT, link-local (incl. `169.254.169.254`), ULA (incl. `fd00:ec2::254`), multicast, documentation or reserved targets — checked on the URL host *and* on every address it resolves to, including IPv4-mapped/compatible, NAT64 and 6to4 IPv6 forms. `localhost`/`*.localhost` are refused by name. A host that resolves to no addresses at all is refused as `dns_resolution_failed` rather than treated as public.
|
|
448
|
+
- Redirects handled manually (`maxRedirects`, default 3); each target is re-validated before it is requested, and credentials headers are dropped on cross-origin hops.
|
|
449
|
+
- One timeout (`timeoutMs`, default 15 000) for DNS, all hops and the body.
|
|
450
|
+
- A size cap (`maxResponseBytes`, default 16 MiB), enforced from `Content-Length` and again while streaming.
|
|
451
|
+
|
|
452
|
+
Rejections throw `GuardedFetchError` with a `reason` (`insecure_scheme`, `private_address`, `too_many_redirects`, `response_too_large`, `timeout`, …).
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
import { createGuardedFetcher, LotlTrustStore } from "@openeudi/openid4vp";
|
|
456
|
+
|
|
457
|
+
const fetcher = createGuardedFetcher({ allowHttp: true, timeoutMs: 10_000, maxResponseBytes: 32 * 1024 * 1024 });
|
|
458
|
+
const trustStore = new LotlTrustStore({ signingAnchors, fetcher });
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
> **Limits.** DNS rebinding: the guard resolves and validates the host, then the transport resolves it *again*, so a hostile DNS server can answer differently the second time. `fetch` gives no portable way to pin the validated address. If attacker-influenced URLs reach your verifier, also route egress through a filtering proxy, or inject a `fetch` whose connector checks the connected address (e.g. an undici `Agent` with a validating `connect.lookup`). In runtimes without `node:dns` (browsers, some edge workers) only IP literals and `localhost` are checked unless you pass `lookup`. Caching is handled by the `cache` option, not the fetcher.
|
|
330
462
|
|
|
331
463
|
## Supported formats
|
|
332
464
|
|
|
@@ -334,6 +466,7 @@ Both `parsePresentation` and `verifyPresentation` accept:
|
|
|
334
466
|
|
|
335
467
|
Selective Disclosure JSON Web Token Verifiable Credentials. The token is a string in `jwt~disclosure~kb` format. The parser:
|
|
336
468
|
|
|
469
|
+
- Requires the issuer JWT `typ` to be `dc+sd-jwt` (draft-ietf-oauth-sd-jwt-vc-19); the legacy `vc+sd-jwt` is rejected unless `allowLegacyVcSdJwtTyp` is set
|
|
337
470
|
- Decodes the issuer JWT and extracts the `x5c` certificate chain
|
|
338
471
|
- Verifies the issuer certificate against your trusted set
|
|
339
472
|
- Checks credential expiry from the `exp` claim
|
|
@@ -348,7 +481,7 @@ Mobile Document credentials as defined in ISO 18013-5. The token is a CBOR-encod
|
|
|
348
481
|
|
|
349
482
|
- Decodes the CBOR DeviceResponse structure
|
|
350
483
|
- Extracts the issuer certificate from the COSE_Sign1 `issuerAuth` (x5chain label 33)
|
|
351
|
-
- Verifies the certificate against your trusted set
|
|
484
|
+
- Verifies the certificate against your trusted set — with `trustStore`, by building a chain from the document signer to an anchor such as an IACA (see [`trustStore`](#parseoptions--verifyoptions))
|
|
352
485
|
- Checks the validity period from `validityInfo`
|
|
353
486
|
- Extracts claims from the `eu.europa.ec.eudi.pid.1` namespace
|
|
354
487
|
- Verifies each `IssuerSignedItem`'s digest against the MSO's `valueDigests`, computed over the full tag-24 `IssuerSignedItemBytes` (`#6.24(bstr .cbor IssuerSignedItem)`) per ISO 18013-5 §9.1.2.4 — not just the inner CBOR — matching how real wallets encode mdocs. mDOC verification, including this digest check and device authentication below, is validated against the OIDF conformance suite acting as an independent ISO 18013-5 mdl wallet.
|
|
@@ -405,6 +538,8 @@ class MyCustomParser implements ICredentialParser {
|
|
|
405
538
|
| `MalformedCredentialError` | Credential structure is malformed | Token cannot be decoded or is structurally invalid |
|
|
406
539
|
| `NonceValidationError` | Nonce does not match expected value | Key binding JWT nonce does not match |
|
|
407
540
|
| `HaipValidationError` | HAIP query constraint violated | DCQL query fails `validateHaipQuery` |
|
|
541
|
+
| `LotlConfigurationError` | No xmldsigjs crypto engine registered | `LotlTrustStore` used without `Application.setEngine` |
|
|
542
|
+
| `GuardedFetchError` | refusing … / exceeds … / timed out | A guarded fetch is refused or cut off (`reason`) |
|
|
408
543
|
|
|
409
544
|
```ts
|
|
410
545
|
import { MalformedCredentialError, ExpiredCredentialError } from "@openeudi/openid4vp";
|
|
@@ -427,10 +562,10 @@ This library implements the **verifier side** of OpenID4VP for SD-JWT VC and mDO
|
|
|
427
562
|
- **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
563
|
- **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
564
|
- **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.
|
|
565
|
+
- **HAIP** — `buildHaipQuery` / `validateHaipQuery` helpers for the High Assurance Interoperability Profile, plus `buildCredentialSetQuery` / `validateCredentialSetQuery` for `credential_sets` disjunctions.
|
|
431
566
|
- **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
567
|
- **Encrypted responses** — `decryptAuthorizationResponse` for `direct_post.jwt` (ECDH-ES + A128GCM/A256GCM), `verifyAuthorizationResponse` for the 1.0 §8.1 object-keyed `vp_token` envelope.
|
|
433
|
-
- **X.509 chain validation** — RFC 5280 chain building including `nameConstraints`, `StaticTrustStore`, `CompositeTrustStore
|
|
568
|
+
- **X.509 chain validation** — RFC 5280 chain building including `nameConstraints`, `StaticTrustStore`, `CompositeTrustStore`; IACA → document-signer chains for `mso_mdoc` with the ISO 18013-5 Annex B certificate profile.
|
|
434
569
|
- **Revocation checking** — OCSP-first with CRL fallback (`revocationPolicy: 'skip' | 'prefer' | 'require'`).
|
|
435
570
|
- **EU List of Trusted Lists** — `LotlTrustStore` resolves national trust lists via signed XML fetch + XAdES verification; populates `provenance` (LoA, qualified status, country, service name) on verified presentations.
|
|
436
571
|
- **OIDF conformance** — automated against the OpenID Foundation conformance suite in CI (`oidf-pr.yml` happy-flow gate, `oidf-release.yml` full plan).
|
|
@@ -473,6 +608,7 @@ See [CHANGELOG.md](./CHANGELOG.md) for per-release changes. Key migration moment
|
|
|
473
608
|
- **0.9.3** — `reflect-metadata` is loaded by the package itself in both ESM and CJS builds. If you added a manual `import "reflect-metadata"` before importing this library to work around the 0.9.2 bug, you can drop it.
|
|
474
609
|
- **0.11.0** — **BREAKING:** `createSignedAuthorizationRequest` now rejects a self-signed leaf certificate with `SignedRequestBuildError: self_signed_leaf`, per HAIP 1.0 Final. Verifiers using a self-signed certificate for their own identity must either move to a CA-issued certificate (the correct fix) or pass `allowSelfSignedCertificate: true` to keep the previous behaviour. Verification of wallet presentations is unaffected — this concerns only the verifier's own request-signing certificate.
|
|
475
610
|
- **0.10.0** — `createSignedAuthorizationRequest` gains `clientIdPrefix` (`x509_san_dns` default, or `x509_hash`), and `hostname` becomes optional — required only for `x509_san_dns`, but still validated against the leaf SAN whenever supplied. **Wire change for existing callers:** the emitted `client_metadata` no longer carries the singular ID3 `authorization_encrypted_response_alg` / `authorization_encrypted_response_enc` fields added in 0.8.0. Verifiers that read the 1.0 Final `encrypted_response_enc_values_supported` array (and `alg` from `client_metadata.jwks`) are unaffected; anything still reading the singular fields needs updating.
|
|
611
|
+
- **0.13.0** — **BREAKING:** SD-JWT VC issuer JWTs must carry `typ: dc+sd-jwt` (draft-ietf-oauth-sd-jwt-vc-19); `vc+sd-jwt` is rejected unless you pass `allowLegacyVcSdJwtTyp: true`, which is already deprecated and goes in 1.0.0. **BREAKING:** trust-module fetches (LOTL / national TL, CRL, OCSP) are SSRF-guarded by default — a CA, OCSP responder or trusted list on a private network now needs `fetcher: createGuardedFetcher({ allowHttp: true, allowPrivateNetworks: true })`. IACA → document-signer chain building only applies on the `trustStore` path: `trustedCertificates` is still byte-equality, so pass `trustStore: new StaticTrustStore([...])` to accept PIDs whose list publishes the IACA rather than the signer.
|
|
476
612
|
|
|
477
613
|
## License
|
|
478
614
|
|