From e1bb4e25d87a6f45384178188081e858f86fcdd2 Mon Sep 17 00:00:00 2001 From: Aere Network Date: Sun, 18 Oct 2026 11:07:27 +0300 Subject: [PATCH] identity: SD-JWT interoperability measured in both directions with @sd-jwt/core 0.23.0 and jose 6.2.12 (ML-DSA-65 included), nested _sd_alg refused, the SD-JWT VC profile (draft-19, dc+sd-jwt, vct, Token Status List offline); conformance: SD-JWT and SD-JWT VC enrolled (213 rules, 13 verifiers, 553 vectors) --- README.md | 10 +- conformance/README.md | 96 ++- conformance/REGULI.json | 245 +++++- conformance/genereaza-vectori.mjs | 213 +++++ conformance/implementare-aere.mjs | 20 + conformance/proba-conformance.mjs | 8 +- conformance/reguli.mjs | 44 +- conformance/surse-proaspete.json | 91 +++ conformance/vectori/INDEX.json | 739 +++++++++++++++++- .../aere-issued.alg-none.json | 66 ++ .../aere-issued.claim-conflict.json | 66 ++ .../sdjwt-presentation/aere-issued.crit.json | 66 ++ .../aere-issued.digest-twice.json | 66 ++ .../aere-issued.disclosure-form-not-json.json | 66 ++ .../aere-issued.disclosure-form-sd.json | 66 ++ .../aere-issued.disclosure-form.json | 66 ++ .../aere-issued.disclosure-name-proto.json | 66 ++ .../aere-issued.disclosure-name.json | 66 ++ .../aere-issued.key-confusion.json | 66 ++ .../aere-issued.sd-alg-nested.json | 66 ++ .../aere-issued.sd-alg.json | 66 ++ .../aere-issued.time-no-exp.json | 66 ++ .../aere-issued.time-years-later.json | 65 ++ .../sdjwt-presentation/aere-issued.typ.json | 66 ++ .../sdjwt-presentation/aere-issued.valid.json | 57 ++ .../aere-ml-dsa-65.valid.json | 59 ++ .../sdjwt-presentation/aere.kb-claims.json | 68 ++ .../sdjwt-presentation/aere.kb-cnf.json | 68 ++ .../aere.kb-freshness-exp.json | 68 ++ .../sdjwt-presentation/aere.signature-kb.json | 68 ++ .../sdjwt-presentation/aere.time-expired.json | 68 ++ .../sdjwt-presentation/aere.time-not-yet.json | 68 ++ .../sdjwt-presentation/aere.typ-kb.json | 68 ++ .../sdjwt-presentation/aere.valid.json | 59 ++ .../rfc9901-issued.disclosure-twice.json | 66 ++ .../rfc9901-issued.form-empty.json | 66 ++ .../rfc9901-issued.unreferenced.json | 66 ++ .../rfc9901-issued.valid.json | 58 ++ .../rfc9901.form-clock.json | 67 ++ .../sdjwt-presentation/rfc9901.form.json | 67 ++ .../sdjwt-presentation/rfc9901.issuer.json | 68 ++ .../rfc9901.kb-audience.json | 67 ++ .../rfc9901.kb-context.json | 65 ++ .../rfc9901.kb-freshness.json | 67 ++ .../sdjwt-presentation/rfc9901.kb-nonce.json | 67 ++ .../rfc9901.kb-required.json | 67 ++ .../rfc9901.kb-sd-hash.json | 67 ++ .../sdjwt-presentation/rfc9901.key.json | 70 ++ .../sdjwt-presentation/rfc9901.signature.json | 72 ++ .../sdjwt-presentation/rfc9901.typ.json | 68 ++ .../sdjwt-presentation/rfc9901.valid.json | 59 ++ .../sd-jwt-core-es256.valid.json | 60 ++ .../sd-jwt-core-ml-dsa-65.valid.json | 59 ++ .../sd-jwt-core-typed.valid.json | 58 ++ .../sdjwt-presentation/sd-jwt-core.alg.json | 68 ++ .../sd-jwt-core.digest-twice.json | 68 ++ .../sd-jwt-core.kb-audience.json | 68 ++ .../sd-jwt-core.kb-sd-hash.json | 68 ++ .../sd-jwt-core.sd-alg.json | 71 ++ .../sd-jwt-core.signature-kb.json | 68 ++ .../sdjwt-presentation/sd-jwt-core.typ.json | 65 ++ .../sd-jwt-core.unreferenced.json | 68 ++ .../sdjwt-presentation/sd-jwt-core.valid.json | 59 ++ .../aere-no-status.valid.json | 69 ++ .../aere-pid-8-bits.valid.json | 76 ++ .../aere-pid-ml-dsa-65.valid.json | 70 ++ .../aere-pid-status-waived.partial.json | 70 ++ .../aere-pid.disclosed-protected.json | 83 ++ .../aere-pid.form-idx.json | 83 ++ .../aere-pid.form-integrity.json | 83 ++ .../aere-pid.form-status.json | 83 ++ .../aere-pid.status-index.json | 78 ++ .../aere-pid.status-list-expired.json | 78 ++ .../aere-pid.status-list-no-iat.json | 78 ++ .../aere-pid.status-list-other-uri.json | 78 ++ .../aere-pid.status-list-stranger.json | 78 ++ .../aere-pid.status-list-typ.json | 78 ++ .../aere-pid.status-revoked.json | 78 ++ .../aere-pid.status-suspended.json | 78 ++ .../aere-pid.status-unjudged.json | 76 ++ .../sdjwt-vc-presentation/aere-pid.valid.json | 70 ++ .../aere-pid.vct-expected.json | 76 ++ .../aere-pid.vct-mismatch.json | 78 ++ .../sdjwt-vc-presentation/aere-pid.vct.json | 79 ++ .../sd-jwt-vc-8-bits.valid.json | 69 ++ .../sd-jwt-vc-es256.valid.json | 70 ++ .../sd-jwt-vc-ml-dsa-65.valid.json | 69 ++ .../sd-jwt-vc-status-waived.partial.json | 69 ++ .../sd-jwt-vc.status-list-expired.json | 78 ++ .../sd-jwt-vc.status-list-other-uri.json | 78 ++ .../sd-jwt-vc.status-revoked.json | 78 ++ .../sd-jwt-vc.status-suspended.json | 78 ++ .../sd-jwt-vc.status-unjudged.json | 77 ++ .../sd-jwt-vc.valid.json | 69 ++ .../sd-jwt-vc.vct-mismatch.json | 78 ++ identity/README.md | 141 +++- identity/control-negativ-sdjwt-vc.mjs | 67 ++ identity/control-negativ-sdjwt.mjs | 55 +- identity/identity-cli.mjs | 53 +- .../interop/fixturi-interop-sdjwt-vc.json | 427 ++++++++++ identity/interop/fixturi-interop-sdjwt.json | 310 ++++++++ identity/interop/interop-sdjwt-vc.mjs | 202 +++++ identity/interop/interop-sdjwt.mjs | 247 ++++++ .../interop/rezultate-interop-sdjwt-vc.json | 266 +++++++ identity/interop/rezultate-interop-sdjwt.json | 247 ++++++ identity/proba-sdjwt-vc.mjs | 152 ++++ identity/proba-sdjwt.mjs | 48 +- identity/sdjwt-vc.mjs | 152 ++++ identity/sdjwt.mjs | 185 +++-- 109 files changed, 9823 insertions(+), 175 deletions(-) create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.alg-none.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.claim-conflict.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.crit.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.digest-twice.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-not-json.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-sd.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name-proto.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.key-confusion.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.sd-alg-nested.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.sd-alg.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.time-no-exp.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.time-years-later.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.typ.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-issued.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/aere-ml-dsa-65.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.kb-claims.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.kb-cnf.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.kb-freshness-exp.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.signature-kb.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.time-expired.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.time-not-yet.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.typ-kb.json create mode 100644 conformance/vectori/sdjwt-presentation/aere.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901-issued.disclosure-twice.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901-issued.form-empty.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901-issued.unreferenced.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901-issued.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.form-clock.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.form.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.issuer.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.kb-audience.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.kb-context.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.kb-freshness.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.kb-nonce.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.kb-required.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.kb-sd-hash.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.key.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.signature.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.typ.json create mode 100644 conformance/vectori/sdjwt-presentation/rfc9901.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core-es256.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core-typed.valid.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.alg.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.digest-twice.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-audience.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-sd-hash.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.sd-alg.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.signature-kb.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.typ.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.unreferenced.json create mode 100644 conformance/vectori/sdjwt-presentation/sd-jwt-core.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-no-status.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid-8-bits.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid-status-waived.partial.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.disclosed-protected.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.form-idx.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.form-integrity.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.form-status.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-index.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-expired.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-no-iat.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-other-uri.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-stranger.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-typ.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-revoked.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-suspended.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.status-unjudged.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-expected.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-mismatch.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/aere-pid.vct.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-es256.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-expired.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-revoked.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-suspended.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-unjudged.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.valid.json create mode 100644 conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch.json create mode 100644 identity/control-negativ-sdjwt-vc.mjs create mode 100644 identity/interop/fixturi-interop-sdjwt-vc.json create mode 100644 identity/interop/fixturi-interop-sdjwt.json create mode 100644 identity/interop/interop-sdjwt-vc.mjs create mode 100644 identity/interop/interop-sdjwt.mjs create mode 100644 identity/interop/rezultate-interop-sdjwt-vc.json create mode 100644 identity/interop/rezultate-interop-sdjwt.json create mode 100644 identity/proba-sdjwt-vc.mjs create mode 100644 identity/sdjwt-vc.mjs diff --git a/README.md b/README.md index 8b11935..6e9158a 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ notarization command of the verification layer and for the agents' x402 wallet ( | [`market-settlement/`](market-settlement/) | the dispute and settlement rail of a verifiable infrastructure market, measured end to end on testnet 28001: an order with its reward in escrow and a provider bond, the result committed on chain with its execution envelope notarized under a post-quantum certified anchor, a challenge window in which anyone disputes with a recomputed result and a bond, an arbiter that can only route the escrow (with a permissionless 14-day timeout), deadline reclaims, and an AIP-23 settlement receipt; a pure judge over the job's timeline that checks deadlines, the window, who resolved, the payout, the replay and the proof | | [`verifiable-data/`](verifiable-data/) | a dataset whose every answer is checkable against a short commitment without the data: RFC 9162 commitments per version (append-only, consistency proofs), equality and range queries proven correct AND complete (contiguous run of a sorted index plus its two neighbours), hash-based selective disclosure of fields, availability sampling against the serving endpoint, and the version's AIP-23 envelope notarized and read back under a post-quantum certified anchor; not zero knowledge, and says so | | [`ai-trust/`](ai-trust/) | the trust chain of an AI result: the agent's identity (agents/), the model artifact's attestation, the host's runtime record (verify-layer/), the policy and signed ledger, the Proof of AI envelope and the chain as witness, joined in one bundle whose verifier checks only the links between them | -| [`conformance/`](conformance/) | a conformance suite for the AIP-23 proof kinds: one verdict form over the verifiers published here (four levels: integrity, authenticity, anchoring, finality; each passed, failed or not measured, with the named rule), 181 rules of eleven verifiers read from their code (the presentation verifier of identity/ and the device verifier of device-identity/ among them since 2026-10-05), 422 vectors derived from the producers and from evidence recorded on testnet 28001 (each invalid one is one operation away from one that is not, or one change at its producer, and must be refused for exactly its named rules), and a runner that scores any implementation given as a command, in any language; a second implementation in Python covers 6 of the 181 rules. Not a certification and not an audit | -| [`identity/`](identity/) | post-quantum credentials: an issuer signs claims (hybrid Ed25519 + ML-DSA-65, both required), the holder shows only the claims it picks (selective disclosure in the manner of SD-JWT, RFC 9901, in a format of its own), bound to the verifier's audience and nonce; delegation to a phone, an agent or a ten-minute session key that can only narrow; revocation and an issuer status list in the manner of W3C Bitstring Status List; all checked offline from the files; and compliance without surveillance: a verifier's policy (issuers, required claims) judged on a presentation, recorded as an AIP-23 envelope that carries no personal data; and the Travel Rule between VASPs, the IVMS101 data sealed for the receiving VASP with a hybrid X25519 + ML-KEM-768 key encapsulation, signed, bound to the transfer and acknowledged; and the same credentials as standard SD-JWT (IETF RFC 9901): issued with the issuer's Ed25519 key (EdDSA) or its ML-DSA-65 key, presented with a key binding JWT, and verified against the RFC's own example vectors (`identity-cli.mjs verify-sdjwt`, behind Aere Cloud's POST /v1/identity/sd-jwt/verify) | +| [`conformance/`](conformance/) | a conformance suite for the AIP-23 proof kinds: one verdict form over the verifiers published here (four levels: integrity, authenticity, anchoring, finality; each passed, failed or not measured, with the named rule), 213 rules of thirteen verifiers read from their code (the presentation verifier of identity/ and the device verifier of device-identity/ among them since 2026-10-05, the SD-JWT and SD-JWT VC verifiers since 2026-10-18), 553 vectors derived from the producers and from evidence recorded on testnet 28001 (each invalid one is one operation away from one that is not, or one change at its producer, and must be refused for exactly its named rules), and a runner that scores any implementation given as a command, in any language; a second implementation in Python covers 6 of the 213 rules. Not a certification and not an audit | +| [`identity/`](identity/) | post-quantum credentials: an issuer signs claims (hybrid Ed25519 + ML-DSA-65, both required), the holder shows only the claims it picks (selective disclosure in the manner of SD-JWT, RFC 9901, in a format of its own), bound to the verifier's audience and nonce; delegation to a phone, an agent or a ten-minute session key that can only narrow; revocation and an issuer status list in the manner of W3C Bitstring Status List; all checked offline from the files; and compliance without surveillance: a verifier's policy (issuers, required claims) judged on a presentation, recorded as an AIP-23 envelope that carries no personal data; and the Travel Rule between VASPs, the IVMS101 data sealed for the receiving VASP with a hybrid X25519 + ML-KEM-768 key encapsulation, signed, bound to the transfer and acknowledged; and the same credentials as standard SD-JWT (IETF RFC 9901): issued with the issuer's Ed25519 key (EdDSA) or its ML-DSA-65 key, presented with a key binding JWT, and verified against the RFC's own example vectors and, since 2026-10-18, interoperable in both directions with a foreign library (@sd-jwt/core 0.23.0 with jose 6.2.12, ML-DSA-65 included; `interop/`), plus the SD-JWT VC profile (draft-ietf-oauth-sd-jwt-vc-19, `dc+sd-jwt`, `vct`, a Token Status List judged offline) (`identity-cli.mjs verify-sdjwt`, behind Aere Cloud's POST /v1/identity/sd-jwt/verify, and `verify-sdjwt-vc`) | | [`device-identity/`](device-identity/) | what a machine is, as a chain of signed statements checked offline: the manufacturer's credential for the device key (the manufacturer and the owners sign hybrid, Ed25519 + ML-DSA-65, both required; the device key is ML-DSA-65), a firmware release with a floor and retractions (a rolled-back or retracted firmware is refused), ownership by transfers each signed by the owner before, the current owner's authorization, a status registry in which the manufacturer's retirement is final and an owner's lasts as long as its ownership (after a sale the records of the previous owner are named and not applied: a seller could date one before the sale after it; a retirement by an owner that survives a sale needs a witness of time that is not built), and the device's fresh attestation to the verifier's nonce, with an AIP-23 envelope that can be notarized and read back under a post-quantum certified anchor; one verifier makes every check it can reach, names every rule that refused and says VALID, PARTIAL (what it was not handed, or could not read) or INVALID. The device key is a software key: no TPM, secure element or TEE is used or checked, and the README says what that leaves open | | [`exposure-report/`](exposure-report/) | classifies Bitcoin and Ethereum addresses by whether their public key is already readable from chain data, in three declared modes (offline, by address or script type only; through your own Electrum server, Esplora index, Bitcoin Core or Ethereum JSON-RPC, one declared target; through a third-party provider only with written consent, recorded in the report), with exactly two labels ("exposed (on-chain evidence)", "no on-chain evidence of exposure") and "unmeasured" when the reading did not happen, the evidence named for each address, and a dated report (JSON, Markdown, an AIP-23 `compliance` envelope that binds the JSON). It records what was readable on the date of the report: it does not protect, move or recover any coins, it does not change what a spend reveals, and it says nothing about the future. The one component with npm dependencies (`@noble/hashes`, `@noble/curves` 1.x: `npm install --ignore-scripts` in its directory) | @@ -44,14 +44,14 @@ test, counts as a failure of the control. Results measured on 2026-09-29 (Node.j | proof-kinds | 24/24 with the same verifier (`AERE_VERIFY_PROOF=... node proba-proof-kinds.mjs`) | six negative controls inside the test | | readiness | 6/6 (`node proba-adrese-private.mjs`: the private-address rules, and a local listener no scan may touch) | the rate limit and the queue bound are tested where the service runs, not here (its README says so) | | control-plane | planner 44/44 (2026-10-18: a key agreement or a client-side TLS configured by the application itself is not routed to the TLS gateway; a self-signed trust anchor is blocked, not "automatic through PKI"; test code is LOW with its own scope), command line 10/10, execution 30/30 on real products started locally, remediation 33/33 on real TLS servers (all five server profiles measured end to end on 2026-10-18: nginx, Apache, HAProxy, Node, Go), compliance report 30/30 (with the AIP-23 verifier; test-code findings are counted apart and are not "exposed today"), console 8/8; the console viewer in a real Chromium, phone and desktop, 26/26 (`node proba-consola-web.mjs`, measured 2026-09-30; needs `playwright-core` and a Chromium, otherwise it exits 2) | remediation 7/7, compliance report 3/3 in this repository; viewer 8/8 (`node control-negativ-consola-web.mjs`) | -| identity | 46/46 (`node proba-identity.mjs`, with the AIP-23 verifier for its envelope test; without it that test is reported as skipped and the exit code is 2), compliance 15/15 (`node proba-conformitate.mjs`), Travel Rule 19/19 (`node proba-travel-rule.mjs`), SD-JWT 23/23 (`node proba-sdjwt.mjs`, the RFC 9901 vectors included), measured 2026-10-05 | 53/53 (`node control-negativ-identity.mjs`); compliance 14/14 (`node control-negativ-conformitate.mjs`); Travel Rule 19/19 (`node control-negativ-travel-rule.mjs`); SD-JWT 29/29 (`node control-negativ-sdjwt.mjs`) | +| identity | 46/46 (`node proba-identity.mjs`, with the AIP-23 verifier for its envelope test; without it that test is reported as skipped and the exit code is 2), compliance 15/15 (`node proba-conformitate.mjs`), Travel Rule 19/19 (`node proba-travel-rule.mjs`), SD-JWT 25/25 (`node proba-sdjwt.mjs`, the RFC 9901 vectors and fixtures derived from @sd-jwt/core 0.23.0 included), SD-JWT VC 10/10 (`node proba-sdjwt-vc.mjs`); interoperability with @sd-jwt/core and jose in both directions 26/26 and 28/28 (`interop/`, with those libraries installed in a folder you name; otherwise reported unmeasured), measured 2026-10-18 | 53/53 (`node control-negativ-identity.mjs`); compliance 14/14 (`node control-negativ-conformitate.mjs`); Travel Rule 19/19 (`node control-negativ-travel-rule.mjs`); SD-JWT 31/31 (`node control-negativ-sdjwt.mjs`); SD-JWT VC 16/16 (`node control-negativ-sdjwt-vc.mjs`) | | agents | policy 27/27 with the AIP-23 verifier (without it 25 run, 2 are reported as skipped and the exit code is 2), ledger 54/54 on 2026-10-05, approval and revocation 39/39, the chain as witness 26/26 without a network and 7/7 on testnet 28001 on 2026-09-30 (`proba-agent-ancora-testnet.mjs`, needs a funded testnet key and the AIP-23 verifier), command line 23/23 through files and processes only (on Linux and macOS one more test checks the key file mode; not measured here); x402 wallet 25/25, 2-of-2 co-signing 16/16 and payment verifier 14/14 without a network; on the public testnet 28001, 9/9 with the wallet key and 13/13 with the 2-of-2 contract wallet (`agents/x402/proba-x402-testnet.mjs`, `agents/x402/proba-cosign-testnet.mjs`, each needs a funded testnet key); the contract's artifact recompiles byte for byte with solc 0.8.23 (`node x402/recompileaza-contract.mjs --solc `) | 26/26 (`node control-negativ-aprobare.mjs`); the chain as witness 11/11 (`node control-negativ-ancora.mjs`); x402 30/30 (`node x402/control-negativ-wallet.mjs`); the contract's own tests (7) and their negative control (4/4) run in the Aere Network contracts project, not in this repository | | proof-of-ai | 6/6 with the AIP-23 verifier (`AERE_VERIFY_PROOF=... node proba-proof-of-ai.mjs`); without it the probe reports NEMASURAT and exits 2 | one negative control inside the test (an envelope touched after its hash: INVALID) | | payments | 23/23 without a chain (`node proba-risc.mjs`: the verdicts under a policy, the reproducible verdict hash, a receipt verified, nine forged ones refused by name, a malformed payment refused by name); 9/9 on testnet 28001 on 2026-10-02 (`AERE_TESTNET_KEY_FILE=... AERE_ETHERS_DIR=... node proba-plata-28001.mjs`: a payment allowed, paid, its receipt notarized and read back with finality PASSED, the public reader VALID; a payment above the limit refused with nothing sent; the fourth in the window refused; a forged receipt and a loosened policy INVALID) | 10/10 (`node proba-risc.mjs --control-negativ`: form, asset, counterparty, rate, per-payment limit, window, linkage, USD arithmetic, verdict reproduction, chain facts, each planted out on a copy and each forged fixture then accepted) | | market-settlement | 20/20 on testnet 28001 on 2026-10-02 (`AERE_TESTNET_KEY_FILE=... AERE_ETHERS_DIR=... node proba-piata-28001.mjs`: five scenarios on AereComputeMarketV3 deployed from the committed artifact, every refusal by its named custom error, the provider's notarized envelope read back under a post-quantum certified anchor); the judge on the recorded timelines 26/26 without a chain (`node proba-judecata.mjs`: seven honest readings VALID, eighteen forged or malformed ones INVALID for their named reason, the settlement receipt) | 10/10 (`node proba-judecata.mjs --control-negativ`: form, completeness of the timeline, posting, deadline, window, arbiter, payout, result bytes, replay, proof, each planted out on a copy and each forged fixture then accepted) | | verifiable-data | 23/23 with the AIP-23 verifier (`AERE_VERIFY_PROOF=... node proba-verifiable-data.mjs`: honest answers VALID, ten forged or malformed ones INVALID for their named reason, availability sampling on a local server; the envelope row is NEMASURAT without the verifier, exit 2); the two chain rows of `--viu` measured on testnet 28001 on 2026-10-02 (a version notarized with a test key and read back under a post-quantum certified anchor; evidence in `dovezi/`) | 5/5 (`node proba-verifiable-data.mjs --control-negativ`: field commitment, index order, completeness, consistency, sampling, each planted out on a copy and each forged fixture then accepted) | | ai-trust | 16/16 with the AIP-23 verifier, measured 2026-10-05 (`AERE_VERIFY_PROOF=... node proba-lant-de-incredere.mjs`: the whole chain on a committed fixture, then thirteen bundles broken on purpose, each refused for its named reason, among them an agent with a classical key and an audit head signed with one); without the verifier it exits 2 | 11/11 (`node proba-lant-de-incredere.mjs --control-negativ`) | -| conformance | 12/12 on 2026-10-14 with the AIP-23 verifier as served (fetched and installed in an empty folder), Python 3 and testnet 28001 read (`AERE_VERIFY_PROOF=... node proba-conformance.mjs --online`: the rules and the vectors are what the code derives, every rule has a vector, every invalid vector is one operation from its base or one declared change at its producer, the published verifiers pass 467/467, an independent Python implementation passes the 62 it claims and the other 405 are reported not covered, 96,757 malformed inputs and 183 malformed envelope files each get a verdict); without `--online` the nine chain vectors are reported unmeasured and the exit code is 2 | 263/263 on 2026-10-14: 181/181 rules (`node proba-conformance.mjs --control-negativ --online`: each rule planted out of its verifier in a copy; the vectors that expect it, and only they, must fail), then 76/76 conditions of the device verifier's compound checks, each planted out alone (exactly the vectors written for it must fail), then six controls of the instruments | +| conformance | 12/12 on 2026-10-18 with the AIP-23 verifier as served (fetched and installed in an empty folder), Python 3 and testnet 28001 read (`AERE_VERIFY_PROOF=... node proba-conformance.mjs --online`: the rules and the vectors are what the code derives, every rule has a vector, every invalid vector is one operation from its base or one declared change at its producer, the published verifiers pass 553/553, an independent Python implementation passes the 62 it claims and the other 491 are reported not covered, 97,966 malformed inputs and 183 malformed envelope files each get a verdict); without `--online` the nine chain vectors are reported unmeasured and the exit code is 2 | 295/295 on 2026-10-18: 213/213 rules (`node proba-conformance.mjs --control-negativ --online`: each rule planted out of its verifier in a copy; the vectors that expect it, and only they, must fail), then 76/76 conditions of the device verifier's compound checks, each planted out alone (exactly the vectors written for it must fail), then six controls of the instruments | | device-identity | 372/372 with the AIP-23 verifier, measured 2026-10-14 (`AERE_VERIFY_PROOF=... node proba-device.mjs`: fifty-four bundles that must be VALID; seventy-seven with something not brought, not read or not readable, each PARTIAL for its named causes; two hundred and four attack rows, each refused for exactly its named rules, among them a clone with another key, a rolled-back or retracted firmware (also when the release is left out of the bundle), a previous owner that still signs, an owner's retirement written under no ownership head, a replayed attestation, an attestation dated ahead of the verifier's clock, a manufacturer the verifier does not trust, a retirement, a classical key under the ML-DSA-65 name, a signature in another base64 text, a day that does not exist; 804 damaged bundles each given a verdict; the command line through files only; the evidence recorded on testnet 28001 judged again offline); the chain as witness 10/10 on testnet 28001 on 2026-10-05, before the repairs of that day (`proba-device-ancora-testnet.mjs`, needs a funded testnet key and the AIP-23 verifier; not run again since: the bundles and readings it recorded give the same verdicts under the verifier of now) | 220/220 (`node control-negativ-device.mjs`: the untouched copy green; each of the 47 rules taken out of a copy, the rows that expect it, and only they, go red; 172 more plantings, most of them one condition of a compound check taken out alone, each with its rows) | | exposure-report | 164 passed and 1 `NEMASURAT` of 165 rows in the AERE development tree on 2026-10-14 (`node proba-expunere.mjs`: codec checks with real public vectors, mode 1 and mode 2 through four mock targets that serve recorded responses, the network guard's proof that in modes 1 and 2 nothing leaves the machine, the language gate, the AIP-23 `compliance` envelopes judged by the reference verifier; the `NEMASURAT` row is mode 3 against a real provider, which would send addresses to a third party); in this copy, after `npm install --ignore-scripts` in its directory: 153 passed, 0 red, 0 broken, 12 `NEMASURAT` with the reason (the rows compared with the AIP-23 verifier, the anchor verifier's RLP encoder and MPT walker and the shield's header pins, none of which is in this repository: with `AERE_PROOF_PROTOCOL_VERIFY`, `AERE_VERIFY_PROOF` and `AERE_EXPUNERE_PINI` naming them the rows run, 162 passed and 3 `NEMASURAT`; the scan of the directory for names from the AERE host inventory; the git-ignore row outside a git tree); the exit code is 0 unless a row is red or broken | inside the test, 2026-10-14: each rule has its reverse planting in a copy of the tool (a foreign provider planted on each network path is caught, a label planted in the language gate is refused, each classification rule taken out turns its row red, a `@noble/curves` 2.x planted first is passed over and alone is named as missing), and the recorded fixtures are judged against their declared date | @@ -62,4 +62,4 @@ interface, command line and data (`definePolicy`, `verifyLedger`, `approve`, ... ## Licence -MIT, see [LICENSE](LICENSE). Files: 743 (pq-gateway 9, pq-kms 10, pq-pki 6, crypto-inventory 73, verify-layer 12, proof-kinds 3, control-plane 27, agents 39, identity 15, proof-of-ai 3, ai-trust 6, verifiable-data 7, market-settlement 9, payments 8, conformance 479, device-identity 11, exposure-report 18, readiness 4). +MIT, see [LICENSE](LICENSE). Files: 838 (pq-gateway 9, pq-kms 10, pq-pki 6, crypto-inventory 73, verify-layer 12, proof-kinds 3, control-plane 27, agents 39, identity 24, proof-of-ai 3, ai-trust 6, verifiable-data 7, market-settlement 9, payments 8, conformance 565, device-identity 11, exposure-report 18, readiness 4). diff --git a/conformance/README.md b/conformance/README.md index 2ea3771..5fc609c 100644 --- a/conformance/README.md +++ b/conformance/README.md @@ -42,9 +42,10 @@ verdict (`vectori/payment-receipt/company-p1-28001.valid.json`). ## What is enrolled -`REGULI.json` is derived from the code (`node deriva-reguli.mjs --verifica`): 181 rules of 11 verifiers, 15 artifact kinds. By level: -142 rules are reported at `integrity`, 36 at `authenticity`, 3 at `anchoring` (one of them, `envelope.finality`, is reported at -`anchoring` or at `finality` by the place that refused). +`REGULI.json` is derived from the code (`node deriva-reguli.mjs --verifica`): 213 rules of 13 verifiers, 17 artifact kinds (since +2026-10-18; 181 rules of 11 verifiers, 15 kinds before the SD-JWT verifiers were enrolled). By level: 170 rules are reported at +`integrity`, 40 at `authenticity`, 3 at `anchoring` (one of them, `envelope.finality`, is reported at `anchoring` or at `finality` by +the place that refused). | artifact kind | judged by | rules | |---|---|---| @@ -59,6 +60,8 @@ verdict (`vectori/payment-receipt/company-p1-28001.valid.json`). | `agent-ledger` (an agent's signed ledger under its policy) | `agents/agent-ledger.mjs` | 16: `agents.ledger-form`, `.policy`, `.other-policy`, `.session`, `.key`, `.identity`, `.anchor`, `.seq`, `.chain`, `.body`, `.signature`, `.hash`, `.time`, `.revocation`, `.approvals`, `.decision` | | `identity-presentation` (a credential shown by its holder or by the last delegate of a chain, judged with what the verifier brings: its audience, its nonce, its clock, the issuers it trusts, the status lists and the revocations it was handed) | `identity/identity.mjs` | 37: `identity.form`, `.issuer-id`, `.holder-id`, `.credential-signature`, `.issuer-trusted`, `.credential-window`, `.status-list`, `.credential-revoked`, `.sd-distinct`, `.disclosure-readable`, `.disclosure-signed`, `.disclosure-once`, `.disclosure-plain`, `.claim-name`, `.binding-credential`, `.binding-disclosures`, `.binding-delegations`, `.presenter`, `.presentation-signature`, `.audience`, `.nonce`, `.freshness`, `.chain-length`, `.delegation-form`, `.delegation-ids`, `.delegation-from`, `.delegation-parent`, `.delegation-signature`, `.delegation-scope`, `.delegation-window`, `.delegation-depth`, `.delegation-narrows`, `.delegation-credential`, `.delegation-claims`, `.delegation-audience`, `.delegation-revoked`, `.unreadable` | | `device-bundle` (the chain of a device: the manufacturer's credential for the device key, a firmware release, the ownership transfers, the owner's authorization, the device's attestation and its AIP-23 envelope, judged with what the verifier brings: its clock, nonce and audience, the manufacturers it trusts, the recall lists, firmware policies and status records it read, its own reading of the notarized envelope) | `device-identity/device.mjs` | 47: `device.form`, `.manufacture-form`, `.manufacturer-id`, `.manufacture-holder`, `.manufacture-signature`, `.manufacturer-trusted`, `.manufacture-window`, `.manufacture-status-list`, `.manufacture-revoked`, `.device-key`, `.device-id`, `.firmware-form`, `.firmware-signer`, `.firmware-signature`, `.firmware-model`, `.firmware-retracted`, `.firmware-rollback`, `.firmware-software`, `.chain-length`, `.transfer-form`, `.transfer-device`, `.transfer-ids`, `.transfer-from`, `.transfer-prev`, `.transfer-signature`, `.transfer-time`, `.authorization-form`, `.authorization-device`, `.authorization-owner`, `.authorization-ownership`, `.authorization-signature`, `.authorization-window`, `.authorization-action`, `.status-retired`, `.status-suspended`, `.attestation-form`, `.attestation-key`, `.attestation-device`, `.attestation-signature`, `.audience`, `.nonce`, `.freshness`, `.attestation-firmware`, `.attestation-ownership`, `.witness-envelope`, `.witness-time`, `.unreadable` | +| `sdjwt-presentation` (an SD-JWT of IETF RFC 9901, as issued or with its Key Binding JWT, judged with what the verifier brings: the issuer key it chose, a public JWK, never one taken from the token; its clock; its audience and nonce; the issuer and the explicit type it expects; whether it requires key binding and `exp`) | `identity/sdjwt.mjs` (enrolled 2026-10-18) | 23: `sdjwt.form`, `.alg`, `.typ`, `.crit`, `.key`, `.signature`, `.issuer`, `.sd-alg`, `.disclosure-form`, `.disclosure-twice`, `.digest-twice`, `.disclosure-name`, `.claim-conflict`, `.unreferenced`, `.time`, `.kb-context`, `.kb-required`, `.kb-cnf`, `.kb-claims`, `.kb-audience`, `.kb-nonce`, `.kb-freshness`, `.kb-sd-hash` | +| `sdjwt-vc-presentation` (an SD-JWT VC of `draft-ietf-oauth-sd-jwt-vc`, judged as the SD-JWT above plus the profile: the credential type the verifier expects, and the Token Status List it fetched for the `status` the credential names) | `identity/sdjwt-vc.mjs` (enrolled 2026-10-18) | 9 of its own, on top of the 23 of `sdjwt`: `sdjwtvc.vct-expected`, `.vct`, `.vct-mismatch`, `.disclosed-protected`, `.form`, `.status-list`, `.status-index`, `.status-revoked`, `.status-unjudged` | A module verifier exports the list of rules it can name (`REGULI`; its helper throws on any other) and marks its rules in one of two ways, both read by the derivation: a marker on every check of a rule (nine modules), or the rule named at every call of the @@ -88,15 +91,21 @@ adapter writes them in the reason of the integrity level, and the vectors compar So `vectori/device-bundle/resold-after-retirement.valid.json` is `VALID` here, and a verifier that drops the naming still passes it; that the naming is there is measured by the device component's own probe, not by this suite. -**Not enrolled**, counted in the same file: three verifiers of the identity component that sit beside the enrolled one or on top of -it: SD-JWT (26 calls of its refusal helper), Travel Rule (20 places that add a reason) and compliance (3). Their refusals are texts, -not rule ids. Their own probes and negative controls stay what checks them. +The SD-JWT verifier and the SD-JWT VC profile (enrolled 2026-10-18) stop at their first refusal and name its rule: an integrity refusal +leaves the authenticity level `NOT_MEASURED` (`not-reached`), an authenticity refusal leaves integrity so. A VC presentation whose +`status` the verifier waived (`requireStatus: false`) and did not judge is `PARTIAL` (`claim-not-checked`), like a credential whose +status list was not read. The profile imports `sdjwt.mjs` from its real file, so a planted copy of `sdjwt.mjs` is reached only through +the artifact `sdjwt-presentation`: no `sdjwt-vc-presentation` vector expects a rule of `sdjwt` (they all exercise them). + +**Not enrolled**, counted in the same file: two verifiers of the identity component that sit on top of the enrolled ones: Travel Rule +(20 places that add a reason) and compliance (3). Their refusals are texts, not rule ids. Their own probes and negative controls stay +what checks them. ## The vectors -`vectori/` holds 467 vectors (458 offline, 9 that read testnet 28001; 19 MB, since every device and identity vector carries its ML-DSA-65 keys and signatures), listed with their digests in `vectori/INDEX.json`: +`vectori/` holds 553 vectors (544 offline, 9 that read testnet 28001; 20 MB, since every device and identity vector carries its ML-DSA-65 keys and signatures), listed with their digests in `vectori/INDEX.json`: envelope 64, payment-risk 11, payment-receipt 10, market-timeline 26, dataset 22, ai-trust-bundle 24, audit-log 19, audit-inclusion -10, audit-consistency 4, agent-ledger 18, identity-presentation 65, device-bundle 194. By expected verdict: 64 `VALID`, 66 `PARTIAL`, 337 `INVALID`. None is typed by hand +10, audit-consistency 4, agent-ledger 18, identity-presentation 65, device-bundle 194, sdjwt-presentation 54, sdjwt-vc-presentation 32. By expected verdict: 81 `VALID`, 68 `PARTIAL`, 404 `INVALID`. None is typed by hand (`node genereaza-vectori.mjs --verifica` regenerates them and compares byte for byte): - the 16 AIP-23 kinds come from their producers on fixed inputs (the same envelopes as the published AIP-23 kind vectors); the audit @@ -118,13 +127,22 @@ envelope 64, payment-risk 11, payment-receipt 10, market-timeline 26, dataset 22 image and its Proof of Software attestation are the fixtures of the device component; `--proaspat --refa device` makes this one source anew when the producers of the device component change, and every other vector stays byte for byte); an envelope with random content that nobody notarized; a dataset of 16 records with random salts; and the transaction of the recorded receipt read - from the chain (two read calls). + from the chain (two read calls); since 2026-10-18 also an SD-JWT and an SD-JWT VC issued with AERE keys (an issuer, a holder, a + stranger: three hybrid key pairs each, made and discarded), presented to one verifier, the VC's Status List Tokens (clean, revoked, + suspended, 8 bits, for another uri, expired, by a stranger, typed JWT, without `iat`, too short, ML-DSA-65) and the forged siblings + only a key holder can make (a key binding JWT by a stranger or without its nonce, a digest signed twice, a nested `_sd_alg`, a + disclosure named `_sd`, a claim named `__proto__`, an algorithm confusion, a `status` behind a disclosure, and so on); +- the SD-JWT vectors have two more sources that are fixed text: the example of RFC 9901 Section 5 with the key of its Appendix A.5 + (`identity/fixturi-rfc9901.json`), and the tokens of `@sd-jwt/core` 0.23.0 and `@sd-jwt/sd-jwt-vc` 0.23.0 with the status lists of + `@owf/token-status-list` 0.5.0 (`identity/interop/fixturi-interop-*.json`), which the identity component derived from those + libraries' real output on 2026-10-18, with their public test keys. An `INVALID` vector names its `base` and its `mutation`: **one operation** (set, remove or add at one JSON path) applied to the input -of a vector that is not invalid, and it must be refused for exactly the rules in `expected.failed`, not merely refused: 221 of the -337 are made this way. Where the rule sits under a hash or a signature, one place is not reachable (changing an amount under the +of a vector that is not invalid, and it must be refused for exactly the rules in `expected.failed`, not merely refused: 249 of the +404 are made this way. Where the rule sits under a hash or a signature, one place is not reachable (changing an amount under the instruction hash trips the binding first; a false decision in a ledger must still be signed by the agent; a disclosure the issuer never signed must still be signed for by -the holder; an authorization by a previous owner must still be signed by that owner): the other 116 are made at +the holder; an authorization by a previous owner must still be signed by that owner; a digest repeated in an SD-JWT must still be +signed by its issuer, a key binding JWT for another audience by its holder): the other 155 are made at the producer, the commitments above the change recomputed with the published formulas, and every path that moved is declared (`mutation.changed`). Eleven vectors expect more than one rule: rules that guard the same field cannot be separated (a looser policy shown under a receipt also makes the risk verdict not reproduce; a Proof of AI envelope that is changed is also no longer the one the @@ -136,9 +154,9 @@ key breaks both the id derivation and the match with the manufacturer's credenti ``` AERE_VERIFY_PROOF= -node conformance.mjs --impl "node implementare-aere.mjs" # the published verifiers behind the one verdict form: 458 offline vectors +node conformance.mjs --impl "node implementare-aere.mjs" # the published verifiers behind the one verdict form: 544 offline vectors node conformance.mjs --impl "node implementare-aere.mjs" --online # and the 9 that read testnet 28001 (nothing is sent) -node conformance.mjs --impl "python3 implementare-integritate.py" # an independent implementation: 62 vectors, 405 reported NOT COVERED +node conformance.mjs --impl "python3 implementare-integritate.py" # an independent implementation: 62 vectors, 491 reported NOT COVERED node conformance.mjs --impl "" # yours node implementare-aere.mjs [--online] # one artifact { artifact, input }: its verdict ``` @@ -148,8 +166,10 @@ not JSON at all: a file that is not an envelope is refused at the form level, by the vectors show (`{ log, head?, signer? }` for an audit log, `{ ledger, policy }` for an agent's ledger, `{ bundle }` for a trust chain, `{ presentation, now, audience?, nonce?, trustedIssuers?, statusLists?, revocations?, maxAgeS? }` for a presentation of a credential, `{ bundle, now, nonce?, audience?, trustedManufacturers?, statusLists?, firmwarePolicies?, statusRecords?, -softwareAttestation?, anchors?, maxAgeS? }` for a device bundle: `now`, the verifier's clock, is required for both, since a verdict -on the clock of the machine that runs a vector would not reproduce). +softwareAttestation?, anchors?, maxAgeS? }` for a device bundle, `{ sdJwt, issuerKey, issuerAlg?, now, audience?, nonce?, +expectedIssuer?, expectedTyp?, requireKeyBinding?, requireExp?, maxAgeS? }` for an SD-JWT presentation and the same plus +`{ expectedVct, statusListJwt?, statusListKey?, statusListAlg?, requireStatus? }` for an SD-JWT VC: `now`, the verifier's clock, is +required for all of them, since a verdict on the clock of the machine that runs a vector would not reproduce). An implementation is a command that answers three calls with JSON on stdout: `--capabilities` (`{ artifacts, rules, online, batch }`: what it claims to judge), ` [--online]` (the verdict above for the file's `{ artifact, input }`), and, if it says @@ -159,14 +179,33 @@ exact set of failed rules and the state of each of the four levels are the expec refusal. Without `--online` an implementation must not open a connection. `implementare-integritate.py` is the second implementation: Python, standard library only, written from the rules and not from the -JavaScript. It claims 6 of the 181 rules (the form and the statement hash of an envelope; the form, the commitment, the salted field +JavaScript. It claims 6 of the 213 rules (the form and the statement hash of an envelope; the form, the commitment, the salted field commitments and the RFC 9162 inclusion of a dataset record) and passes all 62 vectors it claims. It cannot check an ML-DSA signature -or read a chain, says so in its capabilities, and the runner reports the rest as not covered: 405 vectors, among them every vector of -the trust chain, the audit log, the agents' ledger, the identity presentations and the device bundles. For those six verifiers the -suite has one implementation, ours. +or read a chain, says so in its capabilities, and the runner reports the rest as not covered: 491 vectors, among them every vector of +the trust chain, the audit log, the agents' ledger, the identity presentations, the device bundles and the SD-JWT presentations. For +those eight verifiers the suite has one implementation, ours (for SD-JWT, the identity component measured our verifier against +`@sd-jwt/core` and `@sd-jwt/sd-jwt-vc` outside this suite; those libraries are not implementations of this suite's contract). ## How the suite itself is checked +Measured on 2026-10-18 (UTC), when the SD-JWT verifier and the SD-JWT VC profile were enrolled (Node.js 24.14.1; the reference +verifier of the development repository; testnet 28001 read, nothing sent): + +- `node proba-conformance.mjs --online`: 12 rows green, 0 red. The rules and the vectors are what the code derives now: 213 rules of + 13 verifiers, 553 vectors (54 of the kind `sdjwt-presentation`, 32 of `sdjwt-vc-presentation`). Every rule has a vector that + expects it (213 of 213); every artifact kind has a valid vector (17); every invalid vector is its base with one operation (249) or + one declared producer change (155); the published verifiers pass 553/553; the independent implementation passes all 62 it claims + and the other 491 are reported not covered; 97,966 malformed inputs given to the module verifiers each got a verdict and none + threw (4,398 still accepted, at 193 distinct paths, 4 of them of `sdjwt-presentation` and 2 of `sdjwt-vc-presentation`: the + optional inputs of the verifier, such as the issuer it expects); 183 malformed envelope files given to the reference verifier each + got a verdict. +- `node proba-conformance.mjs --control-negativ --online`: 295 rows green, 0 red: 213 of 213 rules (each of the 23 rules of the + SD-JWT verifier and the 9 of the VC profile planted out in turn fails exactly the vectors that expect it), 76 of 76 conditions of + the device verifier, six controls of the instruments (an implementation that calls everything valid fails 512 of the 544 offline + vectors). While the enrolment was being made, the control found one thing and it was fixed before this measurement: with + `vct-expected` planted out, the VC verifier threw on the vector that names no expected type instead of refusing it by the next + rule, which the suite reported as a broken vector, not as a refusal. + Measured on 2026-10-14 (UTC), after the third review of the device verifier (Node.js 24.14.1; the AIP-23 reference verifier fetched from aere.network/tools with its four sibling files and `npm install` done in an empty folder, as a stranger would; testnet 28001 read, nothing sent): @@ -267,11 +306,11 @@ On 2026-10-05, while the identity verifier was being enrolled, one more, fixed t ## What it is not, and what is not measured - **Not a certification, not an audit, not a mark.** Passing says that an implementation agrees with the published verifiers on these - 467 inputs. It does not say either of them is correct, and no third party has reviewed the verifiers, the vectors or this suite. + 553 inputs. It does not say either of them is correct, and no third party has reviewed the verifiers, the vectors or this suite. - **The vectors and the verifiers have the same authors.** The expected verdicts were written by the people who wrote the verifiers. - The second implementation is independent in code and language, not in authorship, and it covers 6 rules of 181; the other - 175 rules, among them every rule of the trust chain, the audit log, the agents' ledger, the identity verifier and the device - verifier, are judged here by one implementation. + The second implementation is independent in code and language, not in authorship, and it covers 6 rules of 213; the other + 207 rules, among them every rule of the trust chain, the audit log, the agents' ledger, the identity verifier, the device + verifier and the SD-JWT verifiers, are judged here by one implementation. - **Finality is the chain's.** The level says that the post-quantum certificate of the covering anchor verified on the chain where the artifact was notarized. Every notarized vector here is on chain 28001, a testnet; nothing in this suite ran on mainnet. - **Five of the six finality refusals have no vector.** The reference verifier can refuse at its finality level in six places; the @@ -320,7 +359,12 @@ On 2026-10-05, while the identity verifier was being enrolled, one more, fixed t not read them; the statement carries its own `kind`, which is under the hash. (This file used to quote 526 malformed envelopes, a figure of 2026-10-03 from a run whose script was not kept; the row above replaces it.) - **Not part of AIP-23.** The rule ids, the four levels and the verdict form are this suite's reading of the published verifiers; - AIP-23 defines the envelope. The device verifier is enrolled. Of the identity verifiers published beside these, the presentation verifier is enrolled; SD-JWT, - Travel Rule and compliance are not. + AIP-23 defines the envelope. The device verifier is enrolled. Of the identity verifiers published beside these, the presentation + verifier, the SD-JWT verifier and the SD-JWT VC profile are enrolled; Travel Rule and compliance are not. +- **The SD-JWT vectors say what two libraries agree on, on these inputs.** The tokens of `@sd-jwt/core` and `@sd-jwt/sd-jwt-vc` in + the SD-JWT vectors are the fixtures the identity component derived from those libraries' real output on 2026-10-18 (their versions + are in the vector sources); the expected verdicts are those of our verifiers on them, which the identity component measured against + the libraries' own verdicts in both directions. A verifier that resolves the issuer key from `iss` or `x5c`, fetches the status list + or the type metadata, or takes an untyped token by default, is judged here on inputs where all of that is already brought. - **The Python implementation** writes numbers the way JavaScript does only for integers and plain decimals, and sorts keys by code point (JavaScript's order for keys in the Basic Multilingual Plane). diff --git a/conformance/REGULI.json b/conformance/REGULI.json index c11abd9..4b79c4e 100644 --- a/conformance/REGULI.json +++ b/conformance/REGULI.json @@ -1397,14 +1397,249 @@ } ], "marked": "by a marker on every check" + }, + "sdjwt": { + "artifacts": [ + "sdjwt-presentation" + ], + "rules": [ + { + "id": "sdjwt.form", + "source": "form", + "level": "integrity", + "sites": 7, + "says": "the compact serialization (issuer-signed JWT ~ disclosures ~ key binding) and every JWS part can be read: three parts, canonical base64url, JSON objects, no empty disclosure; the verifier clock is a time" + }, + { + "id": "sdjwt.alg", + "source": "alg", + "level": "authenticity", + "sites": 1, + "says": "the JWS algorithm is one the verifier accepts (ES256, EdDSA, ML-DSA-65); never none" + }, + { + "id": "sdjwt.typ", + "source": "typ", + "level": "integrity", + "sites": 1, + "says": "the issuer-signed JWT carries the explicit type the verifier expects (any ...+sd-jwt by default; RFC 9901 Section 9.11) and the key binding JWT kb+jwt" + }, + { + "id": "sdjwt.crit", + "source": "crit", + "level": "integrity", + "sites": 1, + "says": "no critical header parameter (crit) is present: none is understood" + }, + { + "id": "sdjwt.key", + "source": "key", + "level": "authenticity", + "sites": 3, + "says": "the key given is a public EC, OKP or AKP JWK that can be read, and of the algorithm the JWS declares (no algorithm confusion)" + }, + { + "id": "sdjwt.signature", + "source": "signature", + "level": "authenticity", + "sites": 1, + "says": "the JWS signature verifies with that key: the issuer-signed JWT with the issuer key the verifier chose, the key binding JWT with cnf.jwk" + }, + { + "id": "sdjwt.issuer", + "source": "issuer", + "level": "authenticity", + "sites": 1, + "says": "iss is the issuer the verifier expects, when it names one" + }, + { + "id": "sdjwt.sd-alg", + "source": "sd-alg", + "level": "integrity", + "sites": 2, + "says": "_sd_alg is sha-256 (or absent), and appears only at the top level of the payload (RFC 9901 Section 4.1.1)" + }, + { + "id": "sdjwt.disclosure-form", + "source": "disclosure-form", + "level": "integrity", + "sites": 5, + "says": "every disclosure is base64url JSON of [salt, name, value] for an object property or [salt, value] for an array element, and _sd is a list of strings" + }, + { + "id": "sdjwt.disclosure-twice", + "source": "disclosure-twice", + "level": "integrity", + "sites": 1, + "says": "no disclosure is given twice" + }, + { + "id": "sdjwt.digest-twice", + "source": "digest-twice", + "level": "integrity", + "sites": 1, + "says": "no digest appears more than once in the issuer-signed payload, directly or through disclosures (Section 7.1 step 4)" + }, + { + "id": "sdjwt.disclosure-name", + "source": "disclosure-name", + "level": "integrity", + "sites": 2, + "says": "no disclosure names _sd, ..., _sd_alg or __proto__, and no claim is named __proto__" + }, + { + "id": "sdjwt.claim-conflict", + "source": "claim-conflict", + "level": "integrity", + "sites": 1, + "says": "a disclosed claim does not already exist at its level (Section 7.1 step 3.c.ii.3)" + }, + { + "id": "sdjwt.unreferenced", + "source": "unreferenced", + "level": "integrity", + "sites": 1, + "says": "every disclosure given is referenced by a digest of the issuer-signed JWT (Section 7.1 step 5)" + }, + { + "id": "sdjwt.time", + "source": "time", + "level": "integrity", + "sites": 5, + "says": "exp, nbf and iat are numbers; exp is present when required and has not passed on the verifier clock (no allowance); nbf and iat are not ahead of it by more than the clock skew" + }, + { + "id": "sdjwt.kb-context", + "source": "kb-context", + "level": "integrity", + "sites": 1, + "says": "the verifier gave its audience and nonce when a key binding JWT is present or required (Section 7.3 step 5.f)" + }, + { + "id": "sdjwt.kb-required", + "source": "kb-required", + "level": "integrity", + "sites": 1, + "says": "a key binding JWT is present when the verifier requires one" + }, + { + "id": "sdjwt.kb-cnf", + "source": "kb-cnf", + "level": "integrity", + "sites": 1, + "says": "the issuer-signed JWT names the holder key (cnf.jwk) when a key binding JWT is given" + }, + { + "id": "sdjwt.kb-claims", + "source": "kb-claims", + "level": "integrity", + "sites": 1, + "says": "the key binding JWT carries aud, nonce, iat and sd_hash" + }, + { + "id": "sdjwt.kb-audience", + "source": "kb-audience", + "level": "integrity", + "sites": 1, + "says": "the key binding JWT was made for this verifier (aud)" + }, + { + "id": "sdjwt.kb-nonce", + "source": "kb-nonce", + "level": "integrity", + "sites": 1, + "says": "the key binding JWT carries the nonce this verifier gave" + }, + { + "id": "sdjwt.kb-freshness", + "source": "kb-freshness", + "level": "integrity", + "sites": 3, + "says": "the key binding JWT was made within the allowed age of the verifier clock, and its exp and nbf, if it carries them, hold" + }, + { + "id": "sdjwt.kb-sd-hash", + "source": "kb-sd-hash", + "level": "integrity", + "sites": 1, + "says": "sd_hash is the hash of exactly what was presented (the issuer-signed JWT and the disclosures shown)" + } + ], + "marked": "by a marker on every check" + }, + "sdjwt-vc": { + "artifacts": [ + "sdjwt-vc-presentation" + ], + "rules": [ + { + "id": "sdjwtvc.vct-expected", + "source": "vct-expected", + "level": "integrity", + "sites": 1, + "says": "the verifier names the credential type(s) it expects (expectedVct)" + }, + { + "id": "sdjwtvc.vct", + "source": "vct", + "level": "integrity", + "sites": 1, + "says": "the payload carries vct, a non-empty string (draft-ietf-oauth-sd-jwt-vc Section 2.2.2.3)" + }, + { + "id": "sdjwtvc.vct-mismatch", + "source": "vct-mismatch", + "level": "integrity", + "sites": 1, + "says": "vct is one of the types the verifier expects" + }, + { + "id": "sdjwtvc.disclosed-protected", + "source": "disclosed-protected", + "level": "integrity", + "sites": 1, + "says": "none of iss, nbf, exp, cnf, vct, vct#integrity, aka_vcts, status was selectively disclosed (Section 2.2.2.3)" + }, + { + "id": "sdjwtvc.form", + "source": "form", + "level": "integrity", + "sites": 3, + "says": "vct#integrity, if present, is a string; status is an object, and status.status_list carries a non-negative integer idx and a uri" + }, + { + "id": "sdjwtvc.status-list", + "source": "status-list", + "level": "integrity", + "sites": 9, + "says": "the Status List Token handed to the verifier can be read for the uri the credential names: signed with the key given, typ statuslist+jwt, sub equal to that uri, iat present and not ahead of the clock, exp not passed, status_list with bits 1, 2, 4 or 8 and an lst that inflates" + }, + { + "id": "sdjwtvc.status-index", + "source": "status-index", + "level": "integrity", + "sites": 1, + "says": "the index the credential names is inside the list" + }, + { + "id": "sdjwtvc.status-revoked", + "source": "status-revoked", + "level": "integrity", + "sites": 1, + "says": "the status at that index is 0 (VALID); 1 INVALID, 2 SUSPENDED and any other value refuse" + }, + { + "id": "sdjwtvc.status-unjudged", + "source": "status-unjudged", + "level": "integrity", + "sites": 1, + "says": "a status the credential names was judged, unless the verifier waived it (requireStatus false), in which case the verdict is PARTIAL" + } + ], + "marked": "by a marker on every check" } }, "notEnrolled": [ - { - "verifier": "identity: SD-JWT (RFC 9901)", - "refusalSites": 26, - "why": "its refusals carry texts, not rule ids (counted: the calls of its refusal helper); it is checked by its own probe, on the RFC 9901 vectors" - }, { "verifier": "identity: Travel Rule", "refusalSites": 20, diff --git a/conformance/genereaza-vectori.mjs b/conformance/genereaza-vectori.mjs index 37f0249..647e05e 100644 --- a/conformance/genereaza-vectori.mjs +++ b/conformance/genereaza-vectori.mjs @@ -33,6 +33,8 @@ import { newAgentIdentity, openLedger, agentIdFromKey, sessionId, canonical as c import { construieste as lantAI } from '../ai-trust/lant-de-incredere.mjs'; import * as ID from '../identity/identity.mjs'; import * as DV from '../device-identity/device.mjs'; +import * as SJ from '../identity/sdjwt.mjs'; +import * as SV from '../identity/sdjwt-vc.mjs'; import { hartaPublica, LEVELS } from './reguli.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); @@ -40,6 +42,9 @@ const DIR = path.join(AICI, 'vectori'); const PROASPETE = path.join(AICI, 'surse const DOV = { chitanta: new URL('../payments/dovezi/chitanta-28001-2026-10-02T1716Z.json', import.meta.url), piata: new URL('../market-settlement/dovezi/piata-28001-2026-10-02T1652Z.json', import.meta.url), date: new URL('../verifiable-data/dovezi/notarizare-28001-2026-10-02T0820Z.json', import.meta.url), lantAI: new URL('../ai-trust/dovezi/lant-28001-2026-10-02T0519Z.json', import.meta.url) }; +// fixed inputs of the SD-JWT vectors (2026-10-18): the RFC 9901 vectors, and the tokens of @sd-jwt/core and @sd-jwt/sd-jwt-vc that the +// identity component's interop scripts derived from those libraries' real output (public test keys inside) +const FIX = { rfc: new URL('../identity/fixturi-rfc9901.json', import.meta.url), interop: new URL('../identity/interop/fixturi-interop-sdjwt.json', import.meta.url), interopVc: new URL('../identity/interop/fixturi-interop-sdjwt-vc.json', import.meta.url) }; const citeste = (u) => JSON.parse(fs.readFileSync(fileURLToPath(u), 'utf8')); const clona = (x) => JSON.parse(JSON.stringify(x)); const sha256 = (b) => '0x' + crypto.createHash('sha256').update(b).digest('hex'); @@ -400,6 +405,86 @@ const PROASPETE_IN_PLUS = { hardwareRoot: (() => { const st = clona(X1.statement); st.hardwareRoot = { type: 'tpm2-quote', evidence: 'AAAA' }; return { statement: st, signature: DV.signAttestation(st, dev) }; })(), envelopeOfAnother: DV.proofOfDevice(atest({ now: la(61) }), buildProof) } }; }, + // an SD-JWT (RFC 9901) issued with AERE keys (an issuer, a holder, a stranger: three hybrid key pairs that exist only in this call) at a + // fixed time, presented to one verifier, and the forged siblings only a key holder can make (signed again with the issuer or holder key) + sdjwt: async () => { + const NOW = Math.floor(Date.now() / 1000) - 3600; const iso = (s) => new Date(s * 1000).toISOString(); + const iss = ID.generateKeys(), hol = ID.generateKeys(), strain = ID.generateKeys(); + const AUD = 'https://verifier.example', NONCE = 'n-' + crypto.randomBytes(8).toString('hex'), ISS = 'https://issuer.example'; + const CL = { given_name: 'Ada', family_name: 'Example', age_over_18: true, nationalities: ['RO', 'DE'], address: { locality: 'Cluj', country: 'RO' } }; + const emite = (o = {}) => SJ.issueSdJwt({ issuer: iss, holder: hol, claims: CL, disclosable: ['given_name', 'family_name', 'age_over_18'], arrayDisclosable: ['nationalities'], iss: ISS, iat: NOW, exp: NOW + 365 * 86400, decoys: 2, ...o }); + const arata = (sd, reveal, o = {}) => SJ.presentSdJwt({ sdJwt: sd, reveal, holder: hol, audience: AUD, nonce: NONCE, iat: NOW, ...o }); + const b64u = (x) => Buffer.from(x).toString('base64url'); const dec = (s) => JSON.parse(Buffer.from(s, 'base64url').toString('utf8')); + const jwtDin = (antet, corp, cheie = iss.privat.ed25519) => { const cap = b64u(JSON.stringify(antet)) + '.' + b64u(JSON.stringify(corp)); return cap + '.' + b64u(crypto.sign(null, Buffer.from(cap), cheie)); }; + const sha = (d) => crypto.createHash('sha256').update(d).digest('base64url'); + const E = emite(), M = emite({ alg: 'ML-DSA-65', holderAlg: 'ML-DSA-65' }); + const direct = arata(E.sdJwt, ['age_over_18', { element: 'RO', in: 'nationalities' }]); + const corp = dec(E.sdJwt.split('~')[0].split('.')[1]); + const bazaDirect = direct.split('~').slice(0, -1).join('~') + '~'; + const kbPeste = (baza, corpKb = {}, cheie = hol.privat.ed25519, antet = { alg: 'EdDSA', typ: 'kb+jwt' }) => baza + jwtDin(antet, { iat: NOW, aud: AUD, nonce: NONCE, sd_hash: sha(baza), ...corpKb }, cheie); + // a hand-made issuer-signed JWT (EdDSA, typ aere+sd-jwt, cnf = the holder key), no key binding + const jeton = (extra, antet = { alg: 'EdDSA', typ: SJ.TYP }) => jwtDin(antet, { iss: ISS, iat: NOW, exp: NOW + 365 * 86400, _sd_alg: 'sha-256', cnf: { jwk: SJ.publicJwk(hol) }, ...extra }) + '~'; + const dz = (c) => { const d = b64u(JSON.stringify(c)); return { d, dg: sha(d) }; }; + const d1 = dz(['salt-1', 'a', 1]), dSd = dz(['salt-2', '_sd', ['x']]), dRole = dz(['salt-3', 'role', 'admin']), dUnu = dz(['only-a-salt']); + return { now: iso(NOW + 60), later: iso(NOW + 3660), muchLater: iso(NOW + 400 * 86400), audience: AUD, nonce: NONCE, issuer: ISS, + issuerJwk: SJ.publicJwk(iss), issuerJwkMlDsa: SJ.publicJwk(iss, 'ML-DSA-65'), holderJwk: SJ.publicJwk(hol), + issued: E.sdJwt, direct, directMlDsa: arata(M.sdJwt, ['age_over_18'], { holderAlg: 'ML-DSA-65' }), + forged: { + kbStranger: arata(E.sdJwt, ['age_over_18'], { holder: strain }), + kbNoNonce: kbPeste(bazaDirect, { nonce: undefined }), + kbTypJwt: kbPeste(bazaDirect, {}, hol.privat.ed25519, { alg: 'EdDSA', typ: 'JWT' }), + kbExpired: kbPeste(bazaDirect, { exp: NOW - 100 }), + kbNoCnf: kbPeste(jwtDin({ alg: 'EdDSA', typ: SJ.TYP }, { iss: ISS, iat: NOW, exp: NOW + 1000, _sd_alg: 'sha-256' }) + '~'), + expired: arata(emite({ exp: NOW - 1 }).sdJwt, ['age_over_18']), + notYet: arata(emite({ nbf: NOW + 3600 }).sdJwt, ['age_over_18']), + digestTwice: jeton({ _sd: [d1.dg, d1.dg] }) + d1.d + '~', + nestedSdAlg: jeton({ meta: { _sd_alg: 'sha-256', note: 1 } }), + sdAlg384: jeton({ _sd_alg: 'sha-384' }), + disclosureNamedSd: jeton({ _sd: [dSd.dg] }) + dSd.d + '~', + claimConflict: jeton({ role: 'user', _sd: [dRole.dg] }) + dRole.d + '~', + protoClaim: jwtDin({ alg: 'EdDSA', typ: SJ.TYP }, JSON.parse('{"iss":"' + ISS + '","iat":' + NOW + ',"exp":' + (NOW + 1000) + ',"_sd_alg":"sha-256","__proto__":{"admin":true}}')) + '~', + crit: jwtDin({ alg: 'EdDSA', typ: SJ.TYP, crit: ['b64'], b64: false }, corp) + '~', + typJwt: jwtDin({ alg: 'EdDSA', typ: 'JWT' }, corp) + '~', + algConfusion: jwtDin({ alg: 'ES256', typ: SJ.TYP }, corp) + '~', + algNone: b64u(JSON.stringify({ alg: 'none', typ: SJ.TYP })) + '.' + b64u(JSON.stringify(corp)) + '.~', + noExp: jeton({ exp: undefined }), + disclosureOneElement: jeton({ _sd: [dUnu.dg] }) + dUnu.d + '~', + disclosureNotJson: jeton({ _sd: [sha('bm90LWpzb24')] }) + 'bm90LWpzb24~', + sdNotList: jeton({ _sd: 'x' }) } }; + }, + // an SD-JWT VC (a PID-like credential: vct urn:eudi:pid:1, a Token Status List reference) issued with AERE keys, its Status List Tokens + // (clean, revoked, suspended, 8 bits, for another uri, expired, by a stranger, typed JWT, without iat, too short, ML-DSA-65) and the + // hand-made siblings that break the profile (no vct, status disclosed, a malformed status, a vct#integrity that is not a string) + sdjwtvc: async () => { + const NOW = Math.floor(Date.now() / 1000) - 3600; const iso = (s) => new Date(s * 1000).toISOString(); + const iss = ID.generateKeys(), hol = ID.generateKeys(), strain = ID.generateKeys(); + const AUD = 'https://verifier.example', NONCE = 'n-' + crypto.randomBytes(8).toString('hex'), ISS = 'https://issuer.example', VCT = 'urn:eudi:pid:1', URI = 'https://issuer.example/status/pid/1', IDX = 5; + const CL = { given_name: 'Ada', family_name: 'Example', birthdate: '1990-01-01', age_over_18: true, nationalities: ['RO', 'DE'], address: { locality: 'Cluj', country: 'RO' }, issuing_authority: 'Example Authority', issuing_country: 'RO' }; + const emite = (o = {}) => SV.issueSdJwtVc({ issuer: iss, holder: hol, vct: VCT, claims: CL, disclosable: ['given_name', 'family_name', 'birthdate', 'age_over_18', 'address'], arrayDisclosable: ['nationalities'], iss: ISS, iat: NOW, nbf: NOW, exp: NOW + 365 * 86400, status: { status_list: { idx: IDX, uri: URI } }, decoys: 2, ...o }); + const arata = (sd, reveal, o = {}) => SV.presentSdJwtVc({ sdJwt: sd, reveal, holder: hol, audience: AUD, nonce: NONCE, iat: NOW, ...o }); + const lista = (statuses, bits = 1, o = {}) => SV.issueStatusListJwt({ issuer: iss, uri: URI, statuses, bits, iat: NOW, exp: NOW + 3600, ...o }); + const b64u = (x) => Buffer.from(x).toString('base64url'); + const jwtDin = (antet, corp, cheie = iss.privat.ed25519) => { const cap = b64u(JSON.stringify(antet)) + '.' + b64u(JSON.stringify(corp)); return cap + '.' + b64u(crypto.sign(null, Buffer.from(cap), cheie)); }; + const sha = (d) => crypto.createHash('sha256').update(d).digest('base64url'); + const T0 = new Array(16).fill(0), REV = T0.map((_, i) => (i === IDX ? 1 : 0)), SUS = T0.map((_, i) => (i === IDX ? 2 : 0)); + const E = emite(), M = emite({ alg: 'ML-DSA-65', holderAlg: 'ML-DSA-65' }), faraStare = SV.issueSdJwtVc({ issuer: iss, holder: hol, vct: VCT, claims: CL, disclosable: ['birthdate'], iss: ISS, iat: NOW, exp: NOW + 365 * 86400 }); + const reveal = ['birthdate', 'age_over_18', { element: 'RO', in: 'nationalities' }]; + const corpL = JSON.parse(Buffer.from(lista(T0).split('.')[1], 'base64url').toString('utf8')); + const jeton = (extra, dezv = []) => jwtDin({ alg: 'EdDSA', typ: 'dc+sd-jwt' }, { vct: VCT, iss: ISS, iat: NOW, exp: NOW + 365 * 86400, _sd_alg: 'sha-256', cnf: { jwk: SJ.publicJwk(hol) }, ...extra }) + '~' + dezv.map((d) => d + '~').join(''); + const dStatus = b64u(JSON.stringify(['salt-s', 'status', { status_list: { idx: 1, uri: URI } }])); + return { now: iso(NOW + 60), audience: AUD, nonce: NONCE, issuer: ISS, vct: VCT, uri: URI, idx: IDX, issuerJwk: SJ.publicJwk(iss), issuerJwkMlDsa: SJ.publicJwk(iss, 'ML-DSA-65'), + direct: arata(E.sdJwt, reveal), directMlDsa: arata(M.sdJwt, reveal, { holderAlg: 'ML-DSA-65' }), noStatus: arata(faraStare.sdJwt, ['birthdate']), + lists: { clean: lista(T0), revoked: lista(REV), suspended: lista(SUS, 2), eightBits: lista(T0, 8), otherUri: lista(T0, 1, { uri: URI + '-other' }), expired: lista(T0, 1, { exp: NOW + 30 }), + stranger: SV.issueStatusListJwt({ issuer: strain, uri: URI, statuses: T0, iat: NOW }), short: SV.issueStatusListJwt({ issuer: iss, uri: URI, statuses: [0, 0, 0, 0], bits: 8, iat: NOW }), + typJwt: jwtDin({ alg: 'EdDSA', typ: 'JWT' }, corpL), noIat: jwtDin({ alg: 'EdDSA', typ: 'statuslist+jwt' }, (({ iat, ...r }) => r)(corpL)), + mlDsa: SV.issueStatusListJwt({ issuer: iss, alg: 'ML-DSA-65', uri: URI, statuses: T0, iat: NOW, exp: NOW + 3600 }) }, + forged: { + noVct: arata(SJ.issueSdJwt({ issuer: iss, holder: hol, claims: { given_name: 'Ada' }, iss: ISS, iat: NOW, exp: NOW + 365 * 86400, typ: 'dc+sd-jwt' }).sdJwt, []), + statusDisclosed: jeton({ _sd: [sha(dStatus)] }, [dStatus]), + statusIdxNegative: jeton({ status: { status_list: { idx: -1, uri: URI } } }), + statusNotObject: jeton({ status: 'revoked' }), + vctIntegrityNumber: jeton({ 'vct#integrity': 7 }) } }; + }, }; // ---------- fixed inputs of the AIP-23 kinds (the inputs of the published AIP-23 kind vectors) ---------- @@ -998,6 +1083,134 @@ function construieste() { mm('device-bundle/attestation-only.attestation-member-more', 'the attestation with a member more beside its statement and its signature', ba, ['bundle', 'attestation', 'note'], ['device.attestation-signature']); mm('device-bundle/attestation-only.attestation-signature-member-more', 'the attestation with a member more in its signature object', ba, ['bundle', 'attestation', 'signature', 'note'], ['device.attestation-signature']); tot('device-bundle/active-record-signature-member-more.partial', 'a status record with a member more in its signature object is not a signed record: the only "active" is not believed', bd, { op: 'add', path: ['statusRecords', 0, 'signature', 'note'], value: 'x' }, { ...AP, ...NI }); } + // (K) an SD-JWT presentation (IETF RFC 9901; 2026-10-18): the RFC's own example (ES256, the key of Appendix A.5), the tokens @sd-jwt/core + // issued and presented (the interop fixtures of the identity component, derived from that library's real output), and ours with AERE keys. + // The verifier stops at its first refusal: an integrity refusal leaves authenticity not reached, an authenticity refusal leaves integrity not reached + const curat = (o) => JSON.parse(JSON.stringify(o)); + const schimbate = (a, b) => [...new Set([...Object.keys(a), ...Object.keys(b)])].filter((k) => JSON.stringify(a[k]) !== JSON.stringify(b[k])).sort().map((k) => [k]); + { const SK = Object.keys(HARTA).filter((r) => r.startsWith('sdjwt.')); const A = 'sdjwt-presentation'; const RFC = citeste(FIX.rfc); const IO = citeste(FIX.interop); const X = P.sdjwt; + const AP = { authenticity: 'PASSED' }; const nivelul = (r) => (HARTA[r].level === 'authenticity' ? { integrity: 'NOT_MEASURED', authenticity: 'FAILED' } : { authenticity: 'NOT_MEASURED' }); + const inv = (id, titlu, baza, op, r) => invalid(id, titlu, baza, op, [r], { levels: nivelul(r) }); + const prod = (id, titlu, baza, sdJwt, r, nota, extra = {}) => { const b = V.find((x) => x.id === baza); if (!b) throw new Error('no base ' + baza); const input = curat({ ...clona(b.input), sdJwt, ...extra }); invalid(id, titlu, baza, null, [r], { levels: nivelul(r), producer: { note: nota, input, changed: schimbate(b.input, input) } }); }; + const srcRfc = 'IETF RFC 9901 Section 5 and Appendix A.5 (code components, Revised BSD License), via fixturi-rfc9901.json of the identity component'; + const kb = RFC.keyBindingPayload, laKb = new Date(kb.iat * 1000).toISOString(); const br = 'sdjwt-presentation/rfc9901.valid', bri = 'sdjwt-presentation/rfc9901-issued.valid'; + valid(br, A, 'the presentation of RFC 9901 Section 5.2 (ES256, the issuer key of Appendix A.5) with its Key Binding JWT, judged at the time of that JWT with its audience and nonce', srcRfc, { sdJwt: RFC.presentation, issuerKey: RFC.issuerJwk, issuerAlg: 'ES256', audience: kb.aud, nonce: kb.nonce, now: laKb }, { exercises: SK, levels: AP }); + valid(bri, A, 'the SD-JWT of RFC 9901 Section 5.1 as issued, every disclosure, no key binding (the verifier does not require one)', srcRfc, { sdJwt: RFC.sdJwt, issuerKey: RFC.issuerJwk, issuerAlg: 'ES256', now: laKb, requireKeyBinding: false }, { exercises: SK, levels: AP }); + inv('sdjwt-presentation/rfc9901.kb-audience', 'the same presentation shown to another verifier', br, { op: 'set', path: ['audience'], value: 'https://other.example' }, 'sdjwt.kb-audience'); + inv('sdjwt-presentation/rfc9901.kb-nonce', 'the verifier gave another nonce (a replay)', br, { op: 'set', path: ['nonce'], value: 'another-nonce' }, 'sdjwt.kb-nonce'); + inv('sdjwt-presentation/rfc9901.kb-freshness', 'the verifier clock is an hour after the key binding JWT was made', br, { op: 'set', path: ['now'], value: new Date((kb.iat + 3600) * 1000).toISOString() }, 'sdjwt.kb-freshness'); + inv('sdjwt-presentation/rfc9901.kb-context', 'the verifier gives no audience: a key binding cannot be judged, and the presentation is refused rather than taken on trust', br, { op: 'remove', path: ['audience'] }, 'sdjwt.kb-context'); + inv('sdjwt-presentation/rfc9901.issuer', 'the verifier expects another issuer', br, { op: 'add', path: ['expectedIssuer'], value: 'https://other-issuer.example' }, 'sdjwt.issuer'); + inv('sdjwt-presentation/rfc9901.key', 'the issuer key given is an RSA JWK, which this verifier does not take', br, { op: 'set', path: ['issuerKey'], value: { kty: 'RSA', n: 'AQAB', e: 'AQAB' } }, 'sdjwt.key'); + inv('sdjwt-presentation/rfc9901.signature', 'the issuer key given is the holder key of the example (cnf.jwk): the issuer signature does not verify with it', br, { op: 'set', path: ['issuerKey'], value: RFC.processedPayload.cnf.jwk }, 'sdjwt.signature'); + inv('sdjwt-presentation/rfc9901.typ', 'the verifier expects another explicit type', br, { op: 'add', path: ['expectedTyp'], value: 'other+sd-jwt' }, 'sdjwt.typ'); + inv('sdjwt-presentation/rfc9901.form-clock', 'the verifier clock is not a time', br, { op: 'set', path: ['now'], value: 'yesterday' }, 'sdjwt.form'); + inv('sdjwt-presentation/rfc9901.form', 'the token has no ~ at all (not an SD-JWT)', br, { op: 'set', path: ['sdJwt'], value: RFC.presentation.split('~')[0] }, 'sdjwt.form'); + inv('sdjwt-presentation/rfc9901.kb-required', 'the SD-JWT as issued, no key binding, shown to a verifier that requires one', br, { op: 'set', path: ['sdJwt'], value: RFC.sdJwt }, 'sdjwt.kb-required'); + const pr = RFC.presentation.split('~'); const kbR = pr.pop(); + inv('sdjwt-presentation/rfc9901.kb-sd-hash', 'a disclosure taken out after the key binding JWT was signed', br, { op: 'set', path: ['sdJwt'], value: [...pr.slice(0, 2), ...pr.slice(3), kbR].join('~') }, 'sdjwt.kb-sd-hash'); + const pi = RFC.sdJwt.split('~'); + inv('sdjwt-presentation/rfc9901-issued.disclosure-twice', 'the same disclosure given twice', bri, { op: 'set', path: ['sdJwt'], value: [pi[0], pi[1], pi[1], ...pi.slice(2)].join('~') }, 'sdjwt.disclosure-twice'); + inv('sdjwt-presentation/rfc9901-issued.form-empty', 'an empty disclosure between two ~', bri, { op: 'set', path: ['sdJwt'], value: [pi[0], '', ...pi.slice(1)].join('~') }, 'sdjwt.form'); + { const c = JSON.parse(Buffer.from(pi[1], 'base64url').toString('utf8')); c[2] = String(c[2]) + 'x'; const schimbat = Buffer.from(JSON.stringify(c)).toString('base64url'); + inv('sdjwt-presentation/rfc9901-issued.unreferenced', 'the value of the first disclosure changed: its digest is in no _sd', bri, { op: 'set', path: ['sdJwt'], value: [pi[0], schimbat, ...pi.slice(2)].join('~') }, 'sdjwt.unreferenced'); } + // ours: AERE keys (EdDSA and ML-DSA-65), and the forged siblings only a key holder can make + const srcA = 'producers (sdjwt.mjs: issueSdJwt, presentSdJwt), three hybrid key pairs made and discarded at generation'; + const bo = 'sdjwt-presentation/aere.valid', bom = 'sdjwt-presentation/aere-ml-dsa-65.valid', bi = 'sdjwt-presentation/aere-issued.valid'; + const intrareA = (sdJwt, o = {}) => ({ sdJwt, issuerKey: X.issuerJwk, issuerAlg: 'EdDSA', audience: X.audience, nonce: X.nonce, now: X.now, expectedIssuer: X.issuer, ...o }); + valid(bo, A, 'an SD-JWT issued with AERE keys (EdDSA): two of three disclosable claims and one list element shown, two decoy digests, a key binding JWT for this verifier', srcA, intrareA(X.direct), { exercises: SK, levels: AP }); + valid(bom, A, 'the same credential, issuer and holder keys ML-DSA-65 (RFC 9964, JWK type AKP)', srcA, intrareA(X.directMlDsa, { issuerKey: X.issuerJwkMlDsa, issuerAlg: 'ML-DSA-65' }), { exercises: SK, levels: AP }); + valid(bi, A, 'the same SD-JWT as issued (every disclosure, no key binding), judged by a verifier that does not require key binding', srcA, { sdJwt: X.issued, issuerKey: X.issuerJwk, issuerAlg: 'EdDSA', now: X.now, requireKeyBinding: false }, { exercises: SK, levels: AP }); + const F = X.forged; + prod('sdjwt-presentation/aere.signature-kb', 'the key binding JWT is signed by another key than cnf.jwk', bo, F.kbStranger, 'sdjwt.signature', 'a stranger made the key binding JWT with its own key over the holder\'s SD-JWT'); + prod('sdjwt-presentation/aere.kb-claims', 'the key binding JWT carries no nonce', bo, F.kbNoNonce, 'sdjwt.kb-claims', 'the holder signed a key binding JWT without the nonce claim'); + prod('sdjwt-presentation/aere.typ-kb', 'the key binding JWT is typed JWT, not kb+jwt', bo, F.kbTypJwt, 'sdjwt.typ', 'the holder signed the key binding JWT with typ JWT'); + prod('sdjwt-presentation/aere.kb-freshness-exp', 'the key binding JWT carries an exp that has passed', bo, F.kbExpired, 'sdjwt.kb-freshness', 'the holder signed a key binding JWT with exp in the past'); + prod('sdjwt-presentation/aere.kb-cnf', 'the issuer-signed JWT names no holder key, and a key binding JWT is attached anyway', bo, F.kbNoCnf, 'sdjwt.kb-cnf', 'the issuer signed a JWT without cnf; a key binding JWT was attached to it'); + prod('sdjwt-presentation/aere.time-expired', 'the credential expired a second before the verifier clock', bo, F.expired, 'sdjwt.time', 'the issuer issued the same claims with exp in the past, the holder presented them'); + prod('sdjwt-presentation/aere.time-not-yet', 'the credential is not valid for another hour (nbf ahead of the clock by more than the skew)', bo, F.notYet, 'sdjwt.time', 'the issuer issued the same claims with nbf an hour ahead, the holder presented them'); + prod('sdjwt-presentation/aere-issued.digest-twice', 'the issuer signed the same digest twice in _sd', bi, F.digestTwice, 'sdjwt.digest-twice', 'the issuer signed a payload whose _sd repeats a digest'); + prod('sdjwt-presentation/aere-issued.sd-alg-nested', 'the issuer signed an _sd_alg below the top level (RFC 9901 Section 4.1.1 forbids it)', bi, F.nestedSdAlg, 'sdjwt.sd-alg', 'the issuer signed a payload with _sd_alg inside a nested object'); + prod('sdjwt-presentation/aere-issued.sd-alg', 'the issuer signed _sd_alg sha-384, which this verifier does not understand', bi, F.sdAlg384, 'sdjwt.sd-alg', 'the issuer signed a payload with _sd_alg sha-384'); + prod('sdjwt-presentation/aere-issued.disclosure-name', 'a disclosure named _sd, signed for by the issuer', bi, F.disclosureNamedSd, 'sdjwt.disclosure-name', 'the issuer put in _sd the digest of a disclosure named _sd'); + prod('sdjwt-presentation/aere-issued.disclosure-name-proto', 'a plain claim named __proto__, signed by the issuer', bi, F.protoClaim, 'sdjwt.disclosure-name', 'the issuer signed a payload with a claim named __proto__'); + prod('sdjwt-presentation/aere-issued.claim-conflict', 'a disclosure that would overwrite a claim the payload has in the clear', bi, F.claimConflict, 'sdjwt.claim-conflict', 'the issuer signed a plain claim role and the digest of a disclosure named role'); + prod('sdjwt-presentation/aere-issued.crit', 'the issuer-signed JWT carries a crit header parameter', bi, F.crit, 'sdjwt.crit', 'the issuer signed the header with crit [b64] and b64 false'); + prod('sdjwt-presentation/aere-issued.typ', 'the issuer-signed JWT is typed JWT, not an explicit SD-JWT type', bi, F.typJwt, 'sdjwt.typ', 'the issuer signed the header with typ JWT'); + prod('sdjwt-presentation/aere-issued.key-confusion', 'the header says ES256 and the signature was made with the Ed25519 key (algorithm confusion)', bi, F.algConfusion, 'sdjwt.key', 'the issuer signed with its Ed25519 key under an ES256 header'); + prod('sdjwt-presentation/aere-issued.alg-none', 'alg none, no signature', bi, F.algNone, 'sdjwt.alg', 'the payload re-encoded under an alg none header with an empty signature'); + prod('sdjwt-presentation/aere-issued.time-no-exp', 'the issuer-signed JWT has no exp, and the verifier requires one', bi, F.noExp, 'sdjwt.time', 'the issuer signed a payload without exp'); + prod('sdjwt-presentation/aere-issued.disclosure-form', 'a disclosure that is a one-element list', bi, F.disclosureOneElement, 'sdjwt.disclosure-form', 'the issuer signed the digest of a disclosure that is [salt] alone'); + prod('sdjwt-presentation/aere-issued.disclosure-form-not-json', 'a disclosure that is base64url of text that is not JSON', bi, F.disclosureNotJson, 'sdjwt.disclosure-form', 'the issuer signed the digest of a disclosure whose bytes are not JSON'); + prod('sdjwt-presentation/aere-issued.disclosure-form-sd', '_sd is a string, not a list of digests', bi, F.sdNotList, 'sdjwt.disclosure-form', 'the issuer signed a payload whose _sd is a string'); + inv('sdjwt-presentation/aere-issued.time-years-later', 'the verifier clock is years later: the credential has expired', bi, { op: 'set', path: ['now'], value: X.muchLater }, 'sdjwt.time'); + // @sd-jwt/core (openwallet-foundation-labs/identity-common-ts), from the interop fixtures: its tokens, with its public test keys + const srcIo = `@sd-jwt/core ${IO.biblioteci['@sd-jwt/core']} with jose ${IO.biblioteci.jose} (interop/fixturi-interop-sdjwt.json of the identity component, generated ${IO.generat.slice(0, 10)}; its test keys made and discarded at generation)`; + const laIo = new Date(IO.ceasVerificare * 1000).toISOString(); + const intrareIo = (c) => ({ sdJwt: c.prezentare, issuerKey: c.issuerJwk, issuerAlg: c.alg, audience: IO.audience, nonce: IO.nonce, now: laIo, ...(c.optiuni || {}) }); + const cazIo = (re) => { const c = IO.cazuri.find((x) => re.test(x.nume)); if (!c) throw new Error('the interop fixtures have no case ' + re); return c; }; + const bioE = 'sdjwt-presentation/sd-jwt-core.valid'; + for (const [alg, id, titlu] of [['EdDSA', bioE, 'an SD-JWT issued and presented by @sd-jwt/core (EdDSA): nested disclosures (address.locality), a list element, two decoys, a key binding JWT; the token carries no typ, so the verifier takes any (expectedTyp null)'], ['ES256', 'sdjwt-presentation/sd-jwt-core-es256.valid', 'the same from @sd-jwt/core with ES256 (P-256) keys'], ['ML-DSA-65', 'sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid', 'the same from @sd-jwt/core with ML-DSA-65 keys (RFC 9964)']]) { + const c = cazIo(new RegExp('^' + alg + ': prezentare @sd-jwt/core cu dezvaluiri imbricate')); valid(id, A, titlu, srcIo, intrareIo(c), { exercises: SK, levels: AP }); } + { const c = cazIo(/typ example\+sd-jwt/); valid('sdjwt-presentation/sd-jwt-core-typed.valid', A, 'an SD-JWT from @sd-jwt/core issued with typ example+sd-jwt, taken by the default type of the verifier', srcIo, intrareIo(c), { exercises: SK, levels: AP }); } + inv('sdjwt-presentation/sd-jwt-core.typ', 'the untyped token of @sd-jwt/core under the default type of the verifier (an explicit ...+sd-jwt is required)', bioE, { op: 'remove', path: ['expectedTyp'] }, 'sdjwt.typ'); + const negIo = (id, titlu, re, r, nota) => { const c = cazIo(re); prod(id, titlu, bioE, c.prezentare, r, nota); }; + negIo('sdjwt-presentation/sd-jwt-core.unreferenced', 'the value of a disclosure of @sd-jwt/core changed', /^NEGATIV: dezvaluirea age_over_18 cu valoarea schimbata/, 'sdjwt.unreferenced', 'a disclosure of the @sd-jwt/core token with its value changed (no key binding in that presentation)'); + negIo('sdjwt-presentation/sd-jwt-core.kb-audience', 'presented by @sd-jwt/core for another audience', /^NEGATIV: KB pentru alt aud/, 'sdjwt.kb-audience', '@sd-jwt/core presented the token with a key binding JWT for https://other.example'); + negIo('sdjwt-presentation/sd-jwt-core.alg', 'the @sd-jwt/core payload under alg none', /^NEGATIV: alg none/, 'sdjwt.alg', 'the issuer-signed payload of @sd-jwt/core re-encoded under alg none'); + negIo('sdjwt-presentation/sd-jwt-core.digest-twice', 'the @sd-jwt/core payload with a digest repeated in _sd, signed again by its issuer key', /^NEGATIV: acelasi digest de doua ori/, 'sdjwt.digest-twice', 'the @sd-jwt/core issuer key signed its payload with the first digest of _sd repeated'); + negIo('sdjwt-presentation/sd-jwt-core.signature-kb', 'presented by @sd-jwt/core with a key binding JWT signed by another key than cnf.jwk', /^NEGATIV: KB semnat de alta cheie/, 'sdjwt.signature', '@sd-jwt/core presented the token with a key binding JWT of another key'); + negIo('sdjwt-presentation/sd-jwt-core.kb-sd-hash', 'a disclosure removed from the @sd-jwt/core presentation after key binding', /^NEGATIV: o dezvaluire scoasa/, 'sdjwt.kb-sd-hash', 'a disclosure taken out of the @sd-jwt/core presentation after its key binding JWT was signed'); + { const c = cazIo(/_sd_alg sha-384/); prod('sdjwt-presentation/sd-jwt-core.sd-alg', 'a token @sd-jwt/core issued with _sd_alg sha-384, which this verifier does not understand', bioE, c.prezentare, 'sdjwt.sd-alg', '@sd-jwt/core issued and presented the same claims with hashAlg sha-384 (another issuer key of its own)', { issuerKey: c.issuerJwk }); } } + // (L) an SD-JWT VC presentation (draft-ietf-oauth-sd-jwt-vc with the Token Status List; 2026-10-18): ours with AERE keys and its status + // lists, and the credentials and lists @sd-jwt/sd-jwt-vc and @owf/token-status-list produced (the interop fixtures). No vector here EXPECTS + // a rule of sdjwt: the profile imports sdjwt.mjs from its real file, so a planted copy of sdjwt is not reached through this artifact + { const VK = Object.keys(HARTA).filter((r) => r.startsWith('sdjwt.') || r.startsWith('sdjwtvc.')); const A = 'sdjwt-vc-presentation'; const X = P.sdjwtvc; const IO = citeste(FIX.interopVc); + const AP = { authenticity: 'PASSED' }, NI = { integrity: 'NOT_MEASURED' }, OPR = { authenticity: 'NOT_MEASURED' }; + const inv = (id, titlu, baza, op, r) => invalid(id, titlu, baza, op, [r], { levels: OPR }); + const prod = (id, titlu, baza, sdJwt, r, nota, extra = {}) => { const b = V.find((x) => x.id === baza); if (!b) throw new Error('no base ' + baza); const input = curat({ ...clona(b.input), sdJwt, ...extra }); invalid(id, titlu, baza, null, [r], { levels: OPR, producer: { note: nota, input, changed: schimbate(b.input, input) } }); }; + const srcA = 'producers (sdjwt-vc.mjs: issueSdJwtVc, presentSdJwtVc, issueStatusListJwt), three hybrid key pairs made and discarded at generation'; + const intrare = (sdJwt, o = {}) => curat({ sdJwt, issuerKey: X.issuerJwk, issuerAlg: 'EdDSA', audience: X.audience, nonce: X.nonce, now: X.now, expectedIssuer: X.issuer, expectedVct: X.vct, statusListJwt: X.lists.clean, ...o }); + const bv = 'sdjwt-vc-presentation/aere-pid.valid'; + valid(bv, A, `an SD-JWT VC issued with AERE keys (EdDSA; vct ${X.vct}, typ dc+sd-jwt, a status_list reference), three claims shown, judged with the issuer's Status List Token (all VALID)`, srcA, intrare(X.direct), { exercises: VK, levels: AP }); + valid('sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid', A, 'the same credential and its status list, issuer and holder ML-DSA-65', srcA, intrare(X.directMlDsa, { issuerKey: X.issuerJwkMlDsa, issuerAlg: 'ML-DSA-65', statusListJwt: X.lists.mlDsa }), { exercises: VK, levels: AP }); + valid('sdjwt-vc-presentation/aere-no-status.valid', A, 'a credential that names no status, judged without a list', srcA, intrare(X.noStatus, { statusListJwt: undefined }), { exercises: VK, levels: AP }); + valid('sdjwt-vc-presentation/aere-pid-status-waived.partial', A, 'the same credential without its list, the verifier waiving the status (requireStatus false): nothing fails, the status it names was not judged, so it is not VALID', srcA, intrare(X.direct, { statusListJwt: undefined, requireStatus: false }), { exercises: VK, verdict: 'PARTIAL', levels: { ...AP, ...NI } }); + { const op = { op: 'set', path: ['statusListJwt'], value: X.lists.eightBits }; valid('sdjwt-vc-presentation/aere-pid-8-bits.valid', A, 'the same credential with a status list of 8 bits per entry (all VALID)', srcA, aplica(V.find((x) => x.id === bv).input, op), { exercises: VK, levels: AP, base: bv, mutation: op }); } + inv('sdjwt-vc-presentation/aere-pid.vct-expected', 'the verifier names no credential type it expects', bv, { op: 'remove', path: ['expectedVct'] }, 'sdjwtvc.vct-expected'); + inv('sdjwt-vc-presentation/aere-pid.vct-mismatch', 'the verifier expects another credential type', bv, { op: 'set', path: ['expectedVct'], value: 'urn:eudi:pid:2' }, 'sdjwtvc.vct-mismatch'); + inv('sdjwt-vc-presentation/aere-pid.status-revoked', 'the issuer\'s list has status 1 (INVALID) at the credential\'s index', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.revoked }, 'sdjwtvc.status-revoked'); + inv('sdjwt-vc-presentation/aere-pid.status-suspended', 'the issuer\'s list, 2 bits per entry, has status 2 (SUSPENDED) at the index', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.suspended }, 'sdjwtvc.status-revoked'); + inv('sdjwt-vc-presentation/aere-pid.status-list-other-uri', 'the list handed was published for another uri (sub)', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.otherUri }, 'sdjwtvc.status-list'); + inv('sdjwt-vc-presentation/aere-pid.status-list-expired', 'the list handed expired before the verifier clock', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.expired }, 'sdjwtvc.status-list'); + inv('sdjwt-vc-presentation/aere-pid.status-list-stranger', 'the list handed is signed by another key than the issuer\'s', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.stranger }, 'sdjwtvc.status-list'); + inv('sdjwt-vc-presentation/aere-pid.status-list-typ', 'the list handed is typed JWT, not statuslist+jwt', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.typJwt }, 'sdjwtvc.status-list'); + inv('sdjwt-vc-presentation/aere-pid.status-list-no-iat', 'the list handed has no iat', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.noIat }, 'sdjwtvc.status-list'); + inv('sdjwt-vc-presentation/aere-pid.status-index', 'the list handed is shorter than the index the credential names', bv, { op: 'set', path: ['statusListJwt'], value: X.lists.short }, 'sdjwtvc.status-index'); + inv('sdjwt-vc-presentation/aere-pid.status-unjudged', 'no list handed, and the verifier did not waive the status', bv, { op: 'remove', path: ['statusListJwt'] }, 'sdjwtvc.status-unjudged'); + const F = X.forged; + prod('sdjwt-vc-presentation/aere-pid.vct', 'a credential typed dc+sd-jwt with no vct at all', bv, F.noVct, 'sdjwtvc.vct', 'the issuer signed an SD-JWT typed dc+sd-jwt without vct; the holder presented it'); + prod('sdjwt-vc-presentation/aere-pid.disclosed-protected', 'the status claim made selectively disclosable, and disclosed', bv, F.statusDisclosed, 'sdjwtvc.disclosed-protected', 'the issuer put status behind a disclosure (no key binding in this token)', { requireKeyBinding: false }); + prod('sdjwt-vc-presentation/aere-pid.form-idx', 'a status reference with a negative index', bv, F.statusIdxNegative, 'sdjwtvc.form', 'the issuer signed status.status_list.idx -1 (no key binding in this token)', { requireKeyBinding: false }); + prod('sdjwt-vc-presentation/aere-pid.form-status', 'a status claim that is a string', bv, F.statusNotObject, 'sdjwtvc.form', 'the issuer signed status "revoked" (no key binding in this token)', { requireKeyBinding: false }); + prod('sdjwt-vc-presentation/aere-pid.form-integrity', 'a vct#integrity that is a number', bv, F.vctIntegrityNumber, 'sdjwtvc.form', 'the issuer signed vct#integrity 7 (no key binding in this token)', { requireKeyBinding: false }); + // @sd-jwt/sd-jwt-vc and @owf/token-status-list, from the interop fixtures + const srcIo = `@sd-jwt/sd-jwt-vc ${IO.biblioteci['@sd-jwt/sd-jwt-vc']} and @owf/token-status-list ${IO.biblioteci['@owf/token-status-list']} with jose ${IO.biblioteci.jose} (interop/fixturi-interop-sdjwt-vc.json of the identity component, generated ${IO.generat.slice(0, 10)}; their test keys made and discarded at generation)`; + const laIo = new Date(IO.ceasVerificare * 1000).toISOString(); + const intrareIo = (c) => curat({ sdJwt: c.prezentare, issuerKey: c.issuerJwk, issuerAlg: c.alg, audience: IO.audience, nonce: IO.nonce, now: laIo, expectedVct: c.expectedVct, statusListJwt: c.statusListJwt, ...(c.optiuni || {}) }); + const cazIo = (re) => { const c = IO.cazuri.find((x) => re.test(x.nume)); if (!c) throw new Error('the VC interop fixtures have no case ' + re); return c; }; + const bvE = 'sdjwt-vc-presentation/sd-jwt-vc.valid'; + for (const [alg, id, titlu] of [['EdDSA', bvE, 'an SD-JWT VC issued and presented by @sd-jwt/sd-jwt-vc (EdDSA; typ dc+sd-jwt, vct urn:eudi:pid:1, a status_list reference) with the Status List Token of @owf/token-status-list (all VALID)'], ['ES256', 'sdjwt-vc-presentation/sd-jwt-vc-es256.valid', 'the same with ES256 keys'], ['ML-DSA-65', 'sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid', 'the same with ML-DSA-65 keys']]) { + const c = cazIo(new RegExp('^' + alg + ': SD-JWT VC @sd-jwt/sd-jwt-vc')); valid(id, A, titlu, srcIo, intrareIo(c), { exercises: VK, levels: AP }); } + { const c = cazIo(/^lista LOR pe 8 biti/); valid('sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid', A, 'the same credential with the 8-bit list of @owf/token-status-list', srcIo, intrareIo(c), { exercises: VK, levels: AP }); } + { const c = cazIo(/^fara lista, la noi cu requireStatus:false/); valid('sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial', A, 'the @sd-jwt/sd-jwt-vc credential without its list, the status waived: not judged, so not VALID', srcIo, intrareIo(c), { exercises: VK, verdict: 'PARTIAL', levels: { ...AP, ...NI } }); } + const negIo = (id, titlu, re, r, nota) => { const c = cazIo(re); const b = V.find((x) => x.id === bvE); const input = intrareIo(c); invalid(id, titlu, bvE, null, [r], { levels: OPR, producer: { note: nota, input, changed: schimbate(b.input, input) } }); }; + negIo('sdjwt-vc-presentation/sd-jwt-vc.status-revoked', 'the list of @owf/token-status-list with status 1 at the index', /^NEGATIV: lista LOR cu indexul 5 = 1/, 'sdjwtvc.status-revoked', '@owf/token-status-list wrote the list with INVALID at the credential\'s index'); + negIo('sdjwt-vc-presentation/sd-jwt-vc.status-suspended', 'the 2-bit list of @owf/token-status-list with status 2 at the index', /^NEGATIV: lista LOR pe 2 biti/, 'sdjwtvc.status-revoked', '@owf/token-status-list wrote a 2-bit list with SUSPENDED at the credential\'s index'); + negIo('sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri', 'the list of @owf/token-status-list published for another uri', /^NEGATIV: lista LOR pentru ALT uri/, 'sdjwtvc.status-list', '@owf/token-status-list wrote the list with another sub'); + negIo('sdjwt-vc-presentation/sd-jwt-vc.status-list-expired', 'the list of @owf/token-status-list, expired', /^NEGATIV: lista LOR expirata/, 'sdjwtvc.status-list', '@owf/token-status-list wrote the list with exp before the verifier clock'); + negIo('sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch', 'the verifier expects another credential type than the @sd-jwt/sd-jwt-vc credential carries', /^NEGATIV: verificatorul asteapta alt vct/, 'sdjwtvc.vct-mismatch', 'the same credential and list, the verifier expecting urn:eudi:pid:2'); + negIo('sdjwt-vc-presentation/sd-jwt-vc.status-unjudged', 'the @sd-jwt/sd-jwt-vc credential without its list, the status not waived', /^NEGATIV: fara lista, la noi implicit/, 'sdjwtvc.status-unjudged', 'the same credential, no list handed'); } // (E) a dataset: a record, a range answer, a consistency proof, an availability sample const DS = P.dataset; const REC = ['dataset.form', 'dataset.commitment', 'dataset.field', 'dataset.inclusion']; const src = 'producer (verifiable-data), random salts, generated ' + P.at; valid('dataset-record/r5.valid', 'dataset-record', 'one record against the commitment of version 2, two fields disclosed', src, { record: DS.record, commitment: DS.newer }, { exercises: REC }); diff --git a/conformance/implementare-aere.mjs b/conformance/implementare-aere.mjs index 898206d..cde4696 100644 --- a/conformance/implementare-aere.mjs +++ b/conformance/implementare-aere.mjs @@ -172,6 +172,26 @@ async function judeca(artifact, input, online) { else if (st.witness === 'UNMEASURED') ambele(online ? 'unmeasurable' : 'claim-not-checked', online ? String(det.witness.detail).slice(0, 200) : 'the bundle brings notarized heads; this run was offline, they were not read'); else if (st.form === 'PASSED') ambele('unwitnessed', 'no witness: every time in this bundle is the statement of whoever holds the keys'); if (claim) nemasurat(acc, 'anchoring', 'claim-not-checked', 'an envelope of the bundle claims a notarization; this run was offline, the claim was not checked'); + } else if (artifact === 'sdjwt-presentation' || artifact === 'sdjwt-vc-presentation') { + // an SD-JWT (RFC 9901) or an SD-JWT VC presentation, judged by sdjwt.mjs / sdjwt-vc.mjs with what THIS verifier brings: the issuer + // key it chose (a public JWK), its clock (required), its audience and nonce, the issuer and the type it expects and, for a VC, the + // credential type it expects and the Status List Token it fetched. These verifiers stop at their first refusal and name its rule; + // a VC refusal may name a rule of sdjwt (the profile verifies the SD-JWT first) + const vc = artifact === 'sdjwt-vc-presentation'; + const M = await incarca(vc ? 'sdjwtvc' : 'sdjwt'); const RB = VERIFICATOARE.sdjwt.reguli, RV = VERIFICATOARE['sdjwt-vc'].reguli; + if (typeof input.now !== 'string') throw new Error('an SD-JWT presentation is judged on the verifier\'s clock: input.now (an RFC 3339 time) is required'); + const o = { now: input.now }; for (const k of ['issuerKey', 'issuerAlg', 'audience', 'nonce', 'expectedIssuer', 'requireKeyBinding', 'requireExp', 'maxAgeS', 'expectedTyp', 'expectedVct', 'statusListJwt', 'statusListKey', 'statusListAlg', 'requireStatus']) if (input[k] !== undefined) o[k] = input[k]; + const r = vc ? M.verifySdJwtVc(input.sdJwt, o) : M.verifySdJwt(input.sdJwt, o); + if (r.valid !== (r.rule == null)) throw new Error('the SD-JWT verifier refused without naming a rule'); + if (!r.valid) { + const m = (vc && RV[r.rule]) || RB[r.rule]; if (!m) throw new Error('the SD-JWT verifier named a rule this suite does not map: ' + r.rule); + pica(acc, m[1], m[0], r.reason); nemasurat(acc, m[1] === 'integrity' ? 'authenticity' : 'integrity', 'not-reached', 'the verifier stopped at its first refusal'); + } else { + trece(acc, 'integrity', `no rule of the SD-JWT${vc ? ' VC' : ''} verifier refused: ${r.disclosed.length} disclosure(s) bound to the issuer-signed JWT${vc ? ', vct ' + r.vct : ''}`); + trece(acc, 'authenticity', `the issuer-signed JWT verifies (${r.alg}) with the issuer key the verifier gave` + (r.keyBinding ? `; the key binding JWT (${r.keyBinding.alg}) verifies with cnf.jwk for this audience and nonce` : '; no key binding (the verifier did not require one)')); + if (vc && r.status && r.status.present && !r.status.judged) nemasurat(acc, 'integrity', 'claim-not-checked', `the credential names a status (${r.status.mechanism}${r.status.uri ? ' at ' + r.status.uri : ''}) and no list was judged: the verifier waived it`); + } + for (const l of ['anchoring', 'finality']) nemasurat(acc, l, 'not-judged', 'an SD-JWT is anchored by notarizing an AIP-23 envelope of it, judged as the artifact `envelope`'); } else if (artifact.startsWith('dataset-')) { const M = await incarca('baza'); let r; if (artifact === 'dataset-record') r = M.verificaInregistrare(input.record, input.commitment); diff --git a/conformance/proba-conformance.mjs b/conformance/proba-conformance.mjs index 8dcef38..80f7726 100644 --- a/conformance/proba-conformance.mjs +++ b/conformance/proba-conformance.mjs @@ -185,7 +185,9 @@ const ramase = () => [...Object.values(MODULE).map((m) => path.dirname(fileURLTo * @returns {{ cazuri: number, aruncate: string[], acceptate: string[] }} acceptate = the paths (without array positions) whose damage was accepted */ async function malformate() { - const R = await incarca('risc'), C = await incarca('chitanta'), P = await incarca('piata'), B = await incarca('baza'), SC = await incarca('sidecar'), AR = await incarca('arbore'), L = await incarca('ledger'), ID = await incarca('identity'), DV = await incarca('device'); const clona = (x) => JSON.parse(JSON.stringify(x)); + const R = await incarca('risc'), C = await incarca('chitanta'), P = await incarca('piata'), B = await incarca('baza'), SC = await incarca('sidecar'), AR = await incarca('arbore'), L = await incarca('ledger'), ID = await incarca('identity'), DV = await incarca('device'), SJ = await incarca('sdjwt'), SV = await incarca('sdjwtvc'); const clona = (x) => JSON.parse(JSON.stringify(x)); + // the SD-JWT verifiers (2026-10-18), called the way the adapter calls them; a VC whose status was waived and not judged is PARTIAL, not accepted + const optSd = (i) => { const o = { now: i.now }; for (const k of ['issuerKey', 'issuerAlg', 'audience', 'nonce', 'expectedIssuer', 'requireKeyBinding', 'requireExp', 'maxAgeS', 'expectedTyp', 'expectedVct', 'statusListJwt', 'statusListKey', 'statusListAlg', 'requireStatus']) if (i[k] !== undefined) o[k] = i[k]; return o; }; const J = { 'payment-risk': (i) => R.judeca(i.policy, i.inputs).decision === 'ALLOW', 'payment-receipt': (i) => C.verificaChitanta(i.receipt, { policy: i.policy, inputs: i.inputs, tx: i.tx, receipt: i.txReceipt }).verdict === 'VALID', 'market-timeline': (i) => P.judeca(i).verdict === 'VALID', 'dataset-record': (i) => B.verificaInregistrare(i.record, i.commitment).ok, 'dataset-answer': (i) => B.verificaRaspuns(i.answer, i.commitment).verdict === 'VALID', 'dataset-consistency': (i) => B.verificaConsistentaVersiuni(i.proof, i.older, i.newer).ok, // the verifiers enrolled after the first four (2026-10-05), called the way the adapter calls them; ai-trust is not here: each case would run the reference verifier several times @@ -196,7 +198,9 @@ async function malformate() { // identity (2026-10-05): the presentation and everything handed with it; the verifier's own configuration is left out below 'identity-presentation': (i) => { const o = { now: i.now }; for (const k of ['audience', 'nonce', 'trustedIssuers', 'statusLists', 'revocations', 'maxAgeS']) if (i[k] !== undefined) o[k] = i[k]; const r = ID.verifyPresentation(i.presentation, o); return r.valid && !r.unjudged.some((c) => NEJUDECATE_IDENTITY[c]); }, // accepted = what the suite would call VALID, not PARTIAL // a device bundle (2026-10-05) and everything handed with it; the verifier's own configuration (its clock, the manufacturers it trusts, the lists themselves) is left out below - 'device-bundle': (i) => { const o = { now: i.now }; for (const k of ['nonce', 'audience', 'trustedManufacturers', 'statusLists', 'firmwarePolicies', 'statusRecords', 'softwareAttestation', 'anchors', 'maxAgeS']) if (i[k] !== undefined) o[k] = i[k]; return DV.verifyDevice(i.bundle, o).verdict === 'VALID'; } }; + 'device-bundle': (i) => { const o = { now: i.now }; for (const k of ['nonce', 'audience', 'trustedManufacturers', 'statusLists', 'firmwarePolicies', 'statusRecords', 'softwareAttestation', 'anchors', 'maxAgeS']) if (i[k] !== undefined) o[k] = i[k]; return DV.verifyDevice(i.bundle, o).verdict === 'VALID'; }, + 'sdjwt-presentation': (i) => SJ.verifySdJwt(i.sdJwt, optSd(i)).valid, + 'sdjwt-vc-presentation': (i) => { const r = SV.verifySdJwtVc(i.sdJwt, optSd(i)); return r.valid && !(r.status && r.status.present && !r.status.judged); } }; const cai = (x, p = []) => (x !== null && typeof x === 'object' ? [p, ...Object.keys(x).flatMap((k) => cai(x[k], [...p, Array.isArray(x) ? Number(k) : k]))] : [p]).filter((q) => q.length); const VAL = [null, 'x', 7, [], {}]; let cazuri = 0; const aruncate = [], acceptate = [], sarite = []; // a vector whose input is larger than MARE characters is not damaged path by path: thousands of paths, each judged over the whole input diff --git a/conformance/reguli.mjs b/conformance/reguli.mjs index 7e284b2..e628794 100644 --- a/conformance/reguli.mjs +++ b/conformance/reguli.mjs @@ -26,6 +26,10 @@ export const MODULE = { ledger: { url: new URL('../agents/agent-ledger.mjs', import.meta.url), env: 'AERE_CONF_MODUL_LEDGER' }, identity: { url: new URL('../identity/identity.mjs', import.meta.url), env: 'AERE_CONF_MODUL_IDENTITY' }, device: { url: new URL('../device-identity/device.mjs', import.meta.url), env: 'AERE_CONF_MODUL_DEVICE' }, + // 2026-10-18 (B10): SD-JWT (RFC 9901) and its SD-JWT VC profile. The profile imports sdjwt.mjs from its real file: a planted copy of + // sdjwt.mjs is reached only by the sdjwt-presentation artifact, so no sdjwt-vc vector expects a rule of sdjwt (it may exercise them) + sdjwt: { url: new URL('../identity/sdjwt.mjs', import.meta.url), env: 'AERE_CONF_MODUL_SDJWT' }, + sdjwtvc: { url: new URL('../identity/sdjwt-vc.mjs', import.meta.url), env: 'AERE_CONF_MODUL_SDJWTVC' }, }; export const caleModul = (k) => process.env[MODULE[k].env] || fileURLToPath(MODULE[k].url); export const incarca = (k) => import(pathToFileURL(caleModul(k)).href); @@ -241,6 +245,45 @@ export const VERIFICATOARE = { 'witness-envelope': ['device.witness-envelope', I, 'the AIP-23 envelope given is the envelope of a device attestation, hashes to its statementHash and commits to this device and this attestation'], 'witness-time': ['device.witness-time', I, 'the attestation is not dated after the moment the verifier read its envelope on the chain (of several readings, the earliest)'], unreadable: ['device.unreadable', I, 'every field a check reads can be read (a time is an RFC 3339 UTC time, a hash input is JSON)'] } }, + // an SD-JWT presentation (IETF RFC 9901; enrolled 2026-10-18), judged with what the verifier brings: the issuer key it chose (a public + // JWK; never one taken from the token), its clock, its audience and nonce, the issuer and the type it expects. The verifier stops at its + // first refusal and names it; an integrity refusal leaves authenticity not reached, an authenticity refusal leaves integrity not reached + sdjwt: { artifacts: ['sdjwt-presentation'], sursa: 'sdjwt', reguli: { + form: ['sdjwt.form', I, 'the compact serialization (issuer-signed JWT ~ disclosures ~ key binding) and every JWS part can be read: three parts, canonical base64url, JSON objects, no empty disclosure; the verifier clock is a time'], + alg: ['sdjwt.alg', AU, 'the JWS algorithm is one the verifier accepts (ES256, EdDSA, ML-DSA-65); never none'], + typ: ['sdjwt.typ', I, 'the issuer-signed JWT carries the explicit type the verifier expects (any ...+sd-jwt by default; RFC 9901 Section 9.11) and the key binding JWT kb+jwt'], + crit: ['sdjwt.crit', I, 'no critical header parameter (crit) is present: none is understood'], + key: ['sdjwt.key', AU, 'the key given is a public EC, OKP or AKP JWK that can be read, and of the algorithm the JWS declares (no algorithm confusion)'], + signature: ['sdjwt.signature', AU, 'the JWS signature verifies with that key: the issuer-signed JWT with the issuer key the verifier chose, the key binding JWT with cnf.jwk'], + issuer: ['sdjwt.issuer', AU, 'iss is the issuer the verifier expects, when it names one'], + 'sd-alg': ['sdjwt.sd-alg', I, '_sd_alg is sha-256 (or absent), and appears only at the top level of the payload (RFC 9901 Section 4.1.1)'], + 'disclosure-form': ['sdjwt.disclosure-form', I, 'every disclosure is base64url JSON of [salt, name, value] for an object property or [salt, value] for an array element, and _sd is a list of strings'], + 'disclosure-twice': ['sdjwt.disclosure-twice', I, 'no disclosure is given twice'], + 'digest-twice': ['sdjwt.digest-twice', I, 'no digest appears more than once in the issuer-signed payload, directly or through disclosures (Section 7.1 step 4)'], + 'disclosure-name': ['sdjwt.disclosure-name', I, 'no disclosure names _sd, ..., _sd_alg or __proto__, and no claim is named __proto__'], + 'claim-conflict': ['sdjwt.claim-conflict', I, 'a disclosed claim does not already exist at its level (Section 7.1 step 3.c.ii.3)'], + unreferenced: ['sdjwt.unreferenced', I, 'every disclosure given is referenced by a digest of the issuer-signed JWT (Section 7.1 step 5)'], + time: ['sdjwt.time', I, 'exp, nbf and iat are numbers; exp is present when required and has not passed on the verifier clock (no allowance); nbf and iat are not ahead of it by more than the clock skew'], + 'kb-context': ['sdjwt.kb-context', I, 'the verifier gave its audience and nonce when a key binding JWT is present or required (Section 7.3 step 5.f)'], + 'kb-required': ['sdjwt.kb-required', I, 'a key binding JWT is present when the verifier requires one'], + 'kb-cnf': ['sdjwt.kb-cnf', I, 'the issuer-signed JWT names the holder key (cnf.jwk) when a key binding JWT is given'], + 'kb-claims': ['sdjwt.kb-claims', I, 'the key binding JWT carries aud, nonce, iat and sd_hash'], + 'kb-audience': ['sdjwt.kb-audience', I, 'the key binding JWT was made for this verifier (aud)'], + 'kb-nonce': ['sdjwt.kb-nonce', I, 'the key binding JWT carries the nonce this verifier gave'], + 'kb-freshness': ['sdjwt.kb-freshness', I, 'the key binding JWT was made within the allowed age of the verifier clock, and its exp and nbf, if it carries them, hold'], + 'kb-sd-hash': ['sdjwt.kb-sd-hash', I, 'sd_hash is the hash of exactly what was presented (the issuer-signed JWT and the disclosures shown)'] } }, + // an SD-JWT VC presentation (draft-ietf-oauth-sd-jwt-vc, with the Token Status List; enrolled 2026-10-18): the rules of the profile on + // top of sdjwt; the verifier also brings the credential type it expects and the Status List Token it fetched + 'sdjwt-vc': { artifacts: ['sdjwt-vc-presentation'], sursa: 'sdjwtvc', reguli: { + 'vct-expected': ['sdjwtvc.vct-expected', I, 'the verifier names the credential type(s) it expects (expectedVct)'], + vct: ['sdjwtvc.vct', I, 'the payload carries vct, a non-empty string (draft-ietf-oauth-sd-jwt-vc Section 2.2.2.3)'], + 'vct-mismatch': ['sdjwtvc.vct-mismatch', I, 'vct is one of the types the verifier expects'], + 'disclosed-protected': ['sdjwtvc.disclosed-protected', I, 'none of iss, nbf, exp, cnf, vct, vct#integrity, aka_vcts, status was selectively disclosed (Section 2.2.2.3)'], + form: ['sdjwtvc.form', I, 'vct#integrity, if present, is a string; status is an object, and status.status_list carries a non-negative integer idx and a uri'], + 'status-list': ['sdjwtvc.status-list', I, 'the Status List Token handed to the verifier can be read for the uri the credential names: signed with the key given, typ statuslist+jwt, sub equal to that uri, iat present and not ahead of the clock, exp not passed, status_list with bits 1, 2, 4 or 8 and an lst that inflates'], + 'status-index': ['sdjwtvc.status-index', I, 'the index the credential names is inside the list'], + 'status-revoked': ['sdjwtvc.status-revoked', I, 'the status at that index is 0 (VALID); 1 INVALID, 2 SUSPENDED and any other value refuse'], + 'status-unjudged': ['sdjwtvc.status-unjudged', I, 'a status the credential names was judged, unless the verifier waived it (requireStatus false), in which case the verdict is PARTIAL'] } }, }; /** * The FAILED sites of verify-proof's `finality` level, classified. `fragment` must appear on exactly one such source line; `re` @@ -284,7 +327,6 @@ export const NEJUDECATE_DEVICE = { 'manufacture-missing': ['integrity', 'not-sup 'hardware-root': ['authenticity', 'unmeasurable'], 'witness-unread': ['anchoring', 'claim-not-checked'] }; /** Verifiers published beside these that the suite does NOT enrol yet, with the pattern that counts their refusal sites. */ export const NEINROLATE = [ - { name: 'identity: SD-JWT (RFC 9901)', files: [new URL('../identity/sdjwt.mjs', import.meta.url)], re: /\brefuz\(/g, why: 'its refusals carry texts, not rule ids (counted: the calls of its refusal helper); it is checked by its own probe, on the RFC 9901 vectors' }, { name: 'identity: Travel Rule', files: [new URL('../identity/travel-rule.mjs', import.meta.url)], re: /motive\.push\(/g, why: 'its refusals are reasons in a list, not rule ids (counted: the places that add one); it takes the presentation verdict from the enrolled verifier' }, { name: 'identity: compliance', files: [new URL('../identity/conformitate.mjs', import.meta.url)], re: /motive\.push\(/g, why: 'its refusals are reasons in a list, not rule ids (counted: the places that add one); it takes the presentation verdict from the enrolled verifier' }, ]; diff --git a/conformance/surse-proaspete.json b/conformance/surse-proaspete.json index b145993..f3e9d72 100644 --- a/conformance/surse-proaspete.json +++ b/conformance/surse-proaspete.json @@ -13660,5 +13660,96 @@ "statementHash": "0x4f0927ad011351a3ee888ed21c12ba2bfbc8bf6b342e27347da3eda3ede97c4e" } } + }, + "sdjwt": { + "now": "2026-10-18T05:50:12.000Z", + "later": "2026-10-18T06:50:12.000Z", + "muchLater": "2027-11-22T05:49:12.000Z", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "issuer": "https://issuer.example", + "issuerJwk": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerJwkMlDsa": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "6Tn62tdcvySXd3_zFVswffd7sUi83ivTEAoT6I6wLYtTPtk9LPsIOH2SH7px6QgoZA0sG550ZsADKBdHHacbhfWSK5RSRBERfvZIiRhRi9qDazdCTx4t3YxsfkiuRY3KIlEY5Kzq0HMkGycGc5j22IljA2xc7CikUuO9_b1LONfSAB6ngI5mIs2mfHhNxIEaEjG7LBZsZ4Ab5c6Qv9SCNQ3xJtGhuG1eCJ-CYp10DGVphemZLLJAT-OkL7fIWmvMhvIMZKxHMMCU6vFFi3tXIfMVM6oYcw2oJmWcT0Hq0XFP8Wd3qDIbklJ0eiFhjKELZUzECgYCGyl5E-1gd4PlhNf9prXz2npcGwoXv1Hwwf18uWgzBjcmSsDwFl4nyF0eSjdn8dTsOgYD3kkyfuzUrF6Bn0cc4FHLm9PjCTyh3XaMcceJUjLmiEFORAB3qhPVY8pF05AX5Z_5IaTJBfCkuF8GRmGWQiB-n-KfJ6nxqsq-qoCcL3wfZ-TN-xKqHindt2G-3GRxDL_0_2Y8OVwhL_Mpuv3kC52rxCZmZXmJU6U3tCynnxYnsxTX-pqoAbfpuNP2CK7P4I85ljOGS3hsAHNvq7bycr2ENQr_DIrnsO0p8_AvXZo4PxBl_o-QrTtAsb6iNbPGfUPBKyRTBDl99b4eiiLK-tigMnAD5oFqdFYW5kpYC2HhohoGyryQgf_bqcmZgBwGRUhw2qOwTAqxbwl8mAP7HGxXiv5L3ZEfuRf-S_r3n4XWn3E0AV2IkrteKxY-tN-N0DjvxQbdzJF9kfJ7GMIDrLKJVtFHpcOJs0rZN3LW3RC_aJt_3K1djXiycKQhfU5YrPCvprQYcMRbEKXRQcUWG10NutjJJC-CbJTNYvQVAqlnLXy3JZDOuiEaGLXsP-2DOTL10UYh490PUTDwNDRKFdcN7kX8zU6dzQPzwPrzQCJlaul975Ft2SAgenYz4bOHHVx1qFcA68HlTDN1eTCOjUgrofZLyp-mCTZKKKMphb_e-u0LyJ5oSRGz9V2alhjB3bcDE_q9fXT7ajBX5Bcda6x4727JpN5SINavLj7Sw19-ITC257YV7uXxtzg1EO3_0gcXsDIdyRCKsfPjCDWpJL5Gc2-TJXK79sTOfgQSeUp8TW2u_qfyFbGFSDS-TT241Ih4qGGF_LAF3YVGt3XfOVja81bfeJdVmRY9NsXuUi3tV8gVpeAt6DxRnJVLQG33uG92fIEZyuwaTk4FiCy-VObapu526RqUiN_Nq6Iopvu1gm_rs2IbhHWvd3FAmPUO18H03drYOVRyrfplmPvotZ3AyO2-49WTAqZWLvbCw2ae7uO3yJpIX_uHyOBcVG9QZNq_kZ4uVxj7JXrI7foremuuBTpfSsfD72QeUUHzHkzekOKuHncIA9e_6nsc_xzl1yJinvKtpPbUdAq7yCjJjJK6cdKXTP-xEfR5UlX5-vq_25G-gL9IDpen6mG1JBbxQ8Bk1uEPWculbYSIbstvNfo-zbfr5JEQ2lrXrvLEbxbECu8XOrobS_EzOb2FjgDW0ZEg3LnEpd5dGWvHIhT_MBFa2R-VyjnIfW7mBl_lgdP4T8uw2_yP3_bPadkHZRszoh6c26-VZT-tCM3f4RcL5xyu823z4wMOfO43OU0M9CZ42rT_r6UdQDM0H1NzDe2wKvl2xYAByrxrwk2vT2Pa9wRhHhfq7mnhwtkhg_w319OyrX_59Cq-BVoJlMOh3OWDII1qUKcnZODIB3LxIT9c90ly9aA9FHbLdUyteL-j2r-g8lBFvENhnAIVtIz3hPxj5fAIzyXi5tMpZLghO7YM21Ai9e9Af4BTpInKko-EYLPAZt5IKhLbSqvAi7Qt_AIHPfESSlWKirb_1j_MGvvLO9ml7ql2rDSHPH2a9mXvEQ_iugPuq6jwq2XuIaI-AvqU3atM9CAgpvYDxmn9rMuHz1Ad3o-UmZugCx41TliIZlDQk9QEpbPYx-6FiXH0GxS8pM47gl-LmQpDhSOzmUsxZN1MBytrH_n4ELoNp2_VvY3otqz_QeirughA2xxt3gYEperIcC_adE3GuiUR2ymOCWkC3owZpi9neidnW6xxYMoDbRqX-4sy1HeMGzkgxxH4fbtr8TFEVrMNoq3r4mtgDw4oaGk2JrYMwKNGBr_O_CZziMQKHSvUDpH3BbKHN2ZgiyY47RjyDGjG0rfRzY1RbcFDjlq5y6bSoQ1dC4a7Ax4qqb11YjDnlELBuV33DGcUrblExrzSh5TmS9JYp9DeetQA8lgMyqjxKQpw2VKyVjoR04_fYfxtTjIcfScczByG_dzOBpCsALJmbHwrtCl70nHygLmvA5_0Hl7eB9kbr3RyT329A_X_Hkw-aSPJUtS2m-5otm3PK-K_pXoGkvGwYooIHQzpg7KZzO-XqCjMECdaci6narK464wqQxEk4aJMUDIffsOT9rxAWa6ll7QU33_u-Le8Lx2IvfNgphTH_oOVZJxMH2am9_0v-GPTSpV5sJC7swUSNv2rLXo3Sh-nP5LjUvcjYCypMS0g-lF3E7oLAweqhteaI-sKaavHKzgBSDpfwGgZC0krf1J2BRLb3UL1wXgQCbstBbA" + }, + "holderJwk": { + "crv": "Ed25519", + "x": "pdgwYRs8KSv_DIBohAailx0J1KMqTi2wg0Tf7NbZ8V4", + "kty": "OKP" + }, + "issued": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJhcDdQQnplOXZpVnZDNXlGQkp6X2RnIiwiZ2l2ZW5fbmFtZSIsIkFkYSJd~WyJFTUI5Z2JvX21JRk82S0JEaHp3bTlBIiwiZmFtaWx5X25hbWUiLCJFeGFtcGxlIl0~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~WyIxVDEtY0c5Sm5vRWV2OXdQOGxRQkJBIiwiREUiXQ~", + "direct": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IlBWY1dzVDZ1SVFhUHBRUUM1QUQyUzQ3Q3Z5QllpRTBxQ1RVZUtpd0ZfRlUifQ.i8LKIVBV7X67veBsk-vyyCHouKBFEXP5uLl927e3m3-_JE1hOHuyv0KX2gioAO81kI1FY1TV6xHOiQVF-UyBBg", + "directMlDsa": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJhZXJlK3NkLWp3dCJ9.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiIxRlgwR3hrbVlvT2xBSXpiYXhaYUhwQnhLSlI3RmtFWTVKNHBqc2hrMG1zIn0seyIuLi4iOiJSSXVOb2ZvT21scjlsbnFsWmJneGNIdmxKZUp4S0JwaHRZbXRwSWp6NENRIn1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiNTJ3RnVzclB1V0lfLXRfUUdfWmdxTDhWUkg0Njk2MUw0OWtpMGMwRDVPOCIsIk4xNlJZd2lnanc4dW0tMWxza1NfTloxVlpUWFNYaWRaUy1oQ2pYZ1lvVUUiLCJRUGluaVdOOEFHT0QwNDltOHU2TzI5bmtiVWg3YkJhakNkckxzQTFTSUdRIiwiYVZjSTRJdUZweEgwOGNPdFlqQTRYZldJSlJsTGFvMmhsU3h2U2tVbG1YOCIsImJic3FsZWRTUnQ3ZTFPeXpoVmZLdXF3SDZhZ2kybTN1b2h0VG1zMGV4ZGsiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsia3R5IjoiQUtQIiwiYWxnIjoiTUwtRFNBLTY1IiwicHViIjoiekxNT3Y5eEJrRzE5ZTVacnNqLVhVbXJhVk9wNkMyVS1WYi0zQURQWU05NUduRXBLdVVnLXBNN2tOM0tiWi1ZLUlJQ0pZa05IbFA2ZThRUGtpNzJkaGtGUTdUbnBXdnJoQXJ2d2dkZ1JibWtxSFNDcEo3OTc3ZU1kQjNfMmhYcmhLN0J3a0g0elZGdXk5eFJDN0RyZUlHeGNIZHdEaDFfYTFQRWJXVUlWcklhNXZvZURRSVpSMF9HQWlkRlEwN042Y1lQZ1BzallJVERpVHF3N0x1Tnk2MVlObFF6R2F5OFlYRV9xU2ZYdVhpWkxFU29KNS1ZaG5BWjRqMHRlQ1V6ZkJmcmE3ZnZ5VEhNMGFMN29Bd1M5RmIwcVExbVlLMV82NGJlQjhLTEJfWGFoUV9ZbkpNUXg2ZVZQWGJURVljSTNNNHVqRHIyVXV2dzRTLXptdEZ3N0dRLTZGdzl6Vk80YWJzRTVvb2laT3FvbURoSjFfdldSU1BUX096bDlfMVRhaVIwUzBUQ09ZcVg3YU80bi1sVXFpcko2ZzFTMFJYRUlUTkE2SWJXSEpGbjVueTJUZ09LWVE5WE90ZGFSekVSSi03cHZacS1uLVhHNWE4RlhrNklZWnY2cWduaEw2M3hkcksxUmRFT2d5cXJMcEdvNDdXYlhGb2pFaDQza25jUHEwbVM0bC1YMmdienZFYmhpMzhRRVk3VzRaZ2hueWJBT0QxNVFfeFJSa1IxajVJMVlrNXRGb2gxZ0tyZ1pTckdWRWJnZG52TWQ5dFUtZmZuNVhRZkdja0VqeUJrXzlJVS1wRzRON1QzNmozTUw4SmFEaVRYMHpjRVlCRGxuWEV6UlUwZ3BDdnp3UG5kQjFCcGdGNl9zRENaUDFOQVQ0MGdmZEFKc3VOaXRSb2l2T2tCbEhpYmVDbjY1MEI0WEZSYmdmaFJpTVRzVzF2WnM4OE5yLWh0dHc1SnJwMGdyQXo2T2owczFwa1BPUG5ZNGM3X3VXQ3dVaGFDVTF5b0lEYXQ2X2JRNUk4ZmJjOXFBQjUtYU03S3ktWlU5bkoyU09XS3ZvbHhiV2dwU2NpSFRUcjlCWFpROVlrQktGSGVvRGV4RDF6US1NQURtd2JnSC1lWmhTcXBXYVBNaXNBdUZ6VGU2bDNNdDduTklVSTVuUVJKSnkwTlM1WlBsWUxrX3hMdGZaNEdDWHJhZnRhaFhyRFpjNWFodDdKNURwQlV0VzBBaHl4TExvajdiU1RMNmhvelc0NnVRZEIyYkw0V2VsTjNBX0F2LXBtNmlJRVBndGhxbXo5cUlXdnBXTHNneEZ5SlZYV0Z3R1JCVUstaDM0Zmo1aHR0dW1FcUZZelNfNzBVeTljdWwxSy1qZkNXb1VTSDhFQl9nNXJMVk00Rks0QVpWNDRkN3FzSnk0VmZwUWk4WTJQaUJJVHVTc09UcUhRQkw3ampwVTNWak9NSVNRUi1XRFlzQWpORzJnYVpfVWtNVk9zaDhUQ1RHa2FYNXUyX1hXTzJLSDF4eXhESFJ2VWtsUy1sRWhOVHg1RzV5T3BUaVJnaWg2ajZ0dlVkbEdEM2VOYXBDLXpmUEVuRGhUdUplWFBqUE5PV1RZWXFEZkxtUXB1TEZfLXhXekZIMXQzamRHSFVpT2NocE5ab2VfaDZSRVFoTWx1dUx4cGJkLXhmRi1GTnQ4Z3FUeWwzMDhWaUY4aWR2SzlUWjR1ZHVOenQ3WTdtMTN5cklxRDRFVlV4bUlobFZCQzNCYWZqOW1GZ0NBckFSOU1oOG5GdTBFUGtUS1RoQ2pQbmF2Q0hJeWNJZ1JZaXhzSUdMcHRRZjEtM0w2cHpTenRQTU9sb2dYTmRKeDB4WHZuclVnRldDNUZIS3V1MFI5MlFtQ3FvTXA0bGJ0ZU50TURKbmQ3cDdMS1ZZUlNkODdDRUZBQmJIZXltamxFS1ZhdHBiMXQ1dWFIU3BxcG5tQlJWWlpCUklMa0xnRXAwVExBOHhzcEhnMWxvNjJ6UmRWdmRDYUkyMlJLWVNYcGR3bHNBdS10Mm43b3VqdzRMWmFEN0wzT0tLY254VjEtNVpULWtlb1NjOFhVMEpUbmhIaVdHYmJLbjEzME5fVkZMYUlSalhyQ2lremVXRlI1V2JFVDQ2cVZpcVI5b3FBb3lpekxXbXFoaGxORVFTZXNlcXdLUXA1NExjNTVRWnM3c3djYmstLTJWTHZZOE5WVmxCaFFKS1lVUHJVeWI0dE0ydzdqa3R1WUhHMGFPN0VMSlRnMTZoU3Bua3hZS0g0cERsUW5vQ2phTXMyTXgwYjNoQnNSOGh2QXN0UXRsZEtma1NOVEw0RmVFODB4eEdtckJrS2s5OEY0SHRteHFQemJxbnBPRlp5cWo0Z3BhZkpHd1N0TVFpa1ZLb0RHR1NFc1M1QTBJZDdBdEdGZGdGWjh6OFYySTZxOFVtckN3SzF4Z1dXSkRkTlNpVFlwT2pHdURNRksxUUtMVU1PM3luWDZDSldBOEthaG9JZjdSNVNXQmxtOV9VSUNPeHhJOGlNTmtDMWdiTXpSbDdfWU9ZV0c2d2d5YlVyN3hoeE1NUF9Sd2l0NEZyd0hPXzlYM0NEUTZacUpTVmd3dFZmaHBpeWlZSlJiWFEtNE9DSGZNRmJQalpYNWhURUZoTmp4VTNWMEVCWG5IbmxfRFNuLUd6bXZOcHNTZFJvMHZUVGRPb1RyTUVHcE5jc0s4SGwxaVpuMlJVLUFCV3lBVG5FRXg0bC1pZEVtZV9rVDE0T29CTTV2eTh6Sm9IVHNHcmpHeFktWGtJa0hudEpIWFJGVklWMEJ4ekVaaHhDd3c5MmNMTDRicEJZM0JSejlaVi10NnZKcmhBVG1BQ3lYY28wQ3ktb1d5czFhTW9jS2I0MWJvLWJpSlRFanRRdFhYaW9jRDJuZjlzdzR3NDhGd2FQZVppNTYxQmtYdDB0MEZfbVdZaWx3YmUyRDRaS0RfaHNCeTBsVFUzaDREUUNtOVdxUDdEbkRyaHBKbm1OMTNWZEZWUVZMV1BoOV9aQTdiNEthZ1I0SzdVS3FHUFI0X2ZOUFE3NUo3QW9WZlZKY2RMZElIUU5ocEJJNG9Ba0pVU0RSdTZmUXVMbFJJaERFM2N6MVV5X0xYZlQzT3lUY2NkcFdheVVDdXNqeUZ0M3JkcGFrNlQwV2t4dFNNcHdMQ29GWGNfcnp4QlVYTDhiRDR2ZG9sTng4Um5YcWVIS2RvYTVPR3pYSDNGTWwtQy1EYk5ISTlUaUt5b21rVnUzQm9wbVVBenpzcFRwUzF4RmhwVjEwVmVwem9xZUpjUzhhTUI2LWNyY1lEQm5KMmxpSkxyY2hCT1hsZ3ZLalBKZGc4WjRpVjBjZDQ5ZDN4YTd2WGVIT1Via3AzS3lheWtWUUxhSDA5ZGxrOVZuMlFweFhiaGRJb1RQWlZiSnJCWW4ydnNLRXloU1o3VnJKYmhwZ2cifX19.rzRJtm9JwwdtV_pyYoLNMFh-LeT826WsdO_OSU3s5Hhqu9iZQ_q5g7d74vPNB62EtcAV1CrcpUYorEeJnYyatGz_rcqTHwybNysflBJCBlVK0xBhrdC8LhLwLhhFLrIDit1VP-kZbF2PQXi4pVwRQNRVdVDoSx2FDf6EVlKc6TzpyRJhkrXrxtThAmi4kv8_-58V5L2BFTqrwGzyaaZaXU_vWqHyQzM_1p0Nzw0KrKHIZQsvjQ_md-_TEgK6e0_cUg7h43AOygbek3GfMn9X3gzVA4WVuWa3BcUtlAGZreBDLCwqmaGwWNeiE--P2bHJN-L5Gwg5SFYpIw0VN0nEKXvGuQQH6NPZYQwcDLaclkJNw3C2BtS1FE3XJfrQFMg8Q_XDqfB7VvKib2AYK8_5Ss5Iz81WlpSwvRyVBdTe6F0zf1pJTfnmzGfKHACKyL4Y09t16EmBrek2Zbc6_y-EP4QD3CJV-5GtDpVn7o6t14YEffSZL-dQ3gixShl91wIf4WSnytCiuZm-dqQD2eVkOP613m18UKQ4a36euW_I3lPm_72y5LqUg5Zcx10DvnsFBcBIhuOGZOKUvfFkINwMUEfNQzYME_okAfBtB1NMy3u8z--H9-a36Kgq7zt0Cy4JD-S2E0YyNTMx_BgnsuyLbklKVzRMfXHhy68Y10gRHPAfUPkxIAdaIjF3olgQrQH16tgg-6morpe-g0iEtug4XXFZjwljIiT86UJiF2haJnA4ORb16VOzlOUXEV3g7ZXsNRFm61F0HDsn34Ii3n-guRJBEgprqp91R7XS8i_qOXfAJ6_0ycijSOEBl7WK8uLhfPQY698UtJhvpLtmtzP8oLxpR0tfeV0i7T-VQOA-d1g-De6XF0p53e2DHdEWDZvy6uqaARC52VR-uNsVljeVeuI6SX3LIUQ6U4wYUTy2pBjL4N0MyhrrYG9PA3lihC9yKZyUrRO_AhsMs6bLgmDgUaCI718y70GyoWIGk6TviCGUImCsLBT4FncJpwHHJCAr92J5-nIjEWJLk_UW2PcZOtQCFvTFnXbtab1eZLAAxYHDHtVNix1HOLS6QzzUPolYpntE2y4LTHyMicUjMQOApBkmlfgld4QaZPlqpB76TQPQTQswE5Lzc1KM6h5R_hlINhChWilGd995xf9KYvPMofKT3yuSBU8kZLBNBOXW_T2WWPrOjEL4rGZbZw68sG0YEvN3AoISvGMeTyO0uoBI9Ptvo1EDWz8TJ1wTzRUFUqaKTvAFLphIVuLxJFW8FW4QejLE63DEqJEm8kaZBT2Lp6i0PdITvDG13hEAzfvchhLHq1NsSXc8CgP8KeBDeaTLCOHs1UfHIcFsGabTMkMKpooW7_2hjzqamMhT4RSDjswoaY6DGEZfJS7StAnQA0GOcM0vONMg3nJDqL_PPtDDhccYiDVoxPeEloonb-jnFsSarokclQPbs6HifZP6fsfH9UXOxKz9BUlzSBl6eDb8b5B3x6jFe2sFCWCuZ5a-DFbxVpy-i3jeua4rznyi91hWDGgaquV5zXOzxpF3ZaszqRqmBmkpRhoRCLRF4MAFIl5YMNhgJdfbouwhnW7FDICJC3miJXCQ2lebXvhGZMkWR2JYWXE9-j3EKv-6vJO4XbxFsfuVruHoA4vC_XRaSeQClnHZBgWxvVeVwLRYfXjB1OeRrhb4xaNN_6MDLJvHlnfrgbfaJAAH8VhKIPo5w4EVc_UkRZ5WUDzrEzngU3HnPLQKsSRvYPVSYPvxdSvYUPAHpx3BK57S_AcGIjc7S0ILNUEbJXi49XVTMb411iEDk7_lQ2J-A1XdUofeT13yAVjXbY9vGTh-yh3VY-FYJyHn39ckm10kIlNpQYLC1xrTJZtOLys8bOW7tJkQmMT1uXJofi0vc0CrNsUOV_RPQfn892DK0l4riaVYZrE8cAl8Ac8ThtKev3cVHwNA_C_Sxol612ZPw1GrNbCRriRG2ZNob0C10L8qce8g6Yi4dKm8E2__iR1JqnJ6wsdS3u2QbevjxvPsYsxNv77GmyXsbL9M15jqCXDJlYYwuFXnhtvfAeMDjoK7vCJna4OxMX9rL5AwmKH6-z-s0tKImzhZFrjkWskIzABmXbY2RztStW_t9E8lgV4qSlaOO0X9rtyx9ExJqHUYcM9Db-_7Z9vl7LCn3TkplgP_hIc6aX5LrGbrD3ek-yPPbjAq42xDCYbKK1jaJLeW9Udbt2cMDTBPkUzT7jlMo8EMjKFCiQp5ynjp-m0ZZkmpUpHOoy2OY48xMlordk_BY6HuUzECzoLKiYjDqwui2Re8Ab0PwJegM2myMUV3CmAIxdo1kb8aYKo6L4scIA6y75GEwxtBWjTA3LkYB0l5Ab-uNDi4Xkg5p9U6QN5Kq9_hCb3hxMRYiltm1wfb5SjfT6ZA_nLsGF2N05C-YOfqmppHaBDWLxiXIjCbC9GADedC-TH9Q9sQwWQ8x6wcQWENOkLtT6Cdade9dA7P1rI32CzOpMvMADHm83DgM1SliT4ZoVNO2R2xYHunoRrRcfvqjZKO4khv3bfZzR4YIAEYdWdPV2cn3Gszkqz8bUA8CvQwawwibXmBFvcbkZ-2ylFAd_ZpW8NRgroxnkMLRT5h9KYw0RirTF7eypOLNheyD6Julb9lo8u2cQ2PcaUeqFcXsas7tjU-c3yuDgcVuo3JHXzyXcHef0zMi_vA4nZDbfLWg9oqSnivRuJ4sSVIlcb6S_ZEjVH_DaGdINHom2DtjkEpC2_GvnFK09bpNQfGfWz9Wggv8VGuiEJy3bxQH0jNpR9A1FpkWKoXJbKHP9LEIM5gogA138Y6u9dQ2tg8CyXmOjYEu58tTxIcDucTtPLAGbMEjegtyLuxAoCg3vz-HIyJvBhuL3HaDkxJmafvyZz3Ahv3JlzrMJel8TrzofxUWgs4IjXmoETSbN2Y8YhFmNuClXMDre0FZ4pcB7JW4ys2cWtsIIwcyroG_xd5XOGG_VLDG1R4YCFsZbxgjs82olNEI-qGA9n_00LVch8pXTqPHP8Pw6nNiBgek8qjDEd9ON7S3q7DkYqHjOSbPsFLJWz_Vejuf9GPNZQCqHYUafZSPc1krtETreauN4OAyCUJ-LW2WVsbqK4_D_1CL--atJhxqQQrK48jl-RPPTC_0bPM0ph3KEZ1bWW3dh9xRx763TVw4It-oYrF9WU8BSn43HDtcSGtE8QLHaFoXxLIfbf3RC7V-dfTFr14InB31rCc2ybmZPR-TgEcC3mNajmJVIS51geUNuBRuw-dLtQSAcFzqrcu6J7BjSRF0viSG13-6ObAMM5ugFGukGje-pQgMv5mHK1Z0p1RKl7GD6gjGXTvZl4fGpjAqJuzfr8kOQi1nv01Hv84NnmpR4D6EpO6PGk28jnRF908xwxJa7FzA-_6CyrqYKuGX2e4uF0RHFdlHYgGUVfZThh5kTBwlF6uors9jlmuiH6gaoJUhcHuQHoFMf1ZeWc-ZZO3HczJb2N44gWhMWxo38SjSjBf9LoaDeOp7mvKW9huj6YHaNLiz5rwXdTTwqswqdU_9qBq4zZGJAjmW0S_g4pLPLQdhrpbp8YFBEOh1OeizyHLwgWoQEvf8ZFWeBT_brmvat6pRbZ1ZTuYiL9fWJhwTOY3T55RE7JEBBdtOf8wHzUHaNyI-BZPVbBRu5BPGeErpINkcHopWGfmUMHdyDO9u5risNdGiqxl0IjrKYghMKDIa-gW1mQtFCQWGLA992pkIapZ3Squp6K9lH2Hoyy1ODiJ-t-gFCA44QfkXgWQyIRv2BZap-0BlR0TcGM9W8z8giO725Pj8fmmPnX0rKP1KIdi_UYFH0UwG5XKDugePTtOxE6RxpLL2oTkxrNZP7FsCStMu03jmt9c8LQm2mAb5Bu0NAV-mvJAa26uGNrpVs-aieO7Eq-YtqXnBa5PLuvUaR4dNQ-wnmpkAmtqbt4ALEaut7A5Kb-soZEOOx0i5suMEHJVH1rcYTHtSp7awNsUbu8az1-ZV4qMSx87QHy7sHCeZHNtgPT4Ar6AbMwzFaKUkrLVL4JsE0ulFY61mED2MhrmxD5AgyXOUp7hQUI7olhhFCeth3eleOeo8C5zEqVTaJ5k7dTiv4Zuq6y_68wgIbF8vgobfFK18iqXC3UMh3P3FbA1y2WivO4GUj4KfhDWWlPkoJ5Zo5wN9L-_OMRAUVZbOGwSXRFMW7ONlyPFPBJJj69oeiRF1xpUPqkjNqH0Q81NInHishyIYy95h2LIVg_VxHWJq0ttE4e_UY3aDPGRec90Fg0ue9YF9-LrRCPsKBCVEFIjO4NIh07nFigU-cE0hMTnAwgdJVJ55Pb92-hizjdpgMXyLDZ4ut7zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA0PERYc~WyJFRUFTNGFoVXhYRmxkX1JraWttQzB3IiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJrYitqd3QifQ.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IkIxYnh1LW5uNXRia0FuV2U0cF8zYkNEWEF1VGpsZDBXVldaQWZ2NWhlLUkifQ.A1HrZsE1X-F7fTZGauV-cVRjQt2fMo2CUKV2Iv95uwYP8SEp2dLsiiO0BItZaT0Fkan-J9O6K5JmXbHJlCr3rX-1Hhh4HyMCl_aKDGpgQGLqkI1BitaIxJ0NaM6OQtzBMLRiN-2Rb7M0wVLKazVGIeLxUvEsBCyAh_biD_NXvj6SJ8ka5Q3Kx2op_5jTlrVPUBgKPN0kBYSQuRbVwQsMvnHysocxYipzjNP7RKFgHnTqnn8MdoUC1Uy6eahfOJGq2f_68LhKTR0YNQT7ege7XJnQusZ20ad9X6WKKYVo2eIDm9BJGmn9dT62z4m10hZCm-oobtSO3ZGyl_n-eIw1NFYVTGjG-aXJVzDA51dU24yLkYY4E3XZ--Ha5sBkCNw4adc4nay-4SqeTYbLcUR2uCja5e8ZWV17Z2muZkaiH4scWPPrn8ZC0Qgx4hNPpmTxrnuYrgW7l4JqQGZas70lFS5ytrqTemSq8oh8vEtCa1GYIKETM-e2ioRe6SbySB2uokesThIhrRMz1IEqhHu02gl8SQEDh9KFazpVSLFzT80eZ06OD9DuL5gcwk-6ATLfDMT4LfRgRAx9gQbKxosJM7-kQh_rZQ8ooIQXX9jioQdl4vuaA_sRq-W_wFSlwfWVD9YGaFmvxLqpfbVdZiZo9A_2ENpy0DNAf6uqInJc5eX3vPwvl46AxVNK7t56mrn-MyQz0nQt4d4Ut9y1lJt80BsOLPcQBsZf9wvlXcZ4E0--Ry4f2sm6p5xHXOVvIeDGOvkYXzx3QfPWlHNo5RuXkeUwO8OzUaGBLTOzY1aUAU4PYyiZwkHlh2T_gVdhh5i1egmlSYL7rimmI_gFXLadYxY1KclKY9l2IKEhfFLOlfPcRSkOQmcYU2tocQuKG9nU1lZBOfPP4shc5kMb8B173SprmWbmNXrmZdWZZwp176TX-DZj60XJjIpzHQS6Cey49UyKifWlBV7g7G19KnGihZnud_bxMKKnfb0mhfqZZJ3UJWzDeCOcBXNhftQ1AUf1DKNBE5MxYl_3z4f7LEQTUlWNK-nSxOfgpmwZpFDv8pWQYBBRwmXVb6IlM23g-kQnd5vZohn2W9RYCl8m5cHNLC8RFClrZbBYvb24oICOOLYBtdCo-3QPpZypG6hZroDjrztd5pVMzf8Xu8ANx64U9_LpY4M6SC59pVO_keSk7ZnAjnbGvXYFsp-9IrfLWi-VL7S_WIgnr-Em3nI1u_iPpksRtY_-AsDNBVis2U6D7Skju0Cf3wPN-625PGNKAVeZXjqByRljuMRv3tUmfxNSX2AkBTf9Ua4jYNWUst-KLnJdR2MTpqsbVivscgHAYXE3jCcTVco67G3qrNW8VrvDdYXVK-6Mq_LAnls8beXbsCg1hh8jqHunjp1k9FQd2h7tQoj0Ai-FhN_vtOJaeQAnUgEN9VXsiOQWsKaeH5f3IV4SmAXbhIQYimMQSHH8hOTNsUJYkorJ9XYoEl7VPqwpyp7MElAyIbQKePAYzanpAEErKfHr1ADXtx3iuVuowg9dPSXXyZj4_Pe0Em0fLKvv8rDTYE8mRCHBfwbuQSA8DVjJSlH5PubIV5r9SK7HVJ_APnHAtRs6FsZgvyL-SagP_SYrZwtNgiXTpFTYtdmy1M5G3Y1GEkk0ZaorTPBtpj5HFgPg-FkTeBYDlMnD5sqm3pns9N9q_22NGAPxt_cMhezny4eoNXPzokJy73Y03PWCtetcmkdDT-Zv06GcQwA4FlHtS3mkVBFueaeG_dBAYsZmfWslQmFyxHH3bN1TZOshNsurkXU05pgCDzpoCMZxfz8rkkjbCnljNO-iwOxHz2EBbjRWOjNPUp2WjRa03MMAN71AhlMso78kBPJzoxgPSMvAlq92njXoByD5ODhHd0W8TBS7LbEreBk1wfouA1OAfgFUY3AlSmgcQN_fYjju4cnq7gn1SLqFC2Shnf_zgBC0Bu55GPVk_lf5hilER2kpQjOvs3A6v-uXebKLkQJLLG_28a9CS6S3ra9i9DPr-f9b8iVTGrA4NmLLvfFySx4uGzXGmTQ_yritOx0yri6dJvAnqm0Xce50Zhx7cocJ2ij5sbSpo4YuoLZBQbFE1-ykbIUjK2CVkdkVTYC2cQR4I121XB02kt6z303erUc89eqIxb0ouQYvU_53XElm7X4Eo1UGgEfp1urLgWv_-3_qiUKzoGB4vN0xrnmlg6TK7hRWMecjWGz3b3Pn6KiSIawGeGNDd5RtkeFzkv9Td5svPaERZtGpskGc6RCeIBGz5GQBtSkWeJc1gkE9w5EyhlNCewDn3YyF3ZgYIvbfmX8sL6NiyDS0O-MmlSdMwuKvxrHchA0jYUimEvoWPDFFFFqDfswHODs9Ae06HRIH23su1dQuiD7kR0Yc-U4a-jUS6f4qIbDuMOMnrsZ6uWlr8u8IREMrVcu9qbmx4vdSB6DTgsAlCeV5alnc5WJZqP6Qy3e0wir7AMDcYrMp5AGyhTLdNIASQdUrkPrzpdmsTehd3JEl-VN94pFAWOKz0JhmNgbQhgD6nsFCbsxmb5S_Lik2meb9CgZwZlIt_r6WIzFEFaLlobUFKo3eh2kblhsxFZWyeUi6glWmhICNq_yJf4jgg9hzAFASPdSolc8F77VO2QzCqSSQOmkpf0w2NrwKVFeiKZf83tk4nQyYu1jj4IkNjgPbibd92wCjiFiu7_J5Igy7cOMDpjy0kjujc2jkCyMm_mGfDyjwfn4SbR5u8hS3rkSnR6nCAzh0j118lQ4hFEcwDH2MBfecLsUjEuYj_gh73t2GVK3PxSMdVRmSUy2dfd0Vbqb41xuIOqnr0k11dJP9qg812GaQzdWgAA_bxVRacJ0xO8OPvc2MoralPuw8fWXnH6J8mbXEqV-n5wfQCZz8EYrCZimtFbg29G2tmFfdJLsIYOvVMPlbWdzoRH1elqnH_OGJN07SMzBKWts3divUoxI65dUEy_gh4v9ZVBfiLreTNeYvVTn_yjACuXCkmWGG6mkf7AosBV4004c4e6Jwd9uAELLVzlILZ5ZOzECTjrOd1ZT11oUIW7vJYKuCgqegXDEpIB6abmyHbYsNE6rGU9ZEbixQ2d-x8V-_ac-MBGmn1I6zJcPXkCUZW9sdqlmdbad4AYuJ4f0ts0KFmwimpOgCeN2RP4aR6AMHmVXqlB-pP7-OF8_Wohe9F3WfLszYE3z5IW8tMqt-zCu17GoY3orqSJSXSytOa5fz-hCATslXiq7taFOPX4nR5iwFd6bKie-QZ24skWHJSjWH9P5uIK2fxaf43HZJMoMIvPSXnFHXBogtRNm3GMs4xQA2bOoDxQTHCE7TwAXbeUqS-KlhWtH8jwD_7ODQ3D8Mn3vNkdNDdCmoHxjFzdrK-lN67S__yvwYDi-LTM3K06LcApkHwPCJ52r51bnyQDgaUxzrsQTmI9l3Kky3TIXFu6gBAmFJ7fvc5D7s4-IXlY_kNi0tXFgI7B7dyG3eieEGmKBPvPuCu9q33bzM1EjWxeBViukXwjuiDEdSlGSN_vQaLD2MKbTyCD7GRbyQ0wITH_DqYpmkjcKp_UDT0BUgvvUGZunwg7zeTEDh6gzVWKj56JViUwdQM-KR99EtaIPJ2NFKqqyyxfVuWg6efxLzphSONvwE-bpVOVw1BNYgPFuejvSRtl3QmkwIZRsGP8Fvn1JCsvdbjqvG9kVJK4sAOTrDDII8zFq7aXDcpwEm54fQp1tlsP96G_xNqCjnCFfDz-ln-6ET7BfQFaBmcI06OkUxFWfC2KVLxhzN3n926oMDhdUhXxYTc-LZg8ZvBo3Hbuz2PE_7h2Pa4BjX3CeTSINStbFRrwY_wFDy3TYouROYDUbYToB1pSQipPRmirIunlaah6cqNOVBT7Ga9weG2XeakoAF3R8xEGwCToVZaRPXaYq172q6NAhrqAic461aJxlZMJZwf15LNr3NilCQ2lGfLpswyw1vp9WwxyidoQRrK9ZeMH7PGLBVOxAj_5KAN1xqqYp1Xofj8dCfjFjbifYi28w-VAQ9ylIljiwpCnpWRBQWMgMUmL3f6cAOQkZCKlO7g9FkDBchf_a9wsPa4CwTlwD9suLwQrxoBEBB4S_4gDU7cZbi8vIjiBpHDXpmlDEniVrKgcYKqpU74VfgGm7J2hVAoRHydjzlFhTkYkjJ9NKtLdQkU0XZmj_l1yI4WdlO92akBWQKaGKa4W5CS2XwIO4tFxYL7nkIeXQt9_F7yRgLsWN_vW2wuI2DVN6VkrbU2d8XPJ9bfcIOd50mUS0O1S9ftP_q_kbJJq1CtUFDXx2i2R8k9DpbL71f01vPzac8SFVXcSYvSJaio8zi9v4CJCpYWYet-wMHNTpLpbq-BkBrvtBrcH6YAAAAAAAAAAAAAAAAAAAABQ8XHyQo", + "forged": { + "kbStranger": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6Im4tdnRaMy02UkRVeVNmQWEwWFM5Zjd6S1hEdi1NblhmRWhaSXhNSzJmV1UifQ.bDoA14XQGrt_QnBJqIw8SqdhPszP8Mn-nbhVKmifXg-ZNDey7x_NFjVRP7G8or95EZ1k3M3tbtnFM6bysU98AA", + "kbNoNonce": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsInNkX2hhc2giOiJQVmNXc1Q2dUlRYVBwUVFDNUFEMlM0N0N2eUJZaUUwcUNUVWVLaXdGX0ZVIn0.2Xg-c7x8cfyFRyP5Bz4Or74pjvWqUgJgdkF_JlnjRrUfd5-YqrBxcs2GTHQAOOCy55_CBmGdSJf-N-aUxVFSAA", + "kbTypJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IlBWY1dzVDZ1SVFhUHBRUUM1QUQyUzQ3Q3Z5QllpRTBxQ1RVZUtpd0ZfRlUifQ.M9nBOLw7TTvwyvSIN4MSiq_kXalf7oEVM9VjNC7ijyzRAQeLSj8PYCb6MQul6OzAL5WD6lHVbI9HemGpDnpODA", + "kbExpired": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IlBWY1dzVDZ1SVFhUHBRUUM1QUQyUzQ3Q3Z5QllpRTBxQ1RVZUtpd0ZfRlUiLCJleHAiOjE3OTIzMDI0NTJ9.rWeWitBK6pQtGKD6koJkM4TMssJgPMSUa07QfCMnpNuWlj9X8UKV7T_FrtP5xbTcl7BwkcMmbrSxtEvUo8EoCg", + "kbNoCnf": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE3OTIzMDM1NTIsIl9zZF9hbGciOiJzaGEtMjU2In0.siec0A-CE4I3kL_tWgRWscIb-i-cSNws7MUJgo8it7rgdoI4_wj2hacfV8Pl3GGUL8vft-cUTJp7_-E3QX4HBg~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6InpSakFUMXdud3E2dWxXMnp4UWNGZkp2SzRPUlladW12VGZfMFBQSEVHNm8ifQ.6BcEj9ctCnkuNJjhs7HqjtwFgRKOXjQRsRbqqzN-IMdI63Nz6C6NO0c__y4EeRp7f4IoNvbqvFL9ImfbxHlKAw", + "expired": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiI3WnV4b0RhUEJDNnpRLUFoaUFqNEZxdl9MVFpFYVJhblVoVHFXZ2RWZ3FjIn0seyIuLi4iOiItakxQckhtUHkxc1FyRkJ1RHJabzhsYzVjRTdWNjJHQmpKbnFreVJiVEpRIn1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiVng5Qk9ha0FGdy1HNXpRaTdQWFpPUEg0UU5sSjBUdzhyY01JRWRydUhNVSIsImFpT1EyMVNSWHJKaTJNbHBZdGZLY2J1Umxjd2ZJVWEyMTlaem9BWUFmNVEiLCJtZEZROTJ2bUF4LXcxUUNpUkxUc01zUmY3ZTY3VUhNZ1R2NXdFMWNnNkpzIiwib1RaQWo0QlBXU0ZQbUtSRzVmaGNrMGNod0d4Sy15eGxWRFhIN1UySkRzTSIsIndrbjI3Q0NFTVhPSVlDZkxNZUEwSXVsYTdlUlRRMXdGUlg0SmZsRy1QcmciXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE3OTIzMDI1NTEsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.SIhp6eXkMpF9dA3qjGuCWs2VMZWDeiZ0NUcGMUEX85bCqPvtqneJYLSqJWJ5Q58BqQVR0mLM7aYqsL7lD_yRBQ~WyJJYWlXZGtiUU14Q3BHYWRyUHZDcEpnIiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6InhNdHNFdUxaWTRtY1RpMFpZaElUcnotd0VUV25DZ2t6N3p1ckVIUjgtcmcifQ.uV8nuxzewFxbS5zCIw9eqz_bi3qu-0t4ZAQU90shvQkiDE53LlglTR8zkaHHp--QoqcjlmlZmYwhvjyaIOciAQ", + "notYet": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJnREJuVktpRVp2X2wwTWdPUFhveU5XcGxyM0tPSlgwLVQ4S2ZmMDhMMlowIn0seyIuLi4iOiJVOUFxdVNWeE1mTjJpZUtLTnhxNkNDcXVwaEg3M0FMQ3pEMnY3V1F0QjdRIn1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMjlXbEZHeWFEWWJXVzNrZWlMaGYwTFlaQmQ2VGRXY25lWFhkRjk2RkdZOCIsIjYtOThWZy13N2N3aG5kX0lwa3A0YWNxZE5VazF0U3UtbGNrTTlEMVlteTQiLCJGckVnTllsYlc0S25FSzFmdzFhSmJNekJwZmZjTjVCbmlMTUl3SnB5Nlc0IiwiSlZmQVJLdGc5dnZmSGVzVEpDSXJXRW1MMkN4Vkg4QS1HbGJoZnU2aENHRSIsImU1ZE13bkdobnQwTmVFcWw0QlBCTXVCU09qLVl5SFdiSlc2TDhvdVF1VXMiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIm5iZiI6MTc5MjMwNjE1MiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX19.sy5GRqEhkvQAdNM_C9IMKBpsSF1Nbna1Pq6bR7gxmsBYkwR9_5VWgBW17OwKkhTKxGiS25nGMAIPXmyyqJ9qCQ~WyJiZ21OM0N5Rm1jclF6MzNMcjFBWU53IiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6Im9KSDdQeVhnTzJFNVdQMmRGMy13SkNaVXY3UTVpVm9FUFY5MExqeF9fNncifQ.3Q1m2Pjpv2H5mES1aEZRu-Ckh_nrPwP2Bu6U6CVgFL5lMTDDbRoxN18nFcMf0bjAMBODvOAMlnfaXf9rsgMpAA", + "digestTwice": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyJlcTZoZjhaRmpnY1RxdGc3ME9keG5zUElKUkNWZ3ZHLW94Q29CWDBlQXJzIiwiZXE2aGY4WkZqZ2NUcXRnNzBPZHhuc1BJSlJDVmd2Ry1veENvQlgwZUFycyJdfQ.o118pMTuhwUnzcymlJbPobFjK31qoJBWfZ0qkiPdV-WZqpIlrF5eVEVhQy1FYuP1iT8-tpY4LGLP_GvHI4p8Bg~WyJzYWx0LTEiLCJhIiwxXQ~", + "nestedSdAlg": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIm1ldGEiOnsiX3NkX2FsZyI6InNoYS0yNTYiLCJub3RlIjoxfX0.miCZJvF0MrS1F2eldNJRUJfxOD03J4J4whnxNnEavTOTl5DXK1pF85U5_tmprPskVCCVlHSZgYoTiu1P7nohAw~", + "sdAlg384": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMzg0IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX19.Hu8fus-Adj5-Ri-PhCwX248ABzbWhrVZOZTBj4uU-mZLaOPFWUAV5f6l_oqHtP-g5mZ628xHXi-lMPRLGMTWAg~", + "disclosureNamedSd": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyJFQmdlQmw5UjJOakQzMEJVaTFHM29jeUdIUERCaUpNd2VHdUtLc3diTWF3Il19.i-lUl2Fl1-I8l4-uwcdcqZom-uuYGZkL7-ZHXDh--z2cIF4vrUpp6Qn2y74bl3jBmxApP20YIm49TqK4_TqkAQ~WyJzYWx0LTIiLCJfc2QiLFsieCJdXQ~", + "claimConflict": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sInJvbGUiOiJ1c2VyIiwiX3NkIjpbImp0U2FaZ256d1paOFJNSjhUNzlCMkNIS0xPV0t2MnVWWWJYSkk1YnVodTQiXX0.VFazRIXy0qzMn9g3b_hLb5q7hq6M5EAcjvs9mETMQ6fT3y36ZLVo9fOq7tOPq32ubVT75Q8GMJEDMhVTkl-dAA~WyJzYWx0LTMiLCJyb2xlIiwiYWRtaW4iXQ~", + "protoClaim": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE3OTIzMDM1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiX19wcm90b19fIjp7ImFkbWluIjp0cnVlfX0.Pzf8iZOKj7lR6Zdoyp4kZrd9EKCEc0TaSoBiw8ZoMvpovMuWZEfE6KBbpgbdg17mFq_2Z4FNzVLLn87ZQYfPAg~", + "crit": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0IiwiY3JpdCI6WyJiNjQiXSwiYjY0IjpmYWxzZX0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.81pRXwso1YgaPhC0wcUUxVr-ZVv4R3CK08-A9QzzQ83gN9ahrGFtn5OdXjUhpk5oXuJyQVTGSJEcMr7bO6iWBg~", + "typJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.H_Y6xkCmnk9mMnwgyEz06o6bn7fzLPgltQ8rLvkF70EpIdi8SzqeWldP5FLxdrY2C0kjaYSOFEYgM958K--GDA~", + "algConfusion": "eyJhbGciOiJFUzI1NiIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.znkWKtPFFufaaSFVBWKp561hnJj5tXmCxKFg4TMWjemaG8VLJkN22X6GiAqQ7y1urPxuTYgvBH3oOVPNmuV8Ag~", + "algNone": "eyJhbGciOiJub25lIiwidHlwIjoiYWVyZStzZC1qd3QifQ.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.~", + "noExp": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJfc2RfYWxnIjoic2hhLTI1NiIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.8NI7L4kZ-4Xkihp0rv2xflQEz4nBahV96wuv1M7t7bCpTX5Oe9-JGaNsHkPUhAv7VjB1qx8oQCrFdgBQZarXBA~", + "disclosureOneElement": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyI5SWI0RGhwZVNxbkY5YmEyaXZOeGtQbHNTUzAwYWVxakd4YVFYZ1NPUUpBIl19.c7TNsY2EDEHxk7BF_dlgJ8vxc6p61EXzOvVRtSw-bzlI07lZCiSIS1uTG8sXp7XPGbpTUvVfJRg3qquaKEKiAw~WyJvbmx5LWEtc2FsdCJd~", + "disclosureNotJson": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyI0Wi01OGlEZ1FqQUkwU1dOM0FWYVB2TmhOUEMzLVQ4dDFXQl9fNzEybWlVIl19.ft6nZuVHPQBXFRUi5AI1nopFtRfhB21AjgfDbnsPmqviRXWoC0-a3QoMcONIPdST4MO2Gj652hTQapSvWnTXAQ~bm90LWpzb24~", + "sdNotList": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6IngifQ.JX0bQiY0zje3v_bhU-hqpFB6RPAFLrNS1vYXXKGLp3e6MA8TupBjYutIkOeCg0ZoRUswexj4xCcEbSQllwFyBA~" + } + }, + "sdjwtvc": { + "now": "2026-10-18T05:50:12.000Z", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "issuer": "https://issuer.example", + "vct": "urn:eudi:pid:1", + "uri": "https://issuer.example/status/pid/1", + "idx": 5, + "issuerJwk": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerJwkMlDsa": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "wIZ6ICLeUmiM3Y42iOtALwJ9imQQ7HanvDoYATMUyamkdh5_JFwzUidqTwShiHwx7nNBeXn72UyMw-lP0el9H0KgNHyyggkRjbBVqLUkBY7vFFdGTsZBD3FMm2EuuYmRKGhbtRZTGUgFBmPZpPcsUDFCPp7p-CGfH8v8G0EoebBCTMXbP0GqNVG7COiWqhUQQC4p5O5r8WUIHnF29OjYOaDQl-UM33V-R_XY2NSUpF6WK5dPYaquv430z5aKnB6KCoPcvXRq-9MkjPYO7VbEaUkbYlDQjFDXhDKOJwzeOYVy1S42jWrR4YNrbL-Qx3MPy3rLBOrJFu_ue2cPYU_7-1nT0c1kf27oD5oUzFbSBwdpZzTxF2I5VeU4Ev5XyY9HMqWtc3ZBmFEsnCpgRg-wtIcuDfjyPwDtH30yI_Ih3zQozfDe8cgutfKnovGTKv1Lc8m9qistCTXeTnoNm_P1xNVNaJG7dOqtFq83r0oaq6bkZG9jbHqpyYOsaGFyKc_ihi544NH8V8cE7ba0IRwlVezUpkhX_lOKulmLC5GXBSpJgSms5fnlIGwnmjAd2dIRAtuNcyakeDzntyjlV5uQcZ42aG03M482XY5cfv68QzDA3GuamyZQOFJg95VBAq9vpIjm9DhrxWHLrxEgl1cgJVrgRe56SeStJiRiDrSaU-0k87T2nDfkPJx3accrXrlaRGAAHOsTCgwma0vbj-7X6Fk-KRum4R0e0NXjxuZBiE4eEtwKaiagcenDQXpJFEzxbg31uLuaHnPcyDIUE5ZJnx7HsI4vKySHJmr2cXRk_be6vVCFEDdZ97l6ailRdsjowfWKm6SjrzGy9GKJ_uFSw5B4W1oeFZKXDhHJXT-B1KoDC2w16peekpJSP3qjqz-ah2wsfWLpjHqr8OjeBL8vOXQlHyiHPXR1iwJAWU2KkdtWYcUONzwiJlV6juncHlJbdQlI8VEeJVB3sNV1bZ4xApt1yHrrSGUN4nHUOIZKM4-W-wJ-lm2i2fZ7PUtlxfiRsml27Z4y3vs-OLaBIHHhSVAAkM95c4GF7yC5ryP1UAb2tIbnRBmX3K24KgDE6ZlPGKHIQd0q2wi5rEZlbVUPcjEA9kPwlfoDefDYohFF1DwlsxnLCvFslfd2ibMiFlHE7k2QqZcVb9guWOd5MXhSgYDmBoTFmEHoPZBKGP0Nr9-F_UuR5Myvf0z7nmKJpEz3JARyOSvgpVLBKr9-cgA514TjW_VCi8OysyLj8K3LZV42Cvw3dxt4pWNGDaOXxqT4p1lj8W7W6mzyovOQB5dTTcy8WMRBcgUpgRBqdtQsmTJfEg_VQC15ZihUbPdtq9uDbuq8H-Q83oNFIlgXNqAO_-ijlRonIXiY21UpqypyE8ATATT9jO3YpL8hJT4wWdp7HaSIf_6fBF1q7tLdJTwLDlhFApR9aYRjDHHBFYq3tPNGAYNaYsWkX_pgFxMk0ppLnn-WNW4ysTomK1j9LVbLSXiezvlSmh6yP3mTc83808I8Y-dLf1WEhNztKnAXzLIhxWqLqWl3Ligq82STGspp3nSaMT52sALaZ0T0IRSJY2VMFM4AQ-OOSnDDf9c5z4walt-UZznlmsQ7hVLehPL-lUfrAEUkvUqWAZm011Savv4qUg9VsCb_swKKi2MOjfyXI2rFp9E42uEVQYztnf6wpvpFOFHWaO5jIiafxuQiPrfJ4X234Btt7zMb1b-dpXZV9AOFOp2GqCJDxs2HWs4G0pNLfYhH01PwDdfjGYceOWT5VGCAbWuDdGO9r41tijrgWWvwZepOXFrEvmcTsVwTjxLkgL9kto0dIdrJtLFkWNGgtDZ-i0b95Y7eg17dIzeLYHGdA6rCJ3dEMzNd5aG2FFt9SkqUxVWuBP1Xvr4bYvhbsdPrNkW-IDV6WAJQkpxjXsDwm9736ChHuA3IgCHdxYDCgT8R3D81jaZ92aFIBWeVZ5q503qNLdErL4daezU4GIANmJqf16e2BA6hM0ybF9s8-iJNWfWloFt913iIgXRiqzwGxD8IU_syahOMSppzS5DF1vh4LjARGpotUx_yd399TjHVd-Nk74F1tIENykAhqPda8bPtuSi3y4S3gbXHW7n2IahH2Q_tYzYVboTvuukDOP8L-pHdR5x1lvGebpV17ogazcP-yzUB-MbcBJW_q7BAxp-bVUfKIMEi63KOnSqHityCb_KcgsAx8PJXmU8wIaUN5MqDYbm7Kms_DchUcXaZE2KsPer_CW4-72VZjhNuN4LVxsDBBHeqgx2YFLR7bSZw4qC6bNtnrmmv-jpWZlmUs3FfIKObKsFlCZZy0MJyVM0-p4L7u4y84zXVDqRf5AXZTKTdjZxMXGUdbFbYtDGDjhmknZAavecyh4LwJtJT34LpBEHP6B0Tk3FBU4r23j1e_quuMGYikcWVd8OAwZ4RP3qa21xNMqCFD9lC3pOdmnJ2uovrtBVilugxrIwMwD8I1K8gQY6vvvBTP3fgud19CWn4soXq8Y9z64oCzRorigim1x2j7EwY8G85pAnGL6HPFdCKaG2T2sFvXRvu8NQgjgbRsF5TRBfcz3QtW6wFNaDyjpO3mWbmsBQPbAQ" + }, + "direct": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "directMlDsa": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJkYytzZC1qd3QifQ.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiI1UF9SblY4UGJhNjhmUGxPanQxTnBpdlRCTUhmaE9kWWVBaHA2dElXLTcwIn0seyIuLi4iOiJQNVBSRFJLY1JLV0t1ZUFUTFdUTThmNWd0eVhOMnRBOHZtd05PTC1XT1JRIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiRC1zSFloYXBXeGtxOEZWOXdsUk5RNkgxbjRGSnJsZlFBTXlwTjJkUThfdyIsIkpmV1dka3BZYUE4WmdxcGRGOG5kckFEdW5xb09OYkNMXy1WNEV1eDU3SjgiLCJNa3EtZUFRbnQ0dXNpXzNIdlZzV0tnRVg3d2hmM0lQRHF1UFJpRzctT3ZVIiwiWUdxeGNZZi1sdXJEU1NvSVprRXRhZE9LSUQ4SDA5MjBFLWdBVDZzMjVjRSIsImRETDdaeUdYX0FvY2JjdHNzeTZqUi1LRnp4RldQemhscXgyZ1RDU3pxbjAiLCJrQ0JrR09mdTVpQlA0X2NZNml4RGstSWxIcGp5NWxicG9yZmFYdFRpN3NFIiwia19aYUtxYzE5aXNZb0RXNnRQbS1HZXRwT3pzY0tIQ1BOMHhjam9HMW9GQSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7Imt0eSI6IkFLUCIsImFsZyI6Ik1MLURTQS02NSIsInB1YiI6IlFRSFdRbExZMTRJay1tMC1VNzVSa1p3cVVHai14YWl5T0xpd1BpRkgxcXRXOXN4UDMyUndsM0dWZDZraVhyRXJ0THhuY0ZsSm50anYtbHJzcTBTa29BaDY5dzZDTmJEN003SThkUmJSVzJlYmhXazFIVW00THpGRE5xVmJ0bDVGV21tY2FKUTZ1czZUUG9JUHptQ1MxQmpITkFHcTZkWWNMcTJlcTFuTlBKVWNSajJpMFhuOUhrNFhpX2ZFQmFUNmFJdFBrY0ZwWm1WYkNDQ1pBdTZvcjg1aS11bWZiZGZ0MkM1MVJNWDhtbkJqV1BuaFo5dlpRZENjbnlDTnNCY204VElSdzhOdEV5MGxQVFBMMl9tV3FPa2plc2xIVmVvTWF6Nm9LWHY2ZnpjM2g3NnB6cHlLZy00cjNuQ3J4LWxFcGJ1UVpwNzZza01XY09vNUZjU29FLUlCM2lLV0h6YndOM05YRTFZTGgtZkNsRUtLbXpsYlJHZjRPMmFiMWdfb0xxRTZtR1dNN0JJR0NDMjFMY1BXb0FXTXNXcS1vckp0OVRITTNYNENtX1lVcUF4alZnVWNyQk9Ba0gwdTlPcnJMczdrb2NaUjdSbW9kbFRTRnpjN2pwR1NFWlVVNFJlbU5vSzhackVJazhXZHFtR0xVSE9JQURTZlNmWkRVUFR1QWZoc0tWUFJJcThHQ2dGeWJ0ZkN5UWEwcDBmeXZNRFdCbThKd2xJYko2bGg2X2ZxNTljazI0RDVDaFZQM1gtSjFCb2Jyci1hcFNmUlBpTWxGVWFGcU1KYU9nckF2SmtnT1FldWZ4VmUyQ0xiUjNUcHJMRFRONkN4NmFQbGhDcTh1VDRMTzRwS0tjZm5LZWpYV3paQmowYmE2MXdqWHNlRmpCR24wazdwNXM5NWtMTzNpYW1fYjlzVkZIUlFQZjBKRXBxc042T0VlcnFhMTdXN0hXdTlQblhuMGhFaDBfX19oNmZodlplZkdaWktfZWVkMF85VUtZQmo3czNWbEt0RnBvS1I3eWVibUVhb0ZmdS1JTS05SFdRbExIUGhkekd1ZnNVcEpkRklPdFFwS29EbVVKdUZaZ2tSRUxMVkttOHVHcWc3amc0WXRzbWRONmRpU1dkV2JLVm84WkkwMmJlbG8xQ0JMbFBPU19fcjM1dUR1Q3JaNHZ6NVFkY1VRZ3RqY05pWmo3ZGpoQUVaVklvTjF2Y05rOTI0dWlqcnJSYUo5WWhGeFl4NnFQVDNUVkp2X3BUQ0ZCSktoT2FDT3Z0bzNLWWo3bEJFZHBtaHdkemFDS1FJaHo0eUlhZlNLYkdCczFYZG9PeWlDV1M1WjRWUDRQeW8tNEl0cEFYZk9ld3ZsdHhDWWswV28ybVNsQzItQm5FdnVZNnVhZW9Ud2xteFY4YmxZRl9CZkNQWnYzV3R3NkhKNS1MbE53M1B3eHNSWFJXTkEtb3ctQS1wOGhha0JTOWJVSGtMdzRsOVFDMEI2VTFmZm5rdEhqNS1feFJXMWxNSm1jX1J5dzh3NjAzMWxYZm1ydmJ2NzNYR3BKYXVkWURIM0ttODB6NUVTMmI5WnB5VDNieG9Rai1DYnJFTHFEX0ZPVlROV0phTm1FTmtadzZQUzVhLXlncDRiSUhUOHBXaW1KUV90cXBOQzE5OE1GMVpHcEhpUlpmVFNsS0lVLVgxT2llb194Nnh5V2VteUc5bHJTV0M5S0JSdTJHNnRDckg5UG95em9MZFFubXR4dFRLZ3MzRlZTeXlPdXZNa2hkVEV3OE9jM2c4NHh5bGJBcEZ0eU56eWcyazl1NGpGMzhGaFR5WUt5ZDhhUEUwaDZqcUJ1WHkwZ3NuQUMyTXUtclFhWjhfdmJDSy1wZ1dFNEFxdDRMNTY0UnFEcHE1LUs2YjEzMzZWWnRIeVBoaWQ1RF9PVEFrYzFieHJDOFAzQ2pIUGszdXRjZ0UwZmt6NTFHS0cxR3N5VFRiUnRCRlhnMk5BSUluc1k4Q1dsbFJBM2FRQ0NnbkRLNXpVWDgybzNZWWZ3ZHlMRFdNdDhNWXp2dnRYRm9MeHdRNGp4Zmd3cExEaVQxdkdZUmM3LUZ0cUZudnFWU1loamdSOWw0NkhMR2ZxT1hLb3lKNnM5d2NVWVR5SkE4MUYyRS1UY2FpeUV5YkFmcWZIUUNGUzN1dVNrWl9JSGpxLUR3Y2g5eldhVlJROVRTSUhVVHZwZlBNUW00ODU4bG5vaG41Z2RKaDZkS1ZONXZQUFFyOFFTR0J0MWo2R0Y1X29ncVFXdFROZzdwSEdJaWpHWXZrWmNXdGVfNTdGMENRZTRwaVlJd1lQV2hRb0RDMm1KUDhISTdkbjFrbU43TER0Z2Zma015QXdhYXFlaFhfeUtPQTBMN3pqbU5SUFhoWFVIMV94aG5zLVgxMjdqUFAxeUd4VXNrb0JrNGdaM284aVUtNGo3UHVVT1JNMzh4MVNaZ3NtTVVfLThvdzdLWFhXaEVtenVTTW9aZ3VadkdTNmxTVm5IZzNzUTJOQ1Q1TjNqZlpOUHpCa09fOXpvSUxrVXkyV25mRV9NcEtGZGZRRFdpaUhDckVmWHVzM3Z1WHpZRUdkdDBsQm1RVHRxY1V6TGg4UW9TNUZhcHNNOXUzUW5MMmoyYWlCSVBDaEJjVm9tNFkxT1p0YlI4WWhGbkR4LTFfODU5cmxETDV6anBpRXZJb09CX1F0RHdEel9vSnNMSFpCVnBabUstaHJjN0t5R3RaWGEtVkpMQUxwb21jLVBZOXpCQWNPSWJHTzNLRVlrd1QxMEVkdl95SkN1RjZXVkVZd0RVbzJKNEJkT0lWalJkY1NqUmJ4MzlLbW9xVjBwdUZsd0I0RHF0aVB2TENGMVJmNXBiS3ZhcXE5OFBudC1kVmlfbkxQaFJuMnAtOE9leEdJRExYMG13MmJ5SWhMYkFjajZfWnJUdHhRUk1SNFJKSTVabWpMN0RIOURsZV9taG1KVmtDXzIyWEhKZFYxbVhRbl9remFYUWplcS1kMVhYNzBhZEdWbUR4dnY1b3VCOWFyTXA5WHlIcXVWWnVRazRETW1ZUU5iMjIzOGdPLXE0bkhKdG8tWjFYZkFsZk41cVJaZlo0S25pOFhyZl9NV0NPZ0xZWUI0eWdmSWtVWlRZOE15eTV0S0hYZUhRamVhd0k2b3FvNEFNWUZvS1BJYjVEODdmUUdYa19KbGM4TXl3ZG85bUF3cWkxNUphbUU3bnRoUVUwN0lNN0pEb0FMcGExSFRmWTZ6WDdYWndSeDBoZ0pNWk1tUkVHRncwYUV4ZEVieUNrcHNwRXMxYWx3bEtvSERWRURlQUppWmJMcmRhY21ocWdkME1TMXlMUUhEbmpvVHAzSDVNdzRzYmpQYnI4UnNSNUNkYk9DQ2g0bm1NZXVRN2V4OW1nMEdfM25EaVBpZ2JqcE8xcHV2VEkxNTJQTFBNckw1SXk2clAtREw4In19fQ.-4aLEwnz_3RYJyMTFa-5_zZX6Vja_xn7DOu-hTGp6jn8YkpZLLMx3t92XUeodJisstdNslVLWm7-AeI6g2E2kUWDa3RrxkZVa_jpbGcb4yJVj7ijns0rqUYrVW5Y80qG7dDrlgHjGo2v14YpdvMmZ9Zchah-rL-rQtVc22e4mvSArlHnbHUi6219inOb-gN5JNEaWFREG4FN4UpsOV4PIbAPy79jKGMpS_l1CIGusDgjP4lmSXxM3alSdHsel0hgmp-BCqLHjJeKtRhd73mzYrYND_bDxJNkYTj-etrEsAJdndycMoCSb-wyMQSdS_2zv6saWuDG8GV3vs0YkWB0oI4Sow-2Wqn2Ikhz4iflXGpCQ8AXdqxMUMVcMtt3VSILyFh6pPvPE8PK2x8SYgXMTjbwXIU3PErkHWPYOLzKGuUn2hFr6GNtgLbhMmJjVuonDfEcYIbVKE83oQ1K2yI3upQQQ03ip3BsG4mV2X0QVD2ZblJbtbbMEkhkq9dlAS5xUecsm9HRMGKTj8cjV1Gwla1Oj8KNGClsJjupnAMd1GgPTb3zg72wKDkO74wSpZieznDE4Fszvg_EBhuDFJZT_RQUH5_zLhH1EpvUKFbtWryibjbW5_M1p-mTh5h9pZbcC8qzNI0TWB854n1Mv5M0kNy1w2J1BoDXeZuQFI7A-S1q3ad1RX86TG56RVUnG769VMW3Lq7B5dL4H4CthFRItg_WElTZ-pniMD2hUJezpkyVxZgt8dC-VAL-LH_BpJJaOGIVHS1cYiK-cUawX7Wgz6NdH8zoTLgbEttUXzxi4t0_Fak94Sd3jijex6rP4mxtfA4f-xwCoHK2PbhvCO4hQzqqU1MwIB3XCP17r-pYK5s_-pYkynUJhDjWP-ZtPVerJy4au_FGZjhnlFH3s1zkTKQzIEl98PXFGVJqjEXNjoIcFPKB1oioRkXG1WmA5qAfiW5IHOxmYPUpTvWrFqoIt0pqxyLv7YT7_Qn4NzzJzml2Y9k9DdZkYhGLjLCNlVxoW1JHRYD8aXKJVFN3BDm0MlNeJkc3_HOmHp89eCwRsYIvq5cit_z7OPrtGEn_pe3l_hW9cs9ltRtu5WxhUzqWOpjTCoUD8Y0pvyMswrfRUmLfTjuY7qzNOUvPnW9UewLCbMuJ_FTi66Jp-GPr0_N6rwnZ9Sc4uh8Vhx_r819nuoGE15-CH1w8JcfrqpfKY8xM8Yw93_HKmcsiJqwAdljAKFcLz5jbEEt6_F9FYhTcZe_K2IGAjab7b-1b_kvEpJFuyYs2wdzJK9j1UL-bnFJ8HtQ1hmRHwPAURGIEeSKPRzYug6IwTqiCcx4em-Uo_9_cWJJD2fU_eQLgBdy3eqQkBQOi1l53GfOc9bENHCG7Fl6iBHoNo_eHPQRbsUw7xF01ka03-zTtXCm_ON-zWnQz5gNFVGdoWHcriziOAcq7RxbfMT_pJbvSBEbI6dE3NIdk_Ojl1cp-rb0VKyLp3h-9FIx02U28gosdTMQVtU5RD1V1I9vfMjbQ-g-ien9sYHuIJlxAebLUCYkM_MEDtxQT2Ucsk1K6HHurj6QUcQDYB5Z6i7Be_Lx_0b2UFINjzDDC8RMPoIRuuC2D2lVcOehXnpTTDqhIaTHgyL9MSFfsfs8cHCRmlPFGo9Hw7KFD6y3LbMrJZ26rkTJPJH6uXmFyRTBpgu-wwjW_aUZUMYDLor1pt9PyhF4gyBOTs2lWm-3tzxA0szp8CB2ugZ5Cbe2tyY-12vah_T_oXOQoFLEYHBT6rmVI8ycr6z8graT2je_vABWOLUvnNwL0bIoMIEEnKrDNHHPxdvnHHQjz9TTuAkm_RkORk7PAkdZUAOMiOMceEXT-TeWfVhKjRZe16PSv-wEjAA6mFMWybkuTCBijuJiWSz5VZYNQbXpCdKr6pZl140dnlsX_VX06AsuEuGAeNjN8yTq6ddOxG5FCzC3iqDXnwwJiWFwQdioTCykw9a3rO_D8Dmu5AQw2lGpqu6ONGCMzDvKZS9InlYVosT-Cc6ViYz3UaFoMQtvNX1Imgp70_AWhJSJOlGwFHWjNcEeVQ00ockrabFFEFWbKb9Mr9tnLscxNOV_TW0f4OhGB3IQ_pNR4xXTfy7VNzWUQBeK8qi9hfxZyFtk7--UmTqHw30B7guGZ4Y7za1q6yW3lLIUD8IBbNqL2vGFvbbq1p8oqjdIuKUbGdDF84SCm23I5XtZtF6Ud-H8JQlXEdNZHppH0QfgUUpzTuMS9iHEPgDvzjmIMkIrFw91KMVEPOQi6A68QPqGQeixRnzVMJS--3AbNAA5xVysn6hYhmNsGD9VL-tmGANonFtsPYZdX_Tj4b7hzK4XUnN6IejGbnAIJtUX17WniDXVgGj16JhOqQDvDijiuINCZsz04_7ZXm64MF0QgXRkHUTaTje4c-eg9CqMzL7lP6Tx7UHE049kdO6S_JVlB7KXtmar7pQGoOKmEcovozYQgcLTdjKOfDbGmnEbMvcBAnGVv_I2lMQY1xbxX2-G71wQx5eY7m2dThDqx5DLgDvurKtM9EJ59zpcgo2JVxNw8eRjf44M15yxFvaakKFlgS7fu1UobQbKp60G5gJg4HikHMl4pqpNDwet3TG0akhniXDbBIJsvLAK1qwrcpWmn1XEkK1Z7hxeMMqhepOM-43Z72Dj7E3n_c4Z59n4-1GSqN0KkeO2SoDoxv6lSX5lcAt3oJKIv-35EkW5S8QrjDLTS2d5mY0pdAOnnKvjD70Qe2eP9NoHNZUho2pQ7E_UU9Kuhyj82oRyO_ZNgFsyFGhJEmcpWtaaRg1hR4QuSVvVTABwWx9ISaHINZn6kTDMgEGOQ5RXjRSiWZRG3-Cv-JBTtwsSavzGMQMhL1LPW6t-Jj1A1t5jBN7gMMPY_iS2MlRehfbotrzZJyIDFySowrbpj_ELpYtWCsgIBdlnq_MoKvA7NNmJ0OL7tfmT2ikMwJY4idvL4gC0ZCNeZdLPVWic1H3vgrnvBsRtQu43YZRCYB3dhhCPL0qLYdryjMbtVWM9EYS1xoo-q3yOThI6vnBKPbzUc5aVgzZ7BDm2Hcu3ADhEfBD8BP-2gCSFjQcL6v5OpSOiML4Lx-jycib965l7InOF1VQ4OG34npKD-bwD4p-vDSQPqPTQqRKX-rUqQdJwC9Fmf_6XZu39wvmfVbuRGk5oQQCdLiwYECfSGk_SUfguYOeVdNnfyVSHVLjyB60AM1rWDKio7rRvq9oGmh1IJhKYMFWqBnyj4R9vqjwWzPlGGLsb3c_xuTyQ4bbo8zPwnbNiHDV_9cEKYYb3lfz07FymBYVd1RBOaLA4_hs9MQT4faNjOO6Az-7iremuysBQlPb9fQeyxWQVk88PFQrMW8y7Drq6T2iDEQXWr6M_5v5BHV1eiIkKA_a3_IbOHlX9Ciqab9Bggw0x26_WqdZeuHOyJzfn51iAkfbV8HKJUF6V339CIc0IfvwRI9vAiPHRsi1GvUyiUxI78UZ89_gCxjWyZfFA6gPi7hdg_OIQDbbxLDfn_rIOTm6lAznukJbnUTefTew63pjg3-nEzFJBbkYI3g6uHyENKmesXWj48Ur5wQZlo_Zm3DX9yWCLO598kCyJyEdeA2cfw8LYgTy34UIfPycp_J_AmAB7Mloqg1MZYd3z60MVNyPUdG7VahcjHLKe0-iuMZrnrIkMKams7frYuOi5AE0qNe9RMo8WlqX6ihsCPyflkcZSx80VHry_Wl8OiGe7fYIWmc9KNqB5LlNSBKvl33OvaEK_C_JQ1-CnmDRBzowBHJX9aC-nxrwULmS74BjEabOl-Q0BKVKzrK1qkSRf2tHeUKm6JEOcNGwjp7zWuE03lS5tkUujqWlB7BISJYrd1eG3wivD9lkbNrTNO2_oKO7z-Pj6cHUpoXyWORSyyiP0yTpKZDIyB8NXq2EqGfiFnJbhcHpiKJsHCMIeVYA68AZdNwVZqz083my1btfxfHH80hYrQVLfHpOjSpPpi9NpQXswWCM5Khll9iSM0HHxEYwJ6wrMg9Zb2Ig11Sh6xEB20CtwrDQ0J6y07wj97qKLOE437rYdTv50ADhHafAi4rCSlxdXehpyFi6w95g-maQnOnXwfBjdoqThE186md-zYA3vJh5LXlQAzSbKLyQXRJX26-vYOyeLDzkjikVjWyyWfXIAcaPrPqAFAYPCUuspXhbxZSw_3MlEiDcdd4E5Q5tIyL3He2UlzEZt-q315AlM0KjIQltRNi701mOgrJVANiBfVMWMXSgqC5Eetqy8sIuUVHL05uBeKfapg1PjMoNchgYI_MNSEx8chUZD5I2YC9LXf6MCwtsrup_oDGzplp9UNECs4RnR67n6R8WyLtuUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAYMFBcb~WyJKaEJrVk1pRjdLdEVSWmhQSHQ0ZFR3IiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJJZl9QUlRoSm9EWmJzS2JRSkJFNWJBIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJTR1V5V0lQalMxVEtyNm9VZm13RlNBIiwiUk8iXQ~eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJrYitqd3QifQ.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6Ik9PUGZmckpRNzB5YVlKSVZlZzJVTTBMdHFUQXlIdHZRQ3R2OEtvM2ltQkEifQ.uNVxg5IK1lUNKyN1NvZA2tkiM7FUNPKBRa7mrK_Uuq9OkNWLT8SjnXRLW0lORUBX5QSX3qG-nGT18KorX3FY-0jAWSXbbRqUzJGrV5VaPmiv-WK2MUlIRE1ACvMugZD3Nq0FJhgJBPCfUc7ivyrIQv6GSbeZ98zkraeWX0ImwaeHIC2Wh3BR-yll6a8sDEyHWtxpKgSbLkNHXWFaIQrhJZY7cwWVEn4PMbSI7WLOyc9VfdXmU9J71ifqQFZTRzZsPI4IivK57nrnfu1eL0nHWiFCmTU-ysJn398O3tDKB3f5YFT7srYpV3SRxwb4mu3mk3aShH-bw3i_ijz3ra_zYw_Q0FuTL0XMkwsOi07pB61MoQH9PcUfVCaU-kwq9v8hu7FbORvOl9pEWvJMlKoGSZa5qRsEyCL6VAsBnsniKuSM3BpNrbCFx1-ugR17-1wFrKg8ZAmVHnnDfuOyeyo5EiBorSO5ziFU5yJKuz0RypfKtHM62eMPUecAot0wtSCwt86gMzQHOSOxgNzMUbV2CK9FGfrpqolhKsOrJUctTKarDr9oZ3loRfkvszBcXNxkFhP065zGDLfw7gQWXecuVxqoE6es6nZ6q2PBBDuawxl5lfsp61xmcQa-gTIrMlvTgfJFMyAwcQ2weW-k6J-mN4g2H-GTqhvHDo-NAU3yvJtDEEnrxT-xaZ7zOwTxkQLzb5BDWxOYU5pT3eOzNQeb4Ejh_fIPa-j_K1Ftxc7chJ1Jz2SCJW1lg9hywOwV--IlQYCpEworQcOLDOZQdIssAsD_T_3XFq9sgRF8A5UP5iEScZd6tzAUAbu0dIhyBCt_J8fN_OS3FEd72Upb06mRAFK9ErLndP6ardRGmAq4Qbe4DEd4Lo37-Nnj07IznUxuaKizM9ehO8y22KSkySP-NIhy2Yok37re7oDyqLs1BqcOvvspcMipLBHCxk0P3l9nMQHEtQlKnMsaVDtEAwiNvt0eEK5p2eJAVpHyI0z3Xsd4g1OurXLvOQS5UIzHsLlAGvRCC1_pClEQ4dYid_tmUJeP7LbPRrcA_BxSd-Ozk3-vkn9AsWk4I5456YajT4iGtTwoglOVSsfNbbZmAOO3_2VzYRoqkOhAUNLOnYbWzdYLTbLWA6L36vLPKzR0i3EqueCP_83cmTmBtUC8vdbyYxNesOcCcOlDz-Gb4rYOmyL4y9vsc5Jppo3feq3UgimWH1iFmDmRs77ZAMoa4JaW31Yt-tetr0qP4FT82bag3MuFUevEbhZweHAnJ2QdPktXaPQEtgsL27IIoWaD8q3xRVkOc0-SEij17tinWj1mTjxwCrhumRHFugyYlT9HAUsQHwe-YrCG0RRdEoMCsjypv1HDo9jy5JPNXKEzwgX4lgR67DpuW6Ylt8LwNuFe5dV8njlO7XV1tteoFrdjB9conLRcDXldRsIeFWqzTVhRbJdMFEsJ-HrFPrJ4-dW_7lkofdUFR1UpMh4AV6XAUreRs1NP6dBLopnVwFzGJCzIr58_heuepuh1LZlSrR-0ZH4hL1PvQxEH-qEMHCrPVCOek5nEVS89lEacPZ2XH9HpZBxQIO2xhawSqImBRogm877nwPXPBbwl7wexQvTg-TLKiaVtznn0mvgdTrV2VnFpnIp10jqzsj55JB1evFOpW17AAweRhgXWfmOEoKeMF-Tq6-5_KFTmo2Fuv8pxoj7V3ot-INYGLZ742cudIiqsLdBw2yChRbZQJk7HeroUCA_mbLJKejTcqTFYdoMs6zZFcE2cjPxfGM4bZFq-mrDHpo4YjM4wVWrkauG0nlcSQ3DLMQneEN0dRlfcGA6fTYClmRDWiv_R2o3o047pC5bTQZokZubO68VKREB3UH71r59ToiC9Az8-QIm2pbMd_syX1n1eiMKxaGSOlOULvqi40bhCVK-yWWLPnwsFYPJ1Bf_YJfDu4uN8Jg3_FCAZwCtzjFtg8ZOnIBNu-ZL3t8Y9PRxOoahRRV2Nd0LuNLCMUercr1YL7cjh7V6a79ZUN9FtPmUfE8O6uvovUSRyxO4H9lUi8lDxJnivKZucd4yc8QdB4n5-H-9GyWgTYHcxtmh7pOCbEYJzUQSDeXgZqeUzzhasPD8PwhBq22gTexP8lgOlVZTFTBMYzIbk3nKuuKXLsmkHok75O9--jNkbd7bSSbJSHNKFWCxCOjgEAhWFvra3k7dvJX5gEWLZIroxT7wvUJ0mrz0OqNagK1mzb5aHvcVazSEp9qeVACbQynZUf9_R0wYrFY2zh_M6NPF3DnDYSmGfdcEBLqfz2AjfcDtgpzQUjEwWH_5U0CXq6hjXyHrrArTZxP8XPQ5xHpLGWyjVdHpr5K3My8fpb9QbALLVcluiMaQz3jnIL5EO_tquBoaVIiKqPLHXKD7ASGVT9jO1bRI8NIu9vehJEteRQNYjroSFyx0XzX57V7Zhp7n8VRNmMBwQ0UoZ5c5ZNamN8ANIu_Gt67gKZg80BaYz3JZpUoCIcJV9LL-l5CCB4YHSM4CXKOKo2u5k5bWCNuYaUQw3UxLq5zQtkqpzT43twzzDQMDoAiIKBj49jTHtltuFq3rvcvAY02C4envg0lDyzIbEtXHDY3twLf9mXQDI1RiAN_QS-cmSwZsI-d-v3cfWbzPlhh3-5pdLpK4RzseRzPG0CBQOwGBOJerliK6LllR6yllrrLdCxuNYSCD7tzR3UDAGOFJU5Y4ozkX00rh6mHTy6DFwAWoaf1pg3hrDc3K9hYGWR3TAOVrbayIPySu42ln_ebbz6AHexsZoWwq5I4SljQxN0tdXv9fCFhkW5l676j_Ln8nWTNS1t0TULLG-Oh2AYUuU9XnI_OIISsidOW0SddMz_SQ-fWwIyAHHGyutRFaZUVBF1xye3dX7fXx3P0OpjU1IMVPUhcNTn8dkmvhq6Fc1rNfaOE1WvPzdxwM7tpHtXw01v-xVC9yIk6F8nOEu3ivETiw39n8W1oA_0KRhz04FQKrbTTxilc92-tskTG3phx2kskzqACZ-6qCcFScIBM6rCSGXYWRrMuxGuNaduGA6PkCUdo1GREemlLA7Uz20SSJRQhTHT3cN6OFaLUglZmmUdxZqXmec-MNXZ6TibpVkYj1xspm06qnRhjDx3WQVQX8kSXn3C74Wj3pARCSFNfoE1kySwq120E6CYFapEuiitV1w_7uAI3ip400nrqqpqNF8g7R5ppccyWvfyS7rJZ7ULd8kOvHAwN3_rTbIlwkf6jSHiUN-XfzP4iNcojC_kPLjy6NnkJ_RvfkokQs7UiXI0DZAhEInSMQUsaxvbEplOx3ZpPyDaCAlaqoYdJiMLKTZaA03SyWmNjH2zJRAHwtpvIkpcyryPGpozFlhuOnpbU4LpHOzu7dqadNPagcViOm6e8aSl6y99othBtrNbwdiQUtIg9IHqZgFIRN1RB5lh8kneGi5p5-YdZJyCjb668v546_w4cjeRu47InlsV9J4X3Gda767da6gpw_mktE1RhvH-OEwQPGt-siNXeOjLJFQ2f0ZWPW5QCJKa00r216zxSfXAEvjTbEjYHWqxZIWkJAEqUgtqrGDdM0xNOxo-CTo7F1vQbrLI1ohLCLYnv3RE82m4CkA8fXvovtgqtQunUdGcV5Fb7mebDoLsMd8l7Z_aD79j2XtlvVKOsDSnqB2n_XDfFCiNE6HXdEds4FHYFwOXUSmHeUcOkM7usX9q9GFGWvL5mf8PMySaw-g4z7KbcWP4xxAj87ogv22AyW2gYhs6-bxHCFrpBefmqnvLMCcxoxG1lttpEzKrLkJnipv4bhUpLjrwXTjLyfFRRsVsBjnzoohdSGdzfuOTkqyQH_sEA9GEu4VtWg83EF_pSAQvZCbFhHyptylHVCbgDs9AU9nFceHu_bq2eB-XB3KSZ3K79Pln8UbmuYZMZqvk371O8xAhIhDOjYXUrcF6-qglD9hjWejviW4hrMnVjGC6aPKbGDiXO4geGsvlZAji8OI_YhDM3GkuRc_zj4mDj4BqNgyl7TmA2C3Dj_UJo_vhBYh0ATPT7I9vI8V9ICcSsIZ1h7tJFFMWmkdsDPBOeL3aXXC9Q7TfUnxnhi2hhh0hTDA2NJgG5dsVqItYlrVVt0FtjgPZ9Ss4F2mnGFRfjmM_yPsQs7DMjK8ildXmIJm_KD247IHGWQXk-KmR2bKp5ATZ6T8isoPpP2RIQRyz8ziUpkscSwlTXU6bzjv8vExEeyQSfaf6tbwHSRzi0CE1O2YizlckJ4SPnvA1rguWbj6xlTHNic5DsJB4Uhbmaw_Rvowe9N-fCOYDWKE3PjmwEUjDPjc_iRLTGqYFga-hlRHk7fr-XeUwsnWMDtPbq3i4_8DC2CFGj5IbH2hqazZRIuYnczPAAAAAAAAAAAAAAAAAAAAAAAABQoSFh8l", + "noStatus": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImdpdmVuX25hbWUiOiJBZGEiLCJmYW1pbHlfbmFtZSI6IkV4YW1wbGUiLCJhZ2Vfb3Zlcl8xOCI6dHJ1ZSwibmF0aW9uYWxpdGllcyI6WyJSTyIsIkRFIl0sImFkZHJlc3MiOnsibG9jYWxpdHkiOiJDbHVqIiwiY291bnRyeSI6IlJPIn0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsIl9zZCI6WyI0VXV2UWZmMHl4aGo0QTBCb01fVENZbVoxNnRER1hoQ25DbjMteWZKdl9vIl0sIl9zZF9hbGciOiJzaGEtMjU2IiwiaXNzIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxODIzODM4NTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.mB0Tj6473oyfbSJfzoMViYIOuV6nc-6zpQK2FkNOpGGFDMDD_DIey_EiU0aGSsyBrjRL2GV4bUPQHcx7OiObCg~WyJKVExRdThVWkdDV2lZLU5LYlB6bFdRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6ImFGYmZGMFRPa3JfV0pHTFlXZ2FEQkdFY3M2QUVTUFVGSEZOUGtZOFo0VTQifQ.UXnc093aVrHMIfdNIewXXsoX_MhO_2G_Qba8RZ9G6vF7iTdUUX_VkclxlhjgfJOzz0z6M4fOrKDTFtn_LUYLCA", + "lists": { + "clean": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ", + "revoked": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBUWUFBQUFFSUFJUSJ9fQ.oimbeRq48Zvabtwl6elhRf_5bY5WdAvnTOAdktoHPxbfoip7swrJ3Ux2v1O48LSph-7cceYTVXNksbVcKyTCAQ", + "suspended": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoyLCJsc3QiOiJlTnBqNEdCZ0FBQUFIQUFKIn19.facNVbBrSybeLUNLVCU0FDBpH9XdDZmcVQkGcatktJ7v4fEI-_XBG-JAD4h9VKZr6zmddk3ZtD3x3h_HW8EbBg", + "eightBits": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjo4LCJsc3QiOiJlTnBqWUVBRkFBQVFBQUUifX0.uFiiS91zq-P5V66asGF9tl98Kejm8sfHK2y0EjlSn8NCXvpF7g3oQueidvGR8hFzzXlrrFCey6eq7FWrsKVpCw", + "otherUri": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMS1vdGhlciIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.rUNIGt2ncvgWImphPEIF8xRZmQvObZy37NB330HXiMEFPI-DbGCS-bZG4-TOOhoVLqb8MmTrGy3mOXA0Mbh4DQ", + "expired": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzAyNTgyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.OygFuUeCnTQ0RMOF1ABDYUVwJIY4XOgSt1KTFRrmfBZ7WQLtQifeOaSZDRjjRMmi7KGRVXtnSN6g7ADPboCaDg", + "stranger": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6MSwibHN0IjoiZU5wallBQUFBQUlBQVEifX0.stW22QbAfDuxc9bB_L7S8_Viy8Q-FmMCrp33upkwLZA6Ez9qeGi2Z_WzkYq0GbLQsb0KxG9RTiWHkV-XIW5uBw", + "short": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6OCwibHN0IjoiZU5wallHQmdBQUFBQkFBQiJ9fQ.K7O0Lgxk_ze_VvWSUnv92kKNVeaytqlH5qc-dGTXH8HGBVOUZgD7CG19SGytHkjphiZD4Ym-TqeYqSOjH_SzCw", + "typJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.6U_gARjIurUBzIQYqufPjNYzmT3nvVWebULymAWs3Dth94siwGLwqSJquXJFXEGgEZjjT_-e5fpVpi9uJ1siCg", + "noIat": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImV4cCI6MTc5MjMwNjE1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6MSwibHN0IjoiZU5wallBQUFBQUlBQVEifX0.EsgwUPlLED1rLsG4eRe2TfmMuYhOrKsC5_r-uMqvOpKj-YenmnXD7w29pnRM_zEf86vvAI0bNQp6P87B1sPEAw", + "mlDsa": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJzdGF0dXNsaXN0K2p3dCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.O2acplw6U7bG9zzvXMvpwJonbOMS0LWoyW0DZBlZyH0r7KOuu0KUlsbMttNpBNOc32oVzJxCqiU43J_FJFjrw8HhUFag1hnED3we7EsvXjQaYz2wKAG8QDST5wn-OVUq8b7WDYKmNIfRvqQEw9536HiKlAmj-AeAa4sbPkHi9iSaiIXlxb0uZMVM7xLqm1ECPnnYKuOtPJlLLbXtAEpH-it1_Hr1HN5l-wsu2Aw0RhhZnBAo2xnr163bmgLcucACziwqsg3U8zwHgB9JZsdXtT8xN9yPyHPFdCA_Z9pUNRWvMsAT1XEYipR4Khm0hxvXm_np7g3ZDX8x1CW41H8b114YiffcoN1swZvOkW20p3DjYQRXrGWp04Wkg0BcX2gZTDCWMYKCmxFyWcm2TltlR7zAmN5akPPp7eBnXthaF22f6tWEMMw-TuJNoVEHf37JVf6nzstMqIlTs1WYjK6yzobsSUl7K9LnbMZqK7au2XToM9JlAldW7ULSNppFeSk2ree8c_7D4IVV4GdnXSfVwwGEjbvMmVMSvciL2T2EqV9DG7ETcm8T6fitAomE4XC2VN4VuV3hlOZ-56ea0YAUBb2mYydT8-utafKgCwmD4mi8gd7gIclkM5AKuaW0i3v70y90aSflvH3KTiWrdCncFfIg3kyPqT0FPwzW4Zmzro2PawLQN3VhIvDcomxnbllrWEeXdAef4Gj-V2ynzYfXHy6GEJ5--t1396x_Iuck-OPHKm-u7vOO-DY6MlUd1TL8AoslqCacE7J_OlHIJWnkiRcEwcFOcm6E-Afd_UH7C1OknpqAeM6kc7ZKhLNl548tMArwJTxhInKIQBSnxMZJv-t_kHtvG-2c0NQFAhp_PFgp_YGf7skD7Rlsw3PKP0Cto8LgTCthx-sminRcfUklYAEij-33mnQBtqkXzRD-dM8OfbWwHYXpNbosDyY-6UZEFVHqENgNs-qmcHPQTNCpnDLtwJSYEa96jsyhgynQOFYYqjJINDQVjhp6mStaoSPjgwH1xMFRlxSqrI47mgt32zc6u-_MYO6xrrpEO8rHuohi1HZ6FGRLmsD6wX6rVuDym2Xn_k_2UaeNVu7fOojfxD6DHxSQrC4sGE1uJLwcfAxU8qQSfvZQqQ3wN3PO5NlMfo1RcEcBTjjzKA5Sx-1mKTM5C4VA_GEfqZm9-wf4bI5J-rODuVCkgBoTY7TX4CcO829AuBJnmkiWa4_o5ZMJvb2DJN_h8sJuSf6moSRgiY8fcIGyNy9wQ8rbWzF37Nnz-_4U0NWhyxc30yrJ74MIbs9Lt_H0H48C8j4p6kCC2RU5IibEIgfx8PTrk8jZpKZrW6mHr50oClUbgxVAQL99BpqAoeLLNuvh902gxXxdSXKgw81FSWN7ExbIEIE-VIqHb6evFbOzYVOFl9SUp_L-3BqWghZme_gD0_0xo6poEEZ6p6AJYQcH-QvjBYJYcgGw5WD6-PVZ9xoLBLzN4BZpGh424Sd9tR98ZG3L7oxK72GwVk5QaR4eLdymYRlHMxa8pgmEDgKzuDLg7viX3bcZLfe1fUbqjQw30U51lRf4uwhOQO1DhBZp-AgudglB1NLbSlg7qbQ4fP7p41nyn7PGkBiTSU1pGe8IZkScnv5rLNUwm7ME686vjNmyjLhC6kKSIr-F_s-G7A_EwUjVwn8XXHH-uP4BhQMVN78p1PhF0gahijtPaRJpK2JLZKNLWCRtuOdHAMgpJ0z9qovNPa8cD5xR5FJSFZjBv-OQEPDE_p8DxGLIxG7uroTOw-IDeU5nyk3wkm99C0woktY8kUOgcwfBMoVn9cyPHLBYYkAsV8iPeNEnmW1BRr5xqZAUyESEFslSFZC7NMQYJj68L47JiqLFbsfWDEfC2ViawF3-JfEREHMddxsiROiZmbRcGoMmomLsOc8bXPq9_QCHeTCh6jSwrBUlim2C0kAquGcAZgEFGWHJhGht64yKfDFZkpOsW47AW2tzgd-xAcDExEDp0p7znxj7qYouKy4G0feJ65P5wabQHMvuOz7c8JmMXFJ8p-8RgPZIy15Hj08xS_QzJXFghMklu_8YvzKYr7_GaXzvbvJmDu-UYeMRF7gT6joka6ZlcVKRs-gTFKzqwwRhlJR-wxFOp4DP2-kQVq0Dad_Zeulzn6y5VNBHxz0RYq0Zk-FELD0B6h8fOM5RVchzCxq03xIdNK9aDfRj-hMEbh91zCygAvgjnAr4o6JoIicwJ4DNAIOERWXvF5S3-u75m8zGfBWQepdVljqFeUpaQm7ujl_kzj53CsFnCeh9B0wNmHPrxbXG_t8kbLgP6LenARoPwrg7CZWSXyFoGDGeRHv0is1zPtliOHH6giEGuk-JYc3UxWsiY6-Np44w6uUqcGNNaI7fKWi2nBbo2RlG6CaRgucBgszmbJJYK_FZuOgDQdS4m9GGsNB48sqxFfGknjU0ec6L7o5Co7r8H9VpSAXqFDTgd7dLC-cwbYS1oqIjTkZPBivTKgBhI5uTOWrsC6JQ_lW7bFcX88z_m_pZIn4wrrN-nSDK_ER4hL6qDLAYvl8cid7Ln52cd2m8Jxp5aOsZpSgUpnG_WeYVF1uu14R0OQAqj1NtaVDjk80Kb5tT99tiqBCYb7owQ4LeGU8KzHszTEVVSUKIY9fBrDdvNYLHoRxYaVSeDtIg_vMoNcagsnCOVOTV2bxeS8McFHtNwN7rm5PsDGbMnXyayqnDy0-xaQnP37njPpvfIAcnpvVcn5x6vGHCJR_Cp2RV60GSONNAzYOktSz1axZ7b4AD8u0mPBsf-thOjJLubF7yd9MS-klQb8TxyrDSDxQGiVQNZaWu6Oq1Q_eqhkbzwXQaO6ws0hktmCcey-Z2dZ0OEZ3SyB1BU6glCjKcY264WgiVxXKPMRozOxdejxj0gLBbbtEIdqRvKpfqn_969wdu3e628IdDq3Pmvs3ekuzWiil9pIGRDi0eJInNLD3jlC0O-AOkH2raap-xqv1fnlSxJ_HkZTR2JaHAbOB0XVNdk4y1vyndMKp8Y1xrWOaeNVUrEk9HIXjanQ427JFoUYp1EETHbCAdyTQButD91p1BWOOqVSEAsWxCg8Br9QYlD_tvtWNvh_BkXpCcU3B0w4fPu1igBIsVxVXnJBpKi_r_JiPit3bNPec80eL0SB1RV5gJd6r2TsE5lFepcj6gAbnLd57sBrasuY2aBbzREKjOP4u7BtgDFBBomcT7NFF70TnJJ_-LaqvLXcsPJgwIbM6FF8ppC6feOgEtEUrYp42mteqZMCsgM-rteF9eML8cxCCoToYZVALpnX7lE6DenMCqtb27ghPq9i0as6YWYhOxAgs98h8W5k7-qzLfiViyxe-goVwVcJf9RNu2Ul36bcPawCR-MsrI1p7IvUA9C9O2kLSAtqjW8yJghMMDfZdSkDfeXWYuRxSKjSdl58uxXFlrQjhfMTW75p93_W3GdrttR3EMeAmQJox7khw0oRrE04ML3cGrrwzQoso6S5JRGfBb9esw0-ep8dYA6SQIcKB6HH_BJ6HyHyD15XjdXDnKabiqh79gdxAadBW2IwHTdmYfWcPr_i5OkhxQW2fRj1Wpdcv71viYekD1hpI_pqdRwwHE_sTfOv5ak5FC6d3rYvCIr1FMLjpP-lplknKaJT2Zh0NOOaxa7gRyOkxtgh7rsN_amlU4caG5rHGTia1RbEKDFqNkvIiT9An1DgZP0kzZ_qMsipYMtdJ6IoqhN8jQh6Cnc7RMYR6ytf6ckDSs_ad9Gaor4Ma-9tLQEziBc06GyB4ieC5ia4rsGO8Rwvw0k1DqxaYBcWBnMqDOO4XwYtCOxEBx1ymP15OXDCqz7bOVWoTYrK0OGLafQ6CpaAuq8Dt7yvJKu2Gy_UwyobSwqTfNQgmaav8GEyJZH9iUkZVaOYE2AQkZCEBqHInZqyXz7OlrtGq3qW7C3Gx60Tdu6KM4dwoiTaA3mHO8mBEKVoFhTBfM1_yTiNb0d_mP0y18OsQ3pYiWuGWbtTrXx5C2d9Te1DKPU8Hbjd3x3uFTetn1l85VEQ2KpIWTv7EVYdBpJhWQt38TYcdWWUhK_XbK8dp6X2zvuFxovH7-65j-GZTmhEpi9VQvzZcxBwsyQd88ZVsMbTJtRqn1d1wxaIdbPdB0T9F_Yg_X0SPGjNke7B_X1c-mucpIdmI_5bhEhuTM_XJbgoKxF08aqsXmM7C_IPB2NXbybhCeR2qvJz6qMxMPeWi4ZIH84K5emxCjF91LLX9WjpIK_mRJtwr_fZIPPYnikH0AOv3iGv8eDYvwWsr6GuMx1JOhX7csGslkJz9yRooPdlt34wEnKz2D9y209T5jqO8LGh87W5vV7_0EGnynAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAggLDxgc" + }, + "forged": { + "noVct": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJnaXZlbl9uYW1lIjoiQWRhIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJ3c185V0FUbEl0M1c5NkpVLTZjUHItY2Fsa3pIZk1JNmF1ZWszSzU5VkRRIiwia3R5IjoiT0tQIn19fQ.vgtkVUyEUw5Fq_2vQzmMPhFoEeNmeJatrDDqeSlNKXo5vIm3SOLFUTQABT5_ZWKXOIiBDw1og6x-95xXdAGSBw~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6InJWaWRYbXBJXzNVcTFqSy1rR09EYjFIMEZxQk9IRWdsYnEtUGZhb2FlcGsifQ.BOiEAOVRGdarYAw3qs0gXi3X0qRbQpa-nd88imbiZRKNnkSB9BP-CrCO2eUFy_UwfrCMoVhoX4LP0USEmCP6BQ", + "statusDisclosed": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkRwa05uSmVBamRVMHFSdEJqdV9DdGNBdmNDN2lmaXFEbkpFZk5Kck81U1EiXX0.ZshknlcwIGLJQmqM167plJQIoD73pIcZU4_MPSvCOsFI6k7IiQzFf7raCHTWWyhK1IjwrWMJ4cP5zAw0UWc_BQ~WyJzYWx0LXMiLCJzdGF0dXMiLHsic3RhdHVzX2xpc3QiOnsiaWR4IjoxLCJ1cmkiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSJ9fV0~", + "statusIdxNegative": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6LTEsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19fQ.Fa2p9WGijm3pj2YeK7XO1g5MWt1Q9ZOv-HfBK9MB3IpEvgfJXiBLhazP-PXWWYnlHhcxR7rXOkSeujXIoR2ABw~", + "statusNotObject": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwic3RhdHVzIjoicmV2b2tlZCJ9.3bZlQeCXOmnkJ_WipORhYzEa_eDZ0Xpt8qNOwKPTVSsJT_sOPyfzxVsREtI1C8Nn78fF-7SrXnwbsxpepiI_Aw~", + "vctIntegrityNumber": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwidmN0I2ludGVncml0eSI6N30.KpUk6XDQMp6dudRtH0jboaIqncCm-JwWKCPWtT8E9W2r-i8Oxc93tvxfevtYRkfswsdO0q1joNzd2g-HkpyGDQ~" + } } } diff --git a/conformance/vectori/INDEX.json b/conformance/vectori/INDEX.json index d28f447..8c605a9 100644 --- a/conformance/vectori/INDEX.json +++ b/conformance/vectori/INDEX.json @@ -1,7 +1,7 @@ { "v": 1, "kind": "aere-conformance-vector-index", - "count": 467, + "count": 553, "artifacts": { "envelope": 64, "payment-risk": 11, @@ -14,12 +14,14 @@ "agent-ledger": 18, "identity-presentation": 65, "device-bundle": 194, + "sdjwt-presentation": 54, + "sdjwt-vc-presentation": 32, "dataset-record": 6, "dataset-answer": 11, "dataset-consistency": 3, "dataset-sample": 2 }, - "offline": 458, + "offline": 544, "online": 9, "rules": { "agents.anchor": [ @@ -731,6 +733,137 @@ ], "risk.window": [ "payment-risk/company-p1.window" + ], + "sdjwt.alg": [ + "sdjwt-presentation/aere-issued.alg-none", + "sdjwt-presentation/sd-jwt-core.alg" + ], + "sdjwt.claim-conflict": [ + "sdjwt-presentation/aere-issued.claim-conflict" + ], + "sdjwt.crit": [ + "sdjwt-presentation/aere-issued.crit" + ], + "sdjwt.digest-twice": [ + "sdjwt-presentation/aere-issued.digest-twice", + "sdjwt-presentation/sd-jwt-core.digest-twice" + ], + "sdjwt.disclosure-form": [ + "sdjwt-presentation/aere-issued.disclosure-form", + "sdjwt-presentation/aere-issued.disclosure-form-not-json", + "sdjwt-presentation/aere-issued.disclosure-form-sd" + ], + "sdjwt.disclosure-name": [ + "sdjwt-presentation/aere-issued.disclosure-name", + "sdjwt-presentation/aere-issued.disclosure-name-proto" + ], + "sdjwt.disclosure-twice": [ + "sdjwt-presentation/rfc9901-issued.disclosure-twice" + ], + "sdjwt.form": [ + "sdjwt-presentation/rfc9901.form-clock", + "sdjwt-presentation/rfc9901.form", + "sdjwt-presentation/rfc9901-issued.form-empty" + ], + "sdjwt.issuer": [ + "sdjwt-presentation/rfc9901.issuer" + ], + "sdjwt.kb-audience": [ + "sdjwt-presentation/rfc9901.kb-audience", + "sdjwt-presentation/sd-jwt-core.kb-audience" + ], + "sdjwt.kb-claims": [ + "sdjwt-presentation/aere.kb-claims" + ], + "sdjwt.kb-cnf": [ + "sdjwt-presentation/aere.kb-cnf" + ], + "sdjwt.kb-context": [ + "sdjwt-presentation/rfc9901.kb-context" + ], + "sdjwt.kb-freshness": [ + "sdjwt-presentation/rfc9901.kb-freshness", + "sdjwt-presentation/aere.kb-freshness-exp" + ], + "sdjwt.kb-nonce": [ + "sdjwt-presentation/rfc9901.kb-nonce" + ], + "sdjwt.kb-required": [ + "sdjwt-presentation/rfc9901.kb-required" + ], + "sdjwt.kb-sd-hash": [ + "sdjwt-presentation/rfc9901.kb-sd-hash", + "sdjwt-presentation/sd-jwt-core.kb-sd-hash" + ], + "sdjwt.key": [ + "sdjwt-presentation/rfc9901.key", + "sdjwt-presentation/aere-issued.key-confusion" + ], + "sdjwt.sd-alg": [ + "sdjwt-presentation/aere-issued.sd-alg-nested", + "sdjwt-presentation/aere-issued.sd-alg", + "sdjwt-presentation/sd-jwt-core.sd-alg" + ], + "sdjwt.signature": [ + "sdjwt-presentation/rfc9901.signature", + "sdjwt-presentation/aere.signature-kb", + "sdjwt-presentation/sd-jwt-core.signature-kb" + ], + "sdjwt.time": [ + "sdjwt-presentation/aere.time-expired", + "sdjwt-presentation/aere.time-not-yet", + "sdjwt-presentation/aere-issued.time-no-exp", + "sdjwt-presentation/aere-issued.time-years-later" + ], + "sdjwt.typ": [ + "sdjwt-presentation/rfc9901.typ", + "sdjwt-presentation/aere.typ-kb", + "sdjwt-presentation/aere-issued.typ", + "sdjwt-presentation/sd-jwt-core.typ" + ], + "sdjwt.unreferenced": [ + "sdjwt-presentation/rfc9901-issued.unreferenced", + "sdjwt-presentation/sd-jwt-core.unreferenced" + ], + "sdjwtvc.disclosed-protected": [ + "sdjwt-vc-presentation/aere-pid.disclosed-protected" + ], + "sdjwtvc.form": [ + "sdjwt-vc-presentation/aere-pid.form-idx", + "sdjwt-vc-presentation/aere-pid.form-status", + "sdjwt-vc-presentation/aere-pid.form-integrity" + ], + "sdjwtvc.status-index": [ + "sdjwt-vc-presentation/aere-pid.status-index" + ], + "sdjwtvc.status-list": [ + "sdjwt-vc-presentation/aere-pid.status-list-other-uri", + "sdjwt-vc-presentation/aere-pid.status-list-expired", + "sdjwt-vc-presentation/aere-pid.status-list-stranger", + "sdjwt-vc-presentation/aere-pid.status-list-typ", + "sdjwt-vc-presentation/aere-pid.status-list-no-iat", + "sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri", + "sdjwt-vc-presentation/sd-jwt-vc.status-list-expired" + ], + "sdjwtvc.status-revoked": [ + "sdjwt-vc-presentation/aere-pid.status-revoked", + "sdjwt-vc-presentation/aere-pid.status-suspended", + "sdjwt-vc-presentation/sd-jwt-vc.status-revoked", + "sdjwt-vc-presentation/sd-jwt-vc.status-suspended" + ], + "sdjwtvc.status-unjudged": [ + "sdjwt-vc-presentation/aere-pid.status-unjudged", + "sdjwt-vc-presentation/sd-jwt-vc.status-unjudged" + ], + "sdjwtvc.vct": [ + "sdjwt-vc-presentation/aere-pid.vct" + ], + "sdjwtvc.vct-expected": [ + "sdjwt-vc-presentation/aere-pid.vct-expected" + ], + "sdjwtvc.vct-mismatch": [ + "sdjwt-vc-presentation/aere-pid.vct-mismatch", + "sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch" ] }, "vectors": [ @@ -3867,6 +4000,608 @@ "requires": [], "sha256": "0x9c5c730adbb0fbeacb86537d2105eedcd6c687948742a28dceb9917f2851d8dc" }, + { + "id": "sdjwt-presentation/rfc9901.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xb17ee5bbb8da8bae3d03143e6160d4d64acf63b55a02c25a16fd4094ed8a9ff8" + }, + { + "id": "sdjwt-presentation/rfc9901-issued.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x04c37a5643c2709acdd97554beecd6f236422d43e65d359c3a9285e98ffbda35" + }, + { + "id": "sdjwt-presentation/rfc9901.kb-audience", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x0ffcf487db005bcbace1d7d0961737b5642d4eabc6ccec2fdf383974657cf50b" + }, + { + "id": "sdjwt-presentation/rfc9901.kb-nonce", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xdb638acdc2a716dcdb39bb604193563bb635829be33e71335c591c7e579149f0" + }, + { + "id": "sdjwt-presentation/rfc9901.kb-freshness", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x87d7a9a0b9024a3650ac95e626ed9b6431d8b681e035f4737e7e8769e273eb56" + }, + { + "id": "sdjwt-presentation/rfc9901.kb-context", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xe4d777dc0cf33955839d38d08fb6964d443045b41855f124f0b4b07ec6ae8441" + }, + { + "id": "sdjwt-presentation/rfc9901.issuer", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x79002f5b01ff4319a8ade3c075ab529e4a8f21b0901836495a9b664dd9ea498e" + }, + { + "id": "sdjwt-presentation/rfc9901.key", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xd4f715d484688437ceaed4de485dfc60d23474474c99cb3d5c5ed08e9c114ad5" + }, + { + "id": "sdjwt-presentation/rfc9901.signature", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xbed1f3e911242d854ed61119b0ea7ed3d3ba7b22c66f0093fc411cd07b337ba4" + }, + { + "id": "sdjwt-presentation/rfc9901.typ", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x610b0511d94253f4ed741599f8bdc8560de2ce824a6b265b02af851ef2ad2468" + }, + { + "id": "sdjwt-presentation/rfc9901.form-clock", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x0548482f4dd888b221529a681153f98468c05eeceb71124a062ed6cd3fecd4ff" + }, + { + "id": "sdjwt-presentation/rfc9901.form", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x75c50a18e68f039ee30268349b4f8d596243630283c7aac37e52bfe86a4f4cd9" + }, + { + "id": "sdjwt-presentation/rfc9901.kb-required", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xf7e658e06a4915c8c3c2316e71d94aa39f07f0a8143f711b37cd10c3d215064d" + }, + { + "id": "sdjwt-presentation/rfc9901.kb-sd-hash", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xfbd3aa0ad889053fc367fe07d0ba9c3cb317f9699b5471bdb3945a3b72380ea4" + }, + { + "id": "sdjwt-presentation/rfc9901-issued.disclosure-twice", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x0e7b8c7215d4a411169962bb2427ad362a5d861508c1c694e7a5efa5a71d42d5" + }, + { + "id": "sdjwt-presentation/rfc9901-issued.form-empty", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x4ed4bd8bfcbd330fed266458bedf5924dcd06683918052546ec20b92b15d1f7b" + }, + { + "id": "sdjwt-presentation/rfc9901-issued.unreferenced", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x5c948c3cd0334abfacdd0b45c46165d211218516041d21bc966db66c64666283" + }, + { + "id": "sdjwt-presentation/aere.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xa4bf25e6c7be85907e2faa208a3cfbc24b4afee8a9bdc42afa7e4a03402c4244" + }, + { + "id": "sdjwt-presentation/aere-ml-dsa-65.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x566239bb9b499e3d9880278862d039190862ddc739b81ad047a5bc3cd4c2bd84" + }, + { + "id": "sdjwt-presentation/aere-issued.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x060d56983b8b5866320966db55e0e62bacc03bd50d87f3fabb69909599b6758e" + }, + { + "id": "sdjwt-presentation/aere.signature-kb", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x6c4a37b0ee1f278f680076721f8dd9ca13ae438b50d9c5845e260433bcaa1cdf" + }, + { + "id": "sdjwt-presentation/aere.kb-claims", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xcf83d7bc18ada8ff77c1912c1c3678afbd93a96b790b8af4eb715c0077f41c0e" + }, + { + "id": "sdjwt-presentation/aere.typ-kb", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x5d19972b3f596cc41986eacb9ce8e9fe15eefe64d77578d271c9ec323bb80054" + }, + { + "id": "sdjwt-presentation/aere.kb-freshness-exp", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x113fad84b78b77a54a36b694e446bd97501b53088c53dd0b6370b25e1d1c5d18" + }, + { + "id": "sdjwt-presentation/aere.kb-cnf", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xf9d13dac0ffa00600d47be96bbd5c04e7c59eebd0b247ee9638c7246a321b6c0" + }, + { + "id": "sdjwt-presentation/aere.time-expired", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x69e121ba34eb04588a2600eb1b8ad64ce72e2f9f995994e2ddad4bd863ce08b3" + }, + { + "id": "sdjwt-presentation/aere.time-not-yet", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x062fcd99cb0ff9fe38a67b91d3aaf1219f57401b0aa24a0c78be9257d759e9ac" + }, + { + "id": "sdjwt-presentation/aere-issued.digest-twice", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x44887dec6503ca912cea3a6ddafa4ed5e01333ab826f5259414dc684402e45f0" + }, + { + "id": "sdjwt-presentation/aere-issued.sd-alg-nested", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x0ea82f93edb3b19517207915b79574a6da7f1133a257927ef4186cb5d658d3a2" + }, + { + "id": "sdjwt-presentation/aere-issued.sd-alg", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xa2d1384753a66a5dba6f2687500055c6bf37fc2ffdfa338beba4fbc7206e4301" + }, + { + "id": "sdjwt-presentation/aere-issued.disclosure-name", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x132e6e91a14bc3d0d6677269ec6c2a398c3d8e1adb194e09fab8bff5c34c21fe" + }, + { + "id": "sdjwt-presentation/aere-issued.disclosure-name-proto", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x5338feb82fe56b769e75c5fb64c3f94efe179401e60b855ca1c87919eacebbd4" + }, + { + "id": "sdjwt-presentation/aere-issued.claim-conflict", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xed21f15610061eb4f8e1888283913fb96785e8bf2cd9e7afc8d92a98e2cbc47d" + }, + { + "id": "sdjwt-presentation/aere-issued.crit", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xa2ce76f79c13e9faec8f0a172bab8af7d41d0be77d2eb7bda7966c27c1a712db" + }, + { + "id": "sdjwt-presentation/aere-issued.typ", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x66d813e2099009cb947872aff7afba7d53ae5d57d80c4ff30fb44b9d18b3c873" + }, + { + "id": "sdjwt-presentation/aere-issued.key-confusion", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x170a83409c1388467a3e3a287f21d965aea111738df4bf608ed4c40cdbcf52ac" + }, + { + "id": "sdjwt-presentation/aere-issued.alg-none", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xdd89f1d66bcb56a2f3dbe8153b8c87801f818be52d616702a4d40edcb5102277" + }, + { + "id": "sdjwt-presentation/aere-issued.time-no-exp", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xe673e99b16402da40f4fdfef1dc32c77aba7903972bbb277be76ea802366b5e3" + }, + { + "id": "sdjwt-presentation/aere-issued.disclosure-form", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x9c63eed2d02e6f8207267937799233ff643de6796b3755d44b8c52a60e9739f8" + }, + { + "id": "sdjwt-presentation/aere-issued.disclosure-form-not-json", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xb669d3f8a57b0d926beaf415578e809a3b3e7f90440818a60bc2ae6da92a0373" + }, + { + "id": "sdjwt-presentation/aere-issued.disclosure-form-sd", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x6df675c2e2ddda38eca7dcc925af1532418b90318dbdf88c6ac10bbdb9e7e9a1" + }, + { + "id": "sdjwt-presentation/aere-issued.time-years-later", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xf660f7dea5fe9bedb4495bb7a0df617385b73ef8ad41797d3a6b5ed77303a926" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x71d62658266c8f31fa6aeff83fb5565c407d2b981ab78b6a06e90f580791da59" + }, + { + "id": "sdjwt-presentation/sd-jwt-core-es256.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x1a63524779967f5fbd00b39ffed1af4dcee3cbf87e92be2be21020a15142c2ac" + }, + { + "id": "sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x482b805ad218e84510a35632c63045f310f2b78050d95d0207361ab6bf8b0abc" + }, + { + "id": "sdjwt-presentation/sd-jwt-core-typed.valid", + "artifact": "sdjwt-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xa1d9246df259269051d7a2a7ac3153f7254bb5cc6ff8f37e3c2c2f0368ebbf4f" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.typ", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xfb5ba1d694fb5f7bf163f49a1e4d02916ad8cea38a0f677347f69b3fe82478e1" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.unreferenced", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x456d9abc237881556e309710c823998f2e84b53d3a3a4d3b3878454ef80a32e9" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.kb-audience", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x6cfa3d696a540aaa0ea0b9a721ee4716ee7687bb95413b1119e85f682e0e55dc" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.alg", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x8cd27350a3cd59185d43122746f416477403e75afa100bddca2ed8b064be14db" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.digest-twice", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x02a188377b49d09c05ad3b1983bbf66063c6be05aadeb7024348efb90c4afed8" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.signature-kb", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x424f7a30fe9735ea5908430cbef3514f1bff7b77ce16ab3e4455fa31e3b1a0d5" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.kb-sd-hash", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xfc9fbaf5afb2e166b24747502dd4a07cb8adf72b937546a1e7f2f3cf5daf5f6c" + }, + { + "id": "sdjwt-presentation/sd-jwt-core.sd-alg", + "artifact": "sdjwt-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x72a06db812e62ebf82790e5b6ebe2c17d5db41f171fa6d2c09fd66bbe5519fc8" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x4037fa40a084b4c2f1a7af6802b2571a93bc8042aae8b38e4d6793464e1bab8b" + }, + { + "id": "sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xd9f9a5f9f6ae3565fa24512fb3fc8cf2555c6126bc0712b72959acd2a1aec56b" + }, + { + "id": "sdjwt-vc-presentation/aere-no-status.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xa875911438b0d95388b243f86e76406cd5ae2fa8ba20626f04037a6024816890" + }, + { + "id": "sdjwt-vc-presentation/aere-pid-status-waived.partial", + "artifact": "sdjwt-vc-presentation", + "verdict": "PARTIAL", + "requires": [], + "sha256": "0xb5a2b2ec0165ca31cee3ee3eeed8768f1ba2263738c3efd2f99bdceabf04ab55" + }, + { + "id": "sdjwt-vc-presentation/aere-pid-8-bits.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x83b6a8c4a65390d5b6debaed5042222620f0a82aff53473792e136925c28195a" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.vct-expected", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x45771debbe260bbbc6e2a7b5fbe551317d4660948581925a158edae9689b08f7" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.vct-mismatch", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x2f1e4cd09d7184e0a9ec39466de9053100ff48636ee9a33dab389c50abc9af62" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-revoked", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xd9a95cc74c4b566d23e0513c25ea2d177ac3e7e426534995d36748fc50ff7552" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-suspended", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xa846cc09df82afbe62a374ccf6329cf7d4b2cbfe9ca012696738179d76dc20fe" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-list-other-uri", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xf772ddd4a3807705110eb41028ecd3ab28626de41199710b085215afbbbddd44" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-list-expired", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x75081bea94d1a739b44ae005d6cc81c46e2a960dd3c4c4ebefd2f8d22419c55b" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-list-stranger", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xa079f4cd56609a180571173a91b1e9fc47b84b94916d68a060a26bcbc80e4537" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-list-typ", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x2ad1585933c5901cec2bdae407374f104e95a279e9ab6a66feb339cba355d2b4" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-list-no-iat", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x72a4a8c5085e0c222722413d1e42e71d07a89df6c8fa68067d49fcbcc81a2bd5" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-index", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x22fde994e6e073f8e28f7dffdad024917abce8ae3522de2fe5b7c5e7bc40abf2" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.status-unjudged", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x3ad94f9eda82f09dab7505fabba4ed0809428c5d8ba86e0fc2f73402cac076a9" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.vct", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x114f09bf63c5cbe717905385662ab75a3b9fa61e07e779b1168192389d558884" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.disclosed-protected", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xc8a6be1abaa3dae8f31cf26dad961c812502b2d376988f58ef35cd089892caad" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.form-idx", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x83f5bc27803169753d4ac30ef44d82f66c73ed6e6842650168696cb6397e8459" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.form-status", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x44c5dddb20d400c6091e9deec56b9ebd69a69c6e7f325907e21720603111fddc" + }, + { + "id": "sdjwt-vc-presentation/aere-pid.form-integrity", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xe6a38bfdfb1ebbd0fea2e1d60ffd6832f3370f927a2bfb3fad03cdd590823f31" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0x1404a0597db6f869adaf5ff8abedf8670cb63ba48819083908d3572679e72411" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc-es256.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xf7b34bf9da366783955d233ad50a17ff7582a04a99532b1cb16d489912dcd372" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xdea179ad9cd7ca65e786922c680828a38f0e694ae6c0f263d4fde195982c528f" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid", + "artifact": "sdjwt-vc-presentation", + "verdict": "VALID", + "requires": [], + "sha256": "0xb8197a79e6faddf9b35fd95754d17dc8aa2d8174fe8d8a3be3239c767bd395ce" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial", + "artifact": "sdjwt-vc-presentation", + "verdict": "PARTIAL", + "requires": [], + "sha256": "0xa7311135ea7ca068e7bc3f5e95c361f9462bec2b3abf52c30df8475cf9441a43" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-revoked", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0xeb4ac475c2cd1debe08d4dfc29359e6e9f30419b7cd3c4a01e1a227a14996ef8" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-suspended", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x1aa605fd51ecb74c7bf6508f10921112938d672483a942398bc2f3f15a49d423" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x4020a11a308284d3570b98e72c5476b28ccd24bde24afeb00a2366966404154f" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-list-expired", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x25bbd41833ee8d02cb7d046f1c502a16f826316d8ca246271c37e310635a6b0d" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x6d245525ebed4580c4d4044712df02acf084f8c39671516b5328eb73904159ee" + }, + { + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-unjudged", + "artifact": "sdjwt-vc-presentation", + "verdict": "INVALID", + "requires": [], + "sha256": "0x10fed0db565c3f655e2ba85c08651d31fa42b0f7628b30e3295039aa8f9ac6b1" + }, { "id": "dataset-record/r5.valid", "artifact": "dataset-record", diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.alg-none.json b/conformance/vectori/sdjwt-presentation/aere-issued.alg-none.json new file mode 100644 index 0000000..c309683 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.alg-none.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.alg-none", + "artifact": "sdjwt-presentation", + "title": "alg none, no signature", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the payload re-encoded under an alg none header with an empty signature", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJub25lIiwidHlwIjoiYWVyZStzZC1qd3QifQ.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.alg" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.claim-conflict.json b/conformance/vectori/sdjwt-presentation/aere-issued.claim-conflict.json new file mode 100644 index 0000000..b83808e --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.claim-conflict.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.claim-conflict", + "artifact": "sdjwt-presentation", + "title": "a disclosure that would overwrite a claim the payload has in the clear", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a plain claim role and the digest of a disclosure named role", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sInJvbGUiOiJ1c2VyIiwiX3NkIjpbImp0U2FaZ256d1paOFJNSjhUNzlCMkNIS0xPV0t2MnVWWWJYSkk1YnVodTQiXX0.VFazRIXy0qzMn9g3b_hLb5q7hq6M5EAcjvs9mETMQ6fT3y36ZLVo9fOq7tOPq32ubVT75Q8GMJEDMhVTkl-dAA~WyJzYWx0LTMiLCJyb2xlIiwiYWRtaW4iXQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.claim-conflict" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.crit.json b/conformance/vectori/sdjwt-presentation/aere-issued.crit.json new file mode 100644 index 0000000..c230573 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.crit.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.crit", + "artifact": "sdjwt-presentation", + "title": "the issuer-signed JWT carries a crit header parameter", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed the header with crit [b64] and b64 false", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0IiwiY3JpdCI6WyJiNjQiXSwiYjY0IjpmYWxzZX0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.81pRXwso1YgaPhC0wcUUxVr-ZVv4R3CK08-A9QzzQ83gN9ahrGFtn5OdXjUhpk5oXuJyQVTGSJEcMr7bO6iWBg~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.crit" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.digest-twice.json b/conformance/vectori/sdjwt-presentation/aere-issued.digest-twice.json new file mode 100644 index 0000000..2dee2df --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.digest-twice.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.digest-twice", + "artifact": "sdjwt-presentation", + "title": "the issuer signed the same digest twice in _sd", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a payload whose _sd repeats a digest", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyJlcTZoZjhaRmpnY1RxdGc3ME9keG5zUElKUkNWZ3ZHLW94Q29CWDBlQXJzIiwiZXE2aGY4WkZqZ2NUcXRnNzBPZHhuc1BJSlJDVmd2Ry1veENvQlgwZUFycyJdfQ.o118pMTuhwUnzcymlJbPobFjK31qoJBWfZ0qkiPdV-WZqpIlrF5eVEVhQy1FYuP1iT8-tpY4LGLP_GvHI4p8Bg~WyJzYWx0LTEiLCJhIiwxXQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.digest-twice" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-not-json.json b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-not-json.json new file mode 100644 index 0000000..0846b0a --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-not-json.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.disclosure-form-not-json", + "artifact": "sdjwt-presentation", + "title": "a disclosure that is base64url of text that is not JSON", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed the digest of a disclosure whose bytes are not JSON", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyI0Wi01OGlEZ1FqQUkwU1dOM0FWYVB2TmhOUEMzLVQ4dDFXQl9fNzEybWlVIl19.ft6nZuVHPQBXFRUi5AI1nopFtRfhB21AjgfDbnsPmqviRXWoC0-a3QoMcONIPdST4MO2Gj652hTQapSvWnTXAQ~bm90LWpzb24~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.disclosure-form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-sd.json b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-sd.json new file mode 100644 index 0000000..121ccdd --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form-sd.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.disclosure-form-sd", + "artifact": "sdjwt-presentation", + "title": "_sd is a string, not a list of digests", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a payload whose _sd is a string", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6IngifQ.JX0bQiY0zje3v_bhU-hqpFB6RPAFLrNS1vYXXKGLp3e6MA8TupBjYutIkOeCg0ZoRUswexj4xCcEbSQllwFyBA~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.disclosure-form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form.json b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form.json new file mode 100644 index 0000000..6b15656 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-form.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.disclosure-form", + "artifact": "sdjwt-presentation", + "title": "a disclosure that is a one-element list", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed the digest of a disclosure that is [salt] alone", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyI5SWI0RGhwZVNxbkY5YmEyaXZOeGtQbHNTUzAwYWVxakd4YVFYZ1NPUUpBIl19.c7TNsY2EDEHxk7BF_dlgJ8vxc6p61EXzOvVRtSw-bzlI07lZCiSIS1uTG8sXp7XPGbpTUvVfJRg3qquaKEKiAw~WyJvbmx5LWEtc2FsdCJd~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.disclosure-form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name-proto.json b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name-proto.json new file mode 100644 index 0000000..46cbea4 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name-proto.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.disclosure-name-proto", + "artifact": "sdjwt-presentation", + "title": "a plain claim named __proto__, signed by the issuer", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a payload with a claim named __proto__", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE3OTIzMDM1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiX19wcm90b19fIjp7ImFkbWluIjp0cnVlfX0.Pzf8iZOKj7lR6Zdoyp4kZrd9EKCEc0TaSoBiw8ZoMvpovMuWZEfE6KBbpgbdg17mFq_2Z4FNzVLLn87ZQYfPAg~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.disclosure-name" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name.json b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name.json new file mode 100644 index 0000000..2839210 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.disclosure-name.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.disclosure-name", + "artifact": "sdjwt-presentation", + "title": "a disclosure named _sd, signed for by the issuer", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer put in _sd the digest of a disclosure named _sd", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIl9zZCI6WyJFQmdlQmw5UjJOakQzMEJVaTFHM29jeUdIUERCaUpNd2VHdUtLc3diTWF3Il19.i-lUl2Fl1-I8l4-uwcdcqZom-uuYGZkL7-ZHXDh--z2cIF4vrUpp6Qn2y74bl3jBmxApP20YIm49TqK4_TqkAQ~WyJzYWx0LTIiLCJfc2QiLFsieCJdXQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.disclosure-name" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.key-confusion.json b/conformance/vectori/sdjwt-presentation/aere-issued.key-confusion.json new file mode 100644 index 0000000..ee167e4 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.key-confusion.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.key-confusion", + "artifact": "sdjwt-presentation", + "title": "the header says ES256 and the signature was made with the Ed25519 key (algorithm confusion)", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed with its Ed25519 key under an ES256 header", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.znkWKtPFFufaaSFVBWKp561hnJj5tXmCxKFg4TMWjemaG8VLJkN22X6GiAqQ7y1urPxuTYgvBH3oOVPNmuV8Ag~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.key" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.sd-alg-nested.json b/conformance/vectori/sdjwt-presentation/aere-issued.sd-alg-nested.json new file mode 100644 index 0000000..f98f9be --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.sd-alg-nested.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.sd-alg-nested", + "artifact": "sdjwt-presentation", + "title": "the issuer signed an _sd_alg below the top level (RFC 9901 Section 4.1.1 forbids it)", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a payload with _sd_alg inside a nested object", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMjU2IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX0sIm1ldGEiOnsiX3NkX2FsZyI6InNoYS0yNTYiLCJub3RlIjoxfX0.miCZJvF0MrS1F2eldNJRUJfxOD03J4J4whnxNnEavTOTl5DXK1pF85U5_tmprPskVCCVlHSZgYoTiu1P7nohAw~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.sd-alg" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.sd-alg.json b/conformance/vectori/sdjwt-presentation/aere-issued.sd-alg.json new file mode 100644 index 0000000..b9d2d7c --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.sd-alg.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.sd-alg", + "artifact": "sdjwt-presentation", + "title": "the issuer signed _sd_alg sha-384, which this verifier does not understand", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a payload with _sd_alg sha-384", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIl9zZF9hbGciOiJzaGEtMzg0IiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX19.Hu8fus-Adj5-Ri-PhCwX248ABzbWhrVZOZTBj4uU-mZLaOPFWUAV5f6l_oqHtP-g5mZ628xHXi-lMPRLGMTWAg~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.sd-alg" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.time-no-exp.json b/conformance/vectori/sdjwt-presentation/aere-issued.time-no-exp.json new file mode 100644 index 0000000..38eb350 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.time-no-exp.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.time-no-exp", + "artifact": "sdjwt-presentation", + "title": "the issuer-signed JWT has no exp, and the verifier requires one", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed a payload without exp", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJfc2RfYWxnIjoic2hhLTI1NiIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.8NI7L4kZ-4Xkihp0rv2xflQEz4nBahV96wuv1M7t7bCpTX5Oe9-JGaNsHkPUhAv7VjB1qx8oQCrFdgBQZarXBA~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.time" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.time-years-later.json b/conformance/vectori/sdjwt-presentation/aere-issued.time-years-later.json new file mode 100644 index 0000000..2fc9033 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.time-years-later.json @@ -0,0 +1,65 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.time-years-later", + "artifact": "sdjwt-presentation", + "title": "the verifier clock is years later: the credential has expired", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "op": "set", + "path": [ + "now" + ], + "value": "2027-11-22T05:49:12.000Z" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJhcDdQQnplOXZpVnZDNXlGQkp6X2RnIiwiZ2l2ZW5fbmFtZSIsIkFkYSJd~WyJFTUI5Z2JvX21JRk82S0JEaHp3bTlBIiwiZmFtaWx5X25hbWUiLCJFeGFtcGxlIl0~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~WyIxVDEtY0c5Sm5vRWV2OXdQOGxRQkJBIiwiREUiXQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2027-11-22T05:49:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.time" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.typ.json b/conformance/vectori/sdjwt-presentation/aere-issued.typ.json new file mode 100644 index 0000000..e6c4252 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.typ.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.typ", + "artifact": "sdjwt-presentation", + "title": "the issuer-signed JWT is typed JWT, not an explicit SD-JWT type", + "source": "derived from sdjwt-presentation/aere-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere-issued.valid", + "mutation": { + "producer": "the issuer signed the header with typ JWT", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.H_Y6xkCmnk9mMnwgyEz06o6bn7fzLPgltQ8rLvkF70EpIdi8SzqeWldP5FLxdrY2C0kjaYSOFEYgM958K--GDA~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.typ" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-issued.valid.json b/conformance/vectori/sdjwt-presentation/aere-issued.valid.json new file mode 100644 index 0000000..37d783b --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-issued.valid.json @@ -0,0 +1,57 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-issued.valid", + "artifact": "sdjwt-presentation", + "title": "the same SD-JWT as issued (every disclosure, no key binding), judged by a verifier that does not require key binding", + "source": "producers (sdjwt.mjs: issueSdJwt, presentSdJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJhcDdQQnplOXZpVnZDNXlGQkp6X2RnIiwiZ2l2ZW5fbmFtZSIsIkFkYSJd~WyJFTUI5Z2JvX21JRk82S0JEaHp3bTlBIiwiZmFtaWx5X25hbWUiLCJFeGFtcGxlIl0~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~WyIxVDEtY0c5Sm5vRWV2OXdQOGxRQkJBIiwiREUiXQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "now": "2026-10-18T05:50:12.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere-ml-dsa-65.valid.json b/conformance/vectori/sdjwt-presentation/aere-ml-dsa-65.valid.json new file mode 100644 index 0000000..856241c --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere-ml-dsa-65.valid.json @@ -0,0 +1,59 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere-ml-dsa-65.valid", + "artifact": "sdjwt-presentation", + "title": "the same credential, issuer and holder keys ML-DSA-65 (RFC 9964, JWK type AKP)", + "source": "producers (sdjwt.mjs: issueSdJwt, presentSdJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJhZXJlK3NkLWp3dCJ9.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiIxRlgwR3hrbVlvT2xBSXpiYXhaYUhwQnhLSlI3RmtFWTVKNHBqc2hrMG1zIn0seyIuLi4iOiJSSXVOb2ZvT21scjlsbnFsWmJneGNIdmxKZUp4S0JwaHRZbXRwSWp6NENRIn1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiNTJ3RnVzclB1V0lfLXRfUUdfWmdxTDhWUkg0Njk2MUw0OWtpMGMwRDVPOCIsIk4xNlJZd2lnanc4dW0tMWxza1NfTloxVlpUWFNYaWRaUy1oQ2pYZ1lvVUUiLCJRUGluaVdOOEFHT0QwNDltOHU2TzI5bmtiVWg3YkJhakNkckxzQTFTSUdRIiwiYVZjSTRJdUZweEgwOGNPdFlqQTRYZldJSlJsTGFvMmhsU3h2U2tVbG1YOCIsImJic3FsZWRTUnQ3ZTFPeXpoVmZLdXF3SDZhZ2kybTN1b2h0VG1zMGV4ZGsiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsia3R5IjoiQUtQIiwiYWxnIjoiTUwtRFNBLTY1IiwicHViIjoiekxNT3Y5eEJrRzE5ZTVacnNqLVhVbXJhVk9wNkMyVS1WYi0zQURQWU05NUduRXBLdVVnLXBNN2tOM0tiWi1ZLUlJQ0pZa05IbFA2ZThRUGtpNzJkaGtGUTdUbnBXdnJoQXJ2d2dkZ1JibWtxSFNDcEo3OTc3ZU1kQjNfMmhYcmhLN0J3a0g0elZGdXk5eFJDN0RyZUlHeGNIZHdEaDFfYTFQRWJXVUlWcklhNXZvZURRSVpSMF9HQWlkRlEwN042Y1lQZ1BzallJVERpVHF3N0x1Tnk2MVlObFF6R2F5OFlYRV9xU2ZYdVhpWkxFU29KNS1ZaG5BWjRqMHRlQ1V6ZkJmcmE3ZnZ5VEhNMGFMN29Bd1M5RmIwcVExbVlLMV82NGJlQjhLTEJfWGFoUV9ZbkpNUXg2ZVZQWGJURVljSTNNNHVqRHIyVXV2dzRTLXptdEZ3N0dRLTZGdzl6Vk80YWJzRTVvb2laT3FvbURoSjFfdldSU1BUX096bDlfMVRhaVIwUzBUQ09ZcVg3YU80bi1sVXFpcko2ZzFTMFJYRUlUTkE2SWJXSEpGbjVueTJUZ09LWVE5WE90ZGFSekVSSi03cHZacS1uLVhHNWE4RlhrNklZWnY2cWduaEw2M3hkcksxUmRFT2d5cXJMcEdvNDdXYlhGb2pFaDQza25jUHEwbVM0bC1YMmdienZFYmhpMzhRRVk3VzRaZ2hueWJBT0QxNVFfeFJSa1IxajVJMVlrNXRGb2gxZ0tyZ1pTckdWRWJnZG52TWQ5dFUtZmZuNVhRZkdja0VqeUJrXzlJVS1wRzRON1QzNmozTUw4SmFEaVRYMHpjRVlCRGxuWEV6UlUwZ3BDdnp3UG5kQjFCcGdGNl9zRENaUDFOQVQ0MGdmZEFKc3VOaXRSb2l2T2tCbEhpYmVDbjY1MEI0WEZSYmdmaFJpTVRzVzF2WnM4OE5yLWh0dHc1SnJwMGdyQXo2T2owczFwa1BPUG5ZNGM3X3VXQ3dVaGFDVTF5b0lEYXQ2X2JRNUk4ZmJjOXFBQjUtYU03S3ktWlU5bkoyU09XS3ZvbHhiV2dwU2NpSFRUcjlCWFpROVlrQktGSGVvRGV4RDF6US1NQURtd2JnSC1lWmhTcXBXYVBNaXNBdUZ6VGU2bDNNdDduTklVSTVuUVJKSnkwTlM1WlBsWUxrX3hMdGZaNEdDWHJhZnRhaFhyRFpjNWFodDdKNURwQlV0VzBBaHl4TExvajdiU1RMNmhvelc0NnVRZEIyYkw0V2VsTjNBX0F2LXBtNmlJRVBndGhxbXo5cUlXdnBXTHNneEZ5SlZYV0Z3R1JCVUstaDM0Zmo1aHR0dW1FcUZZelNfNzBVeTljdWwxSy1qZkNXb1VTSDhFQl9nNXJMVk00Rks0QVpWNDRkN3FzSnk0VmZwUWk4WTJQaUJJVHVTc09UcUhRQkw3ampwVTNWak9NSVNRUi1XRFlzQWpORzJnYVpfVWtNVk9zaDhUQ1RHa2FYNXUyX1hXTzJLSDF4eXhESFJ2VWtsUy1sRWhOVHg1RzV5T3BUaVJnaWg2ajZ0dlVkbEdEM2VOYXBDLXpmUEVuRGhUdUplWFBqUE5PV1RZWXFEZkxtUXB1TEZfLXhXekZIMXQzamRHSFVpT2NocE5ab2VfaDZSRVFoTWx1dUx4cGJkLXhmRi1GTnQ4Z3FUeWwzMDhWaUY4aWR2SzlUWjR1ZHVOenQ3WTdtMTN5cklxRDRFVlV4bUlobFZCQzNCYWZqOW1GZ0NBckFSOU1oOG5GdTBFUGtUS1RoQ2pQbmF2Q0hJeWNJZ1JZaXhzSUdMcHRRZjEtM0w2cHpTenRQTU9sb2dYTmRKeDB4WHZuclVnRldDNUZIS3V1MFI5MlFtQ3FvTXA0bGJ0ZU50TURKbmQ3cDdMS1ZZUlNkODdDRUZBQmJIZXltamxFS1ZhdHBiMXQ1dWFIU3BxcG5tQlJWWlpCUklMa0xnRXAwVExBOHhzcEhnMWxvNjJ6UmRWdmRDYUkyMlJLWVNYcGR3bHNBdS10Mm43b3VqdzRMWmFEN0wzT0tLY254VjEtNVpULWtlb1NjOFhVMEpUbmhIaVdHYmJLbjEzME5fVkZMYUlSalhyQ2lremVXRlI1V2JFVDQ2cVZpcVI5b3FBb3lpekxXbXFoaGxORVFTZXNlcXdLUXA1NExjNTVRWnM3c3djYmstLTJWTHZZOE5WVmxCaFFKS1lVUHJVeWI0dE0ydzdqa3R1WUhHMGFPN0VMSlRnMTZoU3Bua3hZS0g0cERsUW5vQ2phTXMyTXgwYjNoQnNSOGh2QXN0UXRsZEtma1NOVEw0RmVFODB4eEdtckJrS2s5OEY0SHRteHFQemJxbnBPRlp5cWo0Z3BhZkpHd1N0TVFpa1ZLb0RHR1NFc1M1QTBJZDdBdEdGZGdGWjh6OFYySTZxOFVtckN3SzF4Z1dXSkRkTlNpVFlwT2pHdURNRksxUUtMVU1PM3luWDZDSldBOEthaG9JZjdSNVNXQmxtOV9VSUNPeHhJOGlNTmtDMWdiTXpSbDdfWU9ZV0c2d2d5YlVyN3hoeE1NUF9Sd2l0NEZyd0hPXzlYM0NEUTZacUpTVmd3dFZmaHBpeWlZSlJiWFEtNE9DSGZNRmJQalpYNWhURUZoTmp4VTNWMEVCWG5IbmxfRFNuLUd6bXZOcHNTZFJvMHZUVGRPb1RyTUVHcE5jc0s4SGwxaVpuMlJVLUFCV3lBVG5FRXg0bC1pZEVtZV9rVDE0T29CTTV2eTh6Sm9IVHNHcmpHeFktWGtJa0hudEpIWFJGVklWMEJ4ekVaaHhDd3c5MmNMTDRicEJZM0JSejlaVi10NnZKcmhBVG1BQ3lYY28wQ3ktb1d5czFhTW9jS2I0MWJvLWJpSlRFanRRdFhYaW9jRDJuZjlzdzR3NDhGd2FQZVppNTYxQmtYdDB0MEZfbVdZaWx3YmUyRDRaS0RfaHNCeTBsVFUzaDREUUNtOVdxUDdEbkRyaHBKbm1OMTNWZEZWUVZMV1BoOV9aQTdiNEthZ1I0SzdVS3FHUFI0X2ZOUFE3NUo3QW9WZlZKY2RMZElIUU5ocEJJNG9Ba0pVU0RSdTZmUXVMbFJJaERFM2N6MVV5X0xYZlQzT3lUY2NkcFdheVVDdXNqeUZ0M3JkcGFrNlQwV2t4dFNNcHdMQ29GWGNfcnp4QlVYTDhiRDR2ZG9sTng4Um5YcWVIS2RvYTVPR3pYSDNGTWwtQy1EYk5ISTlUaUt5b21rVnUzQm9wbVVBenpzcFRwUzF4RmhwVjEwVmVwem9xZUpjUzhhTUI2LWNyY1lEQm5KMmxpSkxyY2hCT1hsZ3ZLalBKZGc4WjRpVjBjZDQ5ZDN4YTd2WGVIT1Via3AzS3lheWtWUUxhSDA5ZGxrOVZuMlFweFhiaGRJb1RQWlZiSnJCWW4ydnNLRXloU1o3VnJKYmhwZ2cifX19.rzRJtm9JwwdtV_pyYoLNMFh-LeT826WsdO_OSU3s5Hhqu9iZQ_q5g7d74vPNB62EtcAV1CrcpUYorEeJnYyatGz_rcqTHwybNysflBJCBlVK0xBhrdC8LhLwLhhFLrIDit1VP-kZbF2PQXi4pVwRQNRVdVDoSx2FDf6EVlKc6TzpyRJhkrXrxtThAmi4kv8_-58V5L2BFTqrwGzyaaZaXU_vWqHyQzM_1p0Nzw0KrKHIZQsvjQ_md-_TEgK6e0_cUg7h43AOygbek3GfMn9X3gzVA4WVuWa3BcUtlAGZreBDLCwqmaGwWNeiE--P2bHJN-L5Gwg5SFYpIw0VN0nEKXvGuQQH6NPZYQwcDLaclkJNw3C2BtS1FE3XJfrQFMg8Q_XDqfB7VvKib2AYK8_5Ss5Iz81WlpSwvRyVBdTe6F0zf1pJTfnmzGfKHACKyL4Y09t16EmBrek2Zbc6_y-EP4QD3CJV-5GtDpVn7o6t14YEffSZL-dQ3gixShl91wIf4WSnytCiuZm-dqQD2eVkOP613m18UKQ4a36euW_I3lPm_72y5LqUg5Zcx10DvnsFBcBIhuOGZOKUvfFkINwMUEfNQzYME_okAfBtB1NMy3u8z--H9-a36Kgq7zt0Cy4JD-S2E0YyNTMx_BgnsuyLbklKVzRMfXHhy68Y10gRHPAfUPkxIAdaIjF3olgQrQH16tgg-6morpe-g0iEtug4XXFZjwljIiT86UJiF2haJnA4ORb16VOzlOUXEV3g7ZXsNRFm61F0HDsn34Ii3n-guRJBEgprqp91R7XS8i_qOXfAJ6_0ycijSOEBl7WK8uLhfPQY698UtJhvpLtmtzP8oLxpR0tfeV0i7T-VQOA-d1g-De6XF0p53e2DHdEWDZvy6uqaARC52VR-uNsVljeVeuI6SX3LIUQ6U4wYUTy2pBjL4N0MyhrrYG9PA3lihC9yKZyUrRO_AhsMs6bLgmDgUaCI718y70GyoWIGk6TviCGUImCsLBT4FncJpwHHJCAr92J5-nIjEWJLk_UW2PcZOtQCFvTFnXbtab1eZLAAxYHDHtVNix1HOLS6QzzUPolYpntE2y4LTHyMicUjMQOApBkmlfgld4QaZPlqpB76TQPQTQswE5Lzc1KM6h5R_hlINhChWilGd995xf9KYvPMofKT3yuSBU8kZLBNBOXW_T2WWPrOjEL4rGZbZw68sG0YEvN3AoISvGMeTyO0uoBI9Ptvo1EDWz8TJ1wTzRUFUqaKTvAFLphIVuLxJFW8FW4QejLE63DEqJEm8kaZBT2Lp6i0PdITvDG13hEAzfvchhLHq1NsSXc8CgP8KeBDeaTLCOHs1UfHIcFsGabTMkMKpooW7_2hjzqamMhT4RSDjswoaY6DGEZfJS7StAnQA0GOcM0vONMg3nJDqL_PPtDDhccYiDVoxPeEloonb-jnFsSarokclQPbs6HifZP6fsfH9UXOxKz9BUlzSBl6eDb8b5B3x6jFe2sFCWCuZ5a-DFbxVpy-i3jeua4rznyi91hWDGgaquV5zXOzxpF3ZaszqRqmBmkpRhoRCLRF4MAFIl5YMNhgJdfbouwhnW7FDICJC3miJXCQ2lebXvhGZMkWR2JYWXE9-j3EKv-6vJO4XbxFsfuVruHoA4vC_XRaSeQClnHZBgWxvVeVwLRYfXjB1OeRrhb4xaNN_6MDLJvHlnfrgbfaJAAH8VhKIPo5w4EVc_UkRZ5WUDzrEzngU3HnPLQKsSRvYPVSYPvxdSvYUPAHpx3BK57S_AcGIjc7S0ILNUEbJXi49XVTMb411iEDk7_lQ2J-A1XdUofeT13yAVjXbY9vGTh-yh3VY-FYJyHn39ckm10kIlNpQYLC1xrTJZtOLys8bOW7tJkQmMT1uXJofi0vc0CrNsUOV_RPQfn892DK0l4riaVYZrE8cAl8Ac8ThtKev3cVHwNA_C_Sxol612ZPw1GrNbCRriRG2ZNob0C10L8qce8g6Yi4dKm8E2__iR1JqnJ6wsdS3u2QbevjxvPsYsxNv77GmyXsbL9M15jqCXDJlYYwuFXnhtvfAeMDjoK7vCJna4OxMX9rL5AwmKH6-z-s0tKImzhZFrjkWskIzABmXbY2RztStW_t9E8lgV4qSlaOO0X9rtyx9ExJqHUYcM9Db-_7Z9vl7LCn3TkplgP_hIc6aX5LrGbrD3ek-yPPbjAq42xDCYbKK1jaJLeW9Udbt2cMDTBPkUzT7jlMo8EMjKFCiQp5ynjp-m0ZZkmpUpHOoy2OY48xMlordk_BY6HuUzECzoLKiYjDqwui2Re8Ab0PwJegM2myMUV3CmAIxdo1kb8aYKo6L4scIA6y75GEwxtBWjTA3LkYB0l5Ab-uNDi4Xkg5p9U6QN5Kq9_hCb3hxMRYiltm1wfb5SjfT6ZA_nLsGF2N05C-YOfqmppHaBDWLxiXIjCbC9GADedC-TH9Q9sQwWQ8x6wcQWENOkLtT6Cdade9dA7P1rI32CzOpMvMADHm83DgM1SliT4ZoVNO2R2xYHunoRrRcfvqjZKO4khv3bfZzR4YIAEYdWdPV2cn3Gszkqz8bUA8CvQwawwibXmBFvcbkZ-2ylFAd_ZpW8NRgroxnkMLRT5h9KYw0RirTF7eypOLNheyD6Julb9lo8u2cQ2PcaUeqFcXsas7tjU-c3yuDgcVuo3JHXzyXcHef0zMi_vA4nZDbfLWg9oqSnivRuJ4sSVIlcb6S_ZEjVH_DaGdINHom2DtjkEpC2_GvnFK09bpNQfGfWz9Wggv8VGuiEJy3bxQH0jNpR9A1FpkWKoXJbKHP9LEIM5gogA138Y6u9dQ2tg8CyXmOjYEu58tTxIcDucTtPLAGbMEjegtyLuxAoCg3vz-HIyJvBhuL3HaDkxJmafvyZz3Ahv3JlzrMJel8TrzofxUWgs4IjXmoETSbN2Y8YhFmNuClXMDre0FZ4pcB7JW4ys2cWtsIIwcyroG_xd5XOGG_VLDG1R4YCFsZbxgjs82olNEI-qGA9n_00LVch8pXTqPHP8Pw6nNiBgek8qjDEd9ON7S3q7DkYqHjOSbPsFLJWz_Vejuf9GPNZQCqHYUafZSPc1krtETreauN4OAyCUJ-LW2WVsbqK4_D_1CL--atJhxqQQrK48jl-RPPTC_0bPM0ph3KEZ1bWW3dh9xRx763TVw4It-oYrF9WU8BSn43HDtcSGtE8QLHaFoXxLIfbf3RC7V-dfTFr14InB31rCc2ybmZPR-TgEcC3mNajmJVIS51geUNuBRuw-dLtQSAcFzqrcu6J7BjSRF0viSG13-6ObAMM5ugFGukGje-pQgMv5mHK1Z0p1RKl7GD6gjGXTvZl4fGpjAqJuzfr8kOQi1nv01Hv84NnmpR4D6EpO6PGk28jnRF908xwxJa7FzA-_6CyrqYKuGX2e4uF0RHFdlHYgGUVfZThh5kTBwlF6uors9jlmuiH6gaoJUhcHuQHoFMf1ZeWc-ZZO3HczJb2N44gWhMWxo38SjSjBf9LoaDeOp7mvKW9huj6YHaNLiz5rwXdTTwqswqdU_9qBq4zZGJAjmW0S_g4pLPLQdhrpbp8YFBEOh1OeizyHLwgWoQEvf8ZFWeBT_brmvat6pRbZ1ZTuYiL9fWJhwTOY3T55RE7JEBBdtOf8wHzUHaNyI-BZPVbBRu5BPGeErpINkcHopWGfmUMHdyDO9u5risNdGiqxl0IjrKYghMKDIa-gW1mQtFCQWGLA992pkIapZ3Squp6K9lH2Hoyy1ODiJ-t-gFCA44QfkXgWQyIRv2BZap-0BlR0TcGM9W8z8giO725Pj8fmmPnX0rKP1KIdi_UYFH0UwG5XKDugePTtOxE6RxpLL2oTkxrNZP7FsCStMu03jmt9c8LQm2mAb5Bu0NAV-mvJAa26uGNrpVs-aieO7Eq-YtqXnBa5PLuvUaR4dNQ-wnmpkAmtqbt4ALEaut7A5Kb-soZEOOx0i5suMEHJVH1rcYTHtSp7awNsUbu8az1-ZV4qMSx87QHy7sHCeZHNtgPT4Ar6AbMwzFaKUkrLVL4JsE0ulFY61mED2MhrmxD5AgyXOUp7hQUI7olhhFCeth3eleOeo8C5zEqVTaJ5k7dTiv4Zuq6y_68wgIbF8vgobfFK18iqXC3UMh3P3FbA1y2WivO4GUj4KfhDWWlPkoJ5Zo5wN9L-_OMRAUVZbOGwSXRFMW7ONlyPFPBJJj69oeiRF1xpUPqkjNqH0Q81NInHishyIYy95h2LIVg_VxHWJq0ttE4e_UY3aDPGRec90Fg0ue9YF9-LrRCPsKBCVEFIjO4NIh07nFigU-cE0hMTnAwgdJVJ55Pb92-hizjdpgMXyLDZ4ut7zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA0PERYc~WyJFRUFTNGFoVXhYRmxkX1JraWttQzB3IiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJrYitqd3QifQ.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IkIxYnh1LW5uNXRia0FuV2U0cF8zYkNEWEF1VGpsZDBXVldaQWZ2NWhlLUkifQ.A1HrZsE1X-F7fTZGauV-cVRjQt2fMo2CUKV2Iv95uwYP8SEp2dLsiiO0BItZaT0Fkan-J9O6K5JmXbHJlCr3rX-1Hhh4HyMCl_aKDGpgQGLqkI1BitaIxJ0NaM6OQtzBMLRiN-2Rb7M0wVLKazVGIeLxUvEsBCyAh_biD_NXvj6SJ8ka5Q3Kx2op_5jTlrVPUBgKPN0kBYSQuRbVwQsMvnHysocxYipzjNP7RKFgHnTqnn8MdoUC1Uy6eahfOJGq2f_68LhKTR0YNQT7ege7XJnQusZ20ad9X6WKKYVo2eIDm9BJGmn9dT62z4m10hZCm-oobtSO3ZGyl_n-eIw1NFYVTGjG-aXJVzDA51dU24yLkYY4E3XZ--Ha5sBkCNw4adc4nay-4SqeTYbLcUR2uCja5e8ZWV17Z2muZkaiH4scWPPrn8ZC0Qgx4hNPpmTxrnuYrgW7l4JqQGZas70lFS5ytrqTemSq8oh8vEtCa1GYIKETM-e2ioRe6SbySB2uokesThIhrRMz1IEqhHu02gl8SQEDh9KFazpVSLFzT80eZ06OD9DuL5gcwk-6ATLfDMT4LfRgRAx9gQbKxosJM7-kQh_rZQ8ooIQXX9jioQdl4vuaA_sRq-W_wFSlwfWVD9YGaFmvxLqpfbVdZiZo9A_2ENpy0DNAf6uqInJc5eX3vPwvl46AxVNK7t56mrn-MyQz0nQt4d4Ut9y1lJt80BsOLPcQBsZf9wvlXcZ4E0--Ry4f2sm6p5xHXOVvIeDGOvkYXzx3QfPWlHNo5RuXkeUwO8OzUaGBLTOzY1aUAU4PYyiZwkHlh2T_gVdhh5i1egmlSYL7rimmI_gFXLadYxY1KclKY9l2IKEhfFLOlfPcRSkOQmcYU2tocQuKG9nU1lZBOfPP4shc5kMb8B173SprmWbmNXrmZdWZZwp176TX-DZj60XJjIpzHQS6Cey49UyKifWlBV7g7G19KnGihZnud_bxMKKnfb0mhfqZZJ3UJWzDeCOcBXNhftQ1AUf1DKNBE5MxYl_3z4f7LEQTUlWNK-nSxOfgpmwZpFDv8pWQYBBRwmXVb6IlM23g-kQnd5vZohn2W9RYCl8m5cHNLC8RFClrZbBYvb24oICOOLYBtdCo-3QPpZypG6hZroDjrztd5pVMzf8Xu8ANx64U9_LpY4M6SC59pVO_keSk7ZnAjnbGvXYFsp-9IrfLWi-VL7S_WIgnr-Em3nI1u_iPpksRtY_-AsDNBVis2U6D7Skju0Cf3wPN-625PGNKAVeZXjqByRljuMRv3tUmfxNSX2AkBTf9Ua4jYNWUst-KLnJdR2MTpqsbVivscgHAYXE3jCcTVco67G3qrNW8VrvDdYXVK-6Mq_LAnls8beXbsCg1hh8jqHunjp1k9FQd2h7tQoj0Ai-FhN_vtOJaeQAnUgEN9VXsiOQWsKaeH5f3IV4SmAXbhIQYimMQSHH8hOTNsUJYkorJ9XYoEl7VPqwpyp7MElAyIbQKePAYzanpAEErKfHr1ADXtx3iuVuowg9dPSXXyZj4_Pe0Em0fLKvv8rDTYE8mRCHBfwbuQSA8DVjJSlH5PubIV5r9SK7HVJ_APnHAtRs6FsZgvyL-SagP_SYrZwtNgiXTpFTYtdmy1M5G3Y1GEkk0ZaorTPBtpj5HFgPg-FkTeBYDlMnD5sqm3pns9N9q_22NGAPxt_cMhezny4eoNXPzokJy73Y03PWCtetcmkdDT-Zv06GcQwA4FlHtS3mkVBFueaeG_dBAYsZmfWslQmFyxHH3bN1TZOshNsurkXU05pgCDzpoCMZxfz8rkkjbCnljNO-iwOxHz2EBbjRWOjNPUp2WjRa03MMAN71AhlMso78kBPJzoxgPSMvAlq92njXoByD5ODhHd0W8TBS7LbEreBk1wfouA1OAfgFUY3AlSmgcQN_fYjju4cnq7gn1SLqFC2Shnf_zgBC0Bu55GPVk_lf5hilER2kpQjOvs3A6v-uXebKLkQJLLG_28a9CS6S3ra9i9DPr-f9b8iVTGrA4NmLLvfFySx4uGzXGmTQ_yritOx0yri6dJvAnqm0Xce50Zhx7cocJ2ij5sbSpo4YuoLZBQbFE1-ykbIUjK2CVkdkVTYC2cQR4I121XB02kt6z303erUc89eqIxb0ouQYvU_53XElm7X4Eo1UGgEfp1urLgWv_-3_qiUKzoGB4vN0xrnmlg6TK7hRWMecjWGz3b3Pn6KiSIawGeGNDd5RtkeFzkv9Td5svPaERZtGpskGc6RCeIBGz5GQBtSkWeJc1gkE9w5EyhlNCewDn3YyF3ZgYIvbfmX8sL6NiyDS0O-MmlSdMwuKvxrHchA0jYUimEvoWPDFFFFqDfswHODs9Ae06HRIH23su1dQuiD7kR0Yc-U4a-jUS6f4qIbDuMOMnrsZ6uWlr8u8IREMrVcu9qbmx4vdSB6DTgsAlCeV5alnc5WJZqP6Qy3e0wir7AMDcYrMp5AGyhTLdNIASQdUrkPrzpdmsTehd3JEl-VN94pFAWOKz0JhmNgbQhgD6nsFCbsxmb5S_Lik2meb9CgZwZlIt_r6WIzFEFaLlobUFKo3eh2kblhsxFZWyeUi6glWmhICNq_yJf4jgg9hzAFASPdSolc8F77VO2QzCqSSQOmkpf0w2NrwKVFeiKZf83tk4nQyYu1jj4IkNjgPbibd92wCjiFiu7_J5Igy7cOMDpjy0kjujc2jkCyMm_mGfDyjwfn4SbR5u8hS3rkSnR6nCAzh0j118lQ4hFEcwDH2MBfecLsUjEuYj_gh73t2GVK3PxSMdVRmSUy2dfd0Vbqb41xuIOqnr0k11dJP9qg812GaQzdWgAA_bxVRacJ0xO8OPvc2MoralPuw8fWXnH6J8mbXEqV-n5wfQCZz8EYrCZimtFbg29G2tmFfdJLsIYOvVMPlbWdzoRH1elqnH_OGJN07SMzBKWts3divUoxI65dUEy_gh4v9ZVBfiLreTNeYvVTn_yjACuXCkmWGG6mkf7AosBV4004c4e6Jwd9uAELLVzlILZ5ZOzECTjrOd1ZT11oUIW7vJYKuCgqegXDEpIB6abmyHbYsNE6rGU9ZEbixQ2d-x8V-_ac-MBGmn1I6zJcPXkCUZW9sdqlmdbad4AYuJ4f0ts0KFmwimpOgCeN2RP4aR6AMHmVXqlB-pP7-OF8_Wohe9F3WfLszYE3z5IW8tMqt-zCu17GoY3orqSJSXSytOa5fz-hCATslXiq7taFOPX4nR5iwFd6bKie-QZ24skWHJSjWH9P5uIK2fxaf43HZJMoMIvPSXnFHXBogtRNm3GMs4xQA2bOoDxQTHCE7TwAXbeUqS-KlhWtH8jwD_7ODQ3D8Mn3vNkdNDdCmoHxjFzdrK-lN67S__yvwYDi-LTM3K06LcApkHwPCJ52r51bnyQDgaUxzrsQTmI9l3Kky3TIXFu6gBAmFJ7fvc5D7s4-IXlY_kNi0tXFgI7B7dyG3eieEGmKBPvPuCu9q33bzM1EjWxeBViukXwjuiDEdSlGSN_vQaLD2MKbTyCD7GRbyQ0wITH_DqYpmkjcKp_UDT0BUgvvUGZunwg7zeTEDh6gzVWKj56JViUwdQM-KR99EtaIPJ2NFKqqyyxfVuWg6efxLzphSONvwE-bpVOVw1BNYgPFuejvSRtl3QmkwIZRsGP8Fvn1JCsvdbjqvG9kVJK4sAOTrDDII8zFq7aXDcpwEm54fQp1tlsP96G_xNqCjnCFfDz-ln-6ET7BfQFaBmcI06OkUxFWfC2KVLxhzN3n926oMDhdUhXxYTc-LZg8ZvBo3Hbuz2PE_7h2Pa4BjX3CeTSINStbFRrwY_wFDy3TYouROYDUbYToB1pSQipPRmirIunlaah6cqNOVBT7Ga9weG2XeakoAF3R8xEGwCToVZaRPXaYq172q6NAhrqAic461aJxlZMJZwf15LNr3NilCQ2lGfLpswyw1vp9WwxyidoQRrK9ZeMH7PGLBVOxAj_5KAN1xqqYp1Xofj8dCfjFjbifYi28w-VAQ9ylIljiwpCnpWRBQWMgMUmL3f6cAOQkZCKlO7g9FkDBchf_a9wsPa4CwTlwD9suLwQrxoBEBB4S_4gDU7cZbi8vIjiBpHDXpmlDEniVrKgcYKqpU74VfgGm7J2hVAoRHydjzlFhTkYkjJ9NKtLdQkU0XZmj_l1yI4WdlO92akBWQKaGKa4W5CS2XwIO4tFxYL7nkIeXQt9_F7yRgLsWN_vW2wuI2DVN6VkrbU2d8XPJ9bfcIOd50mUS0O1S9ftP_q_kbJJq1CtUFDXx2i2R8k9DpbL71f01vPzac8SFVXcSYvSJaio8zi9v4CJCpYWYet-wMHNTpLpbq-BkBrvtBrcH6YAAAAAAAAAAAAAAAAAAAABQ8XHyQo", + "issuerKey": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "6Tn62tdcvySXd3_zFVswffd7sUi83ivTEAoT6I6wLYtTPtk9LPsIOH2SH7px6QgoZA0sG550ZsADKBdHHacbhfWSK5RSRBERfvZIiRhRi9qDazdCTx4t3YxsfkiuRY3KIlEY5Kzq0HMkGycGc5j22IljA2xc7CikUuO9_b1LONfSAB6ngI5mIs2mfHhNxIEaEjG7LBZsZ4Ab5c6Qv9SCNQ3xJtGhuG1eCJ-CYp10DGVphemZLLJAT-OkL7fIWmvMhvIMZKxHMMCU6vFFi3tXIfMVM6oYcw2oJmWcT0Hq0XFP8Wd3qDIbklJ0eiFhjKELZUzECgYCGyl5E-1gd4PlhNf9prXz2npcGwoXv1Hwwf18uWgzBjcmSsDwFl4nyF0eSjdn8dTsOgYD3kkyfuzUrF6Bn0cc4FHLm9PjCTyh3XaMcceJUjLmiEFORAB3qhPVY8pF05AX5Z_5IaTJBfCkuF8GRmGWQiB-n-KfJ6nxqsq-qoCcL3wfZ-TN-xKqHindt2G-3GRxDL_0_2Y8OVwhL_Mpuv3kC52rxCZmZXmJU6U3tCynnxYnsxTX-pqoAbfpuNP2CK7P4I85ljOGS3hsAHNvq7bycr2ENQr_DIrnsO0p8_AvXZo4PxBl_o-QrTtAsb6iNbPGfUPBKyRTBDl99b4eiiLK-tigMnAD5oFqdFYW5kpYC2HhohoGyryQgf_bqcmZgBwGRUhw2qOwTAqxbwl8mAP7HGxXiv5L3ZEfuRf-S_r3n4XWn3E0AV2IkrteKxY-tN-N0DjvxQbdzJF9kfJ7GMIDrLKJVtFHpcOJs0rZN3LW3RC_aJt_3K1djXiycKQhfU5YrPCvprQYcMRbEKXRQcUWG10NutjJJC-CbJTNYvQVAqlnLXy3JZDOuiEaGLXsP-2DOTL10UYh490PUTDwNDRKFdcN7kX8zU6dzQPzwPrzQCJlaul975Ft2SAgenYz4bOHHVx1qFcA68HlTDN1eTCOjUgrofZLyp-mCTZKKKMphb_e-u0LyJ5oSRGz9V2alhjB3bcDE_q9fXT7ajBX5Bcda6x4727JpN5SINavLj7Sw19-ITC257YV7uXxtzg1EO3_0gcXsDIdyRCKsfPjCDWpJL5Gc2-TJXK79sTOfgQSeUp8TW2u_qfyFbGFSDS-TT241Ih4qGGF_LAF3YVGt3XfOVja81bfeJdVmRY9NsXuUi3tV8gVpeAt6DxRnJVLQG33uG92fIEZyuwaTk4FiCy-VObapu526RqUiN_Nq6Iopvu1gm_rs2IbhHWvd3FAmPUO18H03drYOVRyrfplmPvotZ3AyO2-49WTAqZWLvbCw2ae7uO3yJpIX_uHyOBcVG9QZNq_kZ4uVxj7JXrI7foremuuBTpfSsfD72QeUUHzHkzekOKuHncIA9e_6nsc_xzl1yJinvKtpPbUdAq7yCjJjJK6cdKXTP-xEfR5UlX5-vq_25G-gL9IDpen6mG1JBbxQ8Bk1uEPWculbYSIbstvNfo-zbfr5JEQ2lrXrvLEbxbECu8XOrobS_EzOb2FjgDW0ZEg3LnEpd5dGWvHIhT_MBFa2R-VyjnIfW7mBl_lgdP4T8uw2_yP3_bPadkHZRszoh6c26-VZT-tCM3f4RcL5xyu823z4wMOfO43OU0M9CZ42rT_r6UdQDM0H1NzDe2wKvl2xYAByrxrwk2vT2Pa9wRhHhfq7mnhwtkhg_w319OyrX_59Cq-BVoJlMOh3OWDII1qUKcnZODIB3LxIT9c90ly9aA9FHbLdUyteL-j2r-g8lBFvENhnAIVtIz3hPxj5fAIzyXi5tMpZLghO7YM21Ai9e9Af4BTpInKko-EYLPAZt5IKhLbSqvAi7Qt_AIHPfESSlWKirb_1j_MGvvLO9ml7ql2rDSHPH2a9mXvEQ_iugPuq6jwq2XuIaI-AvqU3atM9CAgpvYDxmn9rMuHz1Ad3o-UmZugCx41TliIZlDQk9QEpbPYx-6FiXH0GxS8pM47gl-LmQpDhSOzmUsxZN1MBytrH_n4ELoNp2_VvY3otqz_QeirughA2xxt3gYEperIcC_adE3GuiUR2ymOCWkC3owZpi9neidnW6xxYMoDbRqX-4sy1HeMGzkgxxH4fbtr8TFEVrMNoq3r4mtgDw4oaGk2JrYMwKNGBr_O_CZziMQKHSvUDpH3BbKHN2ZgiyY47RjyDGjG0rfRzY1RbcFDjlq5y6bSoQ1dC4a7Ax4qqb11YjDnlELBuV33DGcUrblExrzSh5TmS9JYp9DeetQA8lgMyqjxKQpw2VKyVjoR04_fYfxtTjIcfScczByG_dzOBpCsALJmbHwrtCl70nHygLmvA5_0Hl7eB9kbr3RyT329A_X_Hkw-aSPJUtS2m-5otm3PK-K_pXoGkvGwYooIHQzpg7KZzO-XqCjMECdaci6narK464wqQxEk4aJMUDIffsOT9rxAWa6ll7QU33_u-Le8Lx2IvfNgphTH_oOVZJxMH2am9_0v-GPTSpV5sJC7swUSNv2rLXo3Sh-nP5LjUvcjYCypMS0g-lF3E7oLAweqhteaI-sKaavHKzgBSDpfwGgZC0krf1J2BRLb3UL1wXgQCbstBbA" + }, + "issuerAlg": "ML-DSA-65", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.kb-claims.json b/conformance/vectori/sdjwt-presentation/aere.kb-claims.json new file mode 100644 index 0000000..982aefe --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.kb-claims.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.kb-claims", + "artifact": "sdjwt-presentation", + "title": "the key binding JWT carries no nonce", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "the holder signed a key binding JWT without the nonce claim", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsInNkX2hhc2giOiJQVmNXc1Q2dUlRYVBwUVFDNUFEMlM0N0N2eUJZaUUwcUNUVWVLaXdGX0ZVIn0.2Xg-c7x8cfyFRyP5Bz4Or74pjvWqUgJgdkF_JlnjRrUfd5-YqrBxcs2GTHQAOOCy55_CBmGdSJf-N-aUxVFSAA", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-claims" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.kb-cnf.json b/conformance/vectori/sdjwt-presentation/aere.kb-cnf.json new file mode 100644 index 0000000..7803bcc --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.kb-cnf.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.kb-cnf", + "artifact": "sdjwt-presentation", + "title": "the issuer-signed JWT names no holder key, and a key binding JWT is attached anyway", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "the issuer signed a JWT without cnf; a key binding JWT was attached to it", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE3OTIzMDM1NTIsIl9zZF9hbGciOiJzaGEtMjU2In0.siec0A-CE4I3kL_tWgRWscIb-i-cSNws7MUJgo8it7rgdoI4_wj2hacfV8Pl3GGUL8vft-cUTJp7_-E3QX4HBg~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6InpSakFUMXdud3E2dWxXMnp4UWNGZkp2SzRPUlladW12VGZfMFBQSEVHNm8ifQ.6BcEj9ctCnkuNJjhs7HqjtwFgRKOXjQRsRbqqzN-IMdI63Nz6C6NO0c__y4EeRp7f4IoNvbqvFL9ImfbxHlKAw", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-cnf" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.kb-freshness-exp.json b/conformance/vectori/sdjwt-presentation/aere.kb-freshness-exp.json new file mode 100644 index 0000000..46de945 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.kb-freshness-exp.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.kb-freshness-exp", + "artifact": "sdjwt-presentation", + "title": "the key binding JWT carries an exp that has passed", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "the holder signed a key binding JWT with exp in the past", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IlBWY1dzVDZ1SVFhUHBRUUM1QUQyUzQ3Q3Z5QllpRTBxQ1RVZUtpd0ZfRlUiLCJleHAiOjE3OTIzMDI0NTJ9.rWeWitBK6pQtGKD6koJkM4TMssJgPMSUa07QfCMnpNuWlj9X8UKV7T_FrtP5xbTcl7BwkcMmbrSxtEvUo8EoCg", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-freshness" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.signature-kb.json b/conformance/vectori/sdjwt-presentation/aere.signature-kb.json new file mode 100644 index 0000000..5bc8847 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.signature-kb.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.signature-kb", + "artifact": "sdjwt-presentation", + "title": "the key binding JWT is signed by another key than cnf.jwk", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "a stranger made the key binding JWT with its own key over the holder's SD-JWT", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6Im4tdnRaMy02UkRVeVNmQWEwWFM5Zjd6S1hEdi1NblhmRWhaSXhNSzJmV1UifQ.bDoA14XQGrt_QnBJqIw8SqdhPszP8Mn-nbhVKmifXg-ZNDey7x_NFjVRP7G8or95EZ1k3M3tbtnFM6bysU98AA", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.signature" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.time-expired.json b/conformance/vectori/sdjwt-presentation/aere.time-expired.json new file mode 100644 index 0000000..049617e --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.time-expired.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.time-expired", + "artifact": "sdjwt-presentation", + "title": "the credential expired a second before the verifier clock", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "the issuer issued the same claims with exp in the past, the holder presented them", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiI3WnV4b0RhUEJDNnpRLUFoaUFqNEZxdl9MVFpFYVJhblVoVHFXZ2RWZ3FjIn0seyIuLi4iOiItakxQckhtUHkxc1FyRkJ1RHJabzhsYzVjRTdWNjJHQmpKbnFreVJiVEpRIn1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiVng5Qk9ha0FGdy1HNXpRaTdQWFpPUEg0UU5sSjBUdzhyY01JRWRydUhNVSIsImFpT1EyMVNSWHJKaTJNbHBZdGZLY2J1Umxjd2ZJVWEyMTlaem9BWUFmNVEiLCJtZEZROTJ2bUF4LXcxUUNpUkxUc01zUmY3ZTY3VUhNZ1R2NXdFMWNnNkpzIiwib1RaQWo0QlBXU0ZQbUtSRzVmaGNrMGNod0d4Sy15eGxWRFhIN1UySkRzTSIsIndrbjI3Q0NFTVhPSVlDZkxNZUEwSXVsYTdlUlRRMXdGUlg0SmZsRy1QcmciXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE3OTIzMDI1NTEsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.SIhp6eXkMpF9dA3qjGuCWs2VMZWDeiZ0NUcGMUEX85bCqPvtqneJYLSqJWJ5Q58BqQVR0mLM7aYqsL7lD_yRBQ~WyJJYWlXZGtiUU14Q3BHYWRyUHZDcEpnIiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6InhNdHNFdUxaWTRtY1RpMFpZaElUcnotd0VUV25DZ2t6N3p1ckVIUjgtcmcifQ.uV8nuxzewFxbS5zCIw9eqz_bi3qu-0t4ZAQU90shvQkiDE53LlglTR8zkaHHp--QoqcjlmlZmYwhvjyaIOciAQ", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.time" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.time-not-yet.json b/conformance/vectori/sdjwt-presentation/aere.time-not-yet.json new file mode 100644 index 0000000..3fc703f --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.time-not-yet.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.time-not-yet", + "artifact": "sdjwt-presentation", + "title": "the credential is not valid for another hour (nbf ahead of the clock by more than the skew)", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "the issuer issued the same claims with nbf an hour ahead, the holder presented them", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJnREJuVktpRVp2X2wwTWdPUFhveU5XcGxyM0tPSlgwLVQ4S2ZmMDhMMlowIn0seyIuLi4iOiJVOUFxdVNWeE1mTjJpZUtLTnhxNkNDcXVwaEg3M0FMQ3pEMnY3V1F0QjdRIn1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMjlXbEZHeWFEWWJXVzNrZWlMaGYwTFlaQmQ2VGRXY25lWFhkRjk2RkdZOCIsIjYtOThWZy13N2N3aG5kX0lwa3A0YWNxZE5VazF0U3UtbGNrTTlEMVlteTQiLCJGckVnTllsYlc0S25FSzFmdzFhSmJNekJwZmZjTjVCbmlMTUl3SnB5Nlc0IiwiSlZmQVJLdGc5dnZmSGVzVEpDSXJXRW1MMkN4Vkg4QS1HbGJoZnU2aENHRSIsImU1ZE13bkdobnQwTmVFcWw0QlBCTXVCU09qLVl5SFdiSlc2TDhvdVF1VXMiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsIm5iZiI6MTc5MjMwNjE1MiwiY25mIjp7Imp3ayI6eyJjcnYiOiJFZDI1NTE5IiwieCI6InBkZ3dZUnM4S1N2X0RJQm9oQWFpbHgwSjFLTXFUaTJ3ZzBUZjdOYlo4VjQiLCJrdHkiOiJPS1AifX19.sy5GRqEhkvQAdNM_C9IMKBpsSF1Nbna1Pq6bR7gxmsBYkwR9_5VWgBW17OwKkhTKxGiS25nGMAIPXmyyqJ9qCQ~WyJiZ21OM0N5Rm1jclF6MzNMcjFBWU53IiwiYWdlX292ZXJfMTgiLHRydWVd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6Im9KSDdQeVhnTzJFNVdQMmRGMy13SkNaVXY3UTVpVm9FUFY5MExqeF9fNncifQ.3Q1m2Pjpv2H5mES1aEZRu-Ckh_nrPwP2Bu6U6CVgFL5lMTDDbRoxN18nFcMf0bjAMBODvOAMlnfaXf9rsgMpAA", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.time" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.typ-kb.json b/conformance/vectori/sdjwt-presentation/aere.typ-kb.json new file mode 100644 index 0000000..fb7580d --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.typ-kb.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.typ-kb", + "artifact": "sdjwt-presentation", + "title": "the key binding JWT is typed JWT, not kb+jwt", + "source": "derived from sdjwt-presentation/aere.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/aere.valid", + "mutation": { + "producer": "the holder signed the key binding JWT with typ JWT", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IlBWY1dzVDZ1SVFhUHBRUUM1QUQyUzQ3Q3Z5QllpRTBxQ1RVZUtpd0ZfRlUifQ.M9nBOLw7TTvwyvSIN4MSiq_kXalf7oEVM9VjNC7ijyzRAQeLSj8PYCb6MQul6OzAL5WD6lHVbI9HemGpDnpODA", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.typ" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/aere.valid.json b/conformance/vectori/sdjwt-presentation/aere.valid.json new file mode 100644 index 0000000..390ce53 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/aere.valid.json @@ -0,0 +1,59 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/aere.valid", + "artifact": "sdjwt-presentation", + "title": "an SD-JWT issued with AERE keys (EdDSA): two of three disclosable claims and one list element shown, two decoy digests, a key binding JWT for this verifier", + "source": "producers (sdjwt.mjs: issueSdJwt, presentSdJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImFlcmUrc2Qtand0In0.eyJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJvR1ZLcV9iYUlSbkdjX0x6S2c3Rjd4R0M2OTdOLXJSWjdNbGJMdk9jMzlvIn0seyIuLi4iOiJYU1BvSVhtdkRMMHY4a3BTZ1NGZ3ZuTWZtcy0zTllLdmtYM0cxd2RCNmg4In1dLCJhZGRyZXNzIjp7ImxvY2FsaXR5IjoiQ2x1aiIsImNvdW50cnkiOiJSTyJ9LCJfc2QiOlsiMGl3bk5fZjRkSGhfcUI0SlhyX201OGdoWFNYRmk3LTk0SDR4QnpOdXBMSSIsIjM1QnNjekpxVEdFNEdWY0ZZa0tEMEY3R0wweUlUdlp5MVpSU0x2Y2tpdTAiLCIzWm5SQk9fMGFZbUZCQUl6Tl9QZmdNYVlacUVYdWNibkg1Y2E5RFNNTFdBIiwiYVptbDlYNUU5cDhxaVJvcExVeGtTeUpsXzgtemEzQVRnRWFEanhBQ2o0OCIsImpLSlJ6WS00NmR5cWFHMnliQkk4OUxuT0ZuQ0xRSl9Ddk5rWnlnOFVxQzAiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJwZGd3WVJzOEtTdl9ESUJvaEFhaWx4MEoxS01xVGkyd2cwVGY3TmJaOFY0Iiwia3R5IjoiT0tQIn19fQ.h75vV6jAkI1n0st_TUrGseDJKEk0RScfX5neSm_CSN2GoVjL2Ml2oKmB0szWDCjjlAcq1Tn1B39KNwEE1dWzBw~WyJSYTAyRkdCZDJmMW5HRlJPUFNUdURnIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJZUVdma1BBSW1UTUpTU09vNmQ1WVJBIiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi04NzlmYzQxN2UzMzFiYzgwIiwic2RfaGFzaCI6IlBWY1dzVDZ1SVFhUHBRUUM1QUQyUzQ3Q3Z5QllpRTBxQ1RVZUtpd0ZfRlUifQ.i8LKIVBV7X67veBsk-vyyCHouKBFEXP5uLl927e3m3-_JE1hOHuyv0KX2gioAO81kI1FY1TV6xHOiQVF-UyBBg", + "issuerKey": { + "crv": "Ed25519", + "x": "hca9rLOG6cMHfk2weCWFz7wily7iDR_Qvhhs6tTQGjA", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-879fc417e331bc80", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901-issued.disclosure-twice.json b/conformance/vectori/sdjwt-presentation/rfc9901-issued.disclosure-twice.json new file mode 100644 index 0000000..785a8e8 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901-issued.disclosure-twice.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901-issued.disclosure-twice", + "artifact": "sdjwt-presentation", + "title": "the same disclosure given twice", + "source": "derived from sdjwt-presentation/rfc9901-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901-issued.valid", + "mutation": { + "op": "set", + "path": [ + "sdJwt" + ], + "value": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "now": "2025-05-29T16:47:24.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.disclosure-twice" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901-issued.form-empty.json b/conformance/vectori/sdjwt-presentation/rfc9901-issued.form-empty.json new file mode 100644 index 0000000..4ad35db --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901-issued.form-empty.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901-issued.form-empty", + "artifact": "sdjwt-presentation", + "title": "an empty disclosure between two ~", + "source": "derived from sdjwt-presentation/rfc9901-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901-issued.valid", + "mutation": { + "op": "set", + "path": [ + "sdJwt" + ], + "value": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "now": "2025-05-29T16:47:24.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901-issued.unreferenced.json b/conformance/vectori/sdjwt-presentation/rfc9901-issued.unreferenced.json new file mode 100644 index 0000000..45487d5 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901-issued.unreferenced.json @@ -0,0 +1,66 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901-issued.unreferenced", + "artifact": "sdjwt-presentation", + "title": "the value of the first disclosure changed: its digest is in no _sd", + "source": "derived from sdjwt-presentation/rfc9901-issued.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901-issued.valid", + "mutation": { + "op": "set", + "path": [ + "sdJwt" + ], + "value": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwiZ2l2ZW5fbmFtZSIsIkpvaG54Il0~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwiZ2l2ZW5fbmFtZSIsIkpvaG54Il0~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "now": "2025-05-29T16:47:24.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.unreferenced" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901-issued.valid.json b/conformance/vectori/sdjwt-presentation/rfc9901-issued.valid.json new file mode 100644 index 0000000..4eae794 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901-issued.valid.json @@ -0,0 +1,58 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901-issued.valid", + "artifact": "sdjwt-presentation", + "title": "the SD-JWT of RFC 9901 Section 5.1 as issued, every disclosure, no key binding (the verifier does not require one)", + "source": "IETF RFC 9901 Section 5 and Appendix A.5 (code components, Revised BSD License), via fixturi-rfc9901.json of the identity component", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "now": "2025-05-29T16:47:24.000Z", + "requireKeyBinding": false + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.form-clock.json b/conformance/vectori/sdjwt-presentation/rfc9901.form-clock.json new file mode 100644 index 0000000..1c17756 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.form-clock.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.form-clock", + "artifact": "sdjwt-presentation", + "title": "the verifier clock is not a time", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "now" + ], + "value": "yesterday" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "yesterday" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.form.json b/conformance/vectori/sdjwt-presentation/rfc9901.form.json new file mode 100644 index 0000000..f6d8734 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.form.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.form", + "artifact": "sdjwt-presentation", + "title": "the token has no ~ at all (not an SD-JWT)", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "sdJwt" + ], + "value": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.issuer.json b/conformance/vectori/sdjwt-presentation/rfc9901.issuer.json new file mode 100644 index 0000000..9938d4f --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.issuer.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.issuer", + "artifact": "sdjwt-presentation", + "title": "the verifier expects another issuer", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "add", + "path": [ + "expectedIssuer" + ], + "value": "https://other-issuer.example" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z", + "expectedIssuer": "https://other-issuer.example" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.issuer" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.kb-audience.json b/conformance/vectori/sdjwt-presentation/rfc9901.kb-audience.json new file mode 100644 index 0000000..569bd06 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.kb-audience.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.kb-audience", + "artifact": "sdjwt-presentation", + "title": "the same presentation shown to another verifier", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "audience" + ], + "value": "https://other.example" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://other.example", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-audience" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.kb-context.json b/conformance/vectori/sdjwt-presentation/rfc9901.kb-context.json new file mode 100644 index 0000000..248ffac --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.kb-context.json @@ -0,0 +1,65 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.kb-context", + "artifact": "sdjwt-presentation", + "title": "the verifier gives no audience: a key binding cannot be judged, and the presentation is refused rather than taken on trust", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "remove", + "path": [ + "audience" + ] + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-context" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.kb-freshness.json b/conformance/vectori/sdjwt-presentation/rfc9901.kb-freshness.json new file mode 100644 index 0000000..7b6d1c5 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.kb-freshness.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.kb-freshness", + "artifact": "sdjwt-presentation", + "title": "the verifier clock is an hour after the key binding JWT was made", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "now" + ], + "value": "2025-05-29T17:47:24.000Z" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T17:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-freshness" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.kb-nonce.json b/conformance/vectori/sdjwt-presentation/rfc9901.kb-nonce.json new file mode 100644 index 0000000..632e7bf --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.kb-nonce.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.kb-nonce", + "artifact": "sdjwt-presentation", + "title": "the verifier gave another nonce (a replay)", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "nonce" + ], + "value": "another-nonce" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "another-nonce", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-nonce" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.kb-required.json b/conformance/vectori/sdjwt-presentation/rfc9901.kb-required.json new file mode 100644 index 0000000..882d0ea --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.kb-required.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.kb-required", + "artifact": "sdjwt-presentation", + "title": "the SD-JWT as issued, no key binding, shown to a verifier that requires one", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "sdJwt" + ], + "value": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgInBob25lX251bWJlcl92ZXJpZmllZCIsIHRydWVd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgInVwZGF0ZWRfYXQiLCAxNTcwMDAwMDAwXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~WyJuUHVvUW5rUkZxM0JJZUFtN0FuWEZBIiwgIkRFIl0~", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-required" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.kb-sd-hash.json b/conformance/vectori/sdjwt-presentation/rfc9901.kb-sd-hash.json new file mode 100644 index 0000000..296e152 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.kb-sd-hash.json @@ -0,0 +1,67 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.kb-sd-hash", + "artifact": "sdjwt-presentation", + "title": "a disclosure taken out after the key binding JWT was signed", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "sdJwt" + ], + "value": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-sd-hash" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.key.json b/conformance/vectori/sdjwt-presentation/rfc9901.key.json new file mode 100644 index 0000000..5e9e198 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.key.json @@ -0,0 +1,70 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.key", + "artifact": "sdjwt-presentation", + "title": "the issuer key given is an RSA JWK, which this verifier does not take", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "issuerKey" + ], + "value": { + "kty": "RSA", + "n": "AQAB", + "e": "AQAB" + } + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "RSA", + "n": "AQAB", + "e": "AQAB" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.key" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.signature.json b/conformance/vectori/sdjwt-presentation/rfc9901.signature.json new file mode 100644 index 0000000..a00205c --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.signature.json @@ -0,0 +1,72 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.signature", + "artifact": "sdjwt-presentation", + "title": "the issuer key given is the holder key of the example (cnf.jwk): the issuer signature does not verify with it", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "set", + "path": [ + "issuerKey" + ], + "value": { + "kty": "EC", + "crv": "P-256", + "x": "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc", + "y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ" + } + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc", + "y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.signature" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.typ.json b/conformance/vectori/sdjwt-presentation/rfc9901.typ.json new file mode 100644 index 0000000..0410151 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.typ.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.typ", + "artifact": "sdjwt-presentation", + "title": "the verifier expects another explicit type", + "source": "derived from sdjwt-presentation/rfc9901.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/rfc9901.valid", + "mutation": { + "op": "add", + "path": [ + "expectedTyp" + ], + "value": "other+sd-jwt" + }, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z", + "expectedTyp": "other+sd-jwt" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.typ" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/rfc9901.valid.json b/conformance/vectori/sdjwt-presentation/rfc9901.valid.json new file mode 100644 index 0000000..7e01197 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/rfc9901.valid.json @@ -0,0 +1,59 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/rfc9901.valid", + "artifact": "sdjwt-presentation", + "title": "the presentation of RFC 9901 Section 5.2 (ES256, the issuer key of Appendix A.5) with its Key Binding JWT, judged at the time of that JWT with its audience and nonce", + "source": "IETF RFC 9901 Section 5 and Appendix A.5 (code components, Revised BSD License), via fixturi-rfc9901.json of the identity component", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0In0.eyJfc2QiOiBbIkNyUWU3UzVrcUJBSHQtbk1ZWGdjNmJkdDJTSDVhVFkxc1VfTS1QZ2tqUEkiLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiWFFfM2tQS3QxWHlYN0tBTmtxVlI2eVoyVmE1TnJQSXZQWWJ5TXZSS0JNTSIsICJYekZyendzY002R242Q0pEYzZ2Vks4QmtNbmZHOHZPU0tmcFBJWmRBZmRFIiwgImdiT3NJNEVkcTJ4Mkt3LXc1d1BFemFrb2I5aFYxY1JEMEFUTjNvUUw5Sk0iLCAianN1OXlWdWx3UVFsaEZsTV8zSmx6TWFTRnpnbGhRRzBEcGZheVF3TFVLNCJdLCAiaXNzIjogImh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwgImlhdCI6IDE2ODMwMDAwMDAsICJleHAiOiAxODgzMDAwMDAwLCAic3ViIjogInVzZXJfNDIiLCAibmF0aW9uYWxpdGllcyI6IFt7Ii4uLiI6ICJwRm5kamtaX1ZDem15VGE2VWpsWm8zZGgta284YUlLUWM5RGxHemhhVllvIn0sIHsiLi4uIjogIjdDZjZKa1B1ZHJ5M2xjYndIZ2VaOGtoQXYxVTFPU2xlclAwVmtCSnJXWjAifV0sICJfc2RfYWxnIjogInNoYS0yNTYiLCAiY25mIjogeyJqd2siOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwgInkiOiAiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.MczwjBFGtzf-6WMT-hIvYbkb11NrV1WMO-jTijpMPNbswNzZ87wY2uHz-CXo6R04b7jYrpj9mNRAvVssXou1iw~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIlVTIl0~eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImtiK2p3dCJ9.eyJub25jZSI6ICIxMjM0NTY3ODkwIiwgImF1ZCI6ICJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUub3JnIiwgImlhdCI6IDE3NDg1MzcyNDQsICJzZF9oYXNoIjogIjBfQWYtMkItRWhMV1g1eWRoX3cyeHp3bU82aU02NkJfMlFDRWFuSTRmVVkifQ.T3SIus2OidNl41nmVkTZVCKKhOAX97aOldMyHFiYjHm261eLiJ1YiuONFiMN8QlCmYzDlBLAdPvrXh52KaLgUQ", + "issuerKey": { + "kty": "EC", + "crv": "P-256", + "x": "b28d4MwZMjw8-00CG4xfnn9SLMVMM19SlqZpVb_uNtQ", + "y": "Xv5zWwuoaTgdS6hV43yI6gBwTnjukmFQQnJ_kCxzqk8" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example.org", + "nonce": "1234567890", + "now": "2025-05-29T16:47:24.000Z" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core-es256.valid.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core-es256.valid.json new file mode 100644 index 0000000..25f9775 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core-es256.valid.json @@ -0,0 +1,60 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core-es256.valid", + "artifact": "sdjwt-presentation", + "title": "the same from @sd-jwt/core with ES256 (P-256) keys", + "source": "@sd-jwt/core 0.23.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt.json of the identity component, generated 2026-10-18; its test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJ5Snp4elppdXBULVlER2szcUM3ejNoVmt1NmZtcUdHQnIxZkEyUHl4b2ZBIn0seyIuLi4iOiJaRXIyakxZdGhoWDhYTHdmTy1ISWtfMnRTNm1mRmwxeW9fRDU5NmFRaWVNIn1dLCJjbmYiOnsiandrIjp7Imt0eSI6IkVDIiwieCI6Ijh3cjJKX1RTdHVLZHo1LUlYQ3dIUGhSaGYwLVU5d3pWLXphd1J4R3FsQVEiLCJ5IjoieVRDeXhlYmtaQUNhM2dLR21MMjVzWjVQWmtuM2g0T0Jkb2FxLWdtc3owcyIsImNydiI6IlAtMjU2In19LCJfc2QiOlsiLW1ORUJ1MkVfUm90aUxEWW9aNWpRN05hUDhUMGZxOUhtOENUUG1GTmRzcyIsIjJqRDRrTWw5cDdwdkdJNW1ONGlnRzZpOGM3RmoxWVNlQ3pWSWpxMEYtY2siLCIzTmE1NUtBNzFPNUlHVW9mRHpSZXozY3B2bUVCUFh1X1pqZm5vdG9xbFd3IiwiRVA4a0p0NEVwUTZNTzhMZ2RJRDhFM0dvS1QzUUQzZ01RVjI3LXF1dEFVUSIsIkhxLTFtdmhJbi1EQjh1aTBaSEpNdlNYOTVpMjRCbDlZRWRjLURuXy00eDgiLCJSQkJMRnUxYVVGck9xMnpoRnJDOW9DNF9oN21BVnBKZ0NmcHZQYUFJV2NvIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.pVRO7rycFsVU67grJdAQy2sGCFG_8TeTDPWCN8BXoQ8S14D3CllLSMbHzzRKtV0ShLS3AIJ1y3H6IQbbKC5rcQ~WyI1NmUwZjk3MzlmYjhjN2NhIiwiYWdlX292ZXJfMTgiLHRydWVd~WyI1ZTg5ZGM2YzE4YTRhY2U3IiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiV0JFYmlSUXJmdzd5Z0o3dHMtWi1DOF93LUQ2N1hmTEVob2d6dDJFSDl3YyIsIm83SV9VRWpYaVlwaXhDUVRpaklINldaVldlZ3RzcF9GM3JWQU1CdXVEcFkiXX1d~WyIyZTQwZjQwNGY3MjRiNWFlIiwibG9jYWxpdHkiLCJDbHVqIl0~WyJlN2VjYmU0MjBjMWUyMzkwIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRms5NUlyM3d2cUV2ZzF0TnFZUHA5ZGNzOW5XY2tZc3ZkQkRTbnY1UE1EZyJ9.9q3SQVmhEiiaoFq36fHnuH-DBr7myT9ACMu1eY-3754X0KO-kT0E5VxKUUViVji5vVVV5Pb3cjTeUf0Ppu9X7w", + "issuerKey": { + "kty": "EC", + "x": "MwvcAG7Qwg-mknZRXu-JS7VHkZzVLlYjvXzYj4TeLPY", + "y": "fLuSX-6-_njH4b6GGbwwmkgPzD7nBZu04TzG0v0A1j8", + "crv": "P-256" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid.json new file mode 100644 index 0000000..2d65d4c --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid.json @@ -0,0 +1,59 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core-ml-dsa-65.valid", + "artifact": "sdjwt-presentation", + "title": "the same from @sd-jwt/core with ML-DSA-65 keys (RFC 9964)", + "source": "@sd-jwt/core 0.23.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt.json of the identity component, generated 2026-10-18; its test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJNTC1EU0EtNjUifQ.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJFY3g3OXIxX29BbDdEbl92V2lGb1dySl9yTU5NM19rUGprMFpIdS1CMWQ0In0seyIuLi4iOiJpSGh3dm5uVGh1ZlNFWlJYdEJ2SW1fakI2T0VqRzR1NHFFR3RIbUFOLVlnIn1dLCJjbmYiOnsiandrIjp7Imt0eSI6IkFLUCIsImFsZyI6Ik1MLURTQS02NSIsInB1YiI6IlZBTGJxMnB3RU94aG1DUjZIbmxFcFFBOFpiWVJrTUtrRHI4V1FCdjV4SVd6TzNqVzF5bzJHRmRMTUl1STBXZ0R0Q0x2bUlPSUFiU3lpOVNwRHRaMjhPalc0R0tqdGpydTVoTEkydFA2M0FnNU41UVd0T2dwSFczRW5DZVl4MEFhZlItTGFVeXhVVXNrNl9RTnVZZ2pLczA3QmY1LVFYX3R1d3RqZktobVZyQUJ2Tk1TbDFLa2N4Nlg5RzdHQWh0a2dPdEZuelViQ1dfNUFkR0dTSEdDb09SVndmZXRIQjZVWm9nMEh0V2t5MXVkZURYeEN3dGwtYV9ZYmdjMW02MTV1TDBZX3l2NlA4VzRuZWEyTy1vbWE2TThXaXI1ZkpkZWZremVoakoyLVNGNXI4ZWZXbUJXX2xNNk1LY2NVOXJSSG5GSHFzbTc2VjF5UUhIZmw0ajRIX1lPTWxlLTdlbDFUcDJvQ095ekU1aEZfeWlTaXlKNEFDcmFhTm4zckxFYXVkRG94ZmlXUlA0dW41eFFlU1ZxejU4YXVOX0N6OTdxOURUbVI4X2lPNmYzNnZ6Rzk1MmZUb3VhaTJBX2o5SW1TOUh1cGZEY1R2eDhGRUNyTnA0cnJrMlpFUGlKY3NPbmc5bVgyeFNuMFVMZktQQlItT2gxR1pWOHNCdVB1b3BxTlI3MEw2SFRaTmhjLU55Uk8zd1o0U1lMRlJBeFRtWi1HYmgweTZvVkVqdGlKOUlHMVhEVkF2NVBJazJmXzhwalo5UHFrbDIySE1Qd3ZZdUNMRXJHWnBVdFFub3YtX2VpeWhyM3pweWhUZlExOF9leFpIZUtBdm1HcTZKbzlLN3pkWVVxaUYxZkJMQ3dUN1B5RUNobm5IZTVxV1lrTVNJWjAwMjhfUVJ5SnhjWHlVS0VPU19ybjFUM182UVRtS2hTN3ZUaWdERVVLNmVFU21rbDJSNC1GaWQxaTdOaFktbmpnQnBDWEg2Y011emlVTDBIVUhUbDZvTTVJX1k0aXVnQ3BvdkMtc21jQmFWeU9nM1doQWktVjRIWVowZXhkNHlCRm5vUHRTaXF3UzMzclBIWTgtQnpVeWtKMkhTNkx5X3VnanJybnJhYkplN1hmTzcwTTRkR0FTdzlnVmFpUjgzbTNFWTlSLWlQdXRmNXNsOWRjcTBmd0g1b19WMEowYVdLREhPRDI1X3h3Tmd3SGphbWJqaXUyWXhEaGVoWDFRZkc3Y3plRS03ZWwzVnJmVDJ5TWF6REtZYXdwM3hUdW8xMkdLS0ZPTk1zZ3FQek5PelktZjJkVkVOY0k4TFAtaHM5VjVsQ3QtTjIzZmpQNnpPWUdDLU1hRUxNOXQ2WE1PNVIxT0ZJTHY4UWVKSksydFpsUTRDSlkyU1UyUXNfekVQLTVnOE5MMVg2Y3JZbnVzRXZicTQ4aWprV3Zta2FRNHJDa0gySmhmckN1c3RfcDJnUnlYSmhud0hsaVRFeTlfYTQ3TjJ6SlFOSlMzWDJxTGk2bTlQMDQ4UnF0Y0U3LVdZeWFFSG1xYTFYOGprSU93M1RMNTdueVJPU3BFSnFielJnODFiZjR2Mi1xUTZNNF9qa1k0X0J0ZEx4ZWduX3d6UVh4U2diTHktbnFLX1BaekhZUWpIcWdvQU1LUlZfN3BTZllyaUNQZV91aDkxcUdRZ1J5VUdwS2ZObHdZZDh2T1JtNnVLUlFQOW1YN0ctNE13M3lyTU13dkxKWHpIU0xyVWpzbXdQZmoydi1KYjMtZzN0SmM0aE0waXFFQmFVR24yU1V0ek44UjVGRUpOLV9UODRZMzQtTkFKRzkxUUxBS0JUcWdpMTRPZnhSWDlFRUMtRVZWZnRqekU1Tm5hMURZVENlZFNJSlFRdExGVENGZS1uejdxLXVEdWJzWDNMaV9ReWVxcjhaQXBaUEZXU1E3bFZmQXhVMFRHNk1PZkZvbS1iekFUaXA1d1pkV3pJal9PY1pMUUg5QjBmVEhWdW9qNHlTUGstNHdUUFBLcDlXVHo2SGdDenRpdjZTSkxWSmlZWEI4N01oX2FxczEyTHZVcnR2TTliNERWVzN1dnlTVWstY3ptR0xGNG05VGUxWjlXbllKNjY1UWNTZ0twUHAwQUpGRmMzYjRKdThlcFZTeFNZXzRRbkZYQzc5WnBDNDAwZ0pZTlRsVDRrMW4tVElwd3JybTN2S0M1bmJEaENYT3JXNlQ2Q0FNV3lLa1E1Vks2cnBaUG9CRmhPS2FCSWg2MmYwaWFzd0VTSXVtSEtoRlBaWnptcVo5dkhlMjFMa3FTMkNzXzhhUFh5VkdNTTdPUngyYUNnY3QzZENxbkJmMlB5QjNYR25teW1Cb3I5b3l4NVh1Rl8tWlhYQmZ1Zm93blNwcFNIbGhfUERKb3c1X1p4MFBzR0Jfank0cFNrSFdKR1hRLXF4aUhRLUJTRlZmc05oUzc1NHBHMFc5NGVLTXdzb3lDRzJhUXMyQlotamFNcW1vNzhkY1d6VURWeVFSWDVuSFNYV0lmYVN4c0tsQ2RwZkxLOVkwdjVtbnhvb1lVTGN0YU5ONWRoQWt3ZmJrdmdacmhzR3Q1ZWg3TV9kYlFmRE40LUp2Z0RLOWZPVUo3MXdvN084Q1lPVHNwY3l0VW4wMXZMZWdhOGtxeDlSOUQxdnRJR3U2bkRjVnJVejRWUjZzYzE5cVEwcG1EdU9LUlhOZU1KaVJNREtuUkFGTWFZOXhKOS1Zd0pRM3F4MHpuUTVfbndiY2wweVFTQS1EUFU5UHdkUndpRnNqdkhNZWc0WHlEX3R1M0FUR3lPeTUzNEpIbUgzR19Od3BWeU13X1d2TF9MTEE1X1hUaWl3R09sVFFvdWlKSm1CX0RpZlUtMHRPcElUWDlTZkRZZ3NoTkkxaXJubnlLclRjZ3FKYThha3pxTkgzWUVwbjJhbUZNV1JnMElXUUs3YUFXN1p3T3hvRG93MHFKYWNGMzNEN3BPVDgwSEk4WFFodlpkQ1FyakpaZTV0UEEzRjI3d3JWUEczTUc0SlRmYnpHbFZZcm9jaWZZcWtkWGlrWVc1andrTGlmR2NrRUg2LVF3VTJNSlpuT2xiNy1ndkJIZGd2WXNaVW13eHdPSjZ6cG1lLUpiWkwxVTY0bXJYTTlxVnpkMjlTSTRJV3E5ZFAyWVppcUx2WlhlQXBPekl3YTJZNXhQSHVaTmJBVWVfNGlqQnhrNUE2OHFYT0xYWFhQZzVuaXZKcWdjSWVxMXdtd0ZpSkxYS0NsSEluRDlWXzl4MjVvNS1vSzVOVFVpX2IyaGRnd0pGVVNxV1ZTM09DTWNheEFVMmRxWkJMU0lQS08wbHUzZHd6NFJfYjNrcjNpZmNYcEI5Ylk5TFVCWFJ0ckxYMHJONllEQ2czVzlWSFZ2R01XT2VJY0pDZkcxMkROUDRYejkxNDV0M2JRMmdFOWZiQ0x5bjlsc3JMWmgxV2ljIn19LCJfc2QiOlsiRWtUeUUybG5rQXItRmhDV1NBeUNyT0ZYX2MtV2dBRndERGp4TDNaeFAwSSIsIk1HQ0xNdk92WlRyRG9lNDJOc2x0THZHZlJ3ckp3X0JVbXM2UGFOZk5CVmMiLCJfZGhZbVBacXFXcUhqQ2cySThtMG5CNXVvRnlBSnp4UTUxVWl5YUs3OXJ3IiwiZm9iNWV0MFVxU2hPVlZZengtekhoZTNhbnVPZWJ1YzUydkl2WlZLazZUTSIsImZzSmI5YmZ6MlFhUnN0cm9SQVFjMmlYaXJMcTNsM2xWQWI4X0o5MDZXZXciLCJmeXFicTFab1h5SWpmOE9XMWNOX2dWdzgyelpWMWxqbmpINDBzay05OGxjIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.kzq5ApOKCkOg5J2OXBIRinyv6tU4EuUsbMa38s8lHLjqYB1CkB85DWHsnCxA7qCKDErRx_t2hQEL6ay2eYpCydIWhTkM5RGqZH94DW_MPz99Me2lRMy4MpHapCfdVL4iQPDQTLGCQO7R6pmmV-TD42RrZPsUEAzU7nEt1OnZt7DOTBmLIgDu-TTJEkhb-hRhlPav413FL7qkyFsYPiqLlHyQwC6AJ86OPIRXPRqSALiVodUPJ-steRRsBbx2zvlJoYI-2KJ3qSvAM0jZARk5GWH1yCv3NJGS4dx8jQGEcvqK6z63HwKyYs5zHDehZhf6dxyiX0LZEXQY8CwU1txL23o4e3hoHT-we9D4BWBi-ztNmG6dVnNcOKacA0dZsh8O0G5ZDZsBL9gSK2vQaIktWWzcFdgvB-k6wH-C0WQiVq1R3aK0nxxq_i11LblmGLjbbYleaFaFNqp0TWSq-yXzRNHW2gYz78aYFoz22Ty4O1G--7TUuj0FQUCyrQ14O7Di5Yv0FcqInw_Talrg_8ouxDXP5JAIhBHSrNLzJ4RO4467tVK3aT4Ig998tdHc316Jm4o6TqS8HYEqPDxfnlvUWy3EsMxEzo3q-fOJ4ju4Impd_sTLTV5ZzFbNv6J_eJXLW7Pe3B85tyRhVA7eY2iG3Q29OzvjvWawD8Ow3rE_Q7oBjU0q4njnKqTOOsBHjTmke3CEml0VbsLPZbrswmUCjwZglsgq_qOJDIsWmNLtpkfsTu7zlCXMBnNSDcK64cbqmEX8Bq9Q278j526LJOfmZrACzTsiNXiDgQZhPQEMSbnn0GfGs9Mc_ivEAB-ZVDVx6qRFagpJp7m7vyPbkasb3re4NBj94-K6tumcCEqYOZn2ECO8XLkOVnbOhQySioTYemGiEA71Yvg8kaawrCE2sGxDx3-g9hQt223xEgT0-w1DC-DpWpmKf1-v-sQo90A8pb53p6HJ3NqJJmcC9B14nHWZfZ0Hv5aJve_neD6c7viIsP4JcMDrW7eOlm6Pxs-AkD-4Ro0OHiOlP0r-kJTu_uiy_-H2uj9cLa5T115NXuCJ2uVIWh8Oj0cbnOYdxjd17Sx9yi7wUVCKylgxMaKLs-YqAiR9SLXs5ku3wAd0_saTmE_-gHzwZfSj3mzJ_uiIFRcQtNsfD3GwJwartf6jgaWY0gcSJhMUGSasbH8_NhXjoVAm-dGDjJdbnYqKEdL8pLQ0ZTkkk5cH96v1uQYeTLMFNAYipT_FvwWYAKWc-Uc5PaBipCrzvL9y_MshidEKTom1p-7scnMzDU6RcAA5Xeu-ocgxjqmMmSE5rDePrKi-Jd0bujdA3UlkwVtMZGE45C_WmcVhuWWdIEivOZp-FAmgv-cISdPMWRCdDFS9NL72uyyaMTIcuOD7C02zi749Xw1BybzoxVHcPGcmtWFDM4q_L7DrlYSO1T1v1cQJ8HdfBMvnOTpGToIfG9SCZmPh5R14wFdcqNr5QglC36De6vtkwDFaw1ASADmlm88uNb_hd16UvVjs8gf91WZIINGNk50Fu4BsFlJTWmy1ZnMKxVZOcGEJs0J_8eqbp25sBR1XtyKtyo45vdJPaLVQtsql3z3jKjoKLEE7J4n31flyYh-p_fShsfcJyw3CZbnhRYVWR-8MdnHDV4INh-rDKGkVsY4JtKQv_VjN78ARG1XPXaNO_2yMXICRWotKNzo4Jwx3btKHQhoM5zwHNdrF0p9ha_WZC960lvJ5XcWAeXTzI0WJP7LZHRzp7zc3iR-osVHhfMNuuy6-prrMdTqT_Pn6JURfCH5L9LEvXoeVXuTLDS_gECVWGrk9HqjFyqbsfftOgseFkH8ELExTQGI2zHCrcjHfdlBqMogj8kv-ya5GBk9DC7iR8REyrsuAKQzJI2FyImxGVxmKKoPNrqKgorKrTgbhHoxay8Mu3YPkWJfLNUYKkLVgRknQRRnu12cnB_noxFBDr83GrvXsmgwKadVe_SGrcB_FI6EIIQfBzHjeRWtLReK_nyfpKhpNUUMgw_wfmQHcde1wdrabw8yIaC5CrsD97U5C2jGNnzO8RTm-JNDsRWjduzXlBhxP2uoe9bRpe6-x2W6LG9o6gS4PIC4DnF6U6zxReBMurDXXOpFwJJhDM2FsZEg6bDHoIwlCVjs4eZX0WS5o2iagjYM5hIykwRZmP78jt_YEAo8isNR1U8Fh79mxMylaIx2TNenf9nj1OhFQp8W7tQ0cBEvvfUlwHIT4KC4yaAuslNX4Mc5BFOwoTiZ3M82hzab3vXowIgdWJxqXTSULVuKvD4-939pFlIVuMIVbaOLdrhXEmN5Rs3aFneEk6Qp7J11TMsXygzqrSYs5o8BNnR7GrOTT4RuGi3-At9fKMpEdln7mmsJ2owkU9DBfRmG6G29l831pfpOD1yCWX5bTwKl09Q-aYIoGYycpoXHm2dct055SO9CFXATPGXd_gPlPyklwdD_0V43Z_Kgm-AH8PRjKVeDgrLnI3skQNaEpiaXl5vV5nNunFCoj4fqb5HuxrcvYf0zcmf5PxVlvuBBhPcmCJSJQ7iYfEYN4Sw3sor3BGYDuOXO3CVnF6acawwvnNCLhMvKpC6PZGLx0-FyVtqJVVeLq4F4TiotNU-fNZffuIw4XYxQiNg1xKG2VvBVbwQ8738bNfhsxkZayqhNQTbJRYKmitVBsWTzhgCAwIBbxHvsNQDgk8GKU9nwYVyaMJUIod2jPuAatvA_39FPe3jC5UKpJe3-Kj9MvN_GlOXqh29Y5-PxWBdIYh7XzHCFM636Ljwte7PQ4IOr8VospDQE2w26cVl2F9xqJoYQB3CQlHWkNlmJXTGxwG9I1g_b2qr4UvueFwkdqNNP2Wg4RzvPWsRJEnrG13irYok7OfqTfZ1CTQRoeqQkHaroOBgW6bb2mTBE0vkK5d7DfaRdcFEFYOjfg520LwzOjyYhAuHstXh7Cd186QIISxKKxOC4fKsA3LgrPHUyVpb6f18InFi3f2OZauPt2EEckpADi1WiviopD4g0RzZ7syuwcmXybZeFRy8fi5hb0OrDvFusACn-o2JyCx-Cl2FkesRoXrO6Uw6PQnW6mYvugCj7ZRkapAGTLYrA0vXMbC0a2DBC6T-eLDZSZDDSfy7J_ZffTffRzth5Gs6j_LKO41FSgC-uxqeBoRihx1a5rh9K2fGRgYPCURHgv3KK93WAhcqzeCAOLt9tBGdNUQBV5_IMW_8RBOBaCFOEC2r_lCVpe1LijV4wYMC133u34AyI51JSJI6Z3V1FlZbKjY7KuvhWVINSrQ7nQIba6u5Ci3e3JbTMJLr7P8_UEM41-0475ts0tadjLrGEFo2aZe1ZwsfSjVfmjYeOtmCFgxjasWpUpIPthJoXdCd-Fu3beO5Jvl9FmFMqqsP9h_z81kQfDu8qi-_TrXWhiamwfpuETG-3nZTi8HqO1nAXPQ8sGNN65FbZrVHj6OOmVMVnNUToMFNsq9unEJZdZIfB_ymDdA3Ggo3T9JZmQ4elMeEJss_wzMwUJqjsbsvNWDzB-UBFXCIkTjht1KQ-CKFMTSvUdZK0jxuSmC3HFT-rMeasqnwp4J-tp28Hq_a7xVQoEvRBcr1yyNgdWdgYPnenUgPGlV8o_p2tEGkpWoozdaIuegqEUTvuKL8rUN6K2hRvcPaWvQe_YFK2oPPsJYse4a-lxUS_nWtLW5P9s6wTq3lhs744oo0kToMamstTYZ5z6qw86LeELrYVy__iRJpXINnZTwwlAOXF9-iuojINf7aNG5Tmj9vovpSiiHpwYQ9vyyJ6OuGoHPqE-zaQwduwdzQb_iBms2E78KOK0gRPyFzwfC9YGZwJBVRqrtbRZSrnWSA_81lp7P9vMnfDnw8nPpi-WuGz1QAW_7XQOpK2xJEHiDfVSQIQUu9-k--g09aFZ386RpAXtuJRNSijtjoucw6ay4Wt1wUuLI8aaTgVPQ4N67XpPMoZQIQ2LkWvQbh3-mHiAS8mXsnujSVqMyRbx1CNPmHvnWYG2MRw8ox90j6hBpIazSk2EY8Bp25e3m2pvdc3Ofyo9E-vYM_OopofS1GJzFFwYI_HYiy_aq1xp4_dhUOsIPhhq3pt5S92Q076mnQGbzz_t2OafEQvknXMeHpoeR4i-02Wmi7m6JzJE8Mz_Ycdqm2quC4VZT1Prm3zVFzAUxutRXhfZHurXuflgAU_LZnvB30MqzxH-J-CrrO7qW5fnpKGfsUkRY7UcjQEn3jykPz-UU_U58HRwCTZnSyIh5fpCc6OJDHju3DeVQ3Emv5sS6IRYQC53Sl7wITb9HvsWZmMuB0feh7W2UjH01ou8zPcKKkledX-Sxs3p_gYZJ3DO0t3o8gsiUmVpdXaF0-_wiOcoO1ddwNcAAAAAAAAAAAAAAAAAAw4XIiQq~WyJiNDRlZWYzOTFmZWNhMGY4IiwiYWdlX292ZXJfMTgiLHRydWVd~WyIxNDQ0M2YzYjdmYTc1NjQzIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiWkwzYkJMeFItWklzLTZRZG0zYVBXeXRGTVJUNzdGSHJQcUlVUjBPYTRvYyIsIlp2ZkE0VGZDbkxIUDllcFFoRlg1dW1TbF9mTkhiVHoxcnpIUktDZDFaTU0iXX1d~WyI2ZWUyZjQyMDU4NjI5ZDA4IiwibG9jYWxpdHkiLCJDbHVqIl0~WyIzMDRmMzljYzNhODY3YzliIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoia3JnQlhnNjJRSXZmMWpPdDM2WU5XbDJwUXdIVWs1elJGVHVtS0puZWhkNCJ9.8Z2Ms4-p4o9gqQ34HBJ1V8IToO4QpsFaPi6-fNdY3Q3Rh3YScikx8c_NW2UjRxD7_XLiayZDyiGok0u4SCkjkW4iRBKoolXZ_TWsiH3TC9Yo53ZJPlKiMtGEAiO4Vh9_NsCQciiHA7D6RN-rLh3YFhlykAJMDZiwNRPBYbLuDrDIwGvsLjjjV3DQKI2Po41KxgdRnhoA1ao4O_uXCixIax4w8ijs_yEj9UkIsBYO6M2rBVPMrEJqEIUX1mi1SXyaPvgV-SSWhjevBFKvVzHFeiT3Qy1wr9XfJ5YlNj1XxxYXZNk1lvkJeRk9NP4NVRm6j7ghDfs7ZWXa_6GLB4tWsAXAwi8r-ll-OF0wm7lZbAHVyhH7mETzkb8DsWwJctYo3YdQjK_eCNlPKn4PyOqPfi3ZNWmWONQ0w6b3EVXSliicTguMIMYLg27wWVpVTqEz_WGwYFYMWSoSUtFwCy35sp155U9h3DaMpSGlxDpi8s2lwmoGEzSfXlJsrVs-7mENVDR-esc-7MF4g_2KLu3vnLxJ8prcAjFbNTGl__R5M1KdEQRinEWLFbiwN4egKLAl4IP1-6CGYVnTP0ReiIU0aGi2vMlq7GqkXMEJ5J8xsdacSZVnEO23r-MPSM8A-sdX3x8e-5CcbPxBRh2Xd7wZELo8SC4N_L-hOZfPKnQ6M-WG3pUvCyAmJ-ufb7MfSkGUuwIrTzcyOLi9hOY6ojVN50OQoSQRVzDQHZj8vIMZOIek2aq4J8Zktf1vksBQxmHcgknjhjdwc9C1IXgi4CSBuCdi1EJD0MvPF6AfsOwuhBclHQizK1RzFYt5aDofG73trkhbEC5xP_MuHhc11_R6id2OB-H6qAVwnGQ8VRdtaRn2bLu-Y43klK_mQTK4aCCh1F-nuVCv5oq5jPbEMwhrJzWEobgaAcZZgyzI4aBe84Q_QyXvH5jZizdyxQezK3BybaPJs1wv4cyrqmaGCjoJwnK5Rw1ff7x5d8P-WZdmQ75vUVWrkFhUkAg6i4ykjH855TN_bggLM060MBkpmC_UH_F2GsPXZ2cE5qf6EsFuK_FY-iQkDU6suUgxUiH2CNtiaREOGLTEVi0jqHcFTGDoImrIb8I7KL4h4p8q51t_KZ61c50bscD0vf6Mql9ZYZ2Q3vMOJ_38Rmt590Ok_XZKpqnX-Ngba4NOYZv5y2_MB-2Ss8aANViOIKtdKXnH3LpMTUiV4Qw-6mE4xao_SE0QzUwAdAS6fE_OIfMUdg75p_djILaTG3Dvh6uqNUFkJRiAyOeJqUqQTqF2nxFgC9Nu542n7jWKa9ZUwX4c7DGiIAf_WGlNDTKFDICfoPPj7bDIhKaS1rAHt0Nge_KRc5PlVsZOSUmuTXN5n5BFcKkIyom-W4hnrC-CBF34qPPpXpI-22_KWIoyF40ZlxFQKkAVZGCvZyIJh2zEqyMFQ6cKE2otZQDYz22ZbNgs3KOr3HXyqeV4_wxAfKEAn9gcBGApI8DF2qhDIeAH5I9pwS7obqsBy7r3I1dxGyAHaiKaAliaamie-4lRll6zyQK5BsKr7i93wyOQcuJFfjcgopw0RrMELIirYT27WrOIPUGnWDFJrlsiywBFGwnrHUfQxgYKOvO3liHhT47KPuTvZqAYaCSTLHfBFRbwQWh36uhxe_-hCBfB5c_n7PgcDS31FsQn5z_x8RJfHnxuzz4W9Gn0C_CYSQ-iXEcKP8tfhjkwEJToZLATnfh2Iq2UMQHvOMgyOLGJ9ioo5TmUp50kwhNRh4hnCiKITPNZmnHQ-jfwVvdwvM7FQ-ITmjTKe1PyfZCCZumeHIU7CfZUhfYVG50qgiRYYLCQVeJhr6KcIRE-v0v0IyHAq11eelGiLJ7JeyrH01HH_cP12DwuWT7ztVDuXW4TriLHOn64C366_s3Skwy4beZeInvp1_wWI44xTyhIZF494HmcQG1mp849J_HN8l6fneAm1wFHV1d8CtK1Q5HAYvQoAodJ2lNM68c0UiPcaI35HE3_Bw1ZJPutZhbCwLCiDIT4xBPEQSxPMexnEpVBSH9qvpSfVtZCBM3W8amyuPOacKbRnv3xIVtl4LEqrNRuIbpN5CfVSqilsR-hf6CQDpLFI7cR9-AstmKn6Tt1KJp71sX6S2zoh-l5wgoU8BeUFu4TfYMGDAEcdT2oGI4f3lllsuDKgmkFwofRT0JEJnd7EA9IcZUrNZeXhhS8cgYTEkdJXItvTJbx0gnuXKHQhNWKXEDWTkddwML7ADvenwqTdM5l9sNgISWU08qIsflz7lJIGEG7dtUiU3VJCHH6iEdRA4AeQUlUuM4EI_iEqRw71-kw_xD8SMcLA0km-4YN6ciO3APKqgswfkFPE1-Vs9jlPTAX3qurrYtTZf4b2T0Dbn9Y9TzZX8WJPvB1L2bWpTNi6ni_4BDYvvnPcT2OQfMuON5TOzvzd1nQXWGoBbDWK-a7I3PEmE4esWzIj2ghb-JWPdnlYH7gPT4zwzebCgTUgSM8lJgXLxxav74e233dol9VftftX_JbFurtq4jC25Sg1MKV68b5B9RJmm_Og9EBmlCuzyOqsBVV8TXb-JRf8IalJQJijz1PKhjgVgr45UpPv8pi42_CMtR_M8JWL82hn7YC5sX76zUr6Gw6h4e3Q0-YUZYn3s_GZy5qXVpqreHl19Aul-OW-fbtv_4zA9E7i2CYz19l4hm3r_YiOCXVVmMmewSPSsOcLb-1lXETbqfirYP-PlJRl9ghfMzGLg0RkS8Ld9gSMJcSJ6mtSAKzycN-dyw39pkQ359WhAshR-LgzAyBhTdPEflwP5CVzViWGwF1rykNvl0m89NOh8zpglJFvhIrcXcxZyMJJMsUk4bzB8FvJxwepSssWKRAuKH5rlbtWkyRSC15IrBqjhbTB9wDovTFRPKd6WhpNIIJ8RrnUGywwTQhnxf-zr4SVP86YQbYUgaeDCjIvlZajo6iyKXH7tcXDdd4LoO_jHRexPAgIXK3Apymh6OPqt3iDcVnAQ3o2Lr3dQQjNC4NXxqL1Mw5Lf3jJVWNO9usKQEl6qvF4THby71y8VBsd3GBMCgsy5y5N2lz6C1QkSt_xQ2bZ8ThmgPauEtDeX8o0rnLNFYtQITwr-sKU9hfVlxngCJ6u0JjVW3M6tTmkpSuWhpozYPtNcRPatIhjNjpeCYObDMZTJSnbB-hCZDvn76otuXalO0m71rQ42dnwbOf11VxVDMX7MKLOLsE2IuoN4ocMuyrIWCvYMvdRS3IC__yTJ5GuMbVymM4sIN_Bm0xP7Ulym9SctbAtWPSCNTq3CpuvjyWAKxEU5NniY-vlYedlJwRlx_J6rHTWqIgjgWm7y0NLs5gfgXQswWT2a6McafT2rpGcKM6leiKZTYzlGpC5Jq8_ciUhX2Y7U2MIMywLtgQdG0Jn_MKLtCIJIN9-klgAMahu7pO09ciMKf0tfb6wzw_um3XAMqKev55617tRQnQaqBZj2k5CORfE2SOOxlSS8ATbVtokyCwVt--SnoQFsNr7BTV8q_v_l2TKOcMoc85DMtsvhFfeJeTLTW-blJA0-TLlm5ToNBjf-K1aGUl_WWpnEg9U4Tc1z7N4GyLH46_TdG3FVws0pV19DghPZ-fjSTOlBfxzNJjQJZje8BtlSFNNs7BswSfp9Yp7qy35Oje3B-kahbZ6JXE97-fp5_N4yntOupwyXD7iTAqCc9LsxAZhBMa8_8ufqGCTPmrjcSnuEdsA_DYly35aTgssoD9dUqgOjDEJXGbhrdQIgloheqs-bj_X6s5t9ObCk7FfE-2BNDukWAc8YHue_la7gxDsRGZ69Yo6UPnwwSSW5dUwNnncDyoMGgwICR1ff-s7zqo6jZ1iTorRSZAznslHm1Djkwwqd3lNqW-tcU1Am7KisMnmbUhOY9pStIIldQXYJHcRotMTXq4Dpq9UxeEKXHITFq8MSPtAm2OP4g6VPKXy3lgnd4aEfiea8bLQZkJzeFhoGP8vzokl_q4novNgdFhXbx1Pj8yVdm7H9RpI64AzfzBiCofRAUoJW3OzZeD1w6VhXmf0FOwpAMLj4U1QYNF7TuCks5GDNk1DPRTg0OWqf8eqTnb8WPEfKYQUI-_ut2svO1cB4tSguU0miBYaYDNmwzFIavz2gbFTew9HHf8STvTi5MgwzKkA_kRAIZ7RBtRwUH5loy07dt2hM556ler3MA3iPKUriKHTcBNmmpCJWWSyW9nlP5HWeW9M8iDDFOP2pnNeJ1bNGNiWYBOtNEIq5jyKiutULRvB04mJgJcsdX5guz38QsOB6Aywv45JbnyViWHoEnzenjzEk6F0CE8TE6OoaLDWJeap7e91Clqe5q8y9klOj1hYmZxvOYFER1PgpSZm-fzAAAAAAAAAAAAAAAAAAAABw4VHigo", + "issuerKey": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "4EW3YEtcEePmfItOC7r8wNICpSBTdXF6aHeTXBW3oQ-ISEoVcVubLhfVb1kMlqGVGSJ0wijbWn46NyosvQzaXaI16zvd9927oabHLfmyBGOyUvbOC5Jj7AUXEzn8OrdtcYvEtARw4r0FKnugy7uKDt4fyNhzrzMCJWEVGTw-ftaMho2-5kh7KYixaWxbQdPTmCgm3QqQk7v0clvVSx6mpJZB8sntXnwROL_NRUlKLWYJdB-4YSNdFzpH-oey7yR7VpnyyE3CMZIZbRuoMIGLbHUMw7R6Zg-C3HLGHAqrScfO3pQLNV2H7xRZ3N6wzAyRZQJrvGW8MalIa8v0VAU8ejuy7IgcyWn_1UEvL-cnv2b2_MGXiL_oYKjlsl1nyGi9DJcK7BRbuamJRUjG3fjTE3SnkRAy-yde4QWX6PGgxA35q5yqoOisong8pWH0RK02JP9tdwRvDbsTEVAGlWnQPUISGc9MFMM6ioF-jztv5hJfKx1yV3qwHaYOV1xeSRL-yM48RuoboRYNpNkslLf55cZrSzFGcNxztTnqtpZ4yP7j3PAcMgPqTCxDu_EEeFAJgp1POm4gxq7d6YkoN42ZAdiX8Uq2yJEBXGm9UaqSNqgtuulAJw90ENUnmaShijqWKeetnclk19qAtGGzbjNOcMx02hB5q-CUmdqPGAzsA5hY1YvbwGbIZewWuS9-QxR_XCPci1sR_XlJhQ7qa71an5y0Zahy8RfJ3hh2BiyN1xsDpP2PHxnbNxxL8OgllNdrM9cpfnc2eQQ1PiIfZaNrXsb4Juwbpte3jAJjzjRKO_7njLHF3SWVAhIxEQMUBdq1qLRIaZysw5FNvIBJ304fetFXGNK7YfCEXvpCoGPNnaT_WL7vu5u153-KzGSoJmVxY5J0bcrsZhkATliIYHyGGMei5XyHvxNtzogresuktQrUTg-zwNhgbz4KjmQMLbCcRoy7VEDzZ5gqhhx3rNuGjJDpUjQygok6VXOXEbZbZiDTPtOc8jEOk_0RVK2vkeaEIJS9eIzfkmPYNOTSchUTgbfUnRdIHwqxMzf_URTIFe8ZXgy0WyLYC8UhnOj8kMyUtNy7emgnCnaBjelgCr5X5rAc8YOwFsmAC09WY9IrMwc4sIs2JDAw24ZxXGFEWyUqiEzRUMUivKw3KsOxP-RJo2pI9Q3_0rnb6LnMpGpoB2gkCc0pM6NbTNMhlVGnaZGHfsJ6anUkXvsocc-CGRzMH3rzlb8BFVH9ejHLTfisp3vTLfyhgPgg1F5G19mdXN-AcpR6-AP4U_kEzNUe7l3WHLhrmjzDZ1GZG7wMnKfkN-nd0pnvhhwGE6EF4KGfshfP0rThVRI4TG3sTn3fumJQMR4YYGv10rJmPUrBeGqbnSv1bz3PcZo1v0aHegVGD6A5sBvqxZTZ6Ul0zrc6nMPK_gcJCOed0uDeetbdKXQhSwYIUdCnPnoKO8a4lqiyIaRQHjkTGDL4ADbvbzMruz1K_PM3YcCORmCfacW5xtsTQwsRyA3J6zEz3M_2neEiHDPaRR8XYKnjC4_sX1RgRAQ8EX_2N3qw6nKPaQLR4p_HSlrkalFv0sYUK-rcVB4XoWW2YMl0wCqA2U-ih5r78mxs9X9f0kOIG6QUKZQg7QcEWy6az-1bmyvcUP0Wur_MofFw5e05ZEdXXmMDderf9bOtRpOvWGP9WNJt5P1toRskMfVuF6FINh0d93I0ZNn0zs3Hjzm_1ADhQiYdXe6GvMl83zqfW9f-cEFlonsXvqyKmiQ6lrGq7bQfL5wtTRDYjgPSgqrfp561n53wIVcURD6eWptPDngSkVG3UJApJiSj9W5nRYGsV_m-wieJ0YukYNXfEkVeA1XF5IY_c8eeleGULKw9IRt1-Na-sFS7bQlN0-gh9lUK026khSCzYZQFMJWDiMa4tSj4DhddC9tsm8CfYzfSaQl-PFHK3jk2aHXfkgfZJeH3QZcPbMwjTUWIybp7TbfFg9tj30XlJ6vm6W5Y-ykMQtg_JeilJl-l56k1VbYRbsehTHBNXk4TF6Uv1sy6DqTzVwU-Ows7XZCM_KWelylsziDuy68vDaZWNNarqs2vJT9cPBRWHav8JB5vi4kRW5p4U7mzLh4Dqq9QXJBhFhjMT0nmSQaWZspo0Nd2c2JaqyaBNhgW-yfXFD48HNtmEXH_jHuQ4qXktA-p8nEL2zTsohSyO_OGZvyvZDUJjouc4srcbE78c8k3zR5omLKhahF5kpVKm63pXC1_dzpc_4rm9ULxDbPcfsby1McoSyDfEieublBWBPeDAKBgNpT_DkzgksXBdATe_9CNlM1nYhHXKsNhaxx74HaSGUl6OIMagmYYkW8yeM3fVIbtx89bpvgl4t6pdJh_avMlCOz-LXFGeZBnIFPZVyCoajwIh_le6sDlmdoH-MP-fgfuNWqo_YLSUOyV6-YW7LXLlnp4k8_YJ-y5Pitf1M-ocyVAZliqzen8rVvm7XfV3QKZ_pxZqMzFGAg-IkNnigBuUmc9rc4wMPDJVqfPynSFwtta2qcRYXiIitOMW_m2xSnqZucwiEYJl5pq4PzWipuglTiydJOObvD6SRg41BPBYLLE9P0" + }, + "issuerAlg": "ML-DSA-65", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core-typed.valid.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core-typed.valid.json new file mode 100644 index 0000000..a348727 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core-typed.valid.json @@ -0,0 +1,58 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core-typed.valid", + "artifact": "sdjwt-presentation", + "title": "an SD-JWT from @sd-jwt/core issued with typ example+sd-jwt, taken by the default type of the verifier", + "source": "@sd-jwt/core 0.23.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt.json of the identity component, generated 2026-10-18; its test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJ0eXAiOiJleGFtcGxlK3NkLWp3dCIsImFsZyI6IkVkRFNBIn0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJlM2dSeEkzMmRtQ0duMjR3SkxPY3lPMmpDcU40U3NQZFFYbkROSHU0Nkp3In0seyIuLi4iOiJrLUdyZVZWcWtIUFNWZGotdWxqMDQ5UFlYOHk5T0JsOV9DOFBjbmJFb0pBIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiZDBrY3VxS3FoQmp1MGM5cXRhOVhCNzdwY2x2Z085b01yQW9lVFhxaVJZMCIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIjhBYzFQZTItVUxYMElvR255dzJJT0g4Wk1WbVFEWHhyVEw5WTVLcUFwZDQiLCJBSW9VMDh0Z0hrYTBrYU1uT0RqS1ZKeXlQX3k1V1NyRGxQc3ZxZzVRZ0NFIiwiYjZTR09mSVZhQzJEaFhsUkFNZjVYT2pwZlJPYm5Bb3J6d1FqcjhRQ3ZCSSIsImx0T1Y0R0NIUzQwc2pHZ2tpZW5aVGJ2UGNsc0draGtlcUJxSS1jRi0xa2ciLCJtLVVzSlNuQjlnc3VSMjFNaXl6SGdSN3JvWUEtVG83YmNTSlFmUFhGUWhRIiwibzg2UnRhQTd4eXZrOWNCQ3NycE5nd3p4Mmg2RE1wdjc3aVJLUmFPUGxiOCJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.7hhpGxaCJG0GpqDOfHXECP22qYC10FBzZE-CVSWwueA16naH0RtCwQlHMhIXnvIdPNrDuPji_L4YGxG96zm4AA~WyIzYTE1ZmNhNGQ2MzE2OTNjIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiMzVlNzFjNTI1ODhkMTdiIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiOVJwNktjR3F0Tk1MdVF3QTFmTmEzSFZhM2ZLM2ZOTXBoQk44dnFKbVNRSSIsInlDendIVEFVSWVqZ0NKN0FqQlRvZkhWTGJ4VG9FcGNUelNucVB4d2diTGMiXX1d~WyIzMTZjOTQzMjM0ZTdhZGEwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyI0OGZlNDgwNmNkZTY2MDZkIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiMjl1UTR4Ul9RQVJXbUNId1JtbVRENDcwcGdmZGhnMTgwX08zc09mWDBOWSJ9.iCOcidDsT_n-KZteZtnt1-3oJ4v7FlZpk3g03wnCc-shcjIzBv9xh2X1ZLGJaHtxbF8oeJ3q5rUCV0TEr7o3Bw", + "issuerKey": { + "crv": "Ed25519", + "x": "nE6yYyZSwKuaQaf0UWpjTfPKu4bRh65eOWSm1teOO0w", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.alg.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.alg.json new file mode 100644 index 0000000..548b60a --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.alg.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.alg", + "artifact": "sdjwt-presentation", + "title": "the @sd-jwt/core payload under alg none", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "the issuer-signed payload of @sd-jwt/core re-encoded under alg none", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.~", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.alg" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.digest-twice.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.digest-twice.json new file mode 100644 index 0000000..58b65bd --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.digest-twice.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.digest-twice", + "artifact": "sdjwt-presentation", + "title": "the @sd-jwt/core payload with a digest repeated in _sd, signed again by its issuer key", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "the @sd-jwt/core issuer key signed its payload with the first digest of _sd repeated", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSIsIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiXSwiX3NkX2FsZyI6InNoYS0yNTYifQ.bnB_QWkrH4IGE4RkrBrwoy-sIS1hSL0f4azdh2DlZ-obGdZKFvz_w76VW_x2PEMKugH01HYgAnDGqHqt0cCLDg~WyI2NjQxOGNlZWY4M2VkODY4Iiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~WyIzMjc5ZTM1NjI4ZDZlYTVjIiwiREUiXQ~WyI3ZTBkNmNkYTliMmFkYzc1IiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyJhYzBlZjNhZWU0N2QwZjlkIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.digest-twice" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-audience.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-audience.json new file mode 100644 index 0000000..e71f567 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-audience.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.kb-audience", + "artifact": "sdjwt-presentation", + "title": "presented by @sd-jwt/core for another audience", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "@sd-jwt/core presented the token with a key binding JWT for https://other.example", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL290aGVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.NmNA2UuLcu2CkbufwjC4GcipNF9EwR5Di43bsRk-RXjPE-cWVS2eljbadOkZU1yQDkQH-yiYDh6e1fDsQXRYAg", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-audience" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-sd-hash.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-sd-hash.json new file mode 100644 index 0000000..26bfeef --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.kb-sd-hash.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.kb-sd-hash", + "artifact": "sdjwt-presentation", + "title": "a disclosure removed from the @sd-jwt/core presentation after key binding", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "a disclosure taken out of the @sd-jwt/core presentation after its key binding JWT was signed", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.Rr9sBYmA9BEp-uSt_d4w854OLSM7S6Sm-L_UHPGTHwVLpY_hVmLilgbZ9KF-X6Mk29KSQEIanQKOW1dzGcQFAg", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.kb-sd-hash" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.sd-alg.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.sd-alg.json new file mode 100644 index 0000000..5c48ed8 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.sd-alg.json @@ -0,0 +1,71 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.sd-alg", + "artifact": "sdjwt-presentation", + "title": "a token @sd-jwt/core issued with _sd_alg sha-384, which this verifier does not understand", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "@sd-jwt/core issued and presented the same claims with hashAlg sha-384 (another issuer key of its own)", + "changed": [ + [ + "issuerKey" + ], + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJUcURkRFVvX0pNa3NGT3J3Q3ZPS3JjajZaZXRWeC1qTkVHa0xhTVlGS0lZM3lmVDNkSzBWanlPRTBubWNESUZXIn0seyIuLi4iOiJWQ1RERXVkcUQxRHdlUTRfV1JFSHh5SWZFQzl1Z2hzODZKMGtYUEcwem5JUE1Sbm9vcnJYaVNhUTVVZXY5eFpSIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiaWhmNi1BVlhLdlpTTlo5bjZaU1ByWUtzTzZfNVdaQ3g2bHo4THRfM3FuYyIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIjZOT0luMkU4NEpUbkJlZWpmZ1FfN3otakZqWWM0aWZWVGI1Y1FxYjhZajh6ZFFiQlB2QnNpZnNuNXBvS3N1cGwiLCJCbXlmRDZ0cHRrZDMtSXo4RTVtdjhQWmN3UWJYLURsSHljVVFyLVliU0VRNlZlTzRCVGdYdkE2aFlIekY5YVNqIiwiQnZjelJTOFl0cU93bkVLNEk5UTgyelpLUUw1clh0SU9tOEdEZE5tYThoVE5wb0d5TnBmTW9RZW9CdWJEZHBtUyIsIkNscmFHR3BlYVJHR0JpLTlPcThpN2RrSEhpbjhzbGxaWkc3VWE5bVc2a2I5NmNFM0dqR21RRFdDX3lqY0hESksiLCJfUTF2VkQ3bW1sQ1IySXhpUDR0WGJKM3pqQ3VGWGNOUjJ2X2hYVldWak1DMHRweFlfRzc5dm15UGNCRk1CV1FLIiwiZ1g4TU55MWIxd3dBajQwSk5oVzl0Qk1ickMxbjdjcXJyWVVWTFJnOXZ1c2szaGdrM0RYSnF2T1FnZW1haUJYaCJdLCJfc2RfYWxnIjoic2hhLTM4NCJ9.AZsWqI-NY3-ce3xfH3Fjt1z7nsF2F6eQMaNVfZb7zhEk3OclAfWlZ2kA9XyeBvaFWSLuy695ktSU0MxaCGwnBQ~WyJiZDdmODdlMjljNjRmZmFjIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiYjBjZDkxMzg2ZWZkNGI1IiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiaFQwV0VOdUFJZE5PaUpfYUNMYnZQeG1YZmxHcEZqbTR2eTRvVTBCcUdOYkg0VnA3TW9rQ0VQb0JLWFBnSFM5QiIsInB0SzZTOUE1WlJzbnB0UWZ4QjBBZEdHbXc1YnFTalhkTjRvWkNJU0JLZjRUR0daVFJUUnlRWVdYYjlzeXROai0iXX1d~WyIwNzQ5Yjc5ZTVjMjVmY2RhIiwibG9jYWxpdHkiLCJDbHVqIl0~WyI4MTgwZTVjNDQyMzQyZjVlIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiTlFRdGRHdVc3QmRadWpQUjBRYWRaQ21PMERaSTY3ZDBBMFd4TEZrOTRSaE5KYkd4ZXJhcXM2WDBDalQ3NVEwaSJ9.7yJQbLknl6-Miy4ITnhBhHCWXpslFPhMZewEQyC3bl20cB6QEG6C1SQtl9X7RKe5u3CVCGyFmrydYQ-bSfA7Cg", + "issuerKey": { + "crv": "Ed25519", + "x": "AxyFfp5Ynr1Ag33qsjnaN0R_mILDj8J10x-1vPCEgl8", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.sd-alg" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.signature-kb.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.signature-kb.json new file mode 100644 index 0000000..63e1740 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.signature-kb.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.signature-kb", + "artifact": "sdjwt-presentation", + "title": "presented by @sd-jwt/core with a key binding JWT signed by another key than cnf.jwk", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "@sd-jwt/core presented the token with a key binding JWT of another key", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.rEJpb_jkTpXEe0iDbhE8KNPo2LWzRwdaFg88pJzE7nUqSx16N7TxK-rcIabqavi1NsFbPdUcW2mkn604zjYWDg", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.signature" + ], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "FAILED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.typ.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.typ.json new file mode 100644 index 0000000..79d3fce --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.typ.json @@ -0,0 +1,65 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.typ", + "artifact": "sdjwt-presentation", + "title": "the untyped token of @sd-jwt/core under the default type of the verifier (an explicit ...+sd-jwt is required)", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "op": "remove", + "path": [ + "expectedTyp" + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.Rr9sBYmA9BEp-uSt_d4w854OLSM7S6Sm-L_UHPGTHwVLpY_hVmLilgbZ9KF-X6Mk29KSQEIanQKOW1dzGcQFAg", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.typ" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.unreferenced.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.unreferenced.json new file mode 100644 index 0000000..57f539a --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.unreferenced.json @@ -0,0 +1,68 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.unreferenced", + "artifact": "sdjwt-presentation", + "title": "the value of a disclosure of @sd-jwt/core changed", + "source": "derived from sdjwt-presentation/sd-jwt-core.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": "sdjwt-presentation/sd-jwt-core.valid", + "mutation": { + "producer": "a disclosure of the @sd-jwt/core token with its value changed (no key binding in that presentation)", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLGZhbHNlXQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwt.unreferenced" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-presentation/sd-jwt-core.valid.json b/conformance/vectori/sdjwt-presentation/sd-jwt-core.valid.json new file mode 100644 index 0000000..8aa0f13 --- /dev/null +++ b/conformance/vectori/sdjwt-presentation/sd-jwt-core.valid.json @@ -0,0 +1,59 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-presentation/sd-jwt-core.valid", + "artifact": "sdjwt-presentation", + "title": "an SD-JWT issued and presented by @sd-jwt/core (EdDSA): nested disclosures (address.locality), a list element, two decoys, a key binding JWT; the token carries no typ, so the verifier takes any (expectedTyp null)", + "source": "@sd-jwt/core 0.23.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt.json of the identity component, generated 2026-10-18; its test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.Rr9sBYmA9BEp-uSt_d4w854OLSM7S6Sm-L_UHPGTHwVLpY_hVmLilgbZ9KF-X6Mk29KSQEIanQKOW1dzGcQFAg", + "issuerKey": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "now": "2026-10-18T00:01:00.000Z", + "expectedTyp": null + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-no-status.valid.json b/conformance/vectori/sdjwt-vc-presentation/aere-no-status.valid.json new file mode 100644 index 0000000..f8492dd --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-no-status.valid.json @@ -0,0 +1,69 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-no-status.valid", + "artifact": "sdjwt-vc-presentation", + "title": "a credential that names no status, judged without a list", + "source": "producers (sdjwt-vc.mjs: issueSdJwtVc, presentSdJwtVc, issueStatusListJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImdpdmVuX25hbWUiOiJBZGEiLCJmYW1pbHlfbmFtZSI6IkV4YW1wbGUiLCJhZ2Vfb3Zlcl8xOCI6dHJ1ZSwibmF0aW9uYWxpdGllcyI6WyJSTyIsIkRFIl0sImFkZHJlc3MiOnsibG9jYWxpdHkiOiJDbHVqIiwiY291bnRyeSI6IlJPIn0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsIl9zZCI6WyI0VXV2UWZmMHl4aGo0QTBCb01fVENZbVoxNnRER1hoQ25DbjMteWZKdl9vIl0sIl9zZF9hbGciOiJzaGEtMjU2IiwiaXNzIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxODIzODM4NTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.mB0Tj6473oyfbSJfzoMViYIOuV6nc-6zpQK2FkNOpGGFDMDD_DIey_EiU0aGSsyBrjRL2GV4bUPQHcx7OiObCg~WyJKVExRdThVWkdDV2lZLU5LYlB6bFdRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6ImFGYmZGMFRPa3JfV0pHTFlXZ2FEQkdFY3M2QUVTUFVGSEZOUGtZOFo0VTQifQ.UXnc093aVrHMIfdNIewXXsoX_MhO_2G_Qba8RZ9G6vF7iTdUUX_VkclxlhjgfJOzz0z6M4fOrKDTFtn_LUYLCA", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid-8-bits.valid.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid-8-bits.valid.json new file mode 100644 index 0000000..1740fbf --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid-8-bits.valid.json @@ -0,0 +1,76 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid-8-bits.valid", + "artifact": "sdjwt-vc-presentation", + "title": "the same credential with a status list of 8 bits per entry (all VALID)", + "source": "producers (sdjwt-vc.mjs: issueSdJwtVc, presentSdJwtVc, issueStatusListJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjo4LCJsc3QiOiJlTnBqWUVBRkFBQVFBQUUifX0.uFiiS91zq-P5V66asGF9tl98Kejm8sfHK2y0EjlSn8NCXvpF7g3oQueidvGR8hFzzXlrrFCey6eq7FWrsKVpCw" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjo4LCJsc3QiOiJlTnBqWUVBRkFBQVFBQUUifX0.uFiiS91zq-P5V66asGF9tl98Kejm8sfHK2y0EjlSn8NCXvpF7g3oQueidvGR8hFzzXlrrFCey6eq7FWrsKVpCw" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid.json new file mode 100644 index 0000000..f3075e4 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid.json @@ -0,0 +1,70 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid-ml-dsa-65.valid", + "artifact": "sdjwt-vc-presentation", + "title": "the same credential and its status list, issuer and holder ML-DSA-65", + "source": "producers (sdjwt-vc.mjs: issueSdJwtVc, presentSdJwtVc, issueStatusListJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJkYytzZC1qd3QifQ.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiI1UF9SblY4UGJhNjhmUGxPanQxTnBpdlRCTUhmaE9kWWVBaHA2dElXLTcwIn0seyIuLi4iOiJQNVBSRFJLY1JLV0t1ZUFUTFdUTThmNWd0eVhOMnRBOHZtd05PTC1XT1JRIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiRC1zSFloYXBXeGtxOEZWOXdsUk5RNkgxbjRGSnJsZlFBTXlwTjJkUThfdyIsIkpmV1dka3BZYUE4WmdxcGRGOG5kckFEdW5xb09OYkNMXy1WNEV1eDU3SjgiLCJNa3EtZUFRbnQ0dXNpXzNIdlZzV0tnRVg3d2hmM0lQRHF1UFJpRzctT3ZVIiwiWUdxeGNZZi1sdXJEU1NvSVprRXRhZE9LSUQ4SDA5MjBFLWdBVDZzMjVjRSIsImRETDdaeUdYX0FvY2JjdHNzeTZqUi1LRnp4RldQemhscXgyZ1RDU3pxbjAiLCJrQ0JrR09mdTVpQlA0X2NZNml4RGstSWxIcGp5NWxicG9yZmFYdFRpN3NFIiwia19aYUtxYzE5aXNZb0RXNnRQbS1HZXRwT3pzY0tIQ1BOMHhjam9HMW9GQSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7Imt0eSI6IkFLUCIsImFsZyI6Ik1MLURTQS02NSIsInB1YiI6IlFRSFdRbExZMTRJay1tMC1VNzVSa1p3cVVHai14YWl5T0xpd1BpRkgxcXRXOXN4UDMyUndsM0dWZDZraVhyRXJ0THhuY0ZsSm50anYtbHJzcTBTa29BaDY5dzZDTmJEN003SThkUmJSVzJlYmhXazFIVW00THpGRE5xVmJ0bDVGV21tY2FKUTZ1czZUUG9JUHptQ1MxQmpITkFHcTZkWWNMcTJlcTFuTlBKVWNSajJpMFhuOUhrNFhpX2ZFQmFUNmFJdFBrY0ZwWm1WYkNDQ1pBdTZvcjg1aS11bWZiZGZ0MkM1MVJNWDhtbkJqV1BuaFo5dlpRZENjbnlDTnNCY204VElSdzhOdEV5MGxQVFBMMl9tV3FPa2plc2xIVmVvTWF6Nm9LWHY2ZnpjM2g3NnB6cHlLZy00cjNuQ3J4LWxFcGJ1UVpwNzZza01XY09vNUZjU29FLUlCM2lLV0h6YndOM05YRTFZTGgtZkNsRUtLbXpsYlJHZjRPMmFiMWdfb0xxRTZtR1dNN0JJR0NDMjFMY1BXb0FXTXNXcS1vckp0OVRITTNYNENtX1lVcUF4alZnVWNyQk9Ba0gwdTlPcnJMczdrb2NaUjdSbW9kbFRTRnpjN2pwR1NFWlVVNFJlbU5vSzhackVJazhXZHFtR0xVSE9JQURTZlNmWkRVUFR1QWZoc0tWUFJJcThHQ2dGeWJ0ZkN5UWEwcDBmeXZNRFdCbThKd2xJYko2bGg2X2ZxNTljazI0RDVDaFZQM1gtSjFCb2Jyci1hcFNmUlBpTWxGVWFGcU1KYU9nckF2SmtnT1FldWZ4VmUyQ0xiUjNUcHJMRFRONkN4NmFQbGhDcTh1VDRMTzRwS0tjZm5LZWpYV3paQmowYmE2MXdqWHNlRmpCR24wazdwNXM5NWtMTzNpYW1fYjlzVkZIUlFQZjBKRXBxc042T0VlcnFhMTdXN0hXdTlQblhuMGhFaDBfX19oNmZodlplZkdaWktfZWVkMF85VUtZQmo3czNWbEt0RnBvS1I3eWVibUVhb0ZmdS1JTS05SFdRbExIUGhkekd1ZnNVcEpkRklPdFFwS29EbVVKdUZaZ2tSRUxMVkttOHVHcWc3amc0WXRzbWRONmRpU1dkV2JLVm84WkkwMmJlbG8xQ0JMbFBPU19fcjM1dUR1Q3JaNHZ6NVFkY1VRZ3RqY05pWmo3ZGpoQUVaVklvTjF2Y05rOTI0dWlqcnJSYUo5WWhGeFl4NnFQVDNUVkp2X3BUQ0ZCSktoT2FDT3Z0bzNLWWo3bEJFZHBtaHdkemFDS1FJaHo0eUlhZlNLYkdCczFYZG9PeWlDV1M1WjRWUDRQeW8tNEl0cEFYZk9ld3ZsdHhDWWswV28ybVNsQzItQm5FdnVZNnVhZW9Ud2xteFY4YmxZRl9CZkNQWnYzV3R3NkhKNS1MbE53M1B3eHNSWFJXTkEtb3ctQS1wOGhha0JTOWJVSGtMdzRsOVFDMEI2VTFmZm5rdEhqNS1feFJXMWxNSm1jX1J5dzh3NjAzMWxYZm1ydmJ2NzNYR3BKYXVkWURIM0ttODB6NUVTMmI5WnB5VDNieG9Rai1DYnJFTHFEX0ZPVlROV0phTm1FTmtadzZQUzVhLXlncDRiSUhUOHBXaW1KUV90cXBOQzE5OE1GMVpHcEhpUlpmVFNsS0lVLVgxT2llb194Nnh5V2VteUc5bHJTV0M5S0JSdTJHNnRDckg5UG95em9MZFFubXR4dFRLZ3MzRlZTeXlPdXZNa2hkVEV3OE9jM2c4NHh5bGJBcEZ0eU56eWcyazl1NGpGMzhGaFR5WUt5ZDhhUEUwaDZqcUJ1WHkwZ3NuQUMyTXUtclFhWjhfdmJDSy1wZ1dFNEFxdDRMNTY0UnFEcHE1LUs2YjEzMzZWWnRIeVBoaWQ1RF9PVEFrYzFieHJDOFAzQ2pIUGszdXRjZ0UwZmt6NTFHS0cxR3N5VFRiUnRCRlhnMk5BSUluc1k4Q1dsbFJBM2FRQ0NnbkRLNXpVWDgybzNZWWZ3ZHlMRFdNdDhNWXp2dnRYRm9MeHdRNGp4Zmd3cExEaVQxdkdZUmM3LUZ0cUZudnFWU1loamdSOWw0NkhMR2ZxT1hLb3lKNnM5d2NVWVR5SkE4MUYyRS1UY2FpeUV5YkFmcWZIUUNGUzN1dVNrWl9JSGpxLUR3Y2g5eldhVlJROVRTSUhVVHZwZlBNUW00ODU4bG5vaG41Z2RKaDZkS1ZONXZQUFFyOFFTR0J0MWo2R0Y1X29ncVFXdFROZzdwSEdJaWpHWXZrWmNXdGVfNTdGMENRZTRwaVlJd1lQV2hRb0RDMm1KUDhISTdkbjFrbU43TER0Z2Zma015QXdhYXFlaFhfeUtPQTBMN3pqbU5SUFhoWFVIMV94aG5zLVgxMjdqUFAxeUd4VXNrb0JrNGdaM284aVUtNGo3UHVVT1JNMzh4MVNaZ3NtTVVfLThvdzdLWFhXaEVtenVTTW9aZ3VadkdTNmxTVm5IZzNzUTJOQ1Q1TjNqZlpOUHpCa09fOXpvSUxrVXkyV25mRV9NcEtGZGZRRFdpaUhDckVmWHVzM3Z1WHpZRUdkdDBsQm1RVHRxY1V6TGg4UW9TNUZhcHNNOXUzUW5MMmoyYWlCSVBDaEJjVm9tNFkxT1p0YlI4WWhGbkR4LTFfODU5cmxETDV6anBpRXZJb09CX1F0RHdEel9vSnNMSFpCVnBabUstaHJjN0t5R3RaWGEtVkpMQUxwb21jLVBZOXpCQWNPSWJHTzNLRVlrd1QxMEVkdl95SkN1RjZXVkVZd0RVbzJKNEJkT0lWalJkY1NqUmJ4MzlLbW9xVjBwdUZsd0I0RHF0aVB2TENGMVJmNXBiS3ZhcXE5OFBudC1kVmlfbkxQaFJuMnAtOE9leEdJRExYMG13MmJ5SWhMYkFjajZfWnJUdHhRUk1SNFJKSTVabWpMN0RIOURsZV9taG1KVmtDXzIyWEhKZFYxbVhRbl9remFYUWplcS1kMVhYNzBhZEdWbUR4dnY1b3VCOWFyTXA5WHlIcXVWWnVRazRETW1ZUU5iMjIzOGdPLXE0bkhKdG8tWjFYZkFsZk41cVJaZlo0S25pOFhyZl9NV0NPZ0xZWUI0eWdmSWtVWlRZOE15eTV0S0hYZUhRamVhd0k2b3FvNEFNWUZvS1BJYjVEODdmUUdYa19KbGM4TXl3ZG85bUF3cWkxNUphbUU3bnRoUVUwN0lNN0pEb0FMcGExSFRmWTZ6WDdYWndSeDBoZ0pNWk1tUkVHRncwYUV4ZEVieUNrcHNwRXMxYWx3bEtvSERWRURlQUppWmJMcmRhY21ocWdkME1TMXlMUUhEbmpvVHAzSDVNdzRzYmpQYnI4UnNSNUNkYk9DQ2g0bm1NZXVRN2V4OW1nMEdfM25EaVBpZ2JqcE8xcHV2VEkxNTJQTFBNckw1SXk2clAtREw4In19fQ.-4aLEwnz_3RYJyMTFa-5_zZX6Vja_xn7DOu-hTGp6jn8YkpZLLMx3t92XUeodJisstdNslVLWm7-AeI6g2E2kUWDa3RrxkZVa_jpbGcb4yJVj7ijns0rqUYrVW5Y80qG7dDrlgHjGo2v14YpdvMmZ9Zchah-rL-rQtVc22e4mvSArlHnbHUi6219inOb-gN5JNEaWFREG4FN4UpsOV4PIbAPy79jKGMpS_l1CIGusDgjP4lmSXxM3alSdHsel0hgmp-BCqLHjJeKtRhd73mzYrYND_bDxJNkYTj-etrEsAJdndycMoCSb-wyMQSdS_2zv6saWuDG8GV3vs0YkWB0oI4Sow-2Wqn2Ikhz4iflXGpCQ8AXdqxMUMVcMtt3VSILyFh6pPvPE8PK2x8SYgXMTjbwXIU3PErkHWPYOLzKGuUn2hFr6GNtgLbhMmJjVuonDfEcYIbVKE83oQ1K2yI3upQQQ03ip3BsG4mV2X0QVD2ZblJbtbbMEkhkq9dlAS5xUecsm9HRMGKTj8cjV1Gwla1Oj8KNGClsJjupnAMd1GgPTb3zg72wKDkO74wSpZieznDE4Fszvg_EBhuDFJZT_RQUH5_zLhH1EpvUKFbtWryibjbW5_M1p-mTh5h9pZbcC8qzNI0TWB854n1Mv5M0kNy1w2J1BoDXeZuQFI7A-S1q3ad1RX86TG56RVUnG769VMW3Lq7B5dL4H4CthFRItg_WElTZ-pniMD2hUJezpkyVxZgt8dC-VAL-LH_BpJJaOGIVHS1cYiK-cUawX7Wgz6NdH8zoTLgbEttUXzxi4t0_Fak94Sd3jijex6rP4mxtfA4f-xwCoHK2PbhvCO4hQzqqU1MwIB3XCP17r-pYK5s_-pYkynUJhDjWP-ZtPVerJy4au_FGZjhnlFH3s1zkTKQzIEl98PXFGVJqjEXNjoIcFPKB1oioRkXG1WmA5qAfiW5IHOxmYPUpTvWrFqoIt0pqxyLv7YT7_Qn4NzzJzml2Y9k9DdZkYhGLjLCNlVxoW1JHRYD8aXKJVFN3BDm0MlNeJkc3_HOmHp89eCwRsYIvq5cit_z7OPrtGEn_pe3l_hW9cs9ltRtu5WxhUzqWOpjTCoUD8Y0pvyMswrfRUmLfTjuY7qzNOUvPnW9UewLCbMuJ_FTi66Jp-GPr0_N6rwnZ9Sc4uh8Vhx_r819nuoGE15-CH1w8JcfrqpfKY8xM8Yw93_HKmcsiJqwAdljAKFcLz5jbEEt6_F9FYhTcZe_K2IGAjab7b-1b_kvEpJFuyYs2wdzJK9j1UL-bnFJ8HtQ1hmRHwPAURGIEeSKPRzYug6IwTqiCcx4em-Uo_9_cWJJD2fU_eQLgBdy3eqQkBQOi1l53GfOc9bENHCG7Fl6iBHoNo_eHPQRbsUw7xF01ka03-zTtXCm_ON-zWnQz5gNFVGdoWHcriziOAcq7RxbfMT_pJbvSBEbI6dE3NIdk_Ojl1cp-rb0VKyLp3h-9FIx02U28gosdTMQVtU5RD1V1I9vfMjbQ-g-ien9sYHuIJlxAebLUCYkM_MEDtxQT2Ucsk1K6HHurj6QUcQDYB5Z6i7Be_Lx_0b2UFINjzDDC8RMPoIRuuC2D2lVcOehXnpTTDqhIaTHgyL9MSFfsfs8cHCRmlPFGo9Hw7KFD6y3LbMrJZ26rkTJPJH6uXmFyRTBpgu-wwjW_aUZUMYDLor1pt9PyhF4gyBOTs2lWm-3tzxA0szp8CB2ugZ5Cbe2tyY-12vah_T_oXOQoFLEYHBT6rmVI8ycr6z8graT2je_vABWOLUvnNwL0bIoMIEEnKrDNHHPxdvnHHQjz9TTuAkm_RkORk7PAkdZUAOMiOMceEXT-TeWfVhKjRZe16PSv-wEjAA6mFMWybkuTCBijuJiWSz5VZYNQbXpCdKr6pZl140dnlsX_VX06AsuEuGAeNjN8yTq6ddOxG5FCzC3iqDXnwwJiWFwQdioTCykw9a3rO_D8Dmu5AQw2lGpqu6ONGCMzDvKZS9InlYVosT-Cc6ViYz3UaFoMQtvNX1Imgp70_AWhJSJOlGwFHWjNcEeVQ00ockrabFFEFWbKb9Mr9tnLscxNOV_TW0f4OhGB3IQ_pNR4xXTfy7VNzWUQBeK8qi9hfxZyFtk7--UmTqHw30B7guGZ4Y7za1q6yW3lLIUD8IBbNqL2vGFvbbq1p8oqjdIuKUbGdDF84SCm23I5XtZtF6Ud-H8JQlXEdNZHppH0QfgUUpzTuMS9iHEPgDvzjmIMkIrFw91KMVEPOQi6A68QPqGQeixRnzVMJS--3AbNAA5xVysn6hYhmNsGD9VL-tmGANonFtsPYZdX_Tj4b7hzK4XUnN6IejGbnAIJtUX17WniDXVgGj16JhOqQDvDijiuINCZsz04_7ZXm64MF0QgXRkHUTaTje4c-eg9CqMzL7lP6Tx7UHE049kdO6S_JVlB7KXtmar7pQGoOKmEcovozYQgcLTdjKOfDbGmnEbMvcBAnGVv_I2lMQY1xbxX2-G71wQx5eY7m2dThDqx5DLgDvurKtM9EJ59zpcgo2JVxNw8eRjf44M15yxFvaakKFlgS7fu1UobQbKp60G5gJg4HikHMl4pqpNDwet3TG0akhniXDbBIJsvLAK1qwrcpWmn1XEkK1Z7hxeMMqhepOM-43Z72Dj7E3n_c4Z59n4-1GSqN0KkeO2SoDoxv6lSX5lcAt3oJKIv-35EkW5S8QrjDLTS2d5mY0pdAOnnKvjD70Qe2eP9NoHNZUho2pQ7E_UU9Kuhyj82oRyO_ZNgFsyFGhJEmcpWtaaRg1hR4QuSVvVTABwWx9ISaHINZn6kTDMgEGOQ5RXjRSiWZRG3-Cv-JBTtwsSavzGMQMhL1LPW6t-Jj1A1t5jBN7gMMPY_iS2MlRehfbotrzZJyIDFySowrbpj_ELpYtWCsgIBdlnq_MoKvA7NNmJ0OL7tfmT2ikMwJY4idvL4gC0ZCNeZdLPVWic1H3vgrnvBsRtQu43YZRCYB3dhhCPL0qLYdryjMbtVWM9EYS1xoo-q3yOThI6vnBKPbzUc5aVgzZ7BDm2Hcu3ADhEfBD8BP-2gCSFjQcL6v5OpSOiML4Lx-jycib965l7InOF1VQ4OG34npKD-bwD4p-vDSQPqPTQqRKX-rUqQdJwC9Fmf_6XZu39wvmfVbuRGk5oQQCdLiwYECfSGk_SUfguYOeVdNnfyVSHVLjyB60AM1rWDKio7rRvq9oGmh1IJhKYMFWqBnyj4R9vqjwWzPlGGLsb3c_xuTyQ4bbo8zPwnbNiHDV_9cEKYYb3lfz07FymBYVd1RBOaLA4_hs9MQT4faNjOO6Az-7iremuysBQlPb9fQeyxWQVk88PFQrMW8y7Drq6T2iDEQXWr6M_5v5BHV1eiIkKA_a3_IbOHlX9Ciqab9Bggw0x26_WqdZeuHOyJzfn51iAkfbV8HKJUF6V339CIc0IfvwRI9vAiPHRsi1GvUyiUxI78UZ89_gCxjWyZfFA6gPi7hdg_OIQDbbxLDfn_rIOTm6lAznukJbnUTefTew63pjg3-nEzFJBbkYI3g6uHyENKmesXWj48Ur5wQZlo_Zm3DX9yWCLO598kCyJyEdeA2cfw8LYgTy34UIfPycp_J_AmAB7Mloqg1MZYd3z60MVNyPUdG7VahcjHLKe0-iuMZrnrIkMKams7frYuOi5AE0qNe9RMo8WlqX6ihsCPyflkcZSx80VHry_Wl8OiGe7fYIWmc9KNqB5LlNSBKvl33OvaEK_C_JQ1-CnmDRBzowBHJX9aC-nxrwULmS74BjEabOl-Q0BKVKzrK1qkSRf2tHeUKm6JEOcNGwjp7zWuE03lS5tkUujqWlB7BISJYrd1eG3wivD9lkbNrTNO2_oKO7z-Pj6cHUpoXyWORSyyiP0yTpKZDIyB8NXq2EqGfiFnJbhcHpiKJsHCMIeVYA68AZdNwVZqz083my1btfxfHH80hYrQVLfHpOjSpPpi9NpQXswWCM5Khll9iSM0HHxEYwJ6wrMg9Zb2Ig11Sh6xEB20CtwrDQ0J6y07wj97qKLOE437rYdTv50ADhHafAi4rCSlxdXehpyFi6w95g-maQnOnXwfBjdoqThE186md-zYA3vJh5LXlQAzSbKLyQXRJX26-vYOyeLDzkjikVjWyyWfXIAcaPrPqAFAYPCUuspXhbxZSw_3MlEiDcdd4E5Q5tIyL3He2UlzEZt-q315AlM0KjIQltRNi701mOgrJVANiBfVMWMXSgqC5Eetqy8sIuUVHL05uBeKfapg1PjMoNchgYI_MNSEx8chUZD5I2YC9LXf6MCwtsrup_oDGzplp9UNECs4RnR67n6R8WyLtuUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAYMFBcb~WyJKaEJrVk1pRjdLdEVSWmhQSHQ0ZFR3IiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJJZl9QUlRoSm9EWmJzS2JRSkJFNWJBIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJTR1V5V0lQalMxVEtyNm9VZm13RlNBIiwiUk8iXQ~eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJrYitqd3QifQ.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6Ik9PUGZmckpRNzB5YVlKSVZlZzJVTTBMdHFUQXlIdHZRQ3R2OEtvM2ltQkEifQ.uNVxg5IK1lUNKyN1NvZA2tkiM7FUNPKBRa7mrK_Uuq9OkNWLT8SjnXRLW0lORUBX5QSX3qG-nGT18KorX3FY-0jAWSXbbRqUzJGrV5VaPmiv-WK2MUlIRE1ACvMugZD3Nq0FJhgJBPCfUc7ivyrIQv6GSbeZ98zkraeWX0ImwaeHIC2Wh3BR-yll6a8sDEyHWtxpKgSbLkNHXWFaIQrhJZY7cwWVEn4PMbSI7WLOyc9VfdXmU9J71ifqQFZTRzZsPI4IivK57nrnfu1eL0nHWiFCmTU-ysJn398O3tDKB3f5YFT7srYpV3SRxwb4mu3mk3aShH-bw3i_ijz3ra_zYw_Q0FuTL0XMkwsOi07pB61MoQH9PcUfVCaU-kwq9v8hu7FbORvOl9pEWvJMlKoGSZa5qRsEyCL6VAsBnsniKuSM3BpNrbCFx1-ugR17-1wFrKg8ZAmVHnnDfuOyeyo5EiBorSO5ziFU5yJKuz0RypfKtHM62eMPUecAot0wtSCwt86gMzQHOSOxgNzMUbV2CK9FGfrpqolhKsOrJUctTKarDr9oZ3loRfkvszBcXNxkFhP065zGDLfw7gQWXecuVxqoE6es6nZ6q2PBBDuawxl5lfsp61xmcQa-gTIrMlvTgfJFMyAwcQ2weW-k6J-mN4g2H-GTqhvHDo-NAU3yvJtDEEnrxT-xaZ7zOwTxkQLzb5BDWxOYU5pT3eOzNQeb4Ejh_fIPa-j_K1Ftxc7chJ1Jz2SCJW1lg9hywOwV--IlQYCpEworQcOLDOZQdIssAsD_T_3XFq9sgRF8A5UP5iEScZd6tzAUAbu0dIhyBCt_J8fN_OS3FEd72Upb06mRAFK9ErLndP6ardRGmAq4Qbe4DEd4Lo37-Nnj07IznUxuaKizM9ehO8y22KSkySP-NIhy2Yok37re7oDyqLs1BqcOvvspcMipLBHCxk0P3l9nMQHEtQlKnMsaVDtEAwiNvt0eEK5p2eJAVpHyI0z3Xsd4g1OurXLvOQS5UIzHsLlAGvRCC1_pClEQ4dYid_tmUJeP7LbPRrcA_BxSd-Ozk3-vkn9AsWk4I5456YajT4iGtTwoglOVSsfNbbZmAOO3_2VzYRoqkOhAUNLOnYbWzdYLTbLWA6L36vLPKzR0i3EqueCP_83cmTmBtUC8vdbyYxNesOcCcOlDz-Gb4rYOmyL4y9vsc5Jppo3feq3UgimWH1iFmDmRs77ZAMoa4JaW31Yt-tetr0qP4FT82bag3MuFUevEbhZweHAnJ2QdPktXaPQEtgsL27IIoWaD8q3xRVkOc0-SEij17tinWj1mTjxwCrhumRHFugyYlT9HAUsQHwe-YrCG0RRdEoMCsjypv1HDo9jy5JPNXKEzwgX4lgR67DpuW6Ylt8LwNuFe5dV8njlO7XV1tteoFrdjB9conLRcDXldRsIeFWqzTVhRbJdMFEsJ-HrFPrJ4-dW_7lkofdUFR1UpMh4AV6XAUreRs1NP6dBLopnVwFzGJCzIr58_heuepuh1LZlSrR-0ZH4hL1PvQxEH-qEMHCrPVCOek5nEVS89lEacPZ2XH9HpZBxQIO2xhawSqImBRogm877nwPXPBbwl7wexQvTg-TLKiaVtznn0mvgdTrV2VnFpnIp10jqzsj55JB1evFOpW17AAweRhgXWfmOEoKeMF-Tq6-5_KFTmo2Fuv8pxoj7V3ot-INYGLZ742cudIiqsLdBw2yChRbZQJk7HeroUCA_mbLJKejTcqTFYdoMs6zZFcE2cjPxfGM4bZFq-mrDHpo4YjM4wVWrkauG0nlcSQ3DLMQneEN0dRlfcGA6fTYClmRDWiv_R2o3o047pC5bTQZokZubO68VKREB3UH71r59ToiC9Az8-QIm2pbMd_syX1n1eiMKxaGSOlOULvqi40bhCVK-yWWLPnwsFYPJ1Bf_YJfDu4uN8Jg3_FCAZwCtzjFtg8ZOnIBNu-ZL3t8Y9PRxOoahRRV2Nd0LuNLCMUercr1YL7cjh7V6a79ZUN9FtPmUfE8O6uvovUSRyxO4H9lUi8lDxJnivKZucd4yc8QdB4n5-H-9GyWgTYHcxtmh7pOCbEYJzUQSDeXgZqeUzzhasPD8PwhBq22gTexP8lgOlVZTFTBMYzIbk3nKuuKXLsmkHok75O9--jNkbd7bSSbJSHNKFWCxCOjgEAhWFvra3k7dvJX5gEWLZIroxT7wvUJ0mrz0OqNagK1mzb5aHvcVazSEp9qeVACbQynZUf9_R0wYrFY2zh_M6NPF3DnDYSmGfdcEBLqfz2AjfcDtgpzQUjEwWH_5U0CXq6hjXyHrrArTZxP8XPQ5xHpLGWyjVdHpr5K3My8fpb9QbALLVcluiMaQz3jnIL5EO_tquBoaVIiKqPLHXKD7ASGVT9jO1bRI8NIu9vehJEteRQNYjroSFyx0XzX57V7Zhp7n8VRNmMBwQ0UoZ5c5ZNamN8ANIu_Gt67gKZg80BaYz3JZpUoCIcJV9LL-l5CCB4YHSM4CXKOKo2u5k5bWCNuYaUQw3UxLq5zQtkqpzT43twzzDQMDoAiIKBj49jTHtltuFq3rvcvAY02C4envg0lDyzIbEtXHDY3twLf9mXQDI1RiAN_QS-cmSwZsI-d-v3cfWbzPlhh3-5pdLpK4RzseRzPG0CBQOwGBOJerliK6LllR6yllrrLdCxuNYSCD7tzR3UDAGOFJU5Y4ozkX00rh6mHTy6DFwAWoaf1pg3hrDc3K9hYGWR3TAOVrbayIPySu42ln_ebbz6AHexsZoWwq5I4SljQxN0tdXv9fCFhkW5l676j_Ln8nWTNS1t0TULLG-Oh2AYUuU9XnI_OIISsidOW0SddMz_SQ-fWwIyAHHGyutRFaZUVBF1xye3dX7fXx3P0OpjU1IMVPUhcNTn8dkmvhq6Fc1rNfaOE1WvPzdxwM7tpHtXw01v-xVC9yIk6F8nOEu3ivETiw39n8W1oA_0KRhz04FQKrbTTxilc92-tskTG3phx2kskzqACZ-6qCcFScIBM6rCSGXYWRrMuxGuNaduGA6PkCUdo1GREemlLA7Uz20SSJRQhTHT3cN6OFaLUglZmmUdxZqXmec-MNXZ6TibpVkYj1xspm06qnRhjDx3WQVQX8kSXn3C74Wj3pARCSFNfoE1kySwq120E6CYFapEuiitV1w_7uAI3ip400nrqqpqNF8g7R5ppccyWvfyS7rJZ7ULd8kOvHAwN3_rTbIlwkf6jSHiUN-XfzP4iNcojC_kPLjy6NnkJ_RvfkokQs7UiXI0DZAhEInSMQUsaxvbEplOx3ZpPyDaCAlaqoYdJiMLKTZaA03SyWmNjH2zJRAHwtpvIkpcyryPGpozFlhuOnpbU4LpHOzu7dqadNPagcViOm6e8aSl6y99othBtrNbwdiQUtIg9IHqZgFIRN1RB5lh8kneGi5p5-YdZJyCjb668v546_w4cjeRu47InlsV9J4X3Gda767da6gpw_mktE1RhvH-OEwQPGt-siNXeOjLJFQ2f0ZWPW5QCJKa00r216zxSfXAEvjTbEjYHWqxZIWkJAEqUgtqrGDdM0xNOxo-CTo7F1vQbrLI1ohLCLYnv3RE82m4CkA8fXvovtgqtQunUdGcV5Fb7mebDoLsMd8l7Z_aD79j2XtlvVKOsDSnqB2n_XDfFCiNE6HXdEds4FHYFwOXUSmHeUcOkM7usX9q9GFGWvL5mf8PMySaw-g4z7KbcWP4xxAj87ogv22AyW2gYhs6-bxHCFrpBefmqnvLMCcxoxG1lttpEzKrLkJnipv4bhUpLjrwXTjLyfFRRsVsBjnzoohdSGdzfuOTkqyQH_sEA9GEu4VtWg83EF_pSAQvZCbFhHyptylHVCbgDs9AU9nFceHu_bq2eB-XB3KSZ3K79Pln8UbmuYZMZqvk371O8xAhIhDOjYXUrcF6-qglD9hjWejviW4hrMnVjGC6aPKbGDiXO4geGsvlZAji8OI_YhDM3GkuRc_zj4mDj4BqNgyl7TmA2C3Dj_UJo_vhBYh0ATPT7I9vI8V9ICcSsIZ1h7tJFFMWmkdsDPBOeL3aXXC9Q7TfUnxnhi2hhh0hTDA2NJgG5dsVqItYlrVVt0FtjgPZ9Ss4F2mnGFRfjmM_yPsQs7DMjK8ildXmIJm_KD247IHGWQXk-KmR2bKp5ATZ6T8isoPpP2RIQRyz8ziUpkscSwlTXU6bzjv8vExEeyQSfaf6tbwHSRzi0CE1O2YizlckJ4SPnvA1rguWbj6xlTHNic5DsJB4Uhbmaw_Rvowe9N-fCOYDWKE3PjmwEUjDPjc_iRLTGqYFga-hlRHk7fr-XeUwsnWMDtPbq3i4_8DC2CFGj5IbH2hqazZRIuYnczPAAAAAAAAAAAAAAAAAAAAAAAABQoSFh8l", + "issuerKey": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "wIZ6ICLeUmiM3Y42iOtALwJ9imQQ7HanvDoYATMUyamkdh5_JFwzUidqTwShiHwx7nNBeXn72UyMw-lP0el9H0KgNHyyggkRjbBVqLUkBY7vFFdGTsZBD3FMm2EuuYmRKGhbtRZTGUgFBmPZpPcsUDFCPp7p-CGfH8v8G0EoebBCTMXbP0GqNVG7COiWqhUQQC4p5O5r8WUIHnF29OjYOaDQl-UM33V-R_XY2NSUpF6WK5dPYaquv430z5aKnB6KCoPcvXRq-9MkjPYO7VbEaUkbYlDQjFDXhDKOJwzeOYVy1S42jWrR4YNrbL-Qx3MPy3rLBOrJFu_ue2cPYU_7-1nT0c1kf27oD5oUzFbSBwdpZzTxF2I5VeU4Ev5XyY9HMqWtc3ZBmFEsnCpgRg-wtIcuDfjyPwDtH30yI_Ih3zQozfDe8cgutfKnovGTKv1Lc8m9qistCTXeTnoNm_P1xNVNaJG7dOqtFq83r0oaq6bkZG9jbHqpyYOsaGFyKc_ihi544NH8V8cE7ba0IRwlVezUpkhX_lOKulmLC5GXBSpJgSms5fnlIGwnmjAd2dIRAtuNcyakeDzntyjlV5uQcZ42aG03M482XY5cfv68QzDA3GuamyZQOFJg95VBAq9vpIjm9DhrxWHLrxEgl1cgJVrgRe56SeStJiRiDrSaU-0k87T2nDfkPJx3accrXrlaRGAAHOsTCgwma0vbj-7X6Fk-KRum4R0e0NXjxuZBiE4eEtwKaiagcenDQXpJFEzxbg31uLuaHnPcyDIUE5ZJnx7HsI4vKySHJmr2cXRk_be6vVCFEDdZ97l6ailRdsjowfWKm6SjrzGy9GKJ_uFSw5B4W1oeFZKXDhHJXT-B1KoDC2w16peekpJSP3qjqz-ah2wsfWLpjHqr8OjeBL8vOXQlHyiHPXR1iwJAWU2KkdtWYcUONzwiJlV6juncHlJbdQlI8VEeJVB3sNV1bZ4xApt1yHrrSGUN4nHUOIZKM4-W-wJ-lm2i2fZ7PUtlxfiRsml27Z4y3vs-OLaBIHHhSVAAkM95c4GF7yC5ryP1UAb2tIbnRBmX3K24KgDE6ZlPGKHIQd0q2wi5rEZlbVUPcjEA9kPwlfoDefDYohFF1DwlsxnLCvFslfd2ibMiFlHE7k2QqZcVb9guWOd5MXhSgYDmBoTFmEHoPZBKGP0Nr9-F_UuR5Myvf0z7nmKJpEz3JARyOSvgpVLBKr9-cgA514TjW_VCi8OysyLj8K3LZV42Cvw3dxt4pWNGDaOXxqT4p1lj8W7W6mzyovOQB5dTTcy8WMRBcgUpgRBqdtQsmTJfEg_VQC15ZihUbPdtq9uDbuq8H-Q83oNFIlgXNqAO_-ijlRonIXiY21UpqypyE8ATATT9jO3YpL8hJT4wWdp7HaSIf_6fBF1q7tLdJTwLDlhFApR9aYRjDHHBFYq3tPNGAYNaYsWkX_pgFxMk0ppLnn-WNW4ysTomK1j9LVbLSXiezvlSmh6yP3mTc83808I8Y-dLf1WEhNztKnAXzLIhxWqLqWl3Ligq82STGspp3nSaMT52sALaZ0T0IRSJY2VMFM4AQ-OOSnDDf9c5z4walt-UZznlmsQ7hVLehPL-lUfrAEUkvUqWAZm011Savv4qUg9VsCb_swKKi2MOjfyXI2rFp9E42uEVQYztnf6wpvpFOFHWaO5jIiafxuQiPrfJ4X234Btt7zMb1b-dpXZV9AOFOp2GqCJDxs2HWs4G0pNLfYhH01PwDdfjGYceOWT5VGCAbWuDdGO9r41tijrgWWvwZepOXFrEvmcTsVwTjxLkgL9kto0dIdrJtLFkWNGgtDZ-i0b95Y7eg17dIzeLYHGdA6rCJ3dEMzNd5aG2FFt9SkqUxVWuBP1Xvr4bYvhbsdPrNkW-IDV6WAJQkpxjXsDwm9736ChHuA3IgCHdxYDCgT8R3D81jaZ92aFIBWeVZ5q503qNLdErL4daezU4GIANmJqf16e2BA6hM0ybF9s8-iJNWfWloFt913iIgXRiqzwGxD8IU_syahOMSppzS5DF1vh4LjARGpotUx_yd399TjHVd-Nk74F1tIENykAhqPda8bPtuSi3y4S3gbXHW7n2IahH2Q_tYzYVboTvuukDOP8L-pHdR5x1lvGebpV17ogazcP-yzUB-MbcBJW_q7BAxp-bVUfKIMEi63KOnSqHityCb_KcgsAx8PJXmU8wIaUN5MqDYbm7Kms_DchUcXaZE2KsPer_CW4-72VZjhNuN4LVxsDBBHeqgx2YFLR7bSZw4qC6bNtnrmmv-jpWZlmUs3FfIKObKsFlCZZy0MJyVM0-p4L7u4y84zXVDqRf5AXZTKTdjZxMXGUdbFbYtDGDjhmknZAavecyh4LwJtJT34LpBEHP6B0Tk3FBU4r23j1e_quuMGYikcWVd8OAwZ4RP3qa21xNMqCFD9lC3pOdmnJ2uovrtBVilugxrIwMwD8I1K8gQY6vvvBTP3fgud19CWn4soXq8Y9z64oCzRorigim1x2j7EwY8G85pAnGL6HPFdCKaG2T2sFvXRvu8NQgjgbRsF5TRBfcz3QtW6wFNaDyjpO3mWbmsBQPbAQ" + }, + "issuerAlg": "ML-DSA-65", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJzdGF0dXNsaXN0K2p3dCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.O2acplw6U7bG9zzvXMvpwJonbOMS0LWoyW0DZBlZyH0r7KOuu0KUlsbMttNpBNOc32oVzJxCqiU43J_FJFjrw8HhUFag1hnED3we7EsvXjQaYz2wKAG8QDST5wn-OVUq8b7WDYKmNIfRvqQEw9536HiKlAmj-AeAa4sbPkHi9iSaiIXlxb0uZMVM7xLqm1ECPnnYKuOtPJlLLbXtAEpH-it1_Hr1HN5l-wsu2Aw0RhhZnBAo2xnr163bmgLcucACziwqsg3U8zwHgB9JZsdXtT8xN9yPyHPFdCA_Z9pUNRWvMsAT1XEYipR4Khm0hxvXm_np7g3ZDX8x1CW41H8b114YiffcoN1swZvOkW20p3DjYQRXrGWp04Wkg0BcX2gZTDCWMYKCmxFyWcm2TltlR7zAmN5akPPp7eBnXthaF22f6tWEMMw-TuJNoVEHf37JVf6nzstMqIlTs1WYjK6yzobsSUl7K9LnbMZqK7au2XToM9JlAldW7ULSNppFeSk2ree8c_7D4IVV4GdnXSfVwwGEjbvMmVMSvciL2T2EqV9DG7ETcm8T6fitAomE4XC2VN4VuV3hlOZ-56ea0YAUBb2mYydT8-utafKgCwmD4mi8gd7gIclkM5AKuaW0i3v70y90aSflvH3KTiWrdCncFfIg3kyPqT0FPwzW4Zmzro2PawLQN3VhIvDcomxnbllrWEeXdAef4Gj-V2ynzYfXHy6GEJ5--t1396x_Iuck-OPHKm-u7vOO-DY6MlUd1TL8AoslqCacE7J_OlHIJWnkiRcEwcFOcm6E-Afd_UH7C1OknpqAeM6kc7ZKhLNl548tMArwJTxhInKIQBSnxMZJv-t_kHtvG-2c0NQFAhp_PFgp_YGf7skD7Rlsw3PKP0Cto8LgTCthx-sminRcfUklYAEij-33mnQBtqkXzRD-dM8OfbWwHYXpNbosDyY-6UZEFVHqENgNs-qmcHPQTNCpnDLtwJSYEa96jsyhgynQOFYYqjJINDQVjhp6mStaoSPjgwH1xMFRlxSqrI47mgt32zc6u-_MYO6xrrpEO8rHuohi1HZ6FGRLmsD6wX6rVuDym2Xn_k_2UaeNVu7fOojfxD6DHxSQrC4sGE1uJLwcfAxU8qQSfvZQqQ3wN3PO5NlMfo1RcEcBTjjzKA5Sx-1mKTM5C4VA_GEfqZm9-wf4bI5J-rODuVCkgBoTY7TX4CcO829AuBJnmkiWa4_o5ZMJvb2DJN_h8sJuSf6moSRgiY8fcIGyNy9wQ8rbWzF37Nnz-_4U0NWhyxc30yrJ74MIbs9Lt_H0H48C8j4p6kCC2RU5IibEIgfx8PTrk8jZpKZrW6mHr50oClUbgxVAQL99BpqAoeLLNuvh902gxXxdSXKgw81FSWN7ExbIEIE-VIqHb6evFbOzYVOFl9SUp_L-3BqWghZme_gD0_0xo6poEEZ6p6AJYQcH-QvjBYJYcgGw5WD6-PVZ9xoLBLzN4BZpGh424Sd9tR98ZG3L7oxK72GwVk5QaR4eLdymYRlHMxa8pgmEDgKzuDLg7viX3bcZLfe1fUbqjQw30U51lRf4uwhOQO1DhBZp-AgudglB1NLbSlg7qbQ4fP7p41nyn7PGkBiTSU1pGe8IZkScnv5rLNUwm7ME686vjNmyjLhC6kKSIr-F_s-G7A_EwUjVwn8XXHH-uP4BhQMVN78p1PhF0gahijtPaRJpK2JLZKNLWCRtuOdHAMgpJ0z9qovNPa8cD5xR5FJSFZjBv-OQEPDE_p8DxGLIxG7uroTOw-IDeU5nyk3wkm99C0woktY8kUOgcwfBMoVn9cyPHLBYYkAsV8iPeNEnmW1BRr5xqZAUyESEFslSFZC7NMQYJj68L47JiqLFbsfWDEfC2ViawF3-JfEREHMddxsiROiZmbRcGoMmomLsOc8bXPq9_QCHeTCh6jSwrBUlim2C0kAquGcAZgEFGWHJhGht64yKfDFZkpOsW47AW2tzgd-xAcDExEDp0p7znxj7qYouKy4G0feJ65P5wabQHMvuOz7c8JmMXFJ8p-8RgPZIy15Hj08xS_QzJXFghMklu_8YvzKYr7_GaXzvbvJmDu-UYeMRF7gT6joka6ZlcVKRs-gTFKzqwwRhlJR-wxFOp4DP2-kQVq0Dad_Zeulzn6y5VNBHxz0RYq0Zk-FELD0B6h8fOM5RVchzCxq03xIdNK9aDfRj-hMEbh91zCygAvgjnAr4o6JoIicwJ4DNAIOERWXvF5S3-u75m8zGfBWQepdVljqFeUpaQm7ujl_kzj53CsFnCeh9B0wNmHPrxbXG_t8kbLgP6LenARoPwrg7CZWSXyFoGDGeRHv0is1zPtliOHH6giEGuk-JYc3UxWsiY6-Np44w6uUqcGNNaI7fKWi2nBbo2RlG6CaRgucBgszmbJJYK_FZuOgDQdS4m9GGsNB48sqxFfGknjU0ec6L7o5Co7r8H9VpSAXqFDTgd7dLC-cwbYS1oqIjTkZPBivTKgBhI5uTOWrsC6JQ_lW7bFcX88z_m_pZIn4wrrN-nSDK_ER4hL6qDLAYvl8cid7Ln52cd2m8Jxp5aOsZpSgUpnG_WeYVF1uu14R0OQAqj1NtaVDjk80Kb5tT99tiqBCYb7owQ4LeGU8KzHszTEVVSUKIY9fBrDdvNYLHoRxYaVSeDtIg_vMoNcagsnCOVOTV2bxeS8McFHtNwN7rm5PsDGbMnXyayqnDy0-xaQnP37njPpvfIAcnpvVcn5x6vGHCJR_Cp2RV60GSONNAzYOktSz1axZ7b4AD8u0mPBsf-thOjJLubF7yd9MS-klQb8TxyrDSDxQGiVQNZaWu6Oq1Q_eqhkbzwXQaO6ws0hktmCcey-Z2dZ0OEZ3SyB1BU6glCjKcY264WgiVxXKPMRozOxdejxj0gLBbbtEIdqRvKpfqn_969wdu3e628IdDq3Pmvs3ekuzWiil9pIGRDi0eJInNLD3jlC0O-AOkH2raap-xqv1fnlSxJ_HkZTR2JaHAbOB0XVNdk4y1vyndMKp8Y1xrWOaeNVUrEk9HIXjanQ427JFoUYp1EETHbCAdyTQButD91p1BWOOqVSEAsWxCg8Br9QYlD_tvtWNvh_BkXpCcU3B0w4fPu1igBIsVxVXnJBpKi_r_JiPit3bNPec80eL0SB1RV5gJd6r2TsE5lFepcj6gAbnLd57sBrasuY2aBbzREKjOP4u7BtgDFBBomcT7NFF70TnJJ_-LaqvLXcsPJgwIbM6FF8ppC6feOgEtEUrYp42mteqZMCsgM-rteF9eML8cxCCoToYZVALpnX7lE6DenMCqtb27ghPq9i0as6YWYhOxAgs98h8W5k7-qzLfiViyxe-goVwVcJf9RNu2Ul36bcPawCR-MsrI1p7IvUA9C9O2kLSAtqjW8yJghMMDfZdSkDfeXWYuRxSKjSdl58uxXFlrQjhfMTW75p93_W3GdrttR3EMeAmQJox7khw0oRrE04ML3cGrrwzQoso6S5JRGfBb9esw0-ep8dYA6SQIcKB6HH_BJ6HyHyD15XjdXDnKabiqh79gdxAadBW2IwHTdmYfWcPr_i5OkhxQW2fRj1Wpdcv71viYekD1hpI_pqdRwwHE_sTfOv5ak5FC6d3rYvCIr1FMLjpP-lplknKaJT2Zh0NOOaxa7gRyOkxtgh7rsN_amlU4caG5rHGTia1RbEKDFqNkvIiT9An1DgZP0kzZ_qMsipYMtdJ6IoqhN8jQh6Cnc7RMYR6ytf6ckDSs_ad9Gaor4Ma-9tLQEziBc06GyB4ieC5ia4rsGO8Rwvw0k1DqxaYBcWBnMqDOO4XwYtCOxEBx1ymP15OXDCqz7bOVWoTYrK0OGLafQ6CpaAuq8Dt7yvJKu2Gy_UwyobSwqTfNQgmaav8GEyJZH9iUkZVaOYE2AQkZCEBqHInZqyXz7OlrtGq3qW7C3Gx60Tdu6KM4dwoiTaA3mHO8mBEKVoFhTBfM1_yTiNb0d_mP0y18OsQ3pYiWuGWbtTrXx5C2d9Te1DKPU8Hbjd3x3uFTetn1l85VEQ2KpIWTv7EVYdBpJhWQt38TYcdWWUhK_XbK8dp6X2zvuFxovH7-65j-GZTmhEpi9VQvzZcxBwsyQd88ZVsMbTJtRqn1d1wxaIdbPdB0T9F_Yg_X0SPGjNke7B_X1c-mucpIdmI_5bhEhuTM_XJbgoKxF08aqsXmM7C_IPB2NXbybhCeR2qvJz6qMxMPeWi4ZIH84K5emxCjF91LLX9WjpIK_mRJtwr_fZIPPYnikH0AOv3iGv8eDYvwWsr6GuMx1JOhX7csGslkJz9yRooPdlt34wEnKz2D9y209T5jqO8LGh87W5vV7_0EGnynAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAggLDxgc" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid-status-waived.partial.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid-status-waived.partial.json new file mode 100644 index 0000000..816ab19 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid-status-waived.partial.json @@ -0,0 +1,70 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid-status-waived.partial", + "artifact": "sdjwt-vc-presentation", + "title": "the same credential without its list, the verifier waiving the status (requireStatus false): nothing fails, the status it names was not judged, so it is not VALID", + "source": "producers (sdjwt-vc.mjs: issueSdJwtVc, presentSdJwtVc, issueStatusListJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "requireStatus": false + }, + "expected": { + "verdict": "PARTIAL", + "failed": [], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.disclosed-protected.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.disclosed-protected.json new file mode 100644 index 0000000..3035d58 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.disclosed-protected.json @@ -0,0 +1,83 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.disclosed-protected", + "artifact": "sdjwt-vc-presentation", + "title": "the status claim made selectively disclosable, and disclosed", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "producer": "the issuer put status behind a disclosure (no key binding in this token)", + "changed": [ + [ + "requireKeyBinding" + ], + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkRwa05uSmVBamRVMHFSdEJqdV9DdGNBdmNDN2lmaXFEbkpFZk5Kck81U1EiXX0.ZshknlcwIGLJQmqM167plJQIoD73pIcZU4_MPSvCOsFI6k7IiQzFf7raCHTWWyhK1IjwrWMJ4cP5zAw0UWc_BQ~WyJzYWx0LXMiLCJzdGF0dXMiLHsic3RhdHVzX2xpc3QiOnsiaWR4IjoxLCJ1cmkiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSJ9fV0~", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.disclosed-protected" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-idx.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-idx.json new file mode 100644 index 0000000..56e4f40 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-idx.json @@ -0,0 +1,83 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.form-idx", + "artifact": "sdjwt-vc-presentation", + "title": "a status reference with a negative index", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "producer": "the issuer signed status.status_list.idx -1 (no key binding in this token)", + "changed": [ + [ + "requireKeyBinding" + ], + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6LTEsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19fQ.Fa2p9WGijm3pj2YeK7XO1g5MWt1Q9ZOv-HfBK9MB3IpEvgfJXiBLhazP-PXWWYnlHhcxR7rXOkSeujXIoR2ABw~", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-integrity.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-integrity.json new file mode 100644 index 0000000..8b9eb21 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-integrity.json @@ -0,0 +1,83 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.form-integrity", + "artifact": "sdjwt-vc-presentation", + "title": "a vct#integrity that is a number", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "producer": "the issuer signed vct#integrity 7 (no key binding in this token)", + "changed": [ + [ + "requireKeyBinding" + ], + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwidmN0I2ludGVncml0eSI6N30.KpUk6XDQMp6dudRtH0jboaIqncCm-JwWKCPWtT8E9W2r-i8Oxc93tvxfevtYRkfswsdO0q1joNzd2g-HkpyGDQ~", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-status.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-status.json new file mode 100644 index 0000000..2cf932f --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.form-status.json @@ -0,0 +1,83 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.form-status", + "artifact": "sdjwt-vc-presentation", + "title": "a status claim that is a string", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "producer": "the issuer signed status \"revoked\" (no key binding in this token)", + "changed": [ + [ + "requireKeyBinding" + ], + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fSwic3RhdHVzIjoicmV2b2tlZCJ9.3bZlQeCXOmnkJ_WipORhYzEa_eDZ0Xpt8qNOwKPTVSsJT_sOPyfzxVsREtI1C8Nn78fF-7SrXnwbsxpepiI_Aw~", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ", + "requireKeyBinding": false + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.form" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-index.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-index.json new file mode 100644 index 0000000..0980c16 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-index.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-index", + "artifact": "sdjwt-vc-presentation", + "title": "the list handed is shorter than the index the credential names", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6OCwibHN0IjoiZU5wallHQmdBQUFBQkFBQiJ9fQ.K7O0Lgxk_ze_VvWSUnv92kKNVeaytqlH5qc-dGTXH8HGBVOUZgD7CG19SGytHkjphiZD4Ym-TqeYqSOjH_SzCw" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6OCwibHN0IjoiZU5wallHQmdBQUFBQkFBQiJ9fQ.K7O0Lgxk_ze_VvWSUnv92kKNVeaytqlH5qc-dGTXH8HGBVOUZgD7CG19SGytHkjphiZD4Ym-TqeYqSOjH_SzCw" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-index" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-expired.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-expired.json new file mode 100644 index 0000000..d68f5a1 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-expired.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-list-expired", + "artifact": "sdjwt-vc-presentation", + "title": "the list handed expired before the verifier clock", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzAyNTgyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.OygFuUeCnTQ0RMOF1ABDYUVwJIY4XOgSt1KTFRrmfBZ7WQLtQifeOaSZDRjjRMmi7KGRVXtnSN6g7ADPboCaDg" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzAyNTgyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.OygFuUeCnTQ0RMOF1ABDYUVwJIY4XOgSt1KTFRrmfBZ7WQLtQifeOaSZDRjjRMmi7KGRVXtnSN6g7ADPboCaDg" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-no-iat.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-no-iat.json new file mode 100644 index 0000000..ba3e162 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-no-iat.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-list-no-iat", + "artifact": "sdjwt-vc-presentation", + "title": "the list handed has no iat", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImV4cCI6MTc5MjMwNjE1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6MSwibHN0IjoiZU5wallBQUFBQUlBQVEifX0.EsgwUPlLED1rLsG4eRe2TfmMuYhOrKsC5_r-uMqvOpKj-YenmnXD7w29pnRM_zEf86vvAI0bNQp6P87B1sPEAw" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImV4cCI6MTc5MjMwNjE1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6MSwibHN0IjoiZU5wallBQUFBQUlBQVEifX0.EsgwUPlLED1rLsG4eRe2TfmMuYhOrKsC5_r-uMqvOpKj-YenmnXD7w29pnRM_zEf86vvAI0bNQp6P87B1sPEAw" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-other-uri.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-other-uri.json new file mode 100644 index 0000000..3aae446 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-other-uri.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-list-other-uri", + "artifact": "sdjwt-vc-presentation", + "title": "the list handed was published for another uri (sub)", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMS1vdGhlciIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.rUNIGt2ncvgWImphPEIF8xRZmQvObZy37NB330HXiMEFPI-DbGCS-bZG4-TOOhoVLqb8MmTrGy3mOXA0Mbh4DQ" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMS1vdGhlciIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.rUNIGt2ncvgWImphPEIF8xRZmQvObZy37NB330HXiMEFPI-DbGCS-bZG4-TOOhoVLqb8MmTrGy3mOXA0Mbh4DQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-stranger.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-stranger.json new file mode 100644 index 0000000..c85b73c --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-stranger.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-list-stranger", + "artifact": "sdjwt-vc-presentation", + "title": "the list handed is signed by another key than the issuer's", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6MSwibHN0IjoiZU5wallBQUFBQUlBQVEifX0.stW22QbAfDuxc9bB_L7S8_Viy8Q-FmMCrp33upkwLZA6Ez9qeGi2Z_WzkYq0GbLQsb0KxG9RTiWHkV-XIW5uBw" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1Miwic3RhdHVzX2xpc3QiOnsiYml0cyI6MSwibHN0IjoiZU5wallBQUFBQUlBQVEifX0.stW22QbAfDuxc9bB_L7S8_Viy8Q-FmMCrp33upkwLZA6Ez9qeGi2Z_WzkYq0GbLQsb0KxG9RTiWHkV-XIW5uBw" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-typ.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-typ.json new file mode 100644 index 0000000..b491f82 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-list-typ.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-list-typ", + "artifact": "sdjwt-vc-presentation", + "title": "the list handed is typed JWT, not statuslist+jwt", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.6U_gARjIurUBzIQYqufPjNYzmT3nvVWebULymAWs3Dth94siwGLwqSJquXJFXEGgEZjjT_-e5fpVpi9uJ1siCg" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.6U_gARjIurUBzIQYqufPjNYzmT3nvVWebULymAWs3Dth94siwGLwqSJquXJFXEGgEZjjT_-e5fpVpi9uJ1siCg" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-revoked.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-revoked.json new file mode 100644 index 0000000..c4d704d --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-revoked.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-revoked", + "artifact": "sdjwt-vc-presentation", + "title": "the issuer's list has status 1 (INVALID) at the credential's index", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBUWUFBQUFFSUFJUSJ9fQ.oimbeRq48Zvabtwl6elhRf_5bY5WdAvnTOAdktoHPxbfoip7swrJ3Ux2v1O48LSph-7cceYTVXNksbVcKyTCAQ" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBUWUFBQUFFSUFJUSJ9fQ.oimbeRq48Zvabtwl6elhRf_5bY5WdAvnTOAdktoHPxbfoip7swrJ3Ux2v1O48LSph-7cceYTVXNksbVcKyTCAQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-revoked" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-suspended.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-suspended.json new file mode 100644 index 0000000..3ee8ba0 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-suspended.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-suspended", + "artifact": "sdjwt-vc-presentation", + "title": "the issuer's list, 2 bits per entry, has status 2 (SUSPENDED) at the index", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "statusListJwt" + ], + "value": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoyLCJsc3QiOiJlTnBqNEdCZ0FBQUFIQUFKIn19.facNVbBrSybeLUNLVCU0FDBpH9XdDZmcVQkGcatktJ7v4fEI-_XBG-JAD4h9VKZr6zmddk3ZtD3x3h_HW8EbBg" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoyLCJsc3QiOiJlTnBqNEdCZ0FBQUFIQUFKIn19.facNVbBrSybeLUNLVCU0FDBpH9XdDZmcVQkGcatktJ7v4fEI-_XBG-JAD4h9VKZr6zmddk3ZtD3x3h_HW8EbBg" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-revoked" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-unjudged.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-unjudged.json new file mode 100644 index 0000000..cfe134f --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.status-unjudged.json @@ -0,0 +1,76 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.status-unjudged", + "artifact": "sdjwt-vc-presentation", + "title": "no list handed, and the verifier did not waive the status", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "remove", + "path": [ + "statusListJwt" + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-unjudged" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.valid.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.valid.json new file mode 100644 index 0000000..ac643d7 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.valid.json @@ -0,0 +1,70 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.valid", + "artifact": "sdjwt-vc-presentation", + "title": "an SD-JWT VC issued with AERE keys (EdDSA; vct urn:eudi:pid:1, typ dc+sd-jwt, a status_list reference), three claims shown, judged with the issuer's Status List Token (all VALID)", + "source": "producers (sdjwt-vc.mjs: issueSdJwtVc, presentSdJwtVc, issueStatusListJwt), three hybrid key pairs made and discarded at generation", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-expected.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-expected.json new file mode 100644 index 0000000..8b3a5dc --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-expected.json @@ -0,0 +1,76 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.vct-expected", + "artifact": "sdjwt-vc-presentation", + "title": "the verifier names no credential type it expects", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "remove", + "path": [ + "expectedVct" + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.vct-expected" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-mismatch.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-mismatch.json new file mode 100644 index 0000000..2ad84e1 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct-mismatch.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.vct-mismatch", + "artifact": "sdjwt-vc-presentation", + "title": "the verifier expects another credential type", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "op": "set", + "path": [ + "expectedVct" + ], + "value": "urn:eudi:pid:2" + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjUsInVyaSI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUvc3RhdHVzL3BpZC8xIn19LCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJtZlVYbmZPYWlKNXlSbVNuMjZMYmVrV1F5TGFJZnRlVFQ0ckJBZ1FEZU9BIn0seyIuLi4iOiJqaG1kQVhKZ213dVhNbHZIVXI5NXRXUFFISVJlNmRiRkI2c2FmN09qUXdFIn1dLCJpc3N1aW5nX2F1dGhvcml0eSI6IkV4YW1wbGUgQXV0aG9yaXR5IiwiaXNzdWluZ19jb3VudHJ5IjoiUk8iLCJfc2QiOlsiMFluYktwU0hQeDgySDlfcFlFd2pIR2trRDZsYTZzT0lXMDI2VUR3bm5KSSIsIjBld2puX2x5UTExZHFlbDZZYWpDYXA4MzMyU0JKRzAtdWgySmx1UUFrZTQiLCJBNWlQMVFHREVUOHR6VnJvQ2oza1h1c0w5VFJDVzh0Wjdzdy1Fek1ob3l3IiwiQkswSzM3V3ZYVVotcy1CTE5ZQ0tYdmdtUkV3TFFvQi0wSGwyQkxkMDVudyIsImJ5R3d1ZGlONXdoUWpRSGZQQmZHLWhubGFnWkd2S1hXS2VqcXEtMmpsU00iLCJoTTZ2U3Q0NkEtVFVlbDFqT3B2OGplTV96WnRDZklnS1BRdFpQcHRHMzVZIiwidjloYXQ5YUw1elNUejVSem81RGloZ1NEUEpSeWVZaXV2Ykd0R3Vmb2dDRSJdLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUiLCJpYXQiOjE3OTIzMDI1NTIsImV4cCI6MTgyMzgzODU1MiwibmJmIjoxNzkyMzAyNTUyLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4Ijoid3NfOVdBVGxJdDNXOTZKVS02Y1ByLWNhbGt6SGZNSTZhdWVrM0s1OVZEUSIsImt0eSI6Ik9LUCJ9fX0.xQWADsMnzqfN1Vdk-GFoBy5EuJ1uKCH58pg_8bg6cA2cZyFO0OQlmiEaoj-996ZpRWriNA-obPdhtsg3Ov3iCQ~WyJRSVY1ZUJweEtiTVhEMkQyaTZYRVFRIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyJ1Q3Rhbnd3eFh1ajN0ZHc0LWo0U01BIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJQZGNUVFNUU3FDRXZwZnh5UXdUZ1d3IiwiUk8iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6IkN0VWxlVmYzS1lHdGNkOU8xS0pzNzZCcTdHaUJqTm56eldhSVk0SmJvMW8ifQ.rF1INd7UF2UUIgw3DWkzI524ASp80-I_VTlMwbvbNVmVmGz9z4zL47aTIfl0AE9tUWrp4EUzk94XbqbTEyr4Cw", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:2", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.vct-mismatch" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct.json b/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct.json new file mode 100644 index 0000000..821feed --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/aere-pid.vct.json @@ -0,0 +1,79 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/aere-pid.vct", + "artifact": "sdjwt-vc-presentation", + "title": "a credential typed dc+sd-jwt with no vct at all", + "source": "derived from sdjwt-vc-presentation/aere-pid.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/aere-pid.valid", + "mutation": { + "producer": "the issuer signed an SD-JWT typed dc+sd-jwt without vct; the holder presented it", + "changed": [ + [ + "sdJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRjK3NkLWp3dCJ9.eyJnaXZlbl9uYW1lIjoiQWRhIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwiaWF0IjoxNzkyMzAyNTUyLCJleHAiOjE4MjM4Mzg1NTIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiJ3c185V0FUbEl0M1c5NkpVLTZjUHItY2Fsa3pIZk1JNmF1ZWszSzU5VkRRIiwia3R5IjoiT0tQIn19fQ.vgtkVUyEUw5Fq_2vQzmMPhFoEeNmeJatrDDqeSlNKXo5vIm3SOLFUTQABT5_ZWKXOIiBDw1og6x-95xXdAGSBw~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE3OTIzMDI1NTIsImF1ZCI6Imh0dHBzOi8vdmVyaWZpZXIuZXhhbXBsZSIsIm5vbmNlIjoibi1hOWRkNzRhMDM5NzBhY2RiIiwic2RfaGFzaCI6InJWaWRYbXBJXzNVcTFqSy1rR09EYjFIMEZxQk9IRWdsYnEtUGZhb2FlcGsifQ.BOiEAOVRGdarYAw3qs0gXi3X0qRbQpa-nd88imbiZRKNnkSB9BP-CrCO2eUFy_UwfrCMoVhoX4LP0USEmCP6BQ", + "issuerKey": { + "crv": "Ed25519", + "x": "xWqc4dXP9LHY_Ia09ijwYuMFxHUjbo2HZOvcquHT0eE", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "n-a9dd74a03970acdb", + "now": "2026-10-18T05:50:12.000Z", + "expectedIssuer": "https://issuer.example", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjMwMjU1MiwiZXhwIjoxNzkyMzA2MTUyLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.-LALHjNMKDkk0wbZvjXQjh-yuGRi-Jz0ZV3kYmT1K5KVRjPnKXZBB7H6SDd4Mrt15-mYduZgcM3LH8zq5w3CBQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.vct" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid.json new file mode 100644 index 0000000..37c956e --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid.json @@ -0,0 +1,69 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc-8-bits.valid", + "artifact": "sdjwt-vc-presentation", + "title": "the same credential with the 8-bit list of @owf/token-status-list", + "source": "@sd-jwt/sd-jwt-vc 0.23.0 and @owf/token-status-list 0.5.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt-vc.json of the identity component, generated 2026-10-18; their test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjo4LCJsc3QiOiJlTnBqWUVBRkFBQVFBQUUifX0.4lWY5Vh_PBhMKFkjLu83rSvZNq4dYowJpUEOyvClhauQqgbBY1lDO0YRA7kQU0MRQFhIvWnQWcDFpeSlMQ0VCg" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-es256.valid.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-es256.valid.json new file mode 100644 index 0000000..0b2ef86 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-es256.valid.json @@ -0,0 +1,70 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc-es256.valid", + "artifact": "sdjwt-vc-presentation", + "title": "the same with ES256 keys", + "source": "@sd-jwt/sd-jwt-vc 0.23.0 and @owf/token-status-list 0.5.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt-vc.json of the identity component, generated 2026-10-18; their test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6Ilh0VWE1a2JRZzdCNnZubERDbjBIR0NMY3F6MU1tdW1hSEp1RHRkQ2RwUkkifSx7Ii4uLiI6IlV1VUI5RGt5MXNyOWdfY1pwbElQZ0V6OEZtaG5OOU5BSkFaSnVoYTRhRTgifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4IjoiWlcwZ0RtM0xxNHFfNWpBbi0wa21DVzVteDVmRGI1ZXJUT0ttUTVDMnNjTSIsInkiOiJsaHJMWlY2MkZDS01KYW5WNlZ2RGZfZ3dEbXBsVHhYWHI2c3ZxM3pYQVR3IiwiY3J2IjoiUC0yNTYifX0sIl9zZCI6WyIwMWh2UldpRHdCbnhIS0NvMW5GeVkzN18zZUFMSTdUUnFJdHd0MExzamIwIiwiQ19XUWdyOFUyamNGbEhaRm1hbFJ6N3cxbVdpNTdtZlY0OWdfZUs0aEZNdyIsIkVPX1Y4T3pzSks2Q3NocXJ6ZXMzSzFQRzY2V05fUkM4b1htOHZpTzNrMTAiLCJSRHFwYUNxb0VPbzFqRHViQXh3aTRDbzkyMlItdVJ0dmFDdVM5UW90UlJVIiwiVkliVUdIWl9DTVpPZVlMTVVOYTUyMHctTEtCUmgzWFQwOGo5elpBWk9XWSIsImdtMHNPNU5sM3NhSjhJODgtMTd4T1NiT3c0UWpGcTVZTUU2VzI2YUYtWVEiLCJrZWpHLTU0YjUzWVBYWmtKV2FSZEpvR1RUZGJyeUlUdmVPY1lrYlRBWnBBIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.p4dhgj0gszwe4kXzwh4TbJKVoY3-sNSjLI0tUlQrWEpHxvlEenToGA6YgcRFDWmitv1_mMHUNzwjW_nd7GOyyA~WyJhYzlkNmM2NDlmNDhhZGUwIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyI1ODAwMzI3YjZiODlhMWFiIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiZTU0Mzg5MjcwMGU5YWYxIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiajFVQTlYdXcwdEx0c3lDWkNsQ0RzVDNrOUhvVVNwY0hjdGphM2l6YlBobyJ9.ZEoIdkNAtBkJD59nrmm1efs9T5pmvUNUbIME4lHJ7lmMVlIqQazaROGiw9tyCndlwMyb9T9mNmrU6rDBf3rg6Q", + "issuerKey": { + "kty": "EC", + "x": "R_TdGYHfNybEvRm1kG75eylpg-XP19wF1jHT0MhAu94", + "y": "641tE1De1QAXA_eevwKYPho1pjGRZdu-SOqyGcysgCM", + "crv": "P-256" + }, + "issuerAlg": "ES256", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.c9Nl7zzk5iGSPH15mq2ADe_VH9qi61n_ZBc4H70VmqPFw02xXvhB8iUU9FhvBBbkiQB9LBIQHtgc2uQeWNuZZw" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid.json new file mode 100644 index 0000000..0e3e40a --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid.json @@ -0,0 +1,69 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc-ml-dsa-65.valid", + "artifact": "sdjwt-vc-presentation", + "title": "the same with ML-DSA-65 keys", + "source": "@sd-jwt/sd-jwt-vc 0.23.0 and @owf/token-status-list 0.5.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt-vc.json of the identity component, generated 2026-10-18; their test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6ImZiQWl0c0p0aHltZzZQLXB4WTRZc0xiYlIyQno1VXM3TWRZNUtBU3FkcVUifSx7Ii4uLiI6IklxVnZFcTl2QnFYcTNONXF0S052VkxHbjFPOTVGeTZvUVhVWVU4dkpyYVkifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsia3R5IjoiQUtQIiwiYWxnIjoiTUwtRFNBLTY1IiwicHViIjoibHNValZMbVFaWldoMkMzdEtFTkFBYWtfcVpYU0FvWmxRLTFheFk4RUVEdTVMdmQ2bm5aNmxkWlc0ZTVNUkpxR1F6cXRJV1VMZF9nVGxndzdZYl9wM0htYVBGZ3RPUG9RcXVTMWgzYWluVENsc19LTzVXMVozZFRFNm1qTGR2dXdRWDRTTUl1RE5jUlJ0a21FLUdIeWs0d21uQTNtTk03eVNCazd3d3pHNnNZbUNMeHJMdUVta3FQdk82TVNFcG9Yc3F6WmFCaDdnZU11SGpPSk5DTjQ4TmRQWnZzQU1ZTF9WWW9ER0JWaUtuU3hxVUoyZkljN0R3Mmwtbk9JNENleDlkV2hpSEI5RlBqOGQ2cU9xVGpIYzFITC1kclJqQnI2Qy1rOTVvOXBKcm5mNEhma05LNnhoYzdKWFlMMTVaTkdWaE5IQm9rVjhCb2twY3RKR0RGZ1VuRUhCQnRoMXdJb2NWWWFiZmNrRzlQS2J2SW5sY1N6ZlYtR1g5WkFIc01sRV9zMl81WDc2WWprUWJNYVlUYi1ON212ZTFQdThiSE01RVpsSUJPNDR1S2dGRG5LTWhVMUFpUmpKSTJQMXhudGFVWnpMZHJYNFNxcjNjd3QzU3BUbnhkZDFmcEd5b25EWUxHeDU0MDhTS01mYW02RzRlRXIwWDMxbFptUHhHUC1PYzIwZjljR1BvQWdaa3NtcHlIV1NGMTY2bFVaTUt3MGFjOHBhUkRIS01WSmRhaWlMQ1BZZHRPa3hwX1hhS0NwZC1xMHZZYlZ2VzZjWEZuQ0dwSmtWMjRjQ3VRbDZWUlNYaElXTmJVNktGZVRWYlJSaVIwWnVMeW5zZmdFRFNoNk1NSi1CMWVHd2IwUmsyXzZQX0hyM3M3MzFEeEVGWTQzU09hX01ncWZBVU1laUZYdUZSaUlXa053aHRuN0tVTmozdS11cGw1dWRqdTFFanh6QU5CSjBLUnlBajVwVGZrYjlCQmxLZDUzWW1CckxHWTE1azgxTV9iOXlNSS1kcU1PRWc5Qm9neXY1a3Fkd1NYYWZ0b1E1Z1FreGw1bEl4bWlaVjV5WWxJdE1KYlA1Zmh5Q1ZxWHNfSW44RHJEN1JBelJDWElCalo2V1FhbjU0cW5uTmVkaU5iZnkwcUFiUTkxV3lEVHJaRXRWWmxvTXp4bnh5NHEwcnFNWDZfVTIzdHQzNEU0MEdZcG5Hd1VuM1E2YUdpcG1aSVlBclp5NVB1YmFNN1dmVVRISk05Q00tbENyVEhKY3RFWkNpa1YwLW4tVURGN2o0MmFKRXVQcXlMcHJsYmZRRDJ1eXRTWWJHbWhTamFEdVVDMWU2QVl1TzdTX0dyUmdTY0p4MmxyM09ZV0FQWHh1QVlBZzdhTFQxaFEtUnBTbVhPdVRZc1dIRlpDRTZuOURDUnJ5aGcwUGtydF9jQ0RJRnJsaHpwWFROX3piTjI5WXhSQ0hZZVFsS2EySDJqdHF6ckJLY0d4SkwwZlhfQlk2WnZDQl9KdEdRTS14U18xWF9Ucm9LSGV1dDVmQ3ZmcXhQLVByWE5QRnFOeXRadzdpQ1JKU01VbXFLWk5obmVTa3pEQ0gzSTc4M3RUajJ3YUhTVll1eUd6R29ZNGIzaTkyT1dJZEJ3WW95UzRNdVp4aFczNUJWUDdiLW9VUTZ6MEhnalc4YVNrblRIVlFtdUJYUno0QU1hOV9iOVJNU3M4ZnZ4OEZaOE9FdTFGeUNLdFdTYlNtd0RMSlN6djI5SmpCYW4tNnpXVURwOFBaanZ1MFd2U0JJeVFadGdZVzRkbFQ4cDNPTnVMOElSMWJ4blBib0tuUkRoYjZLN3dqcW5fMjhiQ0QzRUV0X2ZCUEtuT0pCNERhT0RtSWVyRkpqd21jS0RGMlQ0dzhSazhaTlZUdFczWFZMS1hab1JXNmZ3TFJIZTk0M0Z5VjBick1LYlNjcGZLZWNKYmt2WTViM2ZIeGNTQ2dxdWVyZDZZOFRDb0RoQk1iN1BNb2JiMEFUMDRjblU0X2tUcV9ra3F6ZS0zVGNsOFVXWGttUVl0LTUxRTRpdFdFMGk4NWR6VlJuZzZiWFlULXJlcEhjOW5ZSW5pVDIzaS1ac19nTXN3bi1FSUlqUHZCNWtXMWh2dDNPZUNGRzBESVp6T2VJWkNVQWhxa0syTDM3MkhuaXY5a2JWX3YtSmZ5RTBPNkY4bS1DeDktc2pvLVB2QVN3Qm1Gd01NU09FdUxUQ0JsOWZNX3BVSzhhVWlZOW1mTE9XeXFDV2pha1FYNTNEN1JzYk9xbURSNWluSDhQaWhjbmhWQmVUQlNHUmNnQVZuSl8zcFp6UjRCdjZWZE1Hd1o1TmZURjNZMUx6N21zbnJNSnFsbzgyVmxKR1JHYmlFTWpnUDNKaElWWVBEbTl6Zjd1RkptUldnMzYtekxUcHprbWYxUDEyZ3pscVFwMGdKdmhZenptWDZDZHFxZWoyakFYMzBOeWVNU1BBbkptSWV0QzdXTWNKOFRIOEMtMWdiQ0pVX2MxMi1aaFZLalJOaENZRUxYcmpWVzJXR3FFVm9ka19LLTBua1dKbjZOVGk5cVBpMUE5UllUSjNGNWtBdU10akpaVkFMQzlDcjZwcHpGZUpEZ3pzZXNCS1BwM1V3UlVJbUhLYVdybDNxSUpuRncxSlU4aUJLLWhtcFQyOXQ4c200ZkktM2JQcnlld3RjdnYyRXFTUU1yZW5NWHU0R3IxV084bHdZRVhjWlFFbGp2NzliMl9jYURvRVNwRzIxMjZDRHN6MVV0RGIxcnkzM1R2N3AwM3RNTTVoVGxrNm1SNEE0dzFFQXdJbGhLZzJZT180Mk54RHUzRU9pbnhKclJGWXNOUXNiX191Y01RQm1TSFZ1c0xqYzE0Z0NHYkpPc2JKaG1vOEN1MlgwdEZaWGdOeTBEQmQ0dldlOE5ZaGx5Q2piNndkS2JyMzljbTAtUFJQUm9UcEllcDRYWnZnTGgyaXo3bVNnM2R6czEyZWVTUTBDRm9fVi01N2tGUVZpU1hUN2dOcDFaNGFNMWN4NG93b0Z2ckdSNEZaLXJGa2pJNFkwbV9ZRXNldVdTV0Y2bWZiNEdJX1JaLW9OVzRSQUxVM0loSWw1U3B3M3Bfa01jODEtR3NmWmdDaEtUTWpRV1VvUXY5ajlBZnFwcWc2RWJQQUJIZExCdEFBWkhvVUFVSXhUTktkSmJtWHljT2F2SDZHWUxPMzhXS1VOYkJVWXYxb1ZfYkNHRnc4WWM4UGczcW40WnV4YUxKYktpSllNU3UyY1hwU3JzWDRzT0NFUE15TUpIeXV6cElmSk16c0ZKaTJNT0QxTUtVaUV5VEpOM3VrbG9HQ1RPRFZFNzJDc1d6LThYcV9Eb0I3QXZZaG5LVlhNRVY2OTZLYi00MmMwVlRGNEw2Q3RDY2h2UThjNlZqblMxR0t2RUk2OVF4alpLYjFhcHVkQVYzOFluaWcifX0sIl9zZCI6WyJBdndTV3BwSDdNTkQxUUtSOUx0WktyRnp4cmF2QmVrZlZmUndsOG80ZzFFIiwiRUJMRG9ZSlo5dW1LN3RlVVZfbFBZeElkc2dpbUl0RmRwaWpON283eXdvUSIsIlRFemZ2a3BKMDF4MEFNeXV0OUI3RUtPN1YyTkZvbVpxVU90WUp2MENzR0EiLCJoN3AybGs3SWI0ZlVlSWgzOGtucFNyQnI2Q1Y0U3hqNGxHU09PVEswdzN3IiwibUU4WlZfRjFTRmNHVUt2NnpqVDNISFl2cGpZeVU2SkVpS3NURDhBYTI5QSIsInBPZjJhZXBFZWlXRkhkWVRXRExEbURINEptUDhKNjVZaTBuaC11LWdNcVEiLCJ4QUdxSFNuc2kxbDhfTTZocEh0d0RxT3hjcVZBaVYyZ0J0OXYtMElVTjdvIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.2bXlRPuRrXouZx-Qh-F9zpC4bVQ53KPi8Mkts4yRoZw14adHVhIAUDpliyxSb5EXvDkkD0gukoC0o8oOtQN3nhHAHNFltU14-dfILE0X6tTWwPKwGdqU4XsFSwEmaKB621864PFv9kBwlpy7mQ5nwQOc9CDeBmY0aU-4_hBIhg-zfONN6YcVnvwfc377LGgcjfng0RBUOT1ZJIsJMJ1Oe4DCn-uyP4nDGSfCZ-PmxKmZKG0us3UwD2JUt8VE-4uTiOuACNKVnygeD3umr56lwIdFAQ0J7JOx8GxvhiO4hHA-wP6i6aiIUokoDRpHE9K4LH43M-bWFrpDCoS1JHmG1r6MCzzCLPKjuEWhrbiZfhmxXJZUjUgFwTbsEcM2WAt_l1VPTMvFlnHcTRb9kkDfxe2TEPcZx3C-wFbhUL1XFArkZstDszMaYUvxDl1r2l54MUujibxTNwRDSu_zl5CgGzvmqM__D_g_mDqteOxpdliw8dQ-YBgTjrfHWJfoQeWPnwYLGION6RkxZ9FWjT2Atjru_zubUc7tbxMeOfBh7bpIgRQglb0eKL7ZC17N1dZS5xjchFLOkdCM5q3nLOURkGqqos2uEbL7NzTlb6h71TgQ5b-LJiT8rDB8YeIYNb0_xHluF4bTM1qUM9tbSOdQBAhF1Z18Vv76Si3ybluGPuDibsqJl8tg4IRZ7Uf9jrt0CrGY-wJfn7dpeaXv4FFQ3edkiqxM27nj5eIZFd7k018ft2AVLFvz3lMfLJ2JOA0k2Uz6B5a5e5b4C0Tzr2h92MsGI9GfeidKMhpxsc_tI1fusSnb7h8ViKUsfXm4bDqEzqaaNd9-R_fr8RqKUE8pXB2V1o3MemZg4llKPegNo4uw0a4kYcndr5NjClbrNp6eqIMgPkZivb10NSMqaJLoP8MDqy7V8eiEe98BdoBwlravi8ekaHS13ZfFmWen2sYaBzOKoWLZV8sTS4wUTh7mhoPWiRJnddR8OYC8HsFCyo4jZdm3AOoAp8YzrFhuxiB0F_KL1WOK0qRkgEtMMd8vxP-UnFuPdq7RTSBfvM3YEF9153EyQ0qh-cShIj22UjxPxu3_2sLe1-8YzErTa6kozBC9km9_Pl8Z3EubbLtGjg4xVXrNQoOy8erkDhB21ikpq-Mof4a7KuZgjGVCHz9PbSpLYrMALnpQ-51PTnoOPwh_CmIdfJYI_YIIyox5CFdJ-1W7odWBgrVeh9DKjiqBfN9-VpvGX78U1MyrZVKjfwzhLvyc4XpdhpZRlNvpXmOYGicjdPP4-9iBCwcgFG7wCg8QHCOdQMvw5CKYITG3arJmTy1lVRjcrIW8yX53n00M_5K-Eq0tDNtbBCFBM511JkyPbMmHF4_MTspfK_E_DK5A2EMpkaXX7dTxMXFw5xb45qoB7t-bUC4T-il6FrM5-4LhEdTYRcLM50VBWZ7hPDPHBTai80UrzGOVDIM5sQVXC4H-A1jHOKUWO1VE1jwYurxducec_ZXWny-S4KDEhC9ohg-D31ZSWrjCLoP8E6Jd9sMiDdKFLptiDmWmnZbVK-yTtVOmBu9XyTXX2tniOFH67r9PO3mR5VaW91gFm7067N3SOLCtvDVup24dbbQpJuQwgRlksusy4QxrFxfodLWeWglaAoaSkTe5A-T6mcGx1JWOzm3Rvj3APjaecCHyjONi08i6Hkw35i7wvKFc50_zgj3RUUjN5yaD8ioPfnNBx6hWb7zzjG76_4lPwjSlI-iYXrPKFPHCTWq0PQ2fVTedtxbdri4fGW8CJzeLySBziQirACRAl4yngXNhL4tlGW031Vc9kvVvSRo2czxwHSK2t7xPvyrwBl2PMB21_SEmR4q2p2QR0g9Z63rx8Yo31FWN9kxhKsJtWnyKZGrVGEoYoOC8MIJ2cOlYh7njklXnbjFnzTN2YjrSpN2Op03JuJNR_3Q090KW_WjuAESP2aPQbfSvyAP5JMh0nItu93blEEqqqJwnySGz-8r1y6-LcbjThZfPGoqW0E7HodsDPZ8jIwNlyEb6pY1I5ugNT2qzdciwbOzAS3mOv_dmEM6-0fEtZ8eJWwFQRrcKrCR0JmpjC1yphk-T-3ElyZDn01NP8om0HZ0MbOqpW3iUMsNiHswKpIpUO83vTdKUdnz1L8JjhuPSIVypYWQh5Kb0YC2VhNU1yhcsS1uMm2pE8u7_GUI6C4Z1xjuwocA5JozklA-iM7vr9aAPVPiwhq5HCIiFbbfLjqrfWN-IRXzPkI_fNUE3xu38-dSLpl9Sg9bZbKEE-4xHsYAPaRM7WGLpbyyVsMoBUGir7ZbOZ4FTtJIgiQo2_xG_N5q5vvpNTOOp9AyXrup35ZsY3vXu5UvhjmZFPeTh2Ll9pv3J3wnxL8j8jesp0zsmzoIvz2RXeztMACPOdEBz9R0xgf5LwBM-W_KkHutMBIqimh0hAR6xNtCBcYNYm2Hs2RoBPOmgVwDEhGU74Gcr7H8xjXOXI6_0fLIQWwhYjzmy-tie7f0btQ27RjAQYRLPtOLHaWLIPcTfPDu926kNZUEBYUxsiQ7la3U8EgQxr65LkDhn6ppTIHGUN9_e4GmYNVXIw2sC5JoNNr5FbVdpsfVIP2DDeTCIv9sz2iKrx8tjcmDZl5HcerTE43uF9MnMXE3zzrDw9Tw51-ZFAYcOF46hDpH3mPywGq3MaYUrrsUY36Yw99-72qWC6vVoLN-tWDo97aEeEafd7dzUcOTaJ-8gvpXpc5XFPwvY-x1vP-JmBdT1vkE6UDcgz4UXc0XxFk3NOvgzuXGJwaKmKl2tP5ByxZUiiJVdr7FRwQvfK5OFkM1pgSbeyi6U04CZh1_LCXeUvs3Vmn7RsdO37Xmy8FE1dkq79bmo9rlmq96okdVlskZmaJCkeca8LwK_KrmUX_CWG1bnwSG4-u09f4vLdCQihb1j0dcbKuzeT07ZT_ifsJzBcnOgN7XT6EA8Tz_mn8Znyg05quHwyxxLxsNqDGId_hojoN47zGCZefXToWtMN8caF_mTNQ-tNUBJUx7VNdE4AMxHDy89h8yLCeHwTp5VR5fLUtBB-icc6sJtHiRR6S15T1jVHOzqaZrdXLhpMC-r0NRES8hbTb7mG0-Tm-zynMvgtD6xXmZ6X8ma7PfW4dFqnxK5zdUDFIWa7iVZRpPyccYuPioIyIhIGQ5dAS_xZqpjkELCY4xKEseCTIJ4FP2xlOI8Kfgbntp3T1cmLhGSbi6KfPfnk1rsx6fIjKbp_XWZ9ndKqvbB6769xWmrutUYTAr5fkuuNJ_z4Ybj1ld4zgVmCmFjqQX6z92k6khHdaTNRxSUwyNURHSXRRcYG1yNtWJib7czYOXDshDqo3ZT1HsTKRM1ljaKplG8njXONJKSnYijVZUnEfolf2Z7YwjWnjauJcdUJ2WkjUWrqu11lzs6j2J6czWyIv9IWc8RG_ch90U9bdEfp4MR5r-QmDTd2fZQcllpfSCv3tLQmu9OIZH8xB_YoLKzFHCLK5fRBB0m8QfRL1jl_O9qk6sREqR6XCIoVLY1BKlYVL8SkAfP7wm5Q6X11PngfHu7EfYcBlQSRcP0Q_4vJoY-JW3U-WTZqiDFpPIJ6HlZlxObjcDD1BFiXH18w_aH2wHhGI6kS_gi6-M6Q0_xIXizc37rijYw7u1_zUNw4wfe_pwC1fJyYwa6bAEA7Kom9h3XV0pbS-G05F5ZdMfEOf_tVeAOEaB3q_UpjR41Tw9yhZ02D3bxmE6LmYuWovPVXCp00582UEGczcfHpvKO7PbwSl8AXr6yiKZDMf38kPyA1dFLjfmtPlpx-spoxVIM3t2APbccQ2eWqtSyAPBLpLVJEytxbMCQjoyE3E9gH3R2Xrk3UPV3gBN9Q_4Gx6vrs2bFeL02w7BlrOzfn09dEqUeuMFBZGzPf0hD2EkUiNxSFx8HrwR2uQxumFdeUnDhy8erulXFYtsPEG-Ss9ZvDx8VSzyQLmxJ_awUfrFQYHyb5sPanftWXTwotJmRjMkdATUSFBhFweJi5ZL8JPMk5mPh57-_l0Mf4BNfZESffQQuLYHxco55SYZ6PLckgpxRzVkkeiDrzCwMykITZySrA8hGtDJwO3KlMQ9GT1FVX5jZGQ3eIj5KEE9ibQrxsOxaXjlq11SJqHYPJ9agacKBwhcZRf3QfDjSH2QapArCf1Kj2cK6qJ3UUKwaM1Js2gks4Nia5Jj95-oLjbZSfHm0OhYEsj_fY0u8akQjMTflLETWx7pzORWgZUNBNbFBS8W7ob-1EHe6RNDmKU0lENDm6LSTD_oGFZnGP7OHPhJTve6e8ERy2khhZvKXdwxjkDt1gv0ROELB8hYweozLYGV9j8DT9AkeI2qbs8vQ19oOETFxs8DrAAAAAAAAAAAAAAAAAAAAAAAAAwgNFB4l~WyJkYTk3MDBjNDliYTM3MDkwIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyI2OTFhNTY3NGUxYWNkMzM4IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI1ZWZiYTkxZDlkZDJmYTc5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoidnRBUDZ2SF9uYkdDNW1pZ3J4ZUxTbUczUmo2X3lNc3U4QjR4NG51NnliZyJ9.AJkgVNA0tLEziz9T0V6HglKbQvlSMIT0wAQ9EA3PCJEsrMjGt5A4ME9PFQ-rMch3TZpIsm9qwb50jwVfuDdt1yBXozfuwqTtkt349FNCK42Su2b6yViyeYxvOz6ta-T2WqvLc65dADzk17EeIn7yBOp6f-8TZtnp5aGK8xVoTtZyJ2S4JL3cCNLIJtNkVExikspJf_05tL19Sbftt2XX1qrUSiUQIOb2PYav6Mbr4WdRF3dJ0S3jm1g08p_POPOI4q6ch-LvXNZSpy3DiC-nI0lw2RJv0sHGE1rYW2TeVT7_axbr5yCid9-GcC0s2WKgRuTYQ_L-QQmGWIdSD-dZ0imP8zYd9HJqU0Gzcbnjyph8YXixrtNmA4dgPZhid94YYu3WKbcA-_u96xLJvaX010DJqHE15-lfUxtGMZbfevMXosYbSIBK74LLOXEeQ3KiGhA_mik4aDo85LCRI5HaXNCYmqNWe7olLRLRNP3JRch3WDJHc-eUwC0G4CxH7kjHNfa0RuqthjZeKHIxOS8KSYk1mj3j4WLF5o5y_4Ki-n_79C7np7g_8LV1wdTT0tnAVVMSB3TGbMmsNvCKgxSkjLafEUcZWVDGuRmZq5tlMHokrEC23gXc5lk7lDfRUTZDcZelq19Hj3HwNobHkCvnNcQ0Qj1HCAlIjW2T-Kc8RN5ArJHKXoyRc5ZSD2ymweDN8YQK_UlLfDMAWCnJJtlXrEx0yujZ7r5HrfBAI6fkZLMsnEV2w5lz4b5kIH0omlvMutHN4DWgj7EapUnteB_e_ANpo7_NjqD5oU2UIMV-aOVW9zOtRUjVWZD7P_uXNtO6iTmR-N0mzoi-Duix_fED4bxjCWQ6bFrTZRriWglaXEly44e0tJb9UGHv1330CvVdhjmIIM6rWW-XpipgRs9q-NMvUZ8_Aa1w_Hhyp3QkPPv9hKjLKRUcF3W2FGpbDvpYGWLXWjYxCoALQlQoyHUTzRaIOuC2llAWRJbqTr8kkxZhS7KfspkrDYmKuyQ4kFOQswbp8UScPKy091foYbBiu83rL3EB7JfKpOcrMWZ5kCttRnTQDAIT6o4pDRDSn1rzbTxGsbeEjCKmw2vd3wTqTMkZ7mR2oP2p78WW5mGMG99PcZcCuooDeYDC16q4yA5YqyXg_ZffffYpxOwFXU4b3ClKDIReJOYCvPoESmZVfI0wfxMc0HZykrFTAKo-cJlyx_KJcxQ_KqPlPfy8GhoVrglQIySFg_SOeUCjC2n7lzvnZ1HxsrlgEOqqQpicS_ztj9jzfY9mM7YS9St6nRQ3zrieQckdwgb6eAxDHqe9--8Gg8ZkjttiNVrf7GR6DufaGSg_7L76Y2c21wgWCgaAi_ncxb5ZVYzIfzK7lgoMTs4bFLggRutppbz5_u7DGpHoXH5dUrFTJUdhBdZxZeLwqOCeFcLq3todG4LsS3zRNWy0ds3R_obWzgkcYYX3eMSqbmCYJqk2pTzdGBUPVajk4nmdL5brz4dTVfN-EkqzXbjqZFFPpHomy1kZuCuE4PZjZWOCNB9bcgJWhmOIKH7phn77lbSJMwyLldj3fgKwR1ingiar06LC5WljPhr16zho5SQmW1MFxxbupgHeaN3SQybMMKs92MbfvlhKKaskgl2Ug0EMAkYatsHCZgrn1-lwm_YjRxfKiZD-E8RDFQKTOeQT8EtRbtxeJjsbGnVb9RpvKadT37mSLaejhAFtScY18qiav9mnkoma1aMDcdUugj415gWOXQVF7G4ukjzQxH6d8TurzuAzX6fl6xQR3o6iC967Sd2c4HIRfxUCgB18hpC1JQLA49nhwZP-cPfmLo21vwV3XgwkGMdOB2nZFFaWPJ6iqJaKwv60QCDIfm9nucEqfrIanJF3XNEt0L2PtYciV3ckGpW7FBk3yaCyCeopFyK_LNxiWLZX6ioJXoesQy3dU4yZ_dhkqG3vh1oix-xShhT5FQG64Qjpvp2ogGlb2DrPM7Hb3KbvudWcA7eXgmxC1LNWkdq8_TTtkg84-jvHylz-VbLWMhJPHRWRoGRbg54y47oSUAdkv3c8Xb9QpcnVJ4QgGRixoPJGuMIZLZnOue3v280XKFWZJC-_kE6uCxRd7DdtIwoadPkab-tFGj4ReRANiLQUUUNNHIdQRF3f_ExgsxyyZLlttmn9G6UT6pE2QJxszDPP3HNyHkOj_8hQKgHRCMC4I6js6npeQJdLJ5yGQv7GIhpJgiTOFJzwYF038Bv2K2d-TBKyqnCNrcekqKX7DIXNyi3ulHfxG2RLe8Pqad3awn8Y0JG8xVVsQy0Iq9qWlEB6HHsLTvwy6wlMpT-7dAtD6CnjfxIYf3CUYK9LuhgHa1pwi2JRdb39Gmekf3jqXd6WBqnv8s9SHXHTOGdRUWOVlFjz7Z9hNvYZmuFB6DPiQBUCFETF6KFzqD3pMO5KeU0wsby_grMWd8kko67GfzdKRslZKHKMLdApwqAZF4jRrYVJZ0uerkCx-fr-Do7FJ-wDcxbiPkcft3Jl4p4zBGCJ3VHMhqGChpYGIdXHwCsb1dklaD2zPP5mF_Zc4AXmoR-uR66wf04Q4fhO5w-hEhOSZT-i8lzEPopqbLsQStnMZ1Qvo0TXC0ignzs9izrZSU7SIGYb5wGooWRS7Jmi2WSc8dK3tYug4RzsVqsn8kOT8zGi2H4HdJiDDIgvAs8qzWVopipLyNAsvSdZePIsiy5u3wABB4J1cNZs9ihS1Sv4vqumBvTkVm4N9DKH201gihkcSKTL5lAz1KIyhE9qTyqCdqP-PDSJseS32Ghtv03dQr4eu7Gf7arowv09S2AfnCUn-8eLsL2MtK-pdpWqfWiNoyLuJS2sVGoVvXo_x1oLTCndixmdCy6q_i1po-WhR_JacUcnPVABJ7qOpQLKIpE3BauOB0PB685jIJT7s7ndUnpyix02ErFb19pr1bE-N4j2ehWSZGP6fYW2fQGdGVesEqeNreOCyskrXLfx84fLbrFTBhQE9q5eIgE1G4xtf7OdHtkF_3FKtZWRfHkZ6XtlJAP5Q48AS7OpxGgai9w22Snj_0RuWYlsW93_RQP4TBxb0wUFUpJMFjbBhAkzo_HkgNoSV7hp9lYywMlIRIv7rWvPnWmM8KM4xVUY4-AYCbvqs7l_r_x_3qBWvqGtCMlzk1YO7f2T8o9m848XdlZ-mq71SP5d3XrURscVoKIj710WbBwEOIT3YEqjCPetNY4vSjLNyAf0GGK4fYBl2gxY_6tdgWaqkutsa9CrLLgw8sgt-qOgfsQ4Bmag-SSJt5Fqxe2t-ssGgmRqjpa9DvJenzNSjJBoYqCNku7fRYRm_kXGq2ATWH-w3j7dT0GfOGbwPjuCd8Ud76cpKmeJ_qgoWAcPI_H6D1aLqflj3jHCawimLFjmgd9wRBYoh5RmlFovIPq2rRDc1WmPZqVzsWQuh8MFOaeHJtalzxaJERaKQ1smg8d736IRLVYFIKqqGIBX4C0sBJITF1FREeWMGicc95FwJuDV4318JZHTJzeuWt1hPjHbwjhvBb94RMGG7Z4WYczz7la_Lzre8l-KNJxqeYj0oQiGIktDp0O2etBqEZhFlIuFsT7iOEOE9Hof1uvSURqRY1bbeN-KoVGXcLs3c_jnv4Dgx2kycCzHiCX6xlBM0AOu-Ie8NUHTm1mMNpiWuROj6xqv926o3ankMqImHJQ9xozrutVrUeGE9NOBNGZooAM0sOr2f3t6P7gK6gn3_Z6GC75g2okTLWotPSCPcOO0EH5WSWyFndRpGz7vOth67zBo5mzq_TMrInylImf6YOYZou_BCS9pvJmsyWwjeRFRxnWXpeuTSrq_5S4ncLHsiQ4e1RGkXoy2MEe-88Hk0bJBz02IOV461H2dT90z_-6TbzXQgJijxuuq1qAJWSfKfEYvm5UmJVqDqAxw2LRLKq0JOotPdsBU9RGxjtJ2jhF24dmY_KLDpQaZ-meKb_67ocJzGkh2nZqXm3wGhchtudnW4cB7-KlZmTEYxkwVe30rph7Ca0Y3XJvy1qU8kbs0jFYvvzS0uO2VRqjFJoxig-jDymnn8RH3ZDevyE1fbJh8qYlQ9w6KaLGnP2wpbu8y5yEakL6GKo9-9SMpjK92MPtIyXrN2_dnNFQSSom6KnS1R4Asn5dHcUAfTOyvPEUz3J05UaJbspAag3jHSRNZX-h93e9XaVDmoVFbhAXXCWEqact7BRKayO_9O_lqZpsEkJO4kFzUZRKAcmdLpuSMPV4GMHbMZMbFnjFY808XbeF1bvvx-maQ-ASlrAb6GzxTlfe69qe4M4Kz1ixK7yeyRB-iJoAMeBdXeoTNzto8qeALF4vq-QItg_8gJVin2-sOKsTNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgkOEhgc", + "issuerKey": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "UC0YJ9MxdXaIoAkDQUJ0ucvwKKfAC0i0Q9TscQk8mSMo7Tr6jUF2S1CB5n8mRmvQ5smsukEpYMAx_XNkdaVhezG1CTooq-b6mXq2NRIsUjKwbQzbI1YeATnNFrIe5bFNOdVSgiulzKilwdd7H6SFbiDO_i1qO53xlA61hJZGQcbCjI9d_ohvoqSpOZqeRh9cdCb3ufvv3jGwoGquL4SfLRoLfTYzAYBKF6KI5nGdKSbYDl2n9ob5V1PO7Ip6odOben1sWHQtZScuf77cSR87x8nrPHCeMH7pvwqbaqi9XP5eBnYw_aGgAptiQSlF3r9acHCimTBkarwUh6dWwuF9A_KnDDPPuyyRUNicmKUFyU61bSH_5fZ4B9x1EdGfRyCacBFvrHSem35EzFHRP6M-pooi4YDqcsoWN_hKiaJGttfRSmrqebo1RflHECa6pPY0I8yTn46eAbL5C0txgQsNQeqYfxX4mxTUSTUM2pERbMAjIZxQRTsdo0QKl_3oF-PcFSzpE28cZnBNtCToJhbJ9Vt77Pd_EVLCUEVvCFFdztWFOwH21kpPJAEDuH_OuRZegP9Ukl60ZGx_dZvEQCdWW3FALK_0Knz4QdYrjTXfzCuo1bS4fDBB8mEbuMefSHUxKjoNDVZCVPFfhpbNsTMTkDW79_GWmzinGFnJvpbn1rRlZ2xZl3F8ne29grB9m1A8YhZCezOlkjKjJ8uvTfyKknaznhxXQFlI1iY_frE6mqCyGraWpWuJkV1OW8igdThBHfipDGbbIkRUaWajylZcQq5cID3pDMHAPyEpCgQXZF5aQ-muTOGTIq1RNwMt-E-laRCk6lm6O2v1cR-6k59StR9pXqyFEYzEMTR4maWwUH6hywRKNpCq2PEwXyy21rxrmmvGlVEnVQbVZcJooT2a5eAoynST95IJCOkA91TpcbaLR40-qdNNj08JdOB_BBW2d5ms6S1zos0aYaFVHPAkL41EzrWuWGGRPaESVVD1knz8cRVUvzNT7SB_S7-ovKI2Bc6AnbMnGVkm4V8Z9wbLDAE5RY7Myo9jlt0oqvuQJE3ev0HePvSARsssHvPaaqYlWrpxvtzZwabjbq7KGLBja_fy50zkFmv7Nr0XA4pf4mumTYuFd5m9lnFvO8q1T3KLePI0c6XLCb8maG4p1lh3Ndy0P8_aQaoRZ439gS-1D6w6i_yDdiZyRQZvUc4bSWapT9saxtJ5shwvzsLW7XXU2Ml-gUFhzxPvEgZoSmK3rG82BdvJ-CpqhmW2y_WwsjVJlvmbmjyQvZ-wk80UDWd5UlfwGL7tcYxb3X2LHcrlHelxWCub1ZuYwe2sQ87zmzEHUtHTxi_CV0O_Y7Bb6UiZ0hPbuQXT-y8Y4KbAFwlXtCKacZafLFPJlE5Lamze7SvCNvFDjF0WDJP2cHVROmfWzXtPJukrrIuemTxlz1UwwpYvosZo4GjMNXvUKNun7txfipVpd_DZL2_qYX3UAZPpCwjA-M6_qDjdKucESEtao9I-p7tJFOnvXkTvBfDbOpDXy0viDqvOc_ee6JAr8U0gUVgBMX_ivUeRI3XvtCozHBdnDri1oaezd1SEm9s46aXafXxloVxgPYnjdT2-b1Y7F12hT7WHnhWYYSlsfM04T0bHb5yPy0Vm-ztj47Qf403IRPNeinprubemhsa5ukcyefx4iDwzbVGHjHnbqg6u5N5V3RcioRay1pXKYuXHEHgFVlnzaYWUOCQ031BlHYKISFXG2z7FAp-wYH9wn5s3pgjxStmeepd5hk2Dnl_HfyTm4SxDk2bdaQfBqYeZUlOV7E53FKjkK4mPW3-b9xz7Kc2CpkQ5vFe9-KXNicCsfYzOyQv5o2QriwtFsteKBVCC91fAauccCZXH3tyyRNEAyqGYQQ_wSn-lSFOAPb85UygCfZjCglAK-ooRE5Fl7b5BhZDNRmFPAbpyFOdyX4LswNBZkiubSPmA04fySsaDETZ0Sx2VBakPQe1QW6Rf0xvsWo8dK1l6U3Az1vtg_tSoQbSetg8XhzqML_VqGKFKI_-GaCUO8p0cI4FBnUmhSx92phcsrVjUDNsfcSy8RtUdD7hMiFqxvfDLc6New6tG67ns1QydIhLwY9mRYm6mJdeOfuIh12iA-s6aYv2ePqAaMiZoSYOL87ct0Nl9U32mEjEJ0U5ypgX2JhDxoVPia_lf6ys3Mgte_wbumEyjJmV0nwQceficRgSu0tb_jeh_u0-ggqQMLHqo7ZLGh1cFK8rf9lvRKHsQZb5GzZf7ifQvXWGf0U_dSU0MHtDQV8B14LBvrM5vaNbqSn8Mi4YF6uJIDdGVW7trA8gOszY2M-cXAHLLgk0w0MzchdRTI_5Afru9e8UafNqG4a5gLaMsx_g1EhfELBMZ7dP3zYeONymG_Ds9SBVoQdp4LY_gHPSxt0ZEv_VODdP6xfvxEQvbitrRqLKE4s2PgsTReA5RfE94q590gVn2cv1LDzA_UT6kHCdDFBW6nTUipseT3O0eL4H_y6Yix02xf2XOxMCP3MWRXi5WnX0BD5N4Dmmx_v_Cd5WI8n0IG-381BwklAWhVGPbhxzn9emL1Y2QxYRyMIZFz0k" + }, + "issuerAlg": "ML-DSA-65", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJzdGF0dXNsaXN0K2p3dCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.A-ko-CiOMazwQwPS2PVmElwVm5vINDzYeCKrQg_1mfDMbWGQQo_RsLJAd1GaTLro4Ta35NevB2onHgZYQ0KUNOGRPBatLlEJH1ddctqE8JZZFVS4mgy_R8ngymoLVRul4H1wuwcYuHzst2jqW1KoD6bL9o78EUzBOxS8dKnajusyPr8mgTtBTfDpId8-Wu9DPKmDBhnEsHy5Y45Z8i4nCdLiXaxeEC7tG_yrhB8nJ6WRtWlEMHj5yreHrqomWRkJ48lN_gJHiJt2UTAJuobgz8MSLqDxVvXF8rIqCL_UEf6cej4H6tF2vxfBcYg1h1XxSxj5dnSU1u7Pt5_hCPci8qZ1ci3uJh-hMQ0dTp944HUlMBisTmxEKiR4eZC-DV5Laf0UL4nIrulDgUW7hJO-muYL-e8InmBCnB6uLRTvMC4Fxy3Vbx1IPx6p3n15dOHIT1OzGWFyHLxaCV9fPaf4fBj9Xutj2ArI_f10h1QmdUDgFPFRYrRucjAKG5wGLBnyV9mldndpEivhC7C3fdiYhyXm1o-6T7dSSDMwVKmFOo0y6fiHIocGBwFdhqWjRjZ8F0djJ_e9uVl_gyZ9yQYYl7c56Y6h1qxR0JtPKfLw4nNv70iKV5q_ueABm0rnC9U1s2GiI_chAcEHO3Y6i2sS9Gk7nGrM4oQ8fSGts7_Zrg1iUM2hTn5GbNKzRHWnY3c3-4KiFkcvMvJ4XpdZiHcvcL2K7jTpFrVeXP1zLbzBqIZq95nHblRAvO7rUTErHY6bszWDfJ2g95pEcwuEZ_030LmG245XdjOAADwRwAVFHPNAFHAhA9izrMZ9M7rFpGQ27iZgF5gegZErpWuUXMmQHicSs9D8x174Kam5IAgjWWDvhpnxKXReNRaZQsOJU_3F1i7hb3s8gU4vG1-0fIPFbNHpljbnc4_Lisk188mDORHXn_rNQIuDj-fjSRf5-p21zUOW2THCCGidg26_S_5c_asyd5pRZiOA98m6BqRZrmtH3Lg5NeeBfEpv3ax3lu9n4POz4zY8NKm6ARE2C0iEM6pqeC6RAgaaOPtm2DqRXJkfop-ANZEzkoCeGvGAuNDedLYjXf04UFyBSVg0e8M43k2q-iXOvc2gHLY43mup2DD6u2SJDiIUHYL8BDPObfSqMLnlWvtJmSCpyDssDrJUYkF2e8Ortpiqa4B74UxpUbCFViwyByJDqRX5A6O246qLedU7y_dEMZ94tJqV1-Us1_x0QjlOr4sCa2iOv7lvsRTaDRawjB5jsfU09imn3FZstL8Jcn5yg0yJ1q4muYC3rsv-XKJ9CojZTPIuIkJy5dumiqBOMOoJYMlE8SYshGK-Ak1_AhBJZs55t5s2RAFrUFxpoBeXsRmz0LTHTi4KaV7BK__9e1BLaAQIVTodVWNHZaLtWKGw_zMl_GehV3dJ_67yxPiBxTvuoLGHgJEscvVWy5CcfvS7dQYQ-39isUdBGT3cm_pPKQCUbLpMq7q-jzAv3v5ZwBJDnmuvle1Vw84mOhBs68op6Y5ZthOuGh-s5jQ_Sjn0Oxj7C4zy2XsTxd3_TAbGhQsBtqV2UxHcIhqsw4Qaa26ZHc-RiU4MmQ6Dvre6_t_GcCKlr4LlEiSWsVDUPy7zch4OiyzMJCBq5f449W2ivWRXcG6Urm3A-Csf9cJSexfpR0p2ewiQsxEv1VFeyNnwcuDXmiWTeyfK1BvwZiV9FzTPgBoMXMawLEMsjCru077r4rbx0LKFzjpDt5pyO0wp3s_0IMB-WHkSGEPjtLoQgyyQraqik_hR0I6GETBdjZdNuQnUHVoR8BAwitb5BkqH_OadEW7g7OsLpTDSIuXY3ksvYDydQZaxUR4E8hqKGJCg38bkC7bMgQnk_zS5mV_vjHe0HBiJViRWpiGveD4D3HkwEFKG1l1fWaR7e6xVLeaasQE5oBlgeXWC7C7K9Xw_POy2GU_Ze-VjaYP7P4yzA911RIVK8Tlwuca-0UopO8BwVjp4IOxEZNZBvhm2VIY_PsiOYNbZjgqXsqTZfkp7QL4hjJjeM2Itxn4tFyTC_QDRwI-ZGN_iDZxQUdCRZA0kXbqmoY6adUkE6fN_eqBShueZsJbhd3uaWd_XBmqEXTSW6ZxISmNlB5NeqBtN_VAxsHsmVMo356Wto7iZ4IkOrQO_hGDrdP4Ns4hlDlt_Uw4Ij1f5QPgZhntUpbU9ACajPSc2c0wUfSfSYQH8_lJVpXG8BU26TAmGfneKZCwO2DSCThltzKfqTEhFiFzkfIjPmb9ok0N63vFNV-ITxqZdODzEO3q9TlGaUKDQyP0-J0nPN0hbByF8RasLavRfaBX54-DNQYviL0ej2NmrVKDjcQZXkWA-sOZwXV-Szbu0DETaplqb_tx7eOTs6vUYqV-s3ZR3ZXasm-KWAfLpvahOGVX1Lp2iK-dR4rAtmBKWKleE_ulciXMkmcmE7um8pVhXGOeQB9jXPsE9msKEer_WSaq562Tqtyr1rFKKwke6k05pqP6jzOqMFzgEqzRDnbQ-TXNAXgx5SzP6oHhR6xks2w8vuBARtqhrEMTVZHCRAOIo9ewTKQ_8gvFhU1xdWvU2V6NaonYfy2cJyiAwoLJbyfuTpAYt0ytzY69MV0AtEfMcrwE6kuYq_yRVoQtpUc8jEbG4xX4tQVIpi7oL5klyY8o4R0ZrpOYr_nTjznN-hwSjyLAPjMc7D46TaZyMX7S6YjijEODRQqVxMZ8i0bKtVc1kz4GLSTkNQvsiLqAj2-Tki4845CDi7Q1gYjlZ0-U5oZqweoAjGREfMGX2Hq73HwcE_8UgqxoYzxgDeEqBMVeDVmB33pDHnB_6ewsDz0ZfeQEibnPlP3ptCkdUbp_IUdrvEBq3sgQcenPJ-CyC3mK3_NzAWOnUL0IrB8njw-RvUGRkk_fq-3X_xaf4hG3bGxdnXVUjN19PXt6hPXI8EFvucyAYQG7eAnK8VLyGldW4JZKdewCPkrPXWLGjg9EpvLpX9MDujhyKHJWJCquUQBzt0neqmDB-i4KKY6Rqw_X0JLTPRul6ona-gAUltdMN_RHjzEZbQpZVuuaT3VVcRVeIR4luOTFrHTl0MPcKbojUrr49shemci4cpkjgjKlTzrfcwbOvSvcol4MRkCjbILYL-A0737WRho0eoOOBqFsB7A4r6jvX4ZyI-5KMu0_UUg-64T18hx7n6Tkvcg6df3gdcROes3gndcnmZwhTyC9cDfwSq2m32t0WJXnwP7U3FKqBKlhkVc-hxZ77bezt5oPPYCjkm9gK49jzltKWMmu3AvJ_76bVqpBd9sJAXhwe1CjD3asC9IFimQDO8h6p6vUQmo3JkpbIBYBvMPcv1IOZ517ICwCExztG6_6KzADPzaeGn0A1RJQQ9vY6cGtGUgKX0CeDutZyKWXrKrM6uEAhmKdHgKoEJ6tqIBg9R6B0y6D-NRYNRqS0yRXd_DmvDW5_90q0WbtqTAEHXgu3BEMsjQjxxKvWdhygBzRJMw2L5CRG88kT78mEM6Ix1dmngPyyygHXr-Hp3NP4X2192FQ2srpCHYfvx1QGOX5zmOou0OrCYlpZMyOEXywu-fJYK9gZAkjf1TZsSks2F5USde8fEuuFcXObaxZP2nkdcSbrqH3USezSNQuO5koweIGjG25RgzMvDi9nkamH874c51tjusIfZm2LuxNk6GkBUU9RciiZG-Wxze_S5H9xWqLKW1sMTe2tZG4H7D_iuQWIX9i-f3sfwiO3ARpAGnjW9Vpxm623h6LODxakpz-a7tmshG5SeaaYHoNiBtonAaC_d0opAvdQ7AlfW4zir-VKjYzRsMi2AUn9g7cwtpropZ1EhnyzoTJdySBXAhfuRB-oXbGOp4BVBxJrEH2JSoJeucB2_Fe4JrgLRCqFFwJWAf1oET4z5i99k9nIftQylH_F91T5OpK8cCiqzXpFaGikEXhe2WYvXMMTP7GiEhyNnM1deeXVX6xC95ZMqaNQ3l9WXvfJBLaZNZHPFI5Ix4vQnTKQ4NblIJC8Wymk5N_e4BblEwg33Pz9gXIyb_1CRnqVSPRdHWtncDyKwH2B4KcYPQDZ7ovgtL7bzK7TBPNdM-bsFiDUaEufKdHeopEvxmLayQeJXaVLAQSrvJja9x_vy1hLI3runG1r3sGe5Ua7LlsRrHVaz3M3T7bVct4HF7Ki1B4s5e6IVWNhCpOp0p8kdJtK-soamT2y6p-JYynxy_mYXck84CIGe8EooLvcU42fW9OdsN6FBBN_PmG1ZV4yZpmirzleIqay7aUFv0664jCZ_Lz44_rMrV2mNrSBblo9azgvX6zRM_ImlywQcFwfICIrNm-MKCtWcJe5-B29wdPU6yssLkBZZHpBcIihpqjN_hMxirvS3wAAAAAAAAAAAAAAAAAABw4UGyMp" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial.json new file mode 100644 index 0000000..6c4fd16 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial.json @@ -0,0 +1,69 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc-status-waived.partial", + "artifact": "sdjwt-vc-presentation", + "title": "the @sd-jwt/sd-jwt-vc credential without its list, the status waived: not judged, so not VALID", + "source": "@sd-jwt/sd-jwt-vc 0.23.0 and @owf/token-status-list 0.5.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt-vc.json of the identity component, generated 2026-10-18; their test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "requireStatus": false + }, + "expected": { + "verdict": "PARTIAL", + "failed": [], + "levels": { + "integrity": "NOT_MEASURED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-expired.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-expired.json new file mode 100644 index 0000000..6b568ea --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-expired.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-list-expired", + "artifact": "sdjwt-vc-presentation", + "title": "the list of @owf/token-status-list, expired", + "source": "derived from sdjwt-vc-presentation/sd-jwt-vc.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "mutation": { + "producer": "@owf/token-status-list wrote the list with exp before the verifier clock", + "changed": [ + [ + "statusListJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjgxNjMwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.Kxsth2IkgDtbkwdxbG1tSGSNx_g0_sQNvwaZWjpggXwuv_TQdpqdAWQL9Io8zsOSwi4bSF569tZ35TvVfFNWBQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri.json new file mode 100644 index 0000000..d32c9f3 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-list-other-uri", + "artifact": "sdjwt-vc-presentation", + "title": "the list of @owf/token-status-list published for another uri", + "source": "derived from sdjwt-vc-presentation/sd-jwt-vc.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "mutation": { + "producer": "@owf/token-status-list wrote the list with another sub", + "changed": [ + [ + "statusListJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMS1hbHRhIiwiaWF0IjoxNzkyMjgxNjAwLCJleHAiOjE3OTIyODUyMDAsInN0YXR1c19saXN0Ijp7ImJpdHMiOjEsImxzdCI6ImVOcGpZQUFBQUFJQUFRIn19.SVVx1R0qyArp0nWD0PfwLBg63oZeoaRIZGNhPYdU4QG0yh3YasSZ_kIimjEW2hEz6NzH_HEW3Ci61a5Dze3nCA" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-list" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-revoked.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-revoked.json new file mode 100644 index 0000000..be5618c --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-revoked.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-revoked", + "artifact": "sdjwt-vc-presentation", + "title": "the list of @owf/token-status-list with status 1 at the index", + "source": "derived from sdjwt-vc-presentation/sd-jwt-vc.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "mutation": { + "producer": "@owf/token-status-list wrote the list with INVALID at the credential's index", + "changed": [ + [ + "statusListJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBUWUFBQUFFSUFJUSJ9fQ.E3ryJi_TXj8M0rBCbt0WNKkBeIiwTywQZvDeQVkq_Jl6QO3fVMX3pUa3u98MHOx7gnk36AWzs8Kkm7ix6qirDQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-revoked" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-suspended.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-suspended.json new file mode 100644 index 0000000..a782b02 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-suspended.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-suspended", + "artifact": "sdjwt-vc-presentation", + "title": "the 2-bit list of @owf/token-status-list with status 2 at the index", + "source": "derived from sdjwt-vc-presentation/sd-jwt-vc.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "mutation": { + "producer": "@owf/token-status-list wrote a 2-bit list with SUSPENDED at the credential's index", + "changed": [ + [ + "statusListJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoyLCJsc3QiOiJlTnBqNEdCZ0FBQUFIQUFKIn19.YE9Lr-dw70H4bLl-RslRGHS2E59RQYCRfuhalVQteNzqeDiMyYx1rtvOx0ynhmreetKebIoKQRfzREnHF7ImDA" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-revoked" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-unjudged.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-unjudged.json new file mode 100644 index 0000000..62e0bd2 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.status-unjudged.json @@ -0,0 +1,77 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.status-unjudged", + "artifact": "sdjwt-vc-presentation", + "title": "the @sd-jwt/sd-jwt-vc credential without its list, the status not waived", + "source": "derived from sdjwt-vc-presentation/sd-jwt-vc.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "mutation": { + "producer": "the same credential, no list handed", + "changed": [ + [ + "statusListJwt" + ] + ] + }, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.status-unjudged" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.valid.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.valid.json new file mode 100644 index 0000000..73a7cd7 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.valid.json @@ -0,0 +1,69 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "artifact": "sdjwt-vc-presentation", + "title": "an SD-JWT VC issued and presented by @sd-jwt/sd-jwt-vc (EdDSA; typ dc+sd-jwt, vct urn:eudi:pid:1, a status_list reference) with the Status List Token of @owf/token-status-list (all VALID)", + "source": "@sd-jwt/sd-jwt-vc 0.23.0 and @owf/token-status-list 0.5.0 with jose 6.2.12 (interop/fixturi-interop-sdjwt-vc.json of the identity component, generated 2026-10-18; their test keys made and discarded at generation)", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": null, + "mutation": null, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:1", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.mqBQYXpgRWu78YISD865GiYpBZcni3Ejpt440jL-LNV4kVtHcdBXR-_7XA2rhoPqbTC02MzLTf8MsFS4me0kAQ" + }, + "expected": { + "verdict": "VALID", + "failed": [], + "levels": { + "integrity": "PASSED", + "authenticity": "PASSED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch.json b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch.json new file mode 100644 index 0000000..0ec20d8 --- /dev/null +++ b/conformance/vectori/sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch.json @@ -0,0 +1,78 @@ +{ + "v": 1, + "kind": "aere-conformance-vector", + "id": "sdjwt-vc-presentation/sd-jwt-vc.vct-mismatch", + "artifact": "sdjwt-vc-presentation", + "title": "the verifier expects another credential type than the @sd-jwt/sd-jwt-vc credential carries", + "source": "derived from sdjwt-vc-presentation/sd-jwt-vc.valid", + "requires": [], + "exercises": [ + "sdjwt.alg", + "sdjwt.claim-conflict", + "sdjwt.crit", + "sdjwt.digest-twice", + "sdjwt.disclosure-form", + "sdjwt.disclosure-name", + "sdjwt.disclosure-twice", + "sdjwt.form", + "sdjwt.issuer", + "sdjwt.kb-audience", + "sdjwt.kb-claims", + "sdjwt.kb-cnf", + "sdjwt.kb-context", + "sdjwt.kb-freshness", + "sdjwt.kb-nonce", + "sdjwt.kb-required", + "sdjwt.kb-sd-hash", + "sdjwt.key", + "sdjwt.sd-alg", + "sdjwt.signature", + "sdjwt.time", + "sdjwt.typ", + "sdjwt.unreferenced", + "sdjwtvc.disclosed-protected", + "sdjwtvc.form", + "sdjwtvc.status-index", + "sdjwtvc.status-list", + "sdjwtvc.status-revoked", + "sdjwtvc.status-unjudged", + "sdjwtvc.vct", + "sdjwtvc.vct-expected", + "sdjwtvc.vct-mismatch" + ], + "base": "sdjwt-vc-presentation/sd-jwt-vc.valid", + "mutation": { + "producer": "the same credential and list, the verifier expecting urn:eudi:pid:2", + "changed": [ + [ + "expectedVct" + ] + ] + }, + "input": { + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "issuerKey": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "issuerAlg": "EdDSA", + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "now": "2026-10-18T00:01:00.000Z", + "expectedVct": "urn:eudi:pid:2", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.mqBQYXpgRWu78YISD865GiYpBZcni3Ejpt440jL-LNV4kVtHcdBXR-_7XA2rhoPqbTC02MzLTf8MsFS4me0kAQ" + }, + "expected": { + "verdict": "INVALID", + "failed": [ + "sdjwtvc.vct-mismatch" + ], + "levels": { + "integrity": "FAILED", + "authenticity": "NOT_MEASURED", + "anchoring": "NOT_MEASURED", + "finality": "NOT_MEASURED" + } + } +} diff --git a/identity/README.md b/identity/README.md index d3b9573..be6dca7 100644 --- a/identity/README.md +++ b/identity/README.md @@ -3,7 +3,7 @@ Post-quantum credentials with selective disclosure, bound to the holder's key, with delegation to devices, agents and short-lived session keys, revocation and an issuer status list. Everything verifies offline, by anyone, from the files alone. Node.js 24, no dependencies (`node:crypto` provides Ed25519 and ML-DSA-65, FIPS 204). The same keys also issue and verify standard SD-JWT (IETF -RFC 9901), below. +RFC 9901) and SD-JWT VC (the IETF draft), below, measured against other implementations in both directions. ``` node identity-cli.mjs keygen --out issuer.keys.json @@ -147,7 +147,8 @@ of the exchange. What it does not do: validate the IVMS101 schema (it carries th ## SD-JWT, the IETF standard (`sdjwt.mjs`) The same issuer and holder keys, in the format of the standard: Selective Disclosure for JSON Web Tokens, IETF RFC 9901 (November -2025), compact serialization. Checked against the RFC's own vectors, not against another SD-JWT library (below). +2025), compact serialization. Checked against the RFC's own vectors and, since 2026-10-18, against another SD-JWT library in both +directions (below). ```js import { issueSdJwt, presentSdJwt, verifySdJwt } from './sdjwt.mjs'; @@ -173,14 +174,114 @@ gives exactly the processed payload printed in the RFC; the same presentation fo with a disclosure removed or added after key binding, or with another issuer key, is refused. Algorithms: ES256 (the RFC examples), EdDSA / Ed25519 (RFC 8037; the key every AERE identity has) and ML-DSA-65 with the JWK key -type AKP. The ML-DSA JOSE names come from the IETF draft `draft-ietf-cose-dilithium`, not yet a published standard, so a verifier -that does not know them rejects an ML-DSA-65 SD-JWT; for today's libraries, issue with EdDSA. A hybrid (two signatures in one token) -would need the general JWS JSON serialization and is not done here. The algorithm must match the key the verifier gives (no `none`, -no algorithm confusion); a disclosure not bound to a digest, a digest seen twice, a disclosure naming `_sd`, `...` or `__proto__`, or -one that overwrites a claim, or a claim named `__proto__` anywhere, is refused; the issuer refuses claim values that already carry SD-JWT -structure (`_sd`, `_sd_alg`, `{"...": digest}`), which would let a holder disclose claims the issuer never saw; `exp` gets no allowance and `nbf`/`iat` get 60 s, as for AERE credentials. What it is not: -SD-JWT VC (no `vct`, no type metadata), and no status list inside the token (revocation stays with the AERE credential's list). -Checked against the RFC's vectors, not against another SD-JWT library: that is not measured. +type AKP (`alg` `ML-DSA-65`, parameters `pub` and `priv`), the names and key form of IETF RFC 9964 (May 2026; until then the draft +`draft-ietf-cose-dilithium`, which this file quoted as not yet a standard). Measured 2026-10-18 on Node.js 24.14.1: jose 6.2.12 signs +and verifies ML-DSA-65 JWS through Node's WebCrypto (which prints an experimental-feature warning), its signatures and ours verify +each other, and `@sd-jwt/core` 0.23.0 accepts an ML-DSA-65 SD-JWT and KB-JWT through its injected verifier; a library that does not +know RFC 9964 rejects such a token, so for it issue with EdDSA. A hybrid (two signatures in one token) would need the general JWS JSON +serialization and is not done here. The algorithm must match the key the verifier gives (no `none`, no algorithm confusion); a +disclosure not bound to a digest, a digest seen twice, a disclosure naming `_sd`, `...`, `_sd_alg` or `__proto__`, or one that +overwrites a claim, or a claim named `__proto__` anywhere, is refused; `_sd_alg` below the top level of the payload is refused (RFC +9901 Section 4.1.1: it MUST NOT be nested; until 2026-10-18 it was kept as an ordinary claim); the `typ` value may carry the +`application/` prefix or not (RFC 7515 Section 4.1.9); the issuer refuses claim values that already carry SD-JWT structure (`_sd`, +`_sd_alg`, `{"...": digest}`), which would let a holder disclose claims the issuer never saw; `exp` gets no allowance and `nbf`/`iat` +get 60 s, as for AERE credentials. What it is not: the SD-JWT VC profile is `sdjwt-vc.mjs`, below; a plain SD-JWT carries no status +list (the AERE credential has its own list, and the SD-JWT VC profile reads a Token Status List). + +**Interoperability, measured 2026-10-18** (`interop/interop-sdjwt.mjs`, run with the foreign libraries installed in a folder outside +this repository; Node.js 24.14.1; `@sd-jwt/core` 0.23.0 of openwallet-foundation-labs/identity-common-ts with `@owf/identity-common` +0.5.0, `@sd-jwt/crypto-nodejs` 0.19.0 as its hasher and salt generator, `jose` 6.2.12 as its JWS engine, its keys made in WebCrypto): +26 of 26 rows gave the verdicts expected of both sides. Ours to theirs: an SD-JWT issued and presented here (EdDSA, ES256 and +ML-DSA-65; top-level claims, list elements, two decoy digests, a Key Binding JWT with the verifier's audience and nonce) verifies +there with the same processed payload; a changed disclosure, a KB-JWT made for another audience, `alg` `none`, a digest listed +twice, a KB-JWT signed by another key than `cnf.jwk` and a nested `_sd_alg` are refused by both, each with its reason. Theirs to +ours: an SD-JWT issued and presented by `@sd-jwt/core` (nested disclosures such as `address.locality`, list elements, decoys, a +KB-JWT) verifies here with the same payload for the three algorithms, untyped with `expectedTyp: null` and typed `example+sd-jwt` +under the default, and the same tampered forms plus a disclosure removed after key binding are refused by both. The tokens they +produced are kept as fixtures (`interop/fixturi-interop-sdjwt.json`, 11 cases, with their public test keys) and `proba-sdjwt.mjs` +judges them offline at the recorded clock; the row-by-row table is `interop/rezultate-interop-sdjwt.json`. Differences found, and +what was decided: `@sd-jwt/core` puts no `typ` on an issuer-signed JWT unless told to (`SDJwtVcInstance` puts `dc+sd-jwt`) and never +checks it; our verifier requires an explicit `...+sd-jwt` type by default (RFC 9901 Section 9.11 recommends that verifiers check it) +and takes an untyped token with `expectedTyp: null`: kept. Their verifier compares the KB-JWT audience only when given +`expectedKeyBindingAudience`, and does not look at a KB-JWT at all when no `keyBindingNonce` is given; ours requires the verifier's +audience and nonce whenever a KB-JWT is present or required (Section 7.3 step 5.f): kept. Their issuer takes any secure hash of +the IANA list for `_sd_alg` (`sha-384`, `sha-512`, ...); ours understands only `sha-256` (Section 4.1.1 requires it and leaves the +rest to policy): kept, measured as our refusal of their `sha-384` token. Nested `_sd_alg`: they refused it and we kept it as a +claim; the RFC's MUST NOT decided it, repaired here. The salt of their default helper, `generateSalt(16)` of `@sd-jwt/crypto-nodejs`, +is 16 hexadecimal characters, 64 bits, under the 128 bits Section 9.3 recommends; ours is 16 random bytes; theirs, and the generator +is injectable. Disclosures are ordered by the presentation frame there and by issuance order here; the RFC orders them not at all. +An AKP JWK without `alg` is refused by Node's `crypto` and by jose alike (RFC 9964 Section 3 requires it). + +## SD-JWT VC (`sdjwt-vc.mjs`) + +The profile "SD-JWT-based Verifiable Digital Credentials", IETF `draft-ietf-oauth-sd-jwt-vc-19` (31 August 2026, submitted to the +IESG, not an RFC), as a thin layer over `sdjwt.mjs`, with the Token Status List of `draft-ietf-oauth-status-list-21` (21 June 2026) +read offline. No dependencies. + +```js +import { issueSdJwtVc, presentSdJwtVc, verifySdJwtVc, issueStatusListJwt, readStatusListJwt } from './sdjwt-vc.mjs'; +const { sdJwt } = issueSdJwtVc({ issuer, holder, vct: 'urn:eudi:pid:1', iss, claims, disclosable, arrayDisclosable, exp, + status: { status_list: { idx: 5, uri: 'https://issuer.example/status/1' } } }); // typ dc+sd-jwt; vct, iss, cnf, nbf, exp, status in the clear +const shown = presentSdJwtVc({ sdJwt, reveal: ['birthdate'], holder, audience, nonce }); +const list = issueStatusListJwt({ issuer, uri, statuses: [0, 0, 0, 0, 0, 1], bits: 1, exp }); // typ statuslist+jwt, sub = uri, iat, status_list { bits, lst } +const r = verifySdJwtVc(shown, { issuerKey, audience, nonce, expectedVct: 'urn:eudi:pid:1', statusListJwt: list }); +// r: { valid, reason, payload, disclosed, keyBinding, vct, status: { present, judged, uri, idx, value, name } } +``` + +What the verifier requires beyond RFC 9901: the header type `dc+sd-jwt` (Section 2.2.1); a `vct` in the payload equal to one the +verifier names (`expectedVct` is required: a verifier that does not say which credential type it expects would accept any); none of +`iss`, `nbf`, `exp`, `cnf`, `vct`, `vct#integrity`, `aka_vcts`, `status` selectively disclosed (Section 2.2.2.3; the issuer refuses to +make them disclosable); `exp` by default, as for a plain SD-JWT. A `status` claim is judged from the Status List Token the verifier +fetched from the `uri` the credential names and hands in (`statusListJwt`; signed with the issuer's key unless `statusListKey` says +otherwise): its signature, its `typ`, `sub` equal to that uri, `iat`, `exp`, then the status at `idx` (0 valid; 1 revoked, 2 +suspended and any other value refuse; the bits are packed from the least significant bit, 1, 2, 4 or 8 per entry). A credential +that names a status nobody judged is refused by default (`requireStatus: false` accepts it and reports the status as present and +not judged); one that names no status is judged without a list. Nothing is fetched: not the list, not the type metadata of `vct` +(`vct#integrity` is carried, not resolved), and the issuer's key is the verifier's input, never resolved from `iss` (Section 2.5: +JWT VC Issuer Metadata, `x5c`) or taken from the token. + +From the command line: `node identity-cli.mjs verify-sdjwt-vc --sd-jwt token.txt --issuer-key issuer.pub.json --audience A --nonce N +--expected-vct urn:eudi:pid:1 [--status-list list.txt [--status-list-key k.json]] [--status-not-required] [--expected-issuer I] +[--at T] [--json]`; 0 VALID, 1 INVALID, 2 a usage error. + +**Interoperability, measured 2026-10-18** (`interop/interop-sdjwt-vc.mjs`; `@sd-jwt/sd-jwt-vc` 0.23.0, `@owf/token-status-list` 0.5.0, +jose 6.2.12, Node.js 24.14.1): 28 of 28 rows gave the verdicts expected of both sides. Ours to theirs: an SD-JWT VC issued here +(EdDSA, ES256, ML-DSA-65; `vct` `urn:eudi:pid:1`, a `status_list` reference) with our Status List Token served to their +`statusListFetcher` verifies in `SDJwtVcInstance` with `expectedVct`, the key binding audience and nonce; our list with the index +revoked, or suspended on 2 bits, our list published for another uri, a wrong expected `vct` and a KB-JWT for another audience are +refused by both; our lists on 1, 2 and 8 bits are read by their decoder index by index, and theirs by ours (12 mixed statuses on 2 +bits, written equals read, both ways). Theirs to ours: their credential and their status list verify here under the default type, +and their revoked, suspended, other-uri and expired lists, a wrong `vct`, a KB-JWT for another audience and a credential they issued +without `vct` are refused here with the reason. Their tokens and lists are fixtures (`interop/fixturi-interop-sdjwt-vc.json`, 12 +cases) that `proba-sdjwt-vc.mjs` judges offline. Differences: their issuer does not require `vct` and their verifier checks it only +when given `expectedVct`; here both are required. Their verifier skips the status when told (`disableStatusVerification`) and +otherwise fetches it over the network; here nothing is fetched and an unjudged status is a refusal unless waived. Both refuse to +make `vct` selectively disclosable. + +**The European wallet (ARF) and the PID, read, not claimed.** Read on 2026-10-18: the Architecture and Reference Framework v3.0.0 +(21 July 2026; Annex 2.02, the high-level requirements by topic), the PID Rulebook v1.7 (17 July 2026, in +eu-digital-identity-wallet/eudi-doc-attestation-rulebooks-catalog), the OpenID4VC High Assurance Interoperability Profile 1.0 +(24 December 2025), `draft-ietf-oauth-sd-jwt-vc-19` and `draft-ietf-oauth-status-list-21`. This module claims no EUDI conformance: +the table says, row by row, what is measured here. + +| requirement | where it is written | here | +|---|---|---| +| SD-JWT VC as one of the two common attestation formats, compact serialization | ARF ARB_01; HAIP 6.1 | met; measured against `@sd-jwt/sd-jwt-vc` in both directions | +| `typ` `dc+sd-jwt` | sd-jwt-vc-19 Section 2.2.1 | met (issued and required) | +| `vct` in the `urn:eudi:pid:` namespace, `urn:eudi:pid:1` for the PID | PID Rulebook PID_14, Section 4.2; ARF ARB_05 | met as a mechanism: the issuer sets `vct`, the verifier names the one it expects; the value is the issuer's | +| the mandatory PID attributes (`family_name`, `given_name`, `birthdate`, `place_of_birth`, `nationalities`; the portrait later) and metadata (`issuing_authority`, `issuing_country`) | PID Rulebook Sections 2.2, 2.4 | not met: claims pass through as data, no PID schema is checked | +| claim names from the IANA JWT registry, public or private names; UTF-8 | ARF ARB_06b; PID Rulebook Section 4.1.1 | not judged (JSON is UTF-8; names are not checked against the registry) | +| every claim selectively disclosable on its own | PID Rulebook PID_21; ARF ARB_30 | met for top-level claims and list elements; not for the properties of nested objects at issuance (the verifier reads nested disclosures, the issuer does not make them) | +| key binding (`cnf.jwk`), a KB-JWT always present when the credential is bound | ARF OIA_02; HAIP 6.1.1.1; sd-jwt-vc-19 Section 2.2.2.3 | met (key binding required by default; `cnf` never disclosable) | +| revocation by Token Status List (`status.status_list`) | ARF VCR_01b, VCR_11a; HAIP 6.1; status-list-21 | met offline: the verifier hands in the list it fetched; measured against `@owf/token-status-list`; an unjudged status refuses by default | +| a Relying Party also supports Attestation Revocation Lists | ARF VCR_12 | not met (nothing implemented; VCR_11a notes there is no JSON specification) | +| validity by `nbf` and `exp` | PID Rulebook Section 4; HAIP 6.1 | met (`exp` required by default) | +| algorithms only from the ECCG Agreed Cryptographic Mechanisms v2.0; ES256 at least | ARF OIA_03; HAIP 7 | ES256 met; EdDSA and ML-DSA-65 are offered too, and their standing in ACM v2.0 was not read: not measured | +| hash `sha-256` | HAIP 8; RFC 9901 Section 4.1.1 | met (the only one understood) | +| issuer key from `x5c` (a trust chain, never self-signed) or from JWT VC Issuer Metadata | HAIP 6.1.1; sd-jwt-vc-19 Section 2.5 | not met: the key is the verifier's input | +| type metadata for `vct`, published in a catalog; `vct#integrity` | PID Rulebook PID_15; sd-jwt-vc-19 Section 5 | not met: carried, not resolved | +| presentation over OpenID4VP | ARF ARB_02 note | outside: this is a credential format, not a protocol | +| mdoc (ISO/IEC 18013-5) for proximity; wallets support both formats | ARF ARB_02, ISSU_02 | outside, not today: it would need CBOR (RFC 8949) and COSE (RFC 9052) encoding, the mobile security object, device authentication and the session encryption of ISO/IEC 18013-5 | ## Named rules @@ -194,8 +295,16 @@ not stop at its first refusal: it makes every check it can reach. `valid` is unc no row failed, also when rows were not judged; a caller that needs "nothing left unjudged" reads `unjudged`. With these ids the presentation verifier is enrolled in the conformance suite beside this folder (`conformance/`: 37 rules, -65 vectors of the artifact kind `identity-presentation`, each rule taken out of a copy of the verifier in turn). SD-JWT, Travel Rule -and compliance are not enrolled there. +65 vectors of the artifact kind `identity-presentation`, each rule taken out of a copy of the verifier in turn). Since 2026-10-18 the +SD-JWT verifier and the SD-JWT VC profile are enrolled there too: `verifySdJwt` names the rule of its refusal (`rule`, one of the 23 of +`REGULI` in `sdjwt.mjs`: `form`, `alg`, `typ`, `crit`, `key`, `signature`, `issuer`, `sd-alg`, `disclosure-form`, `disclosure-twice`, +`digest-twice`, `disclosure-name`, `claim-conflict`, `unreferenced`, `time`, `kb-context`, `kb-required`, `kb-cnf`, `kb-claims`, +`kb-audience`, `kb-nonce`, `kb-freshness`, `kb-sd-hash`), and `verifySdJwtVc` one of those or one of its own 9 (`vct-expected`, `vct`, +`vct-mismatch`, `disclosed-protected`, `form`, `status-list`, `status-index`, `status-revoked`, `status-unjudged`); both stop at their +first refusal. The suite holds 54 vectors of the kind `sdjwt-presentation` (the RFC 9901 example, the tokens of `@sd-jwt/core` from the +interop fixtures, and tokens issued with AERE keys) and 32 of `sdjwt-vc-presentation` (ours with their status lists, and the credentials +and lists of `@sd-jwt/sd-jwt-vc` and `@owf/token-status-list`); a VC whose status was waived and not judged is `PARTIAL` there, never +`VALID`. Travel Rule and compliance are not enrolled. Two things changed in behaviour that day, both measured by `proba-identity.mjs`, each with its planting in the negative control: @@ -222,8 +331,12 @@ node proba-conformitate.mjs # 15: compliance policies judged on real pr node control-negativ-conformitate.mjs # on a copy, each of 14 guards removed -> its own named test turns red node proba-travel-rule.mjs # 19: two VASPs with registry credentials, the whole exchange, and each attack of the review node control-negativ-travel-rule.mjs # on a copy, each of 19 guards removed -> its own named test turns red -node proba-sdjwt.mjs # 23: the RFC 9901 vectors, SD-JWTs issued with AERE keys (EdDSA and ML-DSA-65), each attack -node control-negativ-sdjwt.mjs # on a copy, each of 29 guards removed -> its own named test turns red +node proba-sdjwt.mjs # 25: the RFC 9901 vectors, SD-JWTs issued with AERE keys (EdDSA and ML-DSA-65), each attack, the fixtures of @sd-jwt/core +node control-negativ-sdjwt.mjs # on a copy, each of 31 guards removed -> its own named test turns red +node proba-sdjwt-vc.mjs # 10: the SD-JWT VC profile, the status list, the fixtures of @sd-jwt/sd-jwt-vc and @owf/token-status-list, the command line +node control-negativ-sdjwt-vc.mjs # on a copy, each of 16 guards removed -> its own named test turns red +node interop/interop-sdjwt.mjs --lab # the measurement itself, with the foreign libraries installed in , outside this repository +node interop/interop-sdjwt-vc.mjs --lab # (npm: @sd-jwt/core, @sd-jwt/sd-jwt-vc, @sd-jwt/crypto-nodejs, jose); --scrie rewrites the fixtures ``` The envelope test needs the AIP-23 reference verifier (`AERE_VERIFY_PROOF=`); without it that test is reported as diff --git a/identity/control-negativ-sdjwt-vc.mjs b/identity/control-negativ-sdjwt-vc.mjs new file mode 100644 index 0000000..bbf0f19 --- /dev/null +++ b/identity/control-negativ-sdjwt-vc.mjs @@ -0,0 +1,67 @@ +// Controlul negativ al probei SD-JWT VC (sdjwt-vc.mjs, proba-sdjwt-vc.mjs): fiecare paznic se strica intr-o COPIE, proba ruleaza pe copie si +// proba NUMITA trebuie sa iasa rosie, cu proba chiar rulata; pe copia neatinsa, verde. Trei stari: un tipar care nu apare exact o data sau o +// proba care nu ajunge la rezumat e STRICAT si se numara esec. Plantarile sunt ancorate pe randuri STABILE si UNICE ale paznicului. +// node control-negativ-sdjwt-vc.mjs iesire 0 = martorul verde si toate plantarile rosii pe proba lor +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +const S = 'sdjwt-vc.mjs'; +const PLANTARI = [ + // [nume, tipar, inlocuire, proba (inceputul numelui ei)] + ['vct-ul asteptat nu se mai cere verificatorului', "if (!(Array.isArray(vcts) && vcts.length > 0 && vcts.every((v) => typeof v === 'string' && !!v) /*PAZA:vct-expected*/)) return refuz(", 'if (false) return refuz(', 'PROFIL vct'], + ['vct lipsa din jeton primit', "if (!(typeof p.vct === 'string' && !!p.vct /*PAZA:vct*/)) return refuz('vct'", "if (false) return refuz('vct'", 'PROFIL vct'], + ['alt vct decat cel asteptat primit', 'if (!(tipuri.includes(p.vct) /*PAZA:vct-mismatch*/)) return refuz(', 'if (false) return refuz(', 'PROFIL vct'], + ['typ-ul dc+sd-jwt nu se mai cere (orice ...+sd-jwt)', 'requireStatus = true, expectedTyp = TYP_VC, ...o } = {}) {', 'requireStatus = true, expectedTyp = undefined, ...o } = {}) {', 'PROFIL typ'], + ['o afirmatie din s.2.2.2.3 dezvaluita selectiv primita', 'if (!(dez.length === 0 /*PAZA:disclosed-protected*/)) return refuz(', 'if (false) return refuz(', 'PROFIL s.2.2.2.3'], + ['emitentul face dezvaluibile afirmatiile din s.2.2.2.3', 'for (const n of [...disclosable, ...arrayDisclosable]) if (NEDEZVALUIBILE.includes(n)) throw', 'for (const n of [...disclosable, ...arrayDisclosable]) if (false) throw', 'PROFIL s.2.2.2.3'], + ['emitentul nu mai cere vct', "if (typeof vct !== 'string' || !vct) throw new Error('sd-jwt-vc: vct is required", "if (false) throw new Error('sd-jwt-vc: vct is required", 'PROFIL s.2.2.2.3'], + ['starea nejudecata trece implicit drept nerevocata', 'if (!(status.judged || !requireStatus /*PAZA:status-unjudged*/)) return refuz(', 'if (false) return refuz(', 'STARE: lista lipsa'], + ['starea revocata/suspendata primita', 'if (!(v === 0 /*PAZA:status-revoked*/)) return refuz(', 'if (false) return refuz(', 'STARE: revocat'], + ['impachetarea bitilor citita de la bitul cel mai semnificativ (ordinea gresita)', '(octeti[Math.floor(idx * bits / 8)] >> ((idx * bits) % 8)) & ((1 << bits) - 1)', '(octeti[Math.floor(idx * bits / 8)] >> (8 - bits - ((idx * bits) % 8))) & ((1 << bits) - 1)', 'STARE: revocat'], + ['sub-ul listei nu se mai compara cu uri-ul din jeton', 'if (!(corp.sub === uri /*PAZA:status-list*/)) return nu(', 'if (false) return nu(', 'STARE: lista pentru alt uri'], + ['lista expirata primita', 'if (!(corp.exp === undefined || (Number.isFinite(corp.exp) && acum < corp.exp) /*PAZA:status-list*/)) return nu(', 'if (false) return nu(', 'STARE: lista pentru alt uri'], + ['typ-ul statuslist+jwt al listei nu se mai cere', "verifyJws(jwt, publicJwk(key, alg), { typ: TYP_STATUS_LIST })", "verifyJws(jwt, publicJwk(key, alg), { typ: null })", 'STARE: lista pentru alt uri'], + ['iat-ul listei nu se mai cere', "if (!(Number.isFinite(corp.iat) /*PAZA:status-list*/)) return nu('iat is required", "if (false) return nu('iat is required", 'STARE: lista pentru alt uri'], + ['indexul dincolo de lista citit ca 0', 'if (!(v !== null /*PAZA:status-index*/)) return refuz(', 'if (false) return refuz(', 'STARE: lista pentru alt uri'], + // fixturile straine: cu impachetarea gresita, listele @owf/token-status-list pe 1 bit cu indexul 5 = 1 ar fi citite altfel + ['fixturile straine: lista LOR revocata citita cu ordinea gresita a bitilor', 'const statusAt = (idx) => (Number.isInteger(idx) && idx >= 0 && idx < entries ?', 'const statusAt = (idx) => (false && Number.isInteger(idx) && idx >= 0 && idx < entries ?', 'INTEROP'], +]; +function copie() { + const t = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-sdjwt-vc-ctl-')); + for (const f of [S, 'sdjwt.mjs', 'identity.mjs', 'identity-cli.mjs', 'proba-sdjwt-vc.mjs']) fs.copyFileSync(path.join(AICI, f), path.join(t, f)); + fs.mkdirSync(path.join(t, 'interop')); + fs.copyFileSync(path.join(AICI, 'interop', 'fixturi-interop-sdjwt-vc.json'), path.join(t, 'interop', 'fixturi-interop-sdjwt-vc.json')); + return t; +} +function ruleaza(t) { + return new Promise((resolve) => { + const c = spawn(process.execPath, [path.join(t, 'proba-sdjwt-vc.mjs')]); let out = ''; + const ceas = setTimeout(() => c.kill(), 180000); + c.stdout.on('data', (x) => { out += x; }); c.stderr.on('data', (x) => { out += x; }); + c.on('close', (cod) => { clearTimeout(ceas); resolve({ cod, rulat: /aere-sd-jwt-vc: \d+\/\d+/.test(out), rosii: out.split('\n').filter((l) => l.startsWith(' RAU ')) }); }); + }); +} +async function planteaza([nume, din, inl, tinta]) { + const t = copie(); + try { + const f = path.join(t, S); const src = fs.readFileSync(f, 'utf8'); + if (src.split(din).length !== 2) return [false, ` STRICAT ${nume}: tiparul apare de ${src.split(din).length - 1} ori`]; + fs.writeFileSync(f, src.replace(din, inl)); + const r = await ruleaza(t); + if (!r.rulat) return [false, ` STRICAT ${nume}: proba nu a ajuns la rezumat (cod ${r.cod})`]; + if (r.rosii.some((l) => l.startsWith(' RAU ' + tinta))) return [true, ` ROSU cum trebuia ${nume} (proba '${tinta}' pica)`]; + return [false, ` CONTROL CAZUT ${nume}: proba '${tinta}' a ramas verde (${r.rosii.length} rosii altundeva)`]; + } finally { fs.rmSync(t, { recursive: true, force: true }); } +} +let rele = 0; +const t0 = copie(); const m = await ruleaza(t0); fs.rmSync(t0, { recursive: true, force: true }); +if (m.rulat && m.cod === 0 && !m.rosii.length) console.log(' OK martorul: copia neatinsa verde'); else { rele++; console.log(` STRICAT martorul nu e verde (cod ${m.cod}, ${m.rosii.length} rosii)`); } +const rez = new Array(PLANTARI.length); let i = 0; +await Promise.all(Array.from({ length: 4 }, async () => { while (i < PLANTARI.length) { const k = i++; rez[k] = await planteaza(PLANTARI[k]); } })); +for (const [bun, linie] of rez) { console.log(linie); if (!bun) rele++; } +console.log(rele ? `CONTROL NEGATIV: ${rele} probleme` : `DOVEDIT: martorul verde, ${PLANTARI.length} din ${PLANTARI.length} paznici scosi -> proba lor rosie`); +process.exitCode = rele ? 1 : 0; diff --git a/identity/control-negativ-sdjwt.mjs b/identity/control-negativ-sdjwt.mjs index d0535dc..4d7207a 100644 --- a/identity/control-negativ-sdjwt.mjs +++ b/identity/control-negativ-sdjwt.mjs @@ -1,6 +1,8 @@ // Controlul negativ al probei SD-JWT (sdjwt.mjs, proba-sdjwt.mjs): fiecare paznic se strica intr-o COPIE, proba ruleaza pe copie si proba // NUMITA trebuie sa iasa rosie, cu proba chiar rulata; pe copia neatinsa, verde. Trei stari: un tipar care nu apare exact o data sau o // proba care nu ajunge la rezumat e STRICAT si se numara esec. +// 2026-10-18: paznicii poarta marcajele /*PAZA:*/ ale suitei de conformitate pe conditia lor BUNA (`if (!(bun /*PAZA:x*/)) refuz`); +// plantarile de aici fac conditia falsa pe alt drum (`if (false)`), ca sa fie independente de plantarea suitei (care o face adevarata). // node control-negativ-sdjwt.mjs iesire 0 = martorul verde si toate plantarile rosii pe proba lor import fs from 'node:fs'; import os from 'node:os'; @@ -12,41 +14,46 @@ const AICI = path.dirname(fileURLToPath(import.meta.url)); const S = 'sdjwt.mjs'; const PLANTARI = [ // [nume, tipar, inlocuire, proba (inceputul numelui ei)] - ['alg none primit', 'if (!ALGS.includes(antet.alg)) throw', "if (antet.alg === 'nimic') throw", 'ATAC: alg none'], - ['algoritmul nu mai trebuie sa fie al cheii (confuzia)', 'if (!potriveste(antet.alg, key)) throw', 'if (false) throw', 'ATAC: alg none'], - ['o dezvaluire nelegata de niciun digest primita', 'if (folosite.size !== dupaDigest.size) return', 'if (false) return', 'ATAC: o dezvaluire cu valoarea schimbata'], - ['aceeasi dezvaluire de doua ori primita', "if (dupaDigest.has(dg)) return refuz('the same disclosure is given twice');", '', 'ATAC: o dezvaluire cu valoarea schimbata'], - ['numele _sd, ... sau __proto__ primite', "if (c[1] === '_sd' || c[1] === '...' || c[1] === '__proto__') throw", 'if (false) throw', 'ATAC: un emitent care pune in _sd'], - ['o afirmatie dezvaluita peste una in clar primita', 'if (Object.hasOwn(out, c[1])) throw', 'if (false) throw', 'ATAC: un emitent care pune in _sd'], - ['acelasi digest de doua ori primit', 'const vezi = (dg) => { if (vazute.has(dg)) throw', 'const vezi = (dg) => { if (false) throw', 'ATAC: un emitent care pune in _sd'], - ['sd_hash nu se mai compara', 'if (sha256b64u(baza) !== K.sd_hash) return', 'if (false) return', 'RFC 9901: o dezvaluire scoasa'], + ['alg none primit', "if (!(ALGS.includes(antet.alg) /*PAZA:alg*/)) throw", "if (antet.alg === 'nimic') throw", 'ATAC: alg none'], + ['algoritmul nu mai trebuie sa fie al cheii (confuzia)', 'if (!(potriveste(antet.alg, key) /*PAZA:key*/)) throw', 'if (false) throw', 'ATAC: alg none'], + ['o dezvaluire nelegata de niciun digest primita', 'if (!(folosite.size === dupaDigest.size /*PAZA:unreferenced*/)) return', 'if (false) return', 'ATAC: o dezvaluire cu valoarea schimbata'], + ['aceeasi dezvaluire de doua ori primita', "if (!(!dupaDigest.has(dg) /*PAZA:disclosure-twice*/)) return refuz('disclosure-twice', 'the same disclosure is given twice');", '', 'ATAC: o dezvaluire cu valoarea schimbata'], + ['numele _sd, ..., _sd_alg sau __proto__ primite', "if (!(c[1] !== '_sd' && c[1] !== '...' && c[1] !== '_sd_alg' && c[1] !== '__proto__' /*PAZA:disclosure-name*/)) throw", 'if (false) throw', 'ATAC: un emitent care pune in _sd'], + ['o afirmatie dezvaluita peste una in clar primita', 'if (!(!Object.hasOwn(out, c[1]) /*PAZA:claim-conflict*/)) throw', 'if (false) throw', 'ATAC: un emitent care pune in _sd'], + ['acelasi digest de doua ori primit', 'const vezi = (dg) => { if (!(!vazute.has(dg) /*PAZA:digest-twice*/)) throw', 'const vezi = (dg) => { if (false) throw', 'ATAC: un emitent care pune in _sd'], + ['sd_hash nu se mai compara', 'if (!(sha256b64u(baza) === K.sd_hash /*PAZA:kb-sd-hash*/)) return', 'if (false) return', 'RFC 9901: o dezvaluire scoasa'], ['tipul KB (kb+jwt) nu se mai cere', "k = verificaJws(kb, payload.cnf.jwk, { typ: 'kb+jwt' });", 'k = verificaJws(kb, payload.cnf.jwk, { typ: null });', 'ATAC: KB semnat de alta cheie'], - ['publicul KB nu se mai compara', 'if (K.aud !== audience) return', 'if (false) return', 'RFC 9901: aceeasi prezentare pentru ALT verificator'], - ['nonce-ul KB nu se mai compara', 'if (K.nonce !== nonce) return', 'if (false) return', 'RFC 9901: aceeasi prezentare pentru ALT verificator'], - ['KB vechi primit', 'if (Math.abs(acum - K.iat) > maxAgeS) return', 'if (false) return', 'RFC 9901: aceeasi prezentare pentru ALT verificator'], - ['exp nu se mai cere', 'if (payload.exp !== undefined && acum >= payload.exp) return', 'if (false) return', 'timpul'], - ['fara toleranta de ceas pe nbf', 'if (payload.nbf !== undefined && payload.nbf - clockSkewS > acum) return', 'if (payload.nbf !== undefined && payload.nbf > acum) return', 'timpul'], - ['Key Binding cerut, dar lipsa primita', "if (requireKeyBinding) return refuz('key binding is required", "if (false) return refuz('key binding is required", 'RFC 9901: SD-JWT-ul standardului cu ALTA cheie'], + ['publicul KB nu se mai compara', 'if (!(K.aud === audience /*PAZA:kb-audience*/)) return', 'if (false) return', 'RFC 9901: aceeasi prezentare pentru ALT verificator'], + ['nonce-ul KB nu se mai compara', 'if (!(K.nonce === nonce /*PAZA:kb-nonce*/)) return', 'if (false) return', 'RFC 9901: aceeasi prezentare pentru ALT verificator'], + ['KB vechi primit', 'if (!(Math.abs(acum - K.iat) <= maxAgeS /*PAZA:kb-freshness*/)) return', 'if (false) return', 'RFC 9901: aceeasi prezentare pentru ALT verificator'], + ['exp nu se mai cere', 'if (!(payload.exp === undefined || acum < payload.exp /*PAZA:time*/)) return', 'if (false) return', 'timpul'], + ['fara toleranta de ceas pe nbf', 'if (!(payload.nbf === undefined || payload.nbf - clockSkewS <= acum /*PAZA:time*/)) return', 'if (!(payload.nbf === undefined || payload.nbf <= acum /*PAZA:time*/)) return', 'timpul'], + ['Key Binding cerut, dar lipsa primita', "if (!(!requireKeyBinding /*PAZA:kb-required*/)) return refuz('kb-required'", "if (false) return refuz('kb-required'", 'RFC 9901: SD-JWT-ul standardului cu ALTA cheie'], // revizuirea adversariala din 30 sept: forma de dinainte a fiecarei reparatii ['emitentul semneaza structura SD-JWT din valori', 'if (areStructuraSd(claims)) throw', 'if (false) throw', 'REVIZUIRE: emitentul refuza structura'], ['prezentarea arata elementul din orice lista', 'obiect(r) && r.in === l.lista && c.length === 2', 'obiect(r) && c.length === 2', 'REVIZUIRE: prezentarea arata elementul'], - ['publicul si nonce-ul nu se mai cer', "if ((requireKeyBinding || kb !== '') && (typeof audience !== 'string'", "if (false && (typeof audience !== 'string'", 'REVIZUIRE: fara publicul si nonce-ul'], - ['exp nu se mai cere implicit', 'if (requireExp && payload.exp === undefined) return', 'if (false) return', 'REVIZUIRE: exp cerut implicit'], - ['tipul jetonului nu se mai verifica implicit', "if (cerut === undefined) return typeof typ === 'string' && /(^|\\+)sd-jwt$/.test(typ);", 'if (cerut === undefined) return true;', 'REVIZUIRE: tipul jetonului'], - ['expectedIssuer nu se mai compara', 'if (expectedIssuer != null && corp.iss !== expectedIssuer) return', 'if (false) return', 'REVIZUIRE: tipul jetonului'], - ['crit primit', "if (Object.hasOwn(antet, 'crit')) throw", 'if (false) throw', 'REVIZUIRE: crit'], - ['base64url necanonic primit', "if (b.toString('base64url') !== s) throw", 'if (false) throw', 'REVIZUIRE: crit'], - ['exp-ul KB nu se mai cere', 'if (K.exp !== undefined && (!Number.isFinite(K.exp) || acum >= K.exp)) return', 'if (false) return', 'REVIZUIRE: crit'], + ['publicul si nonce-ul nu se mai cer', "if (!(!(requireKeyBinding || kb !== '') || context /*PAZA:kb-context*/)) return", 'if (false) return', 'REVIZUIRE: fara publicul si nonce-ul'], + ['exp nu se mai cere implicit', 'if (!(!requireExp || payload.exp !== undefined /*PAZA:time*/)) return', 'if (false) return', 'REVIZUIRE: exp cerut implicit'], + ['tipul jetonului nu se mai verifica implicit', "if (cerut === undefined) return typeof t === 'string' && /(^|\\+)sd-jwt$/.test(t);", 'if (cerut === undefined) return true;', 'REVIZUIRE: tipul jetonului'], + ['expectedIssuer nu se mai compara', 'if (!(expectedIssuer == null || corp.iss === expectedIssuer /*PAZA:issuer*/)) return', 'if (false) return', 'REVIZUIRE: tipul jetonului'], + ['crit primit', "if (!(!Object.hasOwn(antet, 'crit') /*PAZA:crit*/)) throw", 'if (false) throw', 'REVIZUIRE: crit'], + ['base64url necanonic primit', "if (!(b.toString('base64url') === s /*PAZA:form*/)) throw", 'if (false) throw', 'REVIZUIRE: crit'], + ['exp-ul KB nu se mai cere', 'if (!(K.exp === undefined || (Number.isFinite(K.exp) && acum < K.exp) /*PAZA:kb-freshness*/)) return', 'if (false) return', 'REVIZUIRE: crit'], // 2026-10-01: a doua jumatate a "exp/nbf ale KB"; fara plantarea ei, paznicul scos lasa proba verde (masurat: 23/23) - ['nbf-ul KB nu se mai cere', 'if (K.nbf !== undefined && (!Number.isFinite(K.nbf) || K.nbf - clockSkewS > acum)) return', 'if (false) return', 'REVIZUIRE: crit'], - ['_sd_alg scos de la orice nivel', "!(sus && k === '_sd_alg')", "k !== '_sd_alg'", 'REVIZUIRE: crit'], + ['nbf-ul KB nu se mai cere', 'if (!(K.nbf === undefined || (Number.isFinite(K.nbf) && K.nbf - clockSkewS <= acum) /*PAZA:kb-freshness*/)) return', 'if (false) return', 'REVIZUIRE: crit'], + // 2026-10-18 (interoperarea cu @sd-jwt/core 0.23.0): _sd_alg imbricat era pastrat ca afirmatie; acum e refuzat (RFC 9901 s.4.1.1) + ['_sd_alg imbricat primit (scos in tacere, ca pana pe 18 oct)', "if (k === '_sd_alg') { if (!(sus /*PAZA:sd-alg*/)) throw nu('sd-alg'", "if (k === '_sd_alg') { if (false) throw nu('sd-alg'", 'INTEROP: _sd_alg imbricat'], + ['prefixul application/ al typ-ului nu se mai scoate (RFC 7515 s.4.1.9)', 'const t = faraPrefix(typ);', 'const t = typ;', 'INTEROP: _sd_alg imbricat'], + ['emiterea nu mai cere un typ explicit de SD-JWT', "if (!tipBun(typ, undefined)) throw new Error('sd-jwt: typ must be", "if (false) throw new Error('sd-jwt: typ must be", 'INTEROP: _sd_alg imbricat'], ['cheia publica Node nu mai e primita', "(k.type === 'public' ? k : crypto.createPublicKey(k))", 'crypto.createPublicKey(k)', 'REVIZUIRE: cheia emitentului'], - ['o afirmatie __proto__ primita (prototipul schimbat)', "if (Object.hasOwn(x, '__proto__')) throw", 'if (false) throw', 'ATAC: o afirmatie numita __proto__'], + ['o afirmatie __proto__ primita (prototipul schimbat)', "if (!(!Object.hasOwn(x, '__proto__') /*PAZA:disclosure-name*/)) throw", 'if (false) throw', 'ATAC: o afirmatie numita __proto__'], ['elementele de lista nedezvaluite pastrate', 'if (!c) continue; // nedezvaluit: elementul se scoate', "if (!c) { out.push(e); continue; }", 'AERE -> SD-JWT (EdDSA'], ]; function copie() { const t = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-sdjwt-ctl-')); for (const f of [S, 'identity.mjs', 'identity-cli.mjs', 'proba-sdjwt.mjs', 'fixturi-rfc9901.json']) fs.copyFileSync(path.join(AICI, f), path.join(t, f)); + fs.mkdirSync(path.join(t, 'interop')); + fs.copyFileSync(path.join(AICI, 'interop', 'fixturi-interop-sdjwt.json'), path.join(t, 'interop', 'fixturi-interop-sdjwt.json')); return t; } function ruleaza(t) { diff --git a/identity/identity-cli.mjs b/identity/identity-cli.mjs index 3836196..370cfdc 100644 --- a/identity/identity-cli.mjs +++ b/identity/identity-cli.mjs @@ -18,6 +18,10 @@ // verify-sdjwt --sd-jwt f.txt --issuer-key k.json [--issuer-alg EdDSA|ML-DSA-65|ES256] --audience A --nonce N // [--expected-issuer I] [--expected-typ T] [--max-age S] [--at T] [--json] an SD-JWT+KB (IETF RFC 9901), sdjwt.mjs; // the issuer key is a public JWK or the public keys of an AERE identity (the output of pub) +// verify-sdjwt-vc --sd-jwt f.txt --issuer-key k.json [--issuer-alg A] --audience A --nonce N --expected-vct V [--expected-vct V2 ...] +// [--status-list f.txt [--status-list-key k.json] [--status-list-alg A]] [--status-not-required] [--expected-issuer I] +// [--max-age S] [--at T] [--json] an SD-JWT VC (draft-ietf-oauth-sd-jwt-vc), sdjwt-vc.mjs; the status list is the Token +// Status List JWT the verifier fetched from the uri the credential names (without it a credential with `status` is INVALID) // Coduri de iesire: 0 VALID / COMPLIANT, 1 INVALID / NOT COMPLIANT, 2 intrare respinsa (motivul pe stderr, `error: ...`). // O valoare de --claim se citeste ca JSON daca e JSON (true, 42, {"a":1}), altfel ca text. import fs from 'node:fs'; @@ -128,33 +132,52 @@ async function main() { else console.log(r.compliant ? `COMPLIANT with ${r.policyId} (${r.policyHash})` : `NOT COMPLIANT with ${r.policyId}:\n ` + r.reasons.join('\n ')); return r.compliant ? 0 : 1; } - if (cmd === 'verify-sdjwt') { + if (cmd === 'verify-sdjwt' || cmd === 'verify-sdjwt-vc') { // 2026-09-30: SD-JWT (IETF RFC 9901) cu sdjwt.mjs; jetonul dintr-un fisier text (serializarea compacta, fara spatii) + // 2026-10-18: verify-sdjwt-vc, profilul SD-JWT VC (sdjwt-vc.mjs): --expected-vct cerut, --status-list (altfel, cu `status` in jeton, INVALID: stare nejudecata; --status-not-required o lasa nejudecata si o spune) const { verifySdJwt, publicJwk } = await import('./sdjwt.mjs'); + const vc = cmd === 'verify-sdjwt-vc'; let jeton; try { jeton = fs.readFileSync(cere('--sd-jwt'), 'utf8').trim(); } catch (e) { throw new Folosire(`cannot read --sd-jwt: ${e.message}`); } - const cheie = citeste(cere('--issuer-key')); - const alg = get('--issuer-alg') ?? 'EdDSA'; - if (!['EdDSA', 'Ed25519', 'ES256', 'ML-DSA-65'].includes(alg)) throw new Folosire('--issuer-alg is EdDSA, ES256 or ML-DSA-65'); // revizuirea din 30 sept: cheia emitentului e intrarea VERIFICATORULUI; una care nu se citeste, e privata sau nu e a algoritmului cerut e o // greseala a lui (cod 2, cu motivul), nu un credential INVALID (cheile stricate ieseau INVALID cu mesajul Node) - try { - const jwk = publicJwk(cheie, alg); - if ('d' in jwk || 'priv' in jwk) throw new Error('a private JWK was given where a public key belongs'); - const k = crypto.createPublicKey({ key: jwk, format: 'jwk' }); - const cere2 = alg === 'ES256' ? k.asymmetricKeyType === 'ec' && k.asymmetricKeyDetails.namedCurve === 'prime256v1' : alg === 'ML-DSA-65' ? k.asymmetricKeyType === 'ml-dsa-65' : k.asymmetricKeyType === 'ed25519'; - if (!cere2) throw new Error(`the key is a ${k.asymmetricKeyType} key, not one for ${alg}`); - } catch (e) { throw new Folosire('--issuer-key: ' + String(e.message || e).replace(/^sd-jwt: /, '').slice(0, 160)); } + const cheiePublicaBuna = (optiune, cheie, alg) => { + if (!['EdDSA', 'Ed25519', 'ES256', 'ML-DSA-65'].includes(alg)) throw new Folosire(`${optiune}-alg is EdDSA, ES256 or ML-DSA-65`); + try { + const jwk = publicJwk(cheie, alg); + if ('d' in jwk || 'priv' in jwk) throw new Error('a private JWK was given where a public key belongs'); + const k = crypto.createPublicKey({ key: jwk, format: 'jwk' }); + const buna = alg === 'ES256' ? k.asymmetricKeyType === 'ec' && k.asymmetricKeyDetails.namedCurve === 'prime256v1' : alg === 'ML-DSA-65' ? k.asymmetricKeyType === 'ml-dsa-65' : k.asymmetricKeyType === 'ed25519'; + if (!buna) throw new Error(`the key is a ${k.asymmetricKeyType} key, not one for ${alg}`); + } catch (e) { if (e instanceof Folosire) throw e; throw new Folosire(`${optiune}: ` + String(e.message || e).replace(/^sd-jwt: /, '').slice(0, 160)); } + }; + const cheie = citeste(cere('--issuer-key')); + const alg = get('--issuer-alg') ?? 'EdDSA'; + cheiePublicaBuna('--issuer-key', cheie, alg); const maxAgeS = Number(get('--max-age') ?? 300); if (!Number.isInteger(maxAgeS) || maxAgeS < 1 || maxAgeS > 3600) throw new Folosire('--max-age is a number of seconds, 1..3600'); const tip = get('--expected-typ'); - const r = verifySdJwt(jeton, { issuerKey: cheie, issuerAlg: alg, audience: cere('--audience'), nonce: cere('--nonce'), expectedIssuer: get('--expected-issuer'), - maxAgeS, now: momentul(), ...(tip != null ? { expectedTyp: tip } : {}) }); + const comune = { issuerKey: cheie, issuerAlg: alg, audience: cere('--audience'), nonce: cere('--nonce'), expectedIssuer: get('--expected-issuer'), maxAgeS, now: momentul(), ...(tip != null ? { expectedTyp: tip } : {}) }; + let r; + if (!vc) r = verifySdJwt(jeton, comune); + else { + const { verifySdJwtVc } = await import('./sdjwt-vc.mjs'); + const vcts = toate('--expected-vct'); if (!vcts.length) throw new Folosire('verify-sdjwt-vc needs --expected-vct (the credential type the verifier expects; may be repeated)'); + let statusListJwt = null; if (get('--status-list')) { try { statusListJwt = fs.readFileSync(get('--status-list'), 'utf8').trim(); } catch (e) { throw new Folosire(`cannot read --status-list: ${e.message}`); } } + const statusListKey = get('--status-list-key') ? citeste(get('--status-list-key')) : null, statusListAlg = get('--status-list-alg') ?? alg; + if (statusListKey) cheiePublicaBuna('--status-list-key', statusListKey, statusListAlg); + r = verifySdJwtVc(jeton, { ...comune, expectedVct: vcts, statusListJwt, statusListKey, statusListAlg, requireStatus: !are('--status-not-required') }); + } // JSON compact: cu indentare, iesirea creste cu patratul adancimii afirmatiilor (un jeton de 7 KB imbricat de 2.500 de ori dadea 6 MB) if (are('--json')) console.log(JSON.stringify(r)); - else console.log(r.valid ? `VALID: issued by ${r.issuer}${r.issuerChecked ? '' : ' (not checked against an expected issuer)'}; disclosed: ${r.disclosed.join(', ') || 'nothing'}` : 'INVALID: ' + r.reason); + else if (!r.valid) console.log('INVALID: ' + r.reason); + else { + const stare = !vc ? '' : '; status ' + (r.status.judged ? `${r.status.value} (${r.status.name}) in ${r.status.uri} at ${r.status.idx}` : r.status.present ? `not judged (${r.status.uri ?? r.status.mechanism})` : 'none'); + console.log(`VALID: issued by ${r.issuer}${r.issuerChecked ? '' : ' (not checked against an expected issuer)'}${vc ? `; vct ${r.vct}` : ''}; disclosed: ${r.disclosed.join(', ') || 'nothing'}${stare}`); + } return r.valid ? 0 : 1; } - throw new Folosire('usage: identity-cli.mjs keygen|pub|id|issue|status-list|delegate|revoke|present|verify|comply|verify-sdjwt ... (see README.md)'); + throw new Folosire('usage: identity-cli.mjs keygen|pub|id|issue|status-list|delegate|revoke|present|verify|comply|verify-sdjwt|verify-sdjwt-vc ... (see README.md)'); } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { main().then((c) => { process.exitCode = c; }, (e) => { console.error('error: ' + (e.message || e)); process.exitCode = e instanceof Folosire ? 2 : 1; }); diff --git a/identity/interop/fixturi-interop-sdjwt-vc.json b/identity/interop/fixturi-interop-sdjwt-vc.json new file mode 100644 index 0000000..bc6f1b3 --- /dev/null +++ b/identity/interop/fixturi-interop-sdjwt-vc.json @@ -0,0 +1,427 @@ +{ + "generat": "2026-10-18T06:18:52.552Z", + "unealta": "tools/aere-identity/interop/interop-sdjwt-vc.mjs --scrie", + "nota": "AERE-SINTETIC: credentiale emise de @sd-jwt/sd-jwt-vc si liste de stare de @owf/token-status-list (semnate prin WebCrypto/jose) cu chei de PROBA nascute la generare; numai cheile publice sunt aici. Judecate offline de proba-sdjwt-vc.mjs la ceasVerificare.", + "biblioteci": { + "@sd-jwt/sd-jwt-vc": "0.23.0", + "@sd-jwt/core": "0.23.0", + "@owf/token-status-list": "0.5.0", + "@sd-jwt/crypto-nodejs": "0.19.0", + "jose": "6.2.12", + "node": "v24.14.1" + }, + "ceas": 1792281600, + "ceasVerificare": 1792281660, + "audience": "https://verifier.example", + "nonce": "interop-vc-d76d596a1b7d", + "vct": "urn:eudi:pid:1", + "cazuri": [ + { + "nume": "EdDSA: SD-JWT VC @sd-jwt/sd-jwt-vc cu lista de stare @owf/token-status-list (toate 0)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~WyIyNTgzZmNmYzliNWFmYjkyIiwiREUiXQ~WyIzODAyMzZhZTkwMjNjYTUwIiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyJkNDM0Njk2MmIyMWQzOWUzIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI4ZWNjOWZlYTllZWZiYTNhIiwiYWRkcmVzcyIseyJsb2NhbGl0eSI6IkNsdWoiLCJjb3VudHJ5IjoiUk8ifV0~", + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.mqBQYXpgRWu78YISD865GiYpBZcni3Ejpt440jL-LNV4kVtHcdBXR-_7XA2rhoPqbTC02MzLTf8MsFS4me0kAQ", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": true, + "payload": { + "vct": "urn:eudi:pid:1", + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "nbf": 1792281600, + "exp": 1823817600, + "status": { + "status_list": { + "idx": 5, + "uri": "https://issuer.example/status/pid/1" + } + }, + "nationalities": [ + "RO" + ], + "issuing_authority": "Example Authority", + "issuing_country": "RO", + "cnf": { + "jwk": { + "crv": "Ed25519", + "x": "3IXTA1dXnHQJruWipvQEERs3ZM0a_thCsS3ZopDvamU", + "kty": "OKP" + } + }, + "age_over_18": true, + "birthdate": "1990-01-01" + }, + "disclosed": [ + "[]", + "age_over_18", + "birthdate" + ], + "status": { + "present": true, + "judged": true, + "mechanism": "status_list", + "uri": "https://issuer.example/status/pid/1", + "idx": 5, + "value": 0, + "name": "VALID" + } + } + }, + { + "nume": "ES256: SD-JWT VC @sd-jwt/sd-jwt-vc cu lista de stare @owf/token-status-list (toate 0)", + "alg": "ES256", + "issuerJwk": { + "kty": "EC", + "x": "R_TdGYHfNybEvRm1kG75eylpg-XP19wF1jHT0MhAu94", + "y": "641tE1De1QAXA_eevwKYPho1pjGRZdu-SOqyGcysgCM", + "crv": "P-256" + }, + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6Ilh0VWE1a2JRZzdCNnZubERDbjBIR0NMY3F6MU1tdW1hSEp1RHRkQ2RwUkkifSx7Ii4uLiI6IlV1VUI5RGt5MXNyOWdfY1pwbElQZ0V6OEZtaG5OOU5BSkFaSnVoYTRhRTgifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4IjoiWlcwZ0RtM0xxNHFfNWpBbi0wa21DVzVteDVmRGI1ZXJUT0ttUTVDMnNjTSIsInkiOiJsaHJMWlY2MkZDS01KYW5WNlZ2RGZfZ3dEbXBsVHhYWHI2c3ZxM3pYQVR3IiwiY3J2IjoiUC0yNTYifX0sIl9zZCI6WyIwMWh2UldpRHdCbnhIS0NvMW5GeVkzN18zZUFMSTdUUnFJdHd0MExzamIwIiwiQ19XUWdyOFUyamNGbEhaRm1hbFJ6N3cxbVdpNTdtZlY0OWdfZUs0aEZNdyIsIkVPX1Y4T3pzSks2Q3NocXJ6ZXMzSzFQRzY2V05fUkM4b1htOHZpTzNrMTAiLCJSRHFwYUNxb0VPbzFqRHViQXh3aTRDbzkyMlItdVJ0dmFDdVM5UW90UlJVIiwiVkliVUdIWl9DTVpPZVlMTVVOYTUyMHctTEtCUmgzWFQwOGo5elpBWk9XWSIsImdtMHNPNU5sM3NhSjhJODgtMTd4T1NiT3c0UWpGcTVZTUU2VzI2YUYtWVEiLCJrZWpHLTU0YjUzWVBYWmtKV2FSZEpvR1RUZGJyeUlUdmVPY1lrYlRBWnBBIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.p4dhgj0gszwe4kXzwh4TbJKVoY3-sNSjLI0tUlQrWEpHxvlEenToGA6YgcRFDWmitv1_mMHUNzwjW_nd7GOyyA~WyJiZTU0Mzg5MjcwMGU5YWYxIiwiUk8iXQ~WyJlMzMxYzliNzY3ZDJhNTEyIiwiREUiXQ~WyIzZThlNGYxYjljMmFkZjYxIiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyJlMWRiZDAxMTNmODA0ZDMzIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyJhYzlkNmM2NDlmNDhhZGUwIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyI1ODAwMzI3YjZiODlhMWFiIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjZTk4ZTJkNjI5MTFhYTQ3IiwiYWRkcmVzcyIseyJsb2NhbGl0eSI6IkNsdWoiLCJjb3VudHJ5IjoiUk8ifV0~", + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6Ilh0VWE1a2JRZzdCNnZubERDbjBIR0NMY3F6MU1tdW1hSEp1RHRkQ2RwUkkifSx7Ii4uLiI6IlV1VUI5RGt5MXNyOWdfY1pwbElQZ0V6OEZtaG5OOU5BSkFaSnVoYTRhRTgifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4IjoiWlcwZ0RtM0xxNHFfNWpBbi0wa21DVzVteDVmRGI1ZXJUT0ttUTVDMnNjTSIsInkiOiJsaHJMWlY2MkZDS01KYW5WNlZ2RGZfZ3dEbXBsVHhYWHI2c3ZxM3pYQVR3IiwiY3J2IjoiUC0yNTYifX0sIl9zZCI6WyIwMWh2UldpRHdCbnhIS0NvMW5GeVkzN18zZUFMSTdUUnFJdHd0MExzamIwIiwiQ19XUWdyOFUyamNGbEhaRm1hbFJ6N3cxbVdpNTdtZlY0OWdfZUs0aEZNdyIsIkVPX1Y4T3pzSks2Q3NocXJ6ZXMzSzFQRzY2V05fUkM4b1htOHZpTzNrMTAiLCJSRHFwYUNxb0VPbzFqRHViQXh3aTRDbzkyMlItdVJ0dmFDdVM5UW90UlJVIiwiVkliVUdIWl9DTVpPZVlMTVVOYTUyMHctTEtCUmgzWFQwOGo5elpBWk9XWSIsImdtMHNPNU5sM3NhSjhJODgtMTd4T1NiT3c0UWpGcTVZTUU2VzI2YUYtWVEiLCJrZWpHLTU0YjUzWVBYWmtKV2FSZEpvR1RUZGJyeUlUdmVPY1lrYlRBWnBBIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.p4dhgj0gszwe4kXzwh4TbJKVoY3-sNSjLI0tUlQrWEpHxvlEenToGA6YgcRFDWmitv1_mMHUNzwjW_nd7GOyyA~WyJhYzlkNmM2NDlmNDhhZGUwIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyI1ODAwMzI3YjZiODlhMWFiIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiZTU0Mzg5MjcwMGU5YWYxIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiajFVQTlYdXcwdEx0c3lDWkNsQ0RzVDNrOUhvVVNwY0hjdGphM2l6YlBobyJ9.ZEoIdkNAtBkJD59nrmm1efs9T5pmvUNUbIME4lHJ7lmMVlIqQazaROGiw9tyCndlwMyb9T9mNmrU6rDBf3rg6Q", + "statusListJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.c9Nl7zzk5iGSPH15mq2ADe_VH9qi61n_ZBc4H70VmqPFw02xXvhB8iUU9FhvBBbkiQB9LBIQHtgc2uQeWNuZZw", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": true, + "payload": { + "vct": "urn:eudi:pid:1", + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "nbf": 1792281600, + "exp": 1823817600, + "status": { + "status_list": { + "idx": 5, + "uri": "https://issuer.example/status/pid/1" + } + }, + "nationalities": [ + "RO" + ], + "issuing_authority": "Example Authority", + "issuing_country": "RO", + "cnf": { + "jwk": { + "kty": "EC", + "x": "ZW0gDm3Lq4q_5jAn-0kmCW5mx5fDb5erTOKmQ5C2scM", + "y": "lhrLZV62FCKMJanV6VvDf_gwDmplTxXXr6svq3zXATw", + "crv": "P-256" + } + }, + "birthdate": "1990-01-01", + "age_over_18": true + }, + "disclosed": [ + "[]", + "age_over_18", + "birthdate" + ], + "status": { + "present": true, + "judged": true, + "mechanism": "status_list", + "uri": "https://issuer.example/status/pid/1", + "idx": 5, + "value": 0, + "name": "VALID" + } + } + }, + { + "nume": "ML-DSA-65: SD-JWT VC @sd-jwt/sd-jwt-vc cu lista de stare @owf/token-status-list (toate 0)", + "alg": "ML-DSA-65", + "issuerJwk": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "UC0YJ9MxdXaIoAkDQUJ0ucvwKKfAC0i0Q9TscQk8mSMo7Tr6jUF2S1CB5n8mRmvQ5smsukEpYMAx_XNkdaVhezG1CTooq-b6mXq2NRIsUjKwbQzbI1YeATnNFrIe5bFNOdVSgiulzKilwdd7H6SFbiDO_i1qO53xlA61hJZGQcbCjI9d_ohvoqSpOZqeRh9cdCb3ufvv3jGwoGquL4SfLRoLfTYzAYBKF6KI5nGdKSbYDl2n9ob5V1PO7Ip6odOben1sWHQtZScuf77cSR87x8nrPHCeMH7pvwqbaqi9XP5eBnYw_aGgAptiQSlF3r9acHCimTBkarwUh6dWwuF9A_KnDDPPuyyRUNicmKUFyU61bSH_5fZ4B9x1EdGfRyCacBFvrHSem35EzFHRP6M-pooi4YDqcsoWN_hKiaJGttfRSmrqebo1RflHECa6pPY0I8yTn46eAbL5C0txgQsNQeqYfxX4mxTUSTUM2pERbMAjIZxQRTsdo0QKl_3oF-PcFSzpE28cZnBNtCToJhbJ9Vt77Pd_EVLCUEVvCFFdztWFOwH21kpPJAEDuH_OuRZegP9Ukl60ZGx_dZvEQCdWW3FALK_0Knz4QdYrjTXfzCuo1bS4fDBB8mEbuMefSHUxKjoNDVZCVPFfhpbNsTMTkDW79_GWmzinGFnJvpbn1rRlZ2xZl3F8ne29grB9m1A8YhZCezOlkjKjJ8uvTfyKknaznhxXQFlI1iY_frE6mqCyGraWpWuJkV1OW8igdThBHfipDGbbIkRUaWajylZcQq5cID3pDMHAPyEpCgQXZF5aQ-muTOGTIq1RNwMt-E-laRCk6lm6O2v1cR-6k59StR9pXqyFEYzEMTR4maWwUH6hywRKNpCq2PEwXyy21rxrmmvGlVEnVQbVZcJooT2a5eAoynST95IJCOkA91TpcbaLR40-qdNNj08JdOB_BBW2d5ms6S1zos0aYaFVHPAkL41EzrWuWGGRPaESVVD1knz8cRVUvzNT7SB_S7-ovKI2Bc6AnbMnGVkm4V8Z9wbLDAE5RY7Myo9jlt0oqvuQJE3ev0HePvSARsssHvPaaqYlWrpxvtzZwabjbq7KGLBja_fy50zkFmv7Nr0XA4pf4mumTYuFd5m9lnFvO8q1T3KLePI0c6XLCb8maG4p1lh3Ndy0P8_aQaoRZ439gS-1D6w6i_yDdiZyRQZvUc4bSWapT9saxtJ5shwvzsLW7XXU2Ml-gUFhzxPvEgZoSmK3rG82BdvJ-CpqhmW2y_WwsjVJlvmbmjyQvZ-wk80UDWd5UlfwGL7tcYxb3X2LHcrlHelxWCub1ZuYwe2sQ87zmzEHUtHTxi_CV0O_Y7Bb6UiZ0hPbuQXT-y8Y4KbAFwlXtCKacZafLFPJlE5Lamze7SvCNvFDjF0WDJP2cHVROmfWzXtPJukrrIuemTxlz1UwwpYvosZo4GjMNXvUKNun7txfipVpd_DZL2_qYX3UAZPpCwjA-M6_qDjdKucESEtao9I-p7tJFOnvXkTvBfDbOpDXy0viDqvOc_ee6JAr8U0gUVgBMX_ivUeRI3XvtCozHBdnDri1oaezd1SEm9s46aXafXxloVxgPYnjdT2-b1Y7F12hT7WHnhWYYSlsfM04T0bHb5yPy0Vm-ztj47Qf403IRPNeinprubemhsa5ukcyefx4iDwzbVGHjHnbqg6u5N5V3RcioRay1pXKYuXHEHgFVlnzaYWUOCQ031BlHYKISFXG2z7FAp-wYH9wn5s3pgjxStmeepd5hk2Dnl_HfyTm4SxDk2bdaQfBqYeZUlOV7E53FKjkK4mPW3-b9xz7Kc2CpkQ5vFe9-KXNicCsfYzOyQv5o2QriwtFsteKBVCC91fAauccCZXH3tyyRNEAyqGYQQ_wSn-lSFOAPb85UygCfZjCglAK-ooRE5Fl7b5BhZDNRmFPAbpyFOdyX4LswNBZkiubSPmA04fySsaDETZ0Sx2VBakPQe1QW6Rf0xvsWo8dK1l6U3Az1vtg_tSoQbSetg8XhzqML_VqGKFKI_-GaCUO8p0cI4FBnUmhSx92phcsrVjUDNsfcSy8RtUdD7hMiFqxvfDLc6New6tG67ns1QydIhLwY9mRYm6mJdeOfuIh12iA-s6aYv2ePqAaMiZoSYOL87ct0Nl9U32mEjEJ0U5ypgX2JhDxoVPia_lf6ys3Mgte_wbumEyjJmV0nwQceficRgSu0tb_jeh_u0-ggqQMLHqo7ZLGh1cFK8rf9lvRKHsQZb5GzZf7ifQvXWGf0U_dSU0MHtDQV8B14LBvrM5vaNbqSn8Mi4YF6uJIDdGVW7trA8gOszY2M-cXAHLLgk0w0MzchdRTI_5Afru9e8UafNqG4a5gLaMsx_g1EhfELBMZ7dP3zYeONymG_Ds9SBVoQdp4LY_gHPSxt0ZEv_VODdP6xfvxEQvbitrRqLKE4s2PgsTReA5RfE94q590gVn2cv1LDzA_UT6kHCdDFBW6nTUipseT3O0eL4H_y6Yix02xf2XOxMCP3MWRXi5WnX0BD5N4Dmmx_v_Cd5WI8n0IG-381BwklAWhVGPbhxzn9emL1Y2QxYRyMIZFz0k" + }, + "sdJwt": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6ImZiQWl0c0p0aHltZzZQLXB4WTRZc0xiYlIyQno1VXM3TWRZNUtBU3FkcVUifSx7Ii4uLiI6IklxVnZFcTl2QnFYcTNONXF0S052VkxHbjFPOTVGeTZvUVhVWVU4dkpyYVkifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsia3R5IjoiQUtQIiwiYWxnIjoiTUwtRFNBLTY1IiwicHViIjoibHNValZMbVFaWldoMkMzdEtFTkFBYWtfcVpYU0FvWmxRLTFheFk4RUVEdTVMdmQ2bm5aNmxkWlc0ZTVNUkpxR1F6cXRJV1VMZF9nVGxndzdZYl9wM0htYVBGZ3RPUG9RcXVTMWgzYWluVENsc19LTzVXMVozZFRFNm1qTGR2dXdRWDRTTUl1RE5jUlJ0a21FLUdIeWs0d21uQTNtTk03eVNCazd3d3pHNnNZbUNMeHJMdUVta3FQdk82TVNFcG9Yc3F6WmFCaDdnZU11SGpPSk5DTjQ4TmRQWnZzQU1ZTF9WWW9ER0JWaUtuU3hxVUoyZkljN0R3Mmwtbk9JNENleDlkV2hpSEI5RlBqOGQ2cU9xVGpIYzFITC1kclJqQnI2Qy1rOTVvOXBKcm5mNEhma05LNnhoYzdKWFlMMTVaTkdWaE5IQm9rVjhCb2twY3RKR0RGZ1VuRUhCQnRoMXdJb2NWWWFiZmNrRzlQS2J2SW5sY1N6ZlYtR1g5WkFIc01sRV9zMl81WDc2WWprUWJNYVlUYi1ON212ZTFQdThiSE01RVpsSUJPNDR1S2dGRG5LTWhVMUFpUmpKSTJQMXhudGFVWnpMZHJYNFNxcjNjd3QzU3BUbnhkZDFmcEd5b25EWUxHeDU0MDhTS01mYW02RzRlRXIwWDMxbFptUHhHUC1PYzIwZjljR1BvQWdaa3NtcHlIV1NGMTY2bFVaTUt3MGFjOHBhUkRIS01WSmRhaWlMQ1BZZHRPa3hwX1hhS0NwZC1xMHZZYlZ2VzZjWEZuQ0dwSmtWMjRjQ3VRbDZWUlNYaElXTmJVNktGZVRWYlJSaVIwWnVMeW5zZmdFRFNoNk1NSi1CMWVHd2IwUmsyXzZQX0hyM3M3MzFEeEVGWTQzU09hX01ncWZBVU1laUZYdUZSaUlXa053aHRuN0tVTmozdS11cGw1dWRqdTFFanh6QU5CSjBLUnlBajVwVGZrYjlCQmxLZDUzWW1CckxHWTE1azgxTV9iOXlNSS1kcU1PRWc5Qm9neXY1a3Fkd1NYYWZ0b1E1Z1FreGw1bEl4bWlaVjV5WWxJdE1KYlA1Zmh5Q1ZxWHNfSW44RHJEN1JBelJDWElCalo2V1FhbjU0cW5uTmVkaU5iZnkwcUFiUTkxV3lEVHJaRXRWWmxvTXp4bnh5NHEwcnFNWDZfVTIzdHQzNEU0MEdZcG5Hd1VuM1E2YUdpcG1aSVlBclp5NVB1YmFNN1dmVVRISk05Q00tbENyVEhKY3RFWkNpa1YwLW4tVURGN2o0MmFKRXVQcXlMcHJsYmZRRDJ1eXRTWWJHbWhTamFEdVVDMWU2QVl1TzdTX0dyUmdTY0p4MmxyM09ZV0FQWHh1QVlBZzdhTFQxaFEtUnBTbVhPdVRZc1dIRlpDRTZuOURDUnJ5aGcwUGtydF9jQ0RJRnJsaHpwWFROX3piTjI5WXhSQ0hZZVFsS2EySDJqdHF6ckJLY0d4SkwwZlhfQlk2WnZDQl9KdEdRTS14U18xWF9Ucm9LSGV1dDVmQ3ZmcXhQLVByWE5QRnFOeXRadzdpQ1JKU01VbXFLWk5obmVTa3pEQ0gzSTc4M3RUajJ3YUhTVll1eUd6R29ZNGIzaTkyT1dJZEJ3WW95UzRNdVp4aFczNUJWUDdiLW9VUTZ6MEhnalc4YVNrblRIVlFtdUJYUno0QU1hOV9iOVJNU3M4ZnZ4OEZaOE9FdTFGeUNLdFdTYlNtd0RMSlN6djI5SmpCYW4tNnpXVURwOFBaanZ1MFd2U0JJeVFadGdZVzRkbFQ4cDNPTnVMOElSMWJ4blBib0tuUkRoYjZLN3dqcW5fMjhiQ0QzRUV0X2ZCUEtuT0pCNERhT0RtSWVyRkpqd21jS0RGMlQ0dzhSazhaTlZUdFczWFZMS1hab1JXNmZ3TFJIZTk0M0Z5VjBick1LYlNjcGZLZWNKYmt2WTViM2ZIeGNTQ2dxdWVyZDZZOFRDb0RoQk1iN1BNb2JiMEFUMDRjblU0X2tUcV9ra3F6ZS0zVGNsOFVXWGttUVl0LTUxRTRpdFdFMGk4NWR6VlJuZzZiWFlULXJlcEhjOW5ZSW5pVDIzaS1ac19nTXN3bi1FSUlqUHZCNWtXMWh2dDNPZUNGRzBESVp6T2VJWkNVQWhxa0syTDM3MkhuaXY5a2JWX3YtSmZ5RTBPNkY4bS1DeDktc2pvLVB2QVN3Qm1Gd01NU09FdUxUQ0JsOWZNX3BVSzhhVWlZOW1mTE9XeXFDV2pha1FYNTNEN1JzYk9xbURSNWluSDhQaWhjbmhWQmVUQlNHUmNnQVZuSl8zcFp6UjRCdjZWZE1Hd1o1TmZURjNZMUx6N21zbnJNSnFsbzgyVmxKR1JHYmlFTWpnUDNKaElWWVBEbTl6Zjd1RkptUldnMzYtekxUcHprbWYxUDEyZ3pscVFwMGdKdmhZenptWDZDZHFxZWoyakFYMzBOeWVNU1BBbkptSWV0QzdXTWNKOFRIOEMtMWdiQ0pVX2MxMi1aaFZLalJOaENZRUxYcmpWVzJXR3FFVm9ka19LLTBua1dKbjZOVGk5cVBpMUE5UllUSjNGNWtBdU10akpaVkFMQzlDcjZwcHpGZUpEZ3pzZXNCS1BwM1V3UlVJbUhLYVdybDNxSUpuRncxSlU4aUJLLWhtcFQyOXQ4c200ZkktM2JQcnlld3RjdnYyRXFTUU1yZW5NWHU0R3IxV084bHdZRVhjWlFFbGp2NzliMl9jYURvRVNwRzIxMjZDRHN6MVV0RGIxcnkzM1R2N3AwM3RNTTVoVGxrNm1SNEE0dzFFQXdJbGhLZzJZT180Mk54RHUzRU9pbnhKclJGWXNOUXNiX191Y01RQm1TSFZ1c0xqYzE0Z0NHYkpPc2JKaG1vOEN1MlgwdEZaWGdOeTBEQmQ0dldlOE5ZaGx5Q2piNndkS2JyMzljbTAtUFJQUm9UcEllcDRYWnZnTGgyaXo3bVNnM2R6czEyZWVTUTBDRm9fVi01N2tGUVZpU1hUN2dOcDFaNGFNMWN4NG93b0Z2ckdSNEZaLXJGa2pJNFkwbV9ZRXNldVdTV0Y2bWZiNEdJX1JaLW9OVzRSQUxVM0loSWw1U3B3M3Bfa01jODEtR3NmWmdDaEtUTWpRV1VvUXY5ajlBZnFwcWc2RWJQQUJIZExCdEFBWkhvVUFVSXhUTktkSmJtWHljT2F2SDZHWUxPMzhXS1VOYkJVWXYxb1ZfYkNHRnc4WWM4UGczcW40WnV4YUxKYktpSllNU3UyY1hwU3JzWDRzT0NFUE15TUpIeXV6cElmSk16c0ZKaTJNT0QxTUtVaUV5VEpOM3VrbG9HQ1RPRFZFNzJDc1d6LThYcV9Eb0I3QXZZaG5LVlhNRVY2OTZLYi00MmMwVlRGNEw2Q3RDY2h2UThjNlZqblMxR0t2RUk2OVF4alpLYjFhcHVkQVYzOFluaWcifX0sIl9zZCI6WyJBdndTV3BwSDdNTkQxUUtSOUx0WktyRnp4cmF2QmVrZlZmUndsOG80ZzFFIiwiRUJMRG9ZSlo5dW1LN3RlVVZfbFBZeElkc2dpbUl0RmRwaWpON283eXdvUSIsIlRFemZ2a3BKMDF4MEFNeXV0OUI3RUtPN1YyTkZvbVpxVU90WUp2MENzR0EiLCJoN3AybGs3SWI0ZlVlSWgzOGtucFNyQnI2Q1Y0U3hqNGxHU09PVEswdzN3IiwibUU4WlZfRjFTRmNHVUt2NnpqVDNISFl2cGpZeVU2SkVpS3NURDhBYTI5QSIsInBPZjJhZXBFZWlXRkhkWVRXRExEbURINEptUDhKNjVZaTBuaC11LWdNcVEiLCJ4QUdxSFNuc2kxbDhfTTZocEh0d0RxT3hjcVZBaVYyZ0J0OXYtMElVTjdvIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.2bXlRPuRrXouZx-Qh-F9zpC4bVQ53KPi8Mkts4yRoZw14adHVhIAUDpliyxSb5EXvDkkD0gukoC0o8oOtQN3nhHAHNFltU14-dfILE0X6tTWwPKwGdqU4XsFSwEmaKB621864PFv9kBwlpy7mQ5nwQOc9CDeBmY0aU-4_hBIhg-zfONN6YcVnvwfc377LGgcjfng0RBUOT1ZJIsJMJ1Oe4DCn-uyP4nDGSfCZ-PmxKmZKG0us3UwD2JUt8VE-4uTiOuACNKVnygeD3umr56lwIdFAQ0J7JOx8GxvhiO4hHA-wP6i6aiIUokoDRpHE9K4LH43M-bWFrpDCoS1JHmG1r6MCzzCLPKjuEWhrbiZfhmxXJZUjUgFwTbsEcM2WAt_l1VPTMvFlnHcTRb9kkDfxe2TEPcZx3C-wFbhUL1XFArkZstDszMaYUvxDl1r2l54MUujibxTNwRDSu_zl5CgGzvmqM__D_g_mDqteOxpdliw8dQ-YBgTjrfHWJfoQeWPnwYLGION6RkxZ9FWjT2Atjru_zubUc7tbxMeOfBh7bpIgRQglb0eKL7ZC17N1dZS5xjchFLOkdCM5q3nLOURkGqqos2uEbL7NzTlb6h71TgQ5b-LJiT8rDB8YeIYNb0_xHluF4bTM1qUM9tbSOdQBAhF1Z18Vv76Si3ybluGPuDibsqJl8tg4IRZ7Uf9jrt0CrGY-wJfn7dpeaXv4FFQ3edkiqxM27nj5eIZFd7k018ft2AVLFvz3lMfLJ2JOA0k2Uz6B5a5e5b4C0Tzr2h92MsGI9GfeidKMhpxsc_tI1fusSnb7h8ViKUsfXm4bDqEzqaaNd9-R_fr8RqKUE8pXB2V1o3MemZg4llKPegNo4uw0a4kYcndr5NjClbrNp6eqIMgPkZivb10NSMqaJLoP8MDqy7V8eiEe98BdoBwlravi8ekaHS13ZfFmWen2sYaBzOKoWLZV8sTS4wUTh7mhoPWiRJnddR8OYC8HsFCyo4jZdm3AOoAp8YzrFhuxiB0F_KL1WOK0qRkgEtMMd8vxP-UnFuPdq7RTSBfvM3YEF9153EyQ0qh-cShIj22UjxPxu3_2sLe1-8YzErTa6kozBC9km9_Pl8Z3EubbLtGjg4xVXrNQoOy8erkDhB21ikpq-Mof4a7KuZgjGVCHz9PbSpLYrMALnpQ-51PTnoOPwh_CmIdfJYI_YIIyox5CFdJ-1W7odWBgrVeh9DKjiqBfN9-VpvGX78U1MyrZVKjfwzhLvyc4XpdhpZRlNvpXmOYGicjdPP4-9iBCwcgFG7wCg8QHCOdQMvw5CKYITG3arJmTy1lVRjcrIW8yX53n00M_5K-Eq0tDNtbBCFBM511JkyPbMmHF4_MTspfK_E_DK5A2EMpkaXX7dTxMXFw5xb45qoB7t-bUC4T-il6FrM5-4LhEdTYRcLM50VBWZ7hPDPHBTai80UrzGOVDIM5sQVXC4H-A1jHOKUWO1VE1jwYurxducec_ZXWny-S4KDEhC9ohg-D31ZSWrjCLoP8E6Jd9sMiDdKFLptiDmWmnZbVK-yTtVOmBu9XyTXX2tniOFH67r9PO3mR5VaW91gFm7067N3SOLCtvDVup24dbbQpJuQwgRlksusy4QxrFxfodLWeWglaAoaSkTe5A-T6mcGx1JWOzm3Rvj3APjaecCHyjONi08i6Hkw35i7wvKFc50_zgj3RUUjN5yaD8ioPfnNBx6hWb7zzjG76_4lPwjSlI-iYXrPKFPHCTWq0PQ2fVTedtxbdri4fGW8CJzeLySBziQirACRAl4yngXNhL4tlGW031Vc9kvVvSRo2czxwHSK2t7xPvyrwBl2PMB21_SEmR4q2p2QR0g9Z63rx8Yo31FWN9kxhKsJtWnyKZGrVGEoYoOC8MIJ2cOlYh7njklXnbjFnzTN2YjrSpN2Op03JuJNR_3Q090KW_WjuAESP2aPQbfSvyAP5JMh0nItu93blEEqqqJwnySGz-8r1y6-LcbjThZfPGoqW0E7HodsDPZ8jIwNlyEb6pY1I5ugNT2qzdciwbOzAS3mOv_dmEM6-0fEtZ8eJWwFQRrcKrCR0JmpjC1yphk-T-3ElyZDn01NP8om0HZ0MbOqpW3iUMsNiHswKpIpUO83vTdKUdnz1L8JjhuPSIVypYWQh5Kb0YC2VhNU1yhcsS1uMm2pE8u7_GUI6C4Z1xjuwocA5JozklA-iM7vr9aAPVPiwhq5HCIiFbbfLjqrfWN-IRXzPkI_fNUE3xu38-dSLpl9Sg9bZbKEE-4xHsYAPaRM7WGLpbyyVsMoBUGir7ZbOZ4FTtJIgiQo2_xG_N5q5vvpNTOOp9AyXrup35ZsY3vXu5UvhjmZFPeTh2Ll9pv3J3wnxL8j8jesp0zsmzoIvz2RXeztMACPOdEBz9R0xgf5LwBM-W_KkHutMBIqimh0hAR6xNtCBcYNYm2Hs2RoBPOmgVwDEhGU74Gcr7H8xjXOXI6_0fLIQWwhYjzmy-tie7f0btQ27RjAQYRLPtOLHaWLIPcTfPDu926kNZUEBYUxsiQ7la3U8EgQxr65LkDhn6ppTIHGUN9_e4GmYNVXIw2sC5JoNNr5FbVdpsfVIP2DDeTCIv9sz2iKrx8tjcmDZl5HcerTE43uF9MnMXE3zzrDw9Tw51-ZFAYcOF46hDpH3mPywGq3MaYUrrsUY36Yw99-72qWC6vVoLN-tWDo97aEeEafd7dzUcOTaJ-8gvpXpc5XFPwvY-x1vP-JmBdT1vkE6UDcgz4UXc0XxFk3NOvgzuXGJwaKmKl2tP5ByxZUiiJVdr7FRwQvfK5OFkM1pgSbeyi6U04CZh1_LCXeUvs3Vmn7RsdO37Xmy8FE1dkq79bmo9rlmq96okdVlskZmaJCkeca8LwK_KrmUX_CWG1bnwSG4-u09f4vLdCQihb1j0dcbKuzeT07ZT_ifsJzBcnOgN7XT6EA8Tz_mn8Znyg05quHwyxxLxsNqDGId_hojoN47zGCZefXToWtMN8caF_mTNQ-tNUBJUx7VNdE4AMxHDy89h8yLCeHwTp5VR5fLUtBB-icc6sJtHiRR6S15T1jVHOzqaZrdXLhpMC-r0NRES8hbTb7mG0-Tm-zynMvgtD6xXmZ6X8ma7PfW4dFqnxK5zdUDFIWa7iVZRpPyccYuPioIyIhIGQ5dAS_xZqpjkELCY4xKEseCTIJ4FP2xlOI8Kfgbntp3T1cmLhGSbi6KfPfnk1rsx6fIjKbp_XWZ9ndKqvbB6769xWmrutUYTAr5fkuuNJ_z4Ybj1ld4zgVmCmFjqQX6z92k6khHdaTNRxSUwyNURHSXRRcYG1yNtWJib7czYOXDshDqo3ZT1HsTKRM1ljaKplG8njXONJKSnYijVZUnEfolf2Z7YwjWnjauJcdUJ2WkjUWrqu11lzs6j2J6czWyIv9IWc8RG_ch90U9bdEfp4MR5r-QmDTd2fZQcllpfSCv3tLQmu9OIZH8xB_YoLKzFHCLK5fRBB0m8QfRL1jl_O9qk6sREqR6XCIoVLY1BKlYVL8SkAfP7wm5Q6X11PngfHu7EfYcBlQSRcP0Q_4vJoY-JW3U-WTZqiDFpPIJ6HlZlxObjcDD1BFiXH18w_aH2wHhGI6kS_gi6-M6Q0_xIXizc37rijYw7u1_zUNw4wfe_pwC1fJyYwa6bAEA7Kom9h3XV0pbS-G05F5ZdMfEOf_tVeAOEaB3q_UpjR41Tw9yhZ02D3bxmE6LmYuWovPVXCp00582UEGczcfHpvKO7PbwSl8AXr6yiKZDMf38kPyA1dFLjfmtPlpx-spoxVIM3t2APbccQ2eWqtSyAPBLpLVJEytxbMCQjoyE3E9gH3R2Xrk3UPV3gBN9Q_4Gx6vrs2bFeL02w7BlrOzfn09dEqUeuMFBZGzPf0hD2EkUiNxSFx8HrwR2uQxumFdeUnDhy8erulXFYtsPEG-Ss9ZvDx8VSzyQLmxJ_awUfrFQYHyb5sPanftWXTwotJmRjMkdATUSFBhFweJi5ZL8JPMk5mPh57-_l0Mf4BNfZESffQQuLYHxco55SYZ6PLckgpxRzVkkeiDrzCwMykITZySrA8hGtDJwO3KlMQ9GT1FVX5jZGQ3eIj5KEE9ibQrxsOxaXjlq11SJqHYPJ9agacKBwhcZRf3QfDjSH2QapArCf1Kj2cK6qJ3UUKwaM1Js2gks4Nia5Jj95-oLjbZSfHm0OhYEsj_fY0u8akQjMTflLETWx7pzORWgZUNBNbFBS8W7ob-1EHe6RNDmKU0lENDm6LSTD_oGFZnGP7OHPhJTve6e8ERy2khhZvKXdwxjkDt1gv0ROELB8hYweozLYGV9j8DT9AkeI2qbs8vQ19oOETFxs8DrAAAAAAAAAAAAAAAAAAAAAAAAAwgNFB4l~WyI1ZWZiYTkxZDlkZDJmYTc5IiwiUk8iXQ~WyIzZDgzNjJlMzkyN2JkZjY5IiwiREUiXQ~WyJjYTJhNDMyZjBjN2QxNDNhIiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyI5ZDZjMTdhMzJiYmNiNGZjIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyJkYTk3MDBjNDliYTM3MDkwIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyI2OTFhNTY3NGUxYWNkMzM4IiwiYWdlX292ZXJfMTgiLHRydWVd~WyIwNTI0MmFlNmFmNDU0NGMyIiwiYWRkcmVzcyIseyJsb2NhbGl0eSI6IkNsdWoiLCJjb3VudHJ5IjoiUk8ifV0~", + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6ImZiQWl0c0p0aHltZzZQLXB4WTRZc0xiYlIyQno1VXM3TWRZNUtBU3FkcVUifSx7Ii4uLiI6IklxVnZFcTl2QnFYcTNONXF0S052VkxHbjFPOTVGeTZvUVhVWVU4dkpyYVkifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsia3R5IjoiQUtQIiwiYWxnIjoiTUwtRFNBLTY1IiwicHViIjoibHNValZMbVFaWldoMkMzdEtFTkFBYWtfcVpYU0FvWmxRLTFheFk4RUVEdTVMdmQ2bm5aNmxkWlc0ZTVNUkpxR1F6cXRJV1VMZF9nVGxndzdZYl9wM0htYVBGZ3RPUG9RcXVTMWgzYWluVENsc19LTzVXMVozZFRFNm1qTGR2dXdRWDRTTUl1RE5jUlJ0a21FLUdIeWs0d21uQTNtTk03eVNCazd3d3pHNnNZbUNMeHJMdUVta3FQdk82TVNFcG9Yc3F6WmFCaDdnZU11SGpPSk5DTjQ4TmRQWnZzQU1ZTF9WWW9ER0JWaUtuU3hxVUoyZkljN0R3Mmwtbk9JNENleDlkV2hpSEI5RlBqOGQ2cU9xVGpIYzFITC1kclJqQnI2Qy1rOTVvOXBKcm5mNEhma05LNnhoYzdKWFlMMTVaTkdWaE5IQm9rVjhCb2twY3RKR0RGZ1VuRUhCQnRoMXdJb2NWWWFiZmNrRzlQS2J2SW5sY1N6ZlYtR1g5WkFIc01sRV9zMl81WDc2WWprUWJNYVlUYi1ON212ZTFQdThiSE01RVpsSUJPNDR1S2dGRG5LTWhVMUFpUmpKSTJQMXhudGFVWnpMZHJYNFNxcjNjd3QzU3BUbnhkZDFmcEd5b25EWUxHeDU0MDhTS01mYW02RzRlRXIwWDMxbFptUHhHUC1PYzIwZjljR1BvQWdaa3NtcHlIV1NGMTY2bFVaTUt3MGFjOHBhUkRIS01WSmRhaWlMQ1BZZHRPa3hwX1hhS0NwZC1xMHZZYlZ2VzZjWEZuQ0dwSmtWMjRjQ3VRbDZWUlNYaElXTmJVNktGZVRWYlJSaVIwWnVMeW5zZmdFRFNoNk1NSi1CMWVHd2IwUmsyXzZQX0hyM3M3MzFEeEVGWTQzU09hX01ncWZBVU1laUZYdUZSaUlXa053aHRuN0tVTmozdS11cGw1dWRqdTFFanh6QU5CSjBLUnlBajVwVGZrYjlCQmxLZDUzWW1CckxHWTE1azgxTV9iOXlNSS1kcU1PRWc5Qm9neXY1a3Fkd1NYYWZ0b1E1Z1FreGw1bEl4bWlaVjV5WWxJdE1KYlA1Zmh5Q1ZxWHNfSW44RHJEN1JBelJDWElCalo2V1FhbjU0cW5uTmVkaU5iZnkwcUFiUTkxV3lEVHJaRXRWWmxvTXp4bnh5NHEwcnFNWDZfVTIzdHQzNEU0MEdZcG5Hd1VuM1E2YUdpcG1aSVlBclp5NVB1YmFNN1dmVVRISk05Q00tbENyVEhKY3RFWkNpa1YwLW4tVURGN2o0MmFKRXVQcXlMcHJsYmZRRDJ1eXRTWWJHbWhTamFEdVVDMWU2QVl1TzdTX0dyUmdTY0p4MmxyM09ZV0FQWHh1QVlBZzdhTFQxaFEtUnBTbVhPdVRZc1dIRlpDRTZuOURDUnJ5aGcwUGtydF9jQ0RJRnJsaHpwWFROX3piTjI5WXhSQ0hZZVFsS2EySDJqdHF6ckJLY0d4SkwwZlhfQlk2WnZDQl9KdEdRTS14U18xWF9Ucm9LSGV1dDVmQ3ZmcXhQLVByWE5QRnFOeXRadzdpQ1JKU01VbXFLWk5obmVTa3pEQ0gzSTc4M3RUajJ3YUhTVll1eUd6R29ZNGIzaTkyT1dJZEJ3WW95UzRNdVp4aFczNUJWUDdiLW9VUTZ6MEhnalc4YVNrblRIVlFtdUJYUno0QU1hOV9iOVJNU3M4ZnZ4OEZaOE9FdTFGeUNLdFdTYlNtd0RMSlN6djI5SmpCYW4tNnpXVURwOFBaanZ1MFd2U0JJeVFadGdZVzRkbFQ4cDNPTnVMOElSMWJ4blBib0tuUkRoYjZLN3dqcW5fMjhiQ0QzRUV0X2ZCUEtuT0pCNERhT0RtSWVyRkpqd21jS0RGMlQ0dzhSazhaTlZUdFczWFZMS1hab1JXNmZ3TFJIZTk0M0Z5VjBick1LYlNjcGZLZWNKYmt2WTViM2ZIeGNTQ2dxdWVyZDZZOFRDb0RoQk1iN1BNb2JiMEFUMDRjblU0X2tUcV9ra3F6ZS0zVGNsOFVXWGttUVl0LTUxRTRpdFdFMGk4NWR6VlJuZzZiWFlULXJlcEhjOW5ZSW5pVDIzaS1ac19nTXN3bi1FSUlqUHZCNWtXMWh2dDNPZUNGRzBESVp6T2VJWkNVQWhxa0syTDM3MkhuaXY5a2JWX3YtSmZ5RTBPNkY4bS1DeDktc2pvLVB2QVN3Qm1Gd01NU09FdUxUQ0JsOWZNX3BVSzhhVWlZOW1mTE9XeXFDV2pha1FYNTNEN1JzYk9xbURSNWluSDhQaWhjbmhWQmVUQlNHUmNnQVZuSl8zcFp6UjRCdjZWZE1Hd1o1TmZURjNZMUx6N21zbnJNSnFsbzgyVmxKR1JHYmlFTWpnUDNKaElWWVBEbTl6Zjd1RkptUldnMzYtekxUcHprbWYxUDEyZ3pscVFwMGdKdmhZenptWDZDZHFxZWoyakFYMzBOeWVNU1BBbkptSWV0QzdXTWNKOFRIOEMtMWdiQ0pVX2MxMi1aaFZLalJOaENZRUxYcmpWVzJXR3FFVm9ka19LLTBua1dKbjZOVGk5cVBpMUE5UllUSjNGNWtBdU10akpaVkFMQzlDcjZwcHpGZUpEZ3pzZXNCS1BwM1V3UlVJbUhLYVdybDNxSUpuRncxSlU4aUJLLWhtcFQyOXQ4c200ZkktM2JQcnlld3RjdnYyRXFTUU1yZW5NWHU0R3IxV084bHdZRVhjWlFFbGp2NzliMl9jYURvRVNwRzIxMjZDRHN6MVV0RGIxcnkzM1R2N3AwM3RNTTVoVGxrNm1SNEE0dzFFQXdJbGhLZzJZT180Mk54RHUzRU9pbnhKclJGWXNOUXNiX191Y01RQm1TSFZ1c0xqYzE0Z0NHYkpPc2JKaG1vOEN1MlgwdEZaWGdOeTBEQmQ0dldlOE5ZaGx5Q2piNndkS2JyMzljbTAtUFJQUm9UcEllcDRYWnZnTGgyaXo3bVNnM2R6czEyZWVTUTBDRm9fVi01N2tGUVZpU1hUN2dOcDFaNGFNMWN4NG93b0Z2ckdSNEZaLXJGa2pJNFkwbV9ZRXNldVdTV0Y2bWZiNEdJX1JaLW9OVzRSQUxVM0loSWw1U3B3M3Bfa01jODEtR3NmWmdDaEtUTWpRV1VvUXY5ajlBZnFwcWc2RWJQQUJIZExCdEFBWkhvVUFVSXhUTktkSmJtWHljT2F2SDZHWUxPMzhXS1VOYkJVWXYxb1ZfYkNHRnc4WWM4UGczcW40WnV4YUxKYktpSllNU3UyY1hwU3JzWDRzT0NFUE15TUpIeXV6cElmSk16c0ZKaTJNT0QxTUtVaUV5VEpOM3VrbG9HQ1RPRFZFNzJDc1d6LThYcV9Eb0I3QXZZaG5LVlhNRVY2OTZLYi00MmMwVlRGNEw2Q3RDY2h2UThjNlZqblMxR0t2RUk2OVF4alpLYjFhcHVkQVYzOFluaWcifX0sIl9zZCI6WyJBdndTV3BwSDdNTkQxUUtSOUx0WktyRnp4cmF2QmVrZlZmUndsOG80ZzFFIiwiRUJMRG9ZSlo5dW1LN3RlVVZfbFBZeElkc2dpbUl0RmRwaWpON283eXdvUSIsIlRFemZ2a3BKMDF4MEFNeXV0OUI3RUtPN1YyTkZvbVpxVU90WUp2MENzR0EiLCJoN3AybGs3SWI0ZlVlSWgzOGtucFNyQnI2Q1Y0U3hqNGxHU09PVEswdzN3IiwibUU4WlZfRjFTRmNHVUt2NnpqVDNISFl2cGpZeVU2SkVpS3NURDhBYTI5QSIsInBPZjJhZXBFZWlXRkhkWVRXRExEbURINEptUDhKNjVZaTBuaC11LWdNcVEiLCJ4QUdxSFNuc2kxbDhfTTZocEh0d0RxT3hjcVZBaVYyZ0J0OXYtMElVTjdvIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.2bXlRPuRrXouZx-Qh-F9zpC4bVQ53KPi8Mkts4yRoZw14adHVhIAUDpliyxSb5EXvDkkD0gukoC0o8oOtQN3nhHAHNFltU14-dfILE0X6tTWwPKwGdqU4XsFSwEmaKB621864PFv9kBwlpy7mQ5nwQOc9CDeBmY0aU-4_hBIhg-zfONN6YcVnvwfc377LGgcjfng0RBUOT1ZJIsJMJ1Oe4DCn-uyP4nDGSfCZ-PmxKmZKG0us3UwD2JUt8VE-4uTiOuACNKVnygeD3umr56lwIdFAQ0J7JOx8GxvhiO4hHA-wP6i6aiIUokoDRpHE9K4LH43M-bWFrpDCoS1JHmG1r6MCzzCLPKjuEWhrbiZfhmxXJZUjUgFwTbsEcM2WAt_l1VPTMvFlnHcTRb9kkDfxe2TEPcZx3C-wFbhUL1XFArkZstDszMaYUvxDl1r2l54MUujibxTNwRDSu_zl5CgGzvmqM__D_g_mDqteOxpdliw8dQ-YBgTjrfHWJfoQeWPnwYLGION6RkxZ9FWjT2Atjru_zubUc7tbxMeOfBh7bpIgRQglb0eKL7ZC17N1dZS5xjchFLOkdCM5q3nLOURkGqqos2uEbL7NzTlb6h71TgQ5b-LJiT8rDB8YeIYNb0_xHluF4bTM1qUM9tbSOdQBAhF1Z18Vv76Si3ybluGPuDibsqJl8tg4IRZ7Uf9jrt0CrGY-wJfn7dpeaXv4FFQ3edkiqxM27nj5eIZFd7k018ft2AVLFvz3lMfLJ2JOA0k2Uz6B5a5e5b4C0Tzr2h92MsGI9GfeidKMhpxsc_tI1fusSnb7h8ViKUsfXm4bDqEzqaaNd9-R_fr8RqKUE8pXB2V1o3MemZg4llKPegNo4uw0a4kYcndr5NjClbrNp6eqIMgPkZivb10NSMqaJLoP8MDqy7V8eiEe98BdoBwlravi8ekaHS13ZfFmWen2sYaBzOKoWLZV8sTS4wUTh7mhoPWiRJnddR8OYC8HsFCyo4jZdm3AOoAp8YzrFhuxiB0F_KL1WOK0qRkgEtMMd8vxP-UnFuPdq7RTSBfvM3YEF9153EyQ0qh-cShIj22UjxPxu3_2sLe1-8YzErTa6kozBC9km9_Pl8Z3EubbLtGjg4xVXrNQoOy8erkDhB21ikpq-Mof4a7KuZgjGVCHz9PbSpLYrMALnpQ-51PTnoOPwh_CmIdfJYI_YIIyox5CFdJ-1W7odWBgrVeh9DKjiqBfN9-VpvGX78U1MyrZVKjfwzhLvyc4XpdhpZRlNvpXmOYGicjdPP4-9iBCwcgFG7wCg8QHCOdQMvw5CKYITG3arJmTy1lVRjcrIW8yX53n00M_5K-Eq0tDNtbBCFBM511JkyPbMmHF4_MTspfK_E_DK5A2EMpkaXX7dTxMXFw5xb45qoB7t-bUC4T-il6FrM5-4LhEdTYRcLM50VBWZ7hPDPHBTai80UrzGOVDIM5sQVXC4H-A1jHOKUWO1VE1jwYurxducec_ZXWny-S4KDEhC9ohg-D31ZSWrjCLoP8E6Jd9sMiDdKFLptiDmWmnZbVK-yTtVOmBu9XyTXX2tniOFH67r9PO3mR5VaW91gFm7067N3SOLCtvDVup24dbbQpJuQwgRlksusy4QxrFxfodLWeWglaAoaSkTe5A-T6mcGx1JWOzm3Rvj3APjaecCHyjONi08i6Hkw35i7wvKFc50_zgj3RUUjN5yaD8ioPfnNBx6hWb7zzjG76_4lPwjSlI-iYXrPKFPHCTWq0PQ2fVTedtxbdri4fGW8CJzeLySBziQirACRAl4yngXNhL4tlGW031Vc9kvVvSRo2czxwHSK2t7xPvyrwBl2PMB21_SEmR4q2p2QR0g9Z63rx8Yo31FWN9kxhKsJtWnyKZGrVGEoYoOC8MIJ2cOlYh7njklXnbjFnzTN2YjrSpN2Op03JuJNR_3Q090KW_WjuAESP2aPQbfSvyAP5JMh0nItu93blEEqqqJwnySGz-8r1y6-LcbjThZfPGoqW0E7HodsDPZ8jIwNlyEb6pY1I5ugNT2qzdciwbOzAS3mOv_dmEM6-0fEtZ8eJWwFQRrcKrCR0JmpjC1yphk-T-3ElyZDn01NP8om0HZ0MbOqpW3iUMsNiHswKpIpUO83vTdKUdnz1L8JjhuPSIVypYWQh5Kb0YC2VhNU1yhcsS1uMm2pE8u7_GUI6C4Z1xjuwocA5JozklA-iM7vr9aAPVPiwhq5HCIiFbbfLjqrfWN-IRXzPkI_fNUE3xu38-dSLpl9Sg9bZbKEE-4xHsYAPaRM7WGLpbyyVsMoBUGir7ZbOZ4FTtJIgiQo2_xG_N5q5vvpNTOOp9AyXrup35ZsY3vXu5UvhjmZFPeTh2Ll9pv3J3wnxL8j8jesp0zsmzoIvz2RXeztMACPOdEBz9R0xgf5LwBM-W_KkHutMBIqimh0hAR6xNtCBcYNYm2Hs2RoBPOmgVwDEhGU74Gcr7H8xjXOXI6_0fLIQWwhYjzmy-tie7f0btQ27RjAQYRLPtOLHaWLIPcTfPDu926kNZUEBYUxsiQ7la3U8EgQxr65LkDhn6ppTIHGUN9_e4GmYNVXIw2sC5JoNNr5FbVdpsfVIP2DDeTCIv9sz2iKrx8tjcmDZl5HcerTE43uF9MnMXE3zzrDw9Tw51-ZFAYcOF46hDpH3mPywGq3MaYUrrsUY36Yw99-72qWC6vVoLN-tWDo97aEeEafd7dzUcOTaJ-8gvpXpc5XFPwvY-x1vP-JmBdT1vkE6UDcgz4UXc0XxFk3NOvgzuXGJwaKmKl2tP5ByxZUiiJVdr7FRwQvfK5OFkM1pgSbeyi6U04CZh1_LCXeUvs3Vmn7RsdO37Xmy8FE1dkq79bmo9rlmq96okdVlskZmaJCkeca8LwK_KrmUX_CWG1bnwSG4-u09f4vLdCQihb1j0dcbKuzeT07ZT_ifsJzBcnOgN7XT6EA8Tz_mn8Znyg05quHwyxxLxsNqDGId_hojoN47zGCZefXToWtMN8caF_mTNQ-tNUBJUx7VNdE4AMxHDy89h8yLCeHwTp5VR5fLUtBB-icc6sJtHiRR6S15T1jVHOzqaZrdXLhpMC-r0NRES8hbTb7mG0-Tm-zynMvgtD6xXmZ6X8ma7PfW4dFqnxK5zdUDFIWa7iVZRpPyccYuPioIyIhIGQ5dAS_xZqpjkELCY4xKEseCTIJ4FP2xlOI8Kfgbntp3T1cmLhGSbi6KfPfnk1rsx6fIjKbp_XWZ9ndKqvbB6769xWmrutUYTAr5fkuuNJ_z4Ybj1ld4zgVmCmFjqQX6z92k6khHdaTNRxSUwyNURHSXRRcYG1yNtWJib7czYOXDshDqo3ZT1HsTKRM1ljaKplG8njXONJKSnYijVZUnEfolf2Z7YwjWnjauJcdUJ2WkjUWrqu11lzs6j2J6czWyIv9IWc8RG_ch90U9bdEfp4MR5r-QmDTd2fZQcllpfSCv3tLQmu9OIZH8xB_YoLKzFHCLK5fRBB0m8QfRL1jl_O9qk6sREqR6XCIoVLY1BKlYVL8SkAfP7wm5Q6X11PngfHu7EfYcBlQSRcP0Q_4vJoY-JW3U-WTZqiDFpPIJ6HlZlxObjcDD1BFiXH18w_aH2wHhGI6kS_gi6-M6Q0_xIXizc37rijYw7u1_zUNw4wfe_pwC1fJyYwa6bAEA7Kom9h3XV0pbS-G05F5ZdMfEOf_tVeAOEaB3q_UpjR41Tw9yhZ02D3bxmE6LmYuWovPVXCp00582UEGczcfHpvKO7PbwSl8AXr6yiKZDMf38kPyA1dFLjfmtPlpx-spoxVIM3t2APbccQ2eWqtSyAPBLpLVJEytxbMCQjoyE3E9gH3R2Xrk3UPV3gBN9Q_4Gx6vrs2bFeL02w7BlrOzfn09dEqUeuMFBZGzPf0hD2EkUiNxSFx8HrwR2uQxumFdeUnDhy8erulXFYtsPEG-Ss9ZvDx8VSzyQLmxJ_awUfrFQYHyb5sPanftWXTwotJmRjMkdATUSFBhFweJi5ZL8JPMk5mPh57-_l0Mf4BNfZESffQQuLYHxco55SYZ6PLckgpxRzVkkeiDrzCwMykITZySrA8hGtDJwO3KlMQ9GT1FVX5jZGQ3eIj5KEE9ibQrxsOxaXjlq11SJqHYPJ9agacKBwhcZRf3QfDjSH2QapArCf1Kj2cK6qJ3UUKwaM1Js2gks4Nia5Jj95-oLjbZSfHm0OhYEsj_fY0u8akQjMTflLETWx7pzORWgZUNBNbFBS8W7ob-1EHe6RNDmKU0lENDm6LSTD_oGFZnGP7OHPhJTve6e8ERy2khhZvKXdwxjkDt1gv0ROELB8hYweozLYGV9j8DT9AkeI2qbs8vQ19oOETFxs8DrAAAAAAAAAAAAAAAAAAAAAAAAAwgNFB4l~WyJkYTk3MDBjNDliYTM3MDkwIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyI2OTFhNTY3NGUxYWNkMzM4IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI1ZWZiYTkxZDlkZDJmYTc5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoidnRBUDZ2SF9uYkdDNW1pZ3J4ZUxTbUczUmo2X3lNc3U4QjR4NG51NnliZyJ9.AJkgVNA0tLEziz9T0V6HglKbQvlSMIT0wAQ9EA3PCJEsrMjGt5A4ME9PFQ-rMch3TZpIsm9qwb50jwVfuDdt1yBXozfuwqTtkt349FNCK42Su2b6yViyeYxvOz6ta-T2WqvLc65dADzk17EeIn7yBOp6f-8TZtnp5aGK8xVoTtZyJ2S4JL3cCNLIJtNkVExikspJf_05tL19Sbftt2XX1qrUSiUQIOb2PYav6Mbr4WdRF3dJ0S3jm1g08p_POPOI4q6ch-LvXNZSpy3DiC-nI0lw2RJv0sHGE1rYW2TeVT7_axbr5yCid9-GcC0s2WKgRuTYQ_L-QQmGWIdSD-dZ0imP8zYd9HJqU0Gzcbnjyph8YXixrtNmA4dgPZhid94YYu3WKbcA-_u96xLJvaX010DJqHE15-lfUxtGMZbfevMXosYbSIBK74LLOXEeQ3KiGhA_mik4aDo85LCRI5HaXNCYmqNWe7olLRLRNP3JRch3WDJHc-eUwC0G4CxH7kjHNfa0RuqthjZeKHIxOS8KSYk1mj3j4WLF5o5y_4Ki-n_79C7np7g_8LV1wdTT0tnAVVMSB3TGbMmsNvCKgxSkjLafEUcZWVDGuRmZq5tlMHokrEC23gXc5lk7lDfRUTZDcZelq19Hj3HwNobHkCvnNcQ0Qj1HCAlIjW2T-Kc8RN5ArJHKXoyRc5ZSD2ymweDN8YQK_UlLfDMAWCnJJtlXrEx0yujZ7r5HrfBAI6fkZLMsnEV2w5lz4b5kIH0omlvMutHN4DWgj7EapUnteB_e_ANpo7_NjqD5oU2UIMV-aOVW9zOtRUjVWZD7P_uXNtO6iTmR-N0mzoi-Duix_fED4bxjCWQ6bFrTZRriWglaXEly44e0tJb9UGHv1330CvVdhjmIIM6rWW-XpipgRs9q-NMvUZ8_Aa1w_Hhyp3QkPPv9hKjLKRUcF3W2FGpbDvpYGWLXWjYxCoALQlQoyHUTzRaIOuC2llAWRJbqTr8kkxZhS7KfspkrDYmKuyQ4kFOQswbp8UScPKy091foYbBiu83rL3EB7JfKpOcrMWZ5kCttRnTQDAIT6o4pDRDSn1rzbTxGsbeEjCKmw2vd3wTqTMkZ7mR2oP2p78WW5mGMG99PcZcCuooDeYDC16q4yA5YqyXg_ZffffYpxOwFXU4b3ClKDIReJOYCvPoESmZVfI0wfxMc0HZykrFTAKo-cJlyx_KJcxQ_KqPlPfy8GhoVrglQIySFg_SOeUCjC2n7lzvnZ1HxsrlgEOqqQpicS_ztj9jzfY9mM7YS9St6nRQ3zrieQckdwgb6eAxDHqe9--8Gg8ZkjttiNVrf7GR6DufaGSg_7L76Y2c21wgWCgaAi_ncxb5ZVYzIfzK7lgoMTs4bFLggRutppbz5_u7DGpHoXH5dUrFTJUdhBdZxZeLwqOCeFcLq3todG4LsS3zRNWy0ds3R_obWzgkcYYX3eMSqbmCYJqk2pTzdGBUPVajk4nmdL5brz4dTVfN-EkqzXbjqZFFPpHomy1kZuCuE4PZjZWOCNB9bcgJWhmOIKH7phn77lbSJMwyLldj3fgKwR1ingiar06LC5WljPhr16zho5SQmW1MFxxbupgHeaN3SQybMMKs92MbfvlhKKaskgl2Ug0EMAkYatsHCZgrn1-lwm_YjRxfKiZD-E8RDFQKTOeQT8EtRbtxeJjsbGnVb9RpvKadT37mSLaejhAFtScY18qiav9mnkoma1aMDcdUugj415gWOXQVF7G4ukjzQxH6d8TurzuAzX6fl6xQR3o6iC967Sd2c4HIRfxUCgB18hpC1JQLA49nhwZP-cPfmLo21vwV3XgwkGMdOB2nZFFaWPJ6iqJaKwv60QCDIfm9nucEqfrIanJF3XNEt0L2PtYciV3ckGpW7FBk3yaCyCeopFyK_LNxiWLZX6ioJXoesQy3dU4yZ_dhkqG3vh1oix-xShhT5FQG64Qjpvp2ogGlb2DrPM7Hb3KbvudWcA7eXgmxC1LNWkdq8_TTtkg84-jvHylz-VbLWMhJPHRWRoGRbg54y47oSUAdkv3c8Xb9QpcnVJ4QgGRixoPJGuMIZLZnOue3v280XKFWZJC-_kE6uCxRd7DdtIwoadPkab-tFGj4ReRANiLQUUUNNHIdQRF3f_ExgsxyyZLlttmn9G6UT6pE2QJxszDPP3HNyHkOj_8hQKgHRCMC4I6js6npeQJdLJ5yGQv7GIhpJgiTOFJzwYF038Bv2K2d-TBKyqnCNrcekqKX7DIXNyi3ulHfxG2RLe8Pqad3awn8Y0JG8xVVsQy0Iq9qWlEB6HHsLTvwy6wlMpT-7dAtD6CnjfxIYf3CUYK9LuhgHa1pwi2JRdb39Gmekf3jqXd6WBqnv8s9SHXHTOGdRUWOVlFjz7Z9hNvYZmuFB6DPiQBUCFETF6KFzqD3pMO5KeU0wsby_grMWd8kko67GfzdKRslZKHKMLdApwqAZF4jRrYVJZ0uerkCx-fr-Do7FJ-wDcxbiPkcft3Jl4p4zBGCJ3VHMhqGChpYGIdXHwCsb1dklaD2zPP5mF_Zc4AXmoR-uR66wf04Q4fhO5w-hEhOSZT-i8lzEPopqbLsQStnMZ1Qvo0TXC0ignzs9izrZSU7SIGYb5wGooWRS7Jmi2WSc8dK3tYug4RzsVqsn8kOT8zGi2H4HdJiDDIgvAs8qzWVopipLyNAsvSdZePIsiy5u3wABB4J1cNZs9ihS1Sv4vqumBvTkVm4N9DKH201gihkcSKTL5lAz1KIyhE9qTyqCdqP-PDSJseS32Ghtv03dQr4eu7Gf7arowv09S2AfnCUn-8eLsL2MtK-pdpWqfWiNoyLuJS2sVGoVvXo_x1oLTCndixmdCy6q_i1po-WhR_JacUcnPVABJ7qOpQLKIpE3BauOB0PB685jIJT7s7ndUnpyix02ErFb19pr1bE-N4j2ehWSZGP6fYW2fQGdGVesEqeNreOCyskrXLfx84fLbrFTBhQE9q5eIgE1G4xtf7OdHtkF_3FKtZWRfHkZ6XtlJAP5Q48AS7OpxGgai9w22Snj_0RuWYlsW93_RQP4TBxb0wUFUpJMFjbBhAkzo_HkgNoSV7hp9lYywMlIRIv7rWvPnWmM8KM4xVUY4-AYCbvqs7l_r_x_3qBWvqGtCMlzk1YO7f2T8o9m848XdlZ-mq71SP5d3XrURscVoKIj710WbBwEOIT3YEqjCPetNY4vSjLNyAf0GGK4fYBl2gxY_6tdgWaqkutsa9CrLLgw8sgt-qOgfsQ4Bmag-SSJt5Fqxe2t-ssGgmRqjpa9DvJenzNSjJBoYqCNku7fRYRm_kXGq2ATWH-w3j7dT0GfOGbwPjuCd8Ud76cpKmeJ_qgoWAcPI_H6D1aLqflj3jHCawimLFjmgd9wRBYoh5RmlFovIPq2rRDc1WmPZqVzsWQuh8MFOaeHJtalzxaJERaKQ1smg8d736IRLVYFIKqqGIBX4C0sBJITF1FREeWMGicc95FwJuDV4318JZHTJzeuWt1hPjHbwjhvBb94RMGG7Z4WYczz7la_Lzre8l-KNJxqeYj0oQiGIktDp0O2etBqEZhFlIuFsT7iOEOE9Hof1uvSURqRY1bbeN-KoVGXcLs3c_jnv4Dgx2kycCzHiCX6xlBM0AOu-Ie8NUHTm1mMNpiWuROj6xqv926o3ankMqImHJQ9xozrutVrUeGE9NOBNGZooAM0sOr2f3t6P7gK6gn3_Z6GC75g2okTLWotPSCPcOO0EH5WSWyFndRpGz7vOth67zBo5mzq_TMrInylImf6YOYZou_BCS9pvJmsyWwjeRFRxnWXpeuTSrq_5S4ncLHsiQ4e1RGkXoy2MEe-88Hk0bJBz02IOV461H2dT90z_-6TbzXQgJijxuuq1qAJWSfKfEYvm5UmJVqDqAxw2LRLKq0JOotPdsBU9RGxjtJ2jhF24dmY_KLDpQaZ-meKb_67ocJzGkh2nZqXm3wGhchtudnW4cB7-KlZmTEYxkwVe30rph7Ca0Y3XJvy1qU8kbs0jFYvvzS0uO2VRqjFJoxig-jDymnn8RH3ZDevyE1fbJh8qYlQ9w6KaLGnP2wpbu8y5yEakL6GKo9-9SMpjK92MPtIyXrN2_dnNFQSSom6KnS1R4Asn5dHcUAfTOyvPEUz3J05UaJbspAag3jHSRNZX-h93e9XaVDmoVFbhAXXCWEqact7BRKayO_9O_lqZpsEkJO4kFzUZRKAcmdLpuSMPV4GMHbMZMbFnjFY808XbeF1bvvx-maQ-ASlrAb6GzxTlfe69qe4M4Kz1ixK7yeyRB-iJoAMeBdXeoTNzto8qeALF4vq-QItg_8gJVin2-sOKsTNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgkOEhgc", + "statusListJwt": "eyJhbGciOiJNTC1EU0EtNjUiLCJ0eXAiOiJzdGF0dXNsaXN0K2p3dCJ9.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.A-ko-CiOMazwQwPS2PVmElwVm5vINDzYeCKrQg_1mfDMbWGQQo_RsLJAd1GaTLro4Ta35NevB2onHgZYQ0KUNOGRPBatLlEJH1ddctqE8JZZFVS4mgy_R8ngymoLVRul4H1wuwcYuHzst2jqW1KoD6bL9o78EUzBOxS8dKnajusyPr8mgTtBTfDpId8-Wu9DPKmDBhnEsHy5Y45Z8i4nCdLiXaxeEC7tG_yrhB8nJ6WRtWlEMHj5yreHrqomWRkJ48lN_gJHiJt2UTAJuobgz8MSLqDxVvXF8rIqCL_UEf6cej4H6tF2vxfBcYg1h1XxSxj5dnSU1u7Pt5_hCPci8qZ1ci3uJh-hMQ0dTp944HUlMBisTmxEKiR4eZC-DV5Laf0UL4nIrulDgUW7hJO-muYL-e8InmBCnB6uLRTvMC4Fxy3Vbx1IPx6p3n15dOHIT1OzGWFyHLxaCV9fPaf4fBj9Xutj2ArI_f10h1QmdUDgFPFRYrRucjAKG5wGLBnyV9mldndpEivhC7C3fdiYhyXm1o-6T7dSSDMwVKmFOo0y6fiHIocGBwFdhqWjRjZ8F0djJ_e9uVl_gyZ9yQYYl7c56Y6h1qxR0JtPKfLw4nNv70iKV5q_ueABm0rnC9U1s2GiI_chAcEHO3Y6i2sS9Gk7nGrM4oQ8fSGts7_Zrg1iUM2hTn5GbNKzRHWnY3c3-4KiFkcvMvJ4XpdZiHcvcL2K7jTpFrVeXP1zLbzBqIZq95nHblRAvO7rUTErHY6bszWDfJ2g95pEcwuEZ_030LmG245XdjOAADwRwAVFHPNAFHAhA9izrMZ9M7rFpGQ27iZgF5gegZErpWuUXMmQHicSs9D8x174Kam5IAgjWWDvhpnxKXReNRaZQsOJU_3F1i7hb3s8gU4vG1-0fIPFbNHpljbnc4_Lisk188mDORHXn_rNQIuDj-fjSRf5-p21zUOW2THCCGidg26_S_5c_asyd5pRZiOA98m6BqRZrmtH3Lg5NeeBfEpv3ax3lu9n4POz4zY8NKm6ARE2C0iEM6pqeC6RAgaaOPtm2DqRXJkfop-ANZEzkoCeGvGAuNDedLYjXf04UFyBSVg0e8M43k2q-iXOvc2gHLY43mup2DD6u2SJDiIUHYL8BDPObfSqMLnlWvtJmSCpyDssDrJUYkF2e8Ortpiqa4B74UxpUbCFViwyByJDqRX5A6O246qLedU7y_dEMZ94tJqV1-Us1_x0QjlOr4sCa2iOv7lvsRTaDRawjB5jsfU09imn3FZstL8Jcn5yg0yJ1q4muYC3rsv-XKJ9CojZTPIuIkJy5dumiqBOMOoJYMlE8SYshGK-Ak1_AhBJZs55t5s2RAFrUFxpoBeXsRmz0LTHTi4KaV7BK__9e1BLaAQIVTodVWNHZaLtWKGw_zMl_GehV3dJ_67yxPiBxTvuoLGHgJEscvVWy5CcfvS7dQYQ-39isUdBGT3cm_pPKQCUbLpMq7q-jzAv3v5ZwBJDnmuvle1Vw84mOhBs68op6Y5ZthOuGh-s5jQ_Sjn0Oxj7C4zy2XsTxd3_TAbGhQsBtqV2UxHcIhqsw4Qaa26ZHc-RiU4MmQ6Dvre6_t_GcCKlr4LlEiSWsVDUPy7zch4OiyzMJCBq5f449W2ivWRXcG6Urm3A-Csf9cJSexfpR0p2ewiQsxEv1VFeyNnwcuDXmiWTeyfK1BvwZiV9FzTPgBoMXMawLEMsjCru077r4rbx0LKFzjpDt5pyO0wp3s_0IMB-WHkSGEPjtLoQgyyQraqik_hR0I6GETBdjZdNuQnUHVoR8BAwitb5BkqH_OadEW7g7OsLpTDSIuXY3ksvYDydQZaxUR4E8hqKGJCg38bkC7bMgQnk_zS5mV_vjHe0HBiJViRWpiGveD4D3HkwEFKG1l1fWaR7e6xVLeaasQE5oBlgeXWC7C7K9Xw_POy2GU_Ze-VjaYP7P4yzA911RIVK8Tlwuca-0UopO8BwVjp4IOxEZNZBvhm2VIY_PsiOYNbZjgqXsqTZfkp7QL4hjJjeM2Itxn4tFyTC_QDRwI-ZGN_iDZxQUdCRZA0kXbqmoY6adUkE6fN_eqBShueZsJbhd3uaWd_XBmqEXTSW6ZxISmNlB5NeqBtN_VAxsHsmVMo356Wto7iZ4IkOrQO_hGDrdP4Ns4hlDlt_Uw4Ij1f5QPgZhntUpbU9ACajPSc2c0wUfSfSYQH8_lJVpXG8BU26TAmGfneKZCwO2DSCThltzKfqTEhFiFzkfIjPmb9ok0N63vFNV-ITxqZdODzEO3q9TlGaUKDQyP0-J0nPN0hbByF8RasLavRfaBX54-DNQYviL0ej2NmrVKDjcQZXkWA-sOZwXV-Szbu0DETaplqb_tx7eOTs6vUYqV-s3ZR3ZXasm-KWAfLpvahOGVX1Lp2iK-dR4rAtmBKWKleE_ulciXMkmcmE7um8pVhXGOeQB9jXPsE9msKEer_WSaq562Tqtyr1rFKKwke6k05pqP6jzOqMFzgEqzRDnbQ-TXNAXgx5SzP6oHhR6xks2w8vuBARtqhrEMTVZHCRAOIo9ewTKQ_8gvFhU1xdWvU2V6NaonYfy2cJyiAwoLJbyfuTpAYt0ytzY69MV0AtEfMcrwE6kuYq_yRVoQtpUc8jEbG4xX4tQVIpi7oL5klyY8o4R0ZrpOYr_nTjznN-hwSjyLAPjMc7D46TaZyMX7S6YjijEODRQqVxMZ8i0bKtVc1kz4GLSTkNQvsiLqAj2-Tki4845CDi7Q1gYjlZ0-U5oZqweoAjGREfMGX2Hq73HwcE_8UgqxoYzxgDeEqBMVeDVmB33pDHnB_6ewsDz0ZfeQEibnPlP3ptCkdUbp_IUdrvEBq3sgQcenPJ-CyC3mK3_NzAWOnUL0IrB8njw-RvUGRkk_fq-3X_xaf4hG3bGxdnXVUjN19PXt6hPXI8EFvucyAYQG7eAnK8VLyGldW4JZKdewCPkrPXWLGjg9EpvLpX9MDujhyKHJWJCquUQBzt0neqmDB-i4KKY6Rqw_X0JLTPRul6ona-gAUltdMN_RHjzEZbQpZVuuaT3VVcRVeIR4luOTFrHTl0MPcKbojUrr49shemci4cpkjgjKlTzrfcwbOvSvcol4MRkCjbILYL-A0737WRho0eoOOBqFsB7A4r6jvX4ZyI-5KMu0_UUg-64T18hx7n6Tkvcg6df3gdcROes3gndcnmZwhTyC9cDfwSq2m32t0WJXnwP7U3FKqBKlhkVc-hxZ77bezt5oPPYCjkm9gK49jzltKWMmu3AvJ_76bVqpBd9sJAXhwe1CjD3asC9IFimQDO8h6p6vUQmo3JkpbIBYBvMPcv1IOZ517ICwCExztG6_6KzADPzaeGn0A1RJQQ9vY6cGtGUgKX0CeDutZyKWXrKrM6uEAhmKdHgKoEJ6tqIBg9R6B0y6D-NRYNRqS0yRXd_DmvDW5_90q0WbtqTAEHXgu3BEMsjQjxxKvWdhygBzRJMw2L5CRG88kT78mEM6Ix1dmngPyyygHXr-Hp3NP4X2192FQ2srpCHYfvx1QGOX5zmOou0OrCYlpZMyOEXywu-fJYK9gZAkjf1TZsSks2F5USde8fEuuFcXObaxZP2nkdcSbrqH3USezSNQuO5koweIGjG25RgzMvDi9nkamH874c51tjusIfZm2LuxNk6GkBUU9RciiZG-Wxze_S5H9xWqLKW1sMTe2tZG4H7D_iuQWIX9i-f3sfwiO3ARpAGnjW9Vpxm623h6LODxakpz-a7tmshG5SeaaYHoNiBtonAaC_d0opAvdQ7AlfW4zir-VKjYzRsMi2AUn9g7cwtpropZ1EhnyzoTJdySBXAhfuRB-oXbGOp4BVBxJrEH2JSoJeucB2_Fe4JrgLRCqFFwJWAf1oET4z5i99k9nIftQylH_F91T5OpK8cCiqzXpFaGikEXhe2WYvXMMTP7GiEhyNnM1deeXVX6xC95ZMqaNQ3l9WXvfJBLaZNZHPFI5Ix4vQnTKQ4NblIJC8Wymk5N_e4BblEwg33Pz9gXIyb_1CRnqVSPRdHWtncDyKwH2B4KcYPQDZ7ovgtL7bzK7TBPNdM-bsFiDUaEufKdHeopEvxmLayQeJXaVLAQSrvJja9x_vy1hLI3runG1r3sGe5Ua7LlsRrHVaz3M3T7bVct4HF7Ki1B4s5e6IVWNhCpOp0p8kdJtK-soamT2y6p-JYynxy_mYXck84CIGe8EooLvcU42fW9OdsN6FBBN_PmG1ZV4yZpmirzleIqay7aUFv0664jCZ_Lz44_rMrV2mNrSBblo9azgvX6zRM_ImlywQcFwfICIrNm-MKCtWcJe5-B29wdPU6yssLkBZZHpBcIihpqjN_hMxirvS3wAAAAAAAAAAAAAAAAAABw4UGyMp", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": true, + "payload": { + "vct": "urn:eudi:pid:1", + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "nbf": 1792281600, + "exp": 1823817600, + "status": { + "status_list": { + "idx": 5, + "uri": "https://issuer.example/status/pid/1" + } + }, + "nationalities": [ + "RO" + ], + "issuing_authority": "Example Authority", + "issuing_country": "RO", + "cnf": { + "jwk": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "lsUjVLmQZZWh2C3tKENAAak_qZXSAoZlQ-1axY8EEDu5Lvd6nnZ6ldZW4e5MRJqGQzqtIWULd_gTlgw7Yb_p3HmaPFgtOPoQquS1h3ainTCls_KO5W1Z3dTE6mjLdvuwQX4SMIuDNcRRtkmE-GHyk4wmnA3mNM7ySBk7wwzG6sYmCLxrLuEmkqPvO6MSEpoXsqzZaBh7geMuHjOJNCN48NdPZvsAMYL_VYoDGBViKnSxqUJ2fIc7Dw2l-nOI4Cex9dWhiHB9FPj8d6qOqTjHc1HL-drRjBr6C-k95o9pJrnf4HfkNK6xhc7JXYL15ZNGVhNHBokV8BokpctJGDFgUnEHBBth1wIocVYabfckG9PKbvInlcSzfV-GX9ZAHsMlE_s2_5X76YjkQbMaYTb-N7mve1Pu8bHM5EZlIBO44uKgFDnKMhU1AiRjJI2P1xntaUZzLdrX4Sqr3cwt3SpTnxdd1fpGyonDYLGx5408SKMfam6G4eEr0X31lZmPxGP-Oc20f9cGPoAgZksmpyHWSF166lUZMKw0ac8paRDHKMVJdaiiLCPYdtOkxp_XaKCpd-q0vYbVvW6cXFnCGpJkV24cCuQl6VRSXhIWNbU6KFeTVbRRiR0ZuLynsfgEDSh6MMJ-B1eGwb0Rk2_6P_Hr3s731DxEFY43SOa_MgqfAUMeiFXuFRiIWkNwhtn7KUNj3u-upl5udju1EjxzANBJ0KRyAj5pTfkb9BBlKd53YmBrLGY15k81M_b9yMI-dqMOEg9Bogyv5kqdwSXaftoQ5gQkxl5lIxmiZV5yYlItMJbP5fhyCVqXs_In8DrD7RAzRCXIBjZ6WQan54qnnNediNbfy0qAbQ91WyDTrZEtVZloMzxnxy4q0rqMX6_U23tt34E40GYpnGwUn3Q6aGipmZIYArZy5PubaM7WfUTHJM9CM-lCrTHJctEZCikV0-n-UDF7j42aJEuPqyLprlbfQD2uytSYbGmhSjaDuUC1e6AYuO7S_GrRgScJx2lr3OYWAPXxuAYAg7aLT1hQ-RpSmXOuTYsWHFZCE6n9DCRryhg0Pkrt_cCDIFrlhzpXTN_zbN29YxRCHYeQlKa2H2jtqzrBKcGxJL0fX_BY6ZvCB_JtGQM-xS_1X_TroKHeut5fCvfqxP-PrXNPFqNytZw7iCRJSMUmqKZNhneSkzDCH3I783tTj2waHSVYuyGzGoY4b3i92OWIdBwYoyS4MuZxhW35BVP7b-oUQ6z0HgjW8aSknTHVQmuBXRz4AMa9_b9RMSs8fvx8FZ8OEu1FyCKtWSbSmwDLJSzv29JjBan-6zWUDp8PZjvu0WvSBIyQZtgYW4dlT8p3ONuL8IR1bxnPboKnRDhb6K7wjqn_28bCD3EEt_fBPKnOJB4DaODmIerFJjwmcKDF2T4w8Rk8ZNVTtW3XVLKXZoRW6fwLRHe943FyV0brMKbScpfKecJbkvY5b3fHxcSCgquerd6Y8TCoDhBMb7PMobb0AT04cnU4_kTq_kkqze-3Tcl8UWXkmQYt-51E4itWE0i85dzVRng6bXYT-repHc9nYIniT23i-Zs_gMswn-EIIjPvB5kW1hvt3OeCFG0DIZzOeIZCUAhqkK2L372Hniv9kbV_v-JfyE0O6F8m-Cx9-sjo-PvASwBmFwMMSOEuLTCBl9fM_pUK8aUiY9mfLOWyqCWjakQX53D7RsbOqmDR5inH8PihcnhVBeTBSGRcgAVnJ_3pZzR4Bv6VdMGwZ5NfTF3Y1Lz7msnrMJqlo82VlJGRGbiEMjgP3JhIVYPDm9zf7uFJmRWg36-zLTpzkmf1P12gzlqQp0gJvhYzzmX6Cdqqej2jAX30NyeMSPAnJmIetC7WMcJ8TH8C-1gbCJU_c12-ZhVKjRNhCYELXrjVW2WGqEVodk_K-0nkWJn6NTi9qPi1A9RYTJ3F5kAuMtjJZVALC9Cr6ppzFeJDgzsesBKPp3UwRUImHKaWrl3qIJnFw1JU8iBK-hmpT29t8sm4fI-3bPryewtcvv2EqSQMrenMXu4Gr1WO8lwYEXcZQEljv79b2_caDoESpG2126CDsz1UtDb1ry33Tv7p03tMM5hTlk6mR4A4w1EAwIlhKg2YO_42NxDu3EOinxJrRFYsNQsb__ucMQBmSHVusLjc14gCGbJOsbJhmo8Cu2X0tFZXgNy0DBd4vWe8NYhlyCjb6wdKbr39cm0-PRPRoTpIep4XZvgLh2iz7mSg3dzs12eeSQ0CFo_V-57kFQViSXT7gNp1Z4aM1cx4owoFvrGR4FZ-rFkjI4Y0m_YEseuWSWF6mfb4GI_RZ-oNW4RALU3IhIl5Spw3p_kMc81-GsfZgChKTMjQWUoQv9j9Afqpqg6EbPABHdLBtAAZHoUAUIxTNKdJbmXycOavH6GYLO38WKUNbBUYv1oV_bCGFw8Yc8Pg3qn4ZuxaLJbKiJYMSu2cXpSrsX4sOCEPMyMJHyuzpIfJMzsFJi2MOD1MKUiEyTJN3ukloGCTODVE72CsWz-8Xq_DoB7AvYhnKVXMEV696Kb-42c0VTF4L6CtCchvQ8c6VjnS1GKvEI69QxjZKb1apudAV38Ynig" + } + }, + "birthdate": "1990-01-01", + "age_over_18": true + }, + "disclosed": [ + "[]", + "age_over_18", + "birthdate" + ], + "status": { + "present": true, + "judged": true, + "mechanism": "status_list", + "uri": "https://issuer.example/status/pid/1", + "idx": 5, + "value": 0, + "name": "VALID" + } + } + }, + { + "nume": "NEGATIV: lista LOR cu indexul 5 = 1 (INVALID)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBUWUFBQUFFSUFJUSJ9fQ.E3ryJi_TXj8M0rBCbt0WNKkBeIiwTywQZvDeQVkq_Jl6QO3fVMX3pUa3u98MHOx7gnk36AWzs8Kkm7ix6qirDQ", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "status 1 \\(INVALID\\)" + } + }, + { + "nume": "NEGATIV: lista LOR pe 2 biti cu indexul 5 = 2 (SUSPENDED)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoyLCJsc3QiOiJlTnBqNEdCZ0FBQUFIQUFKIn19.YE9Lr-dw70H4bLl-RslRGHS2E59RQYCRfuhalVQteNzqeDiMyYx1rtvOx0ynhmreetKebIoKQRfzREnHF7ImDA", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "status 2 \\(SUSPENDED\\)" + } + }, + { + "nume": "lista LOR pe 8 biti, toate 0 (impachetarea lor pe mai multi biti citita de noi)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjo4LCJsc3QiOiJlTnBqWUVBRkFBQVFBQUUifX0.4lWY5Vh_PBhMKFkjLu83rSvZNq4dYowJpUEOyvClhauQqgbBY1lDO0YRA7kQU0MRQFhIvWnQWcDFpeSlMQ0VCg", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": true, + "payload": { + "vct": "urn:eudi:pid:1", + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "nbf": 1792281600, + "exp": 1823817600, + "status": { + "status_list": { + "idx": 5, + "uri": "https://issuer.example/status/pid/1" + } + }, + "nationalities": [ + "RO" + ], + "issuing_authority": "Example Authority", + "issuing_country": "RO", + "cnf": { + "jwk": { + "crv": "Ed25519", + "x": "3IXTA1dXnHQJruWipvQEERs3ZM0a_thCsS3ZopDvamU", + "kty": "OKP" + } + }, + "age_over_18": true, + "birthdate": "1990-01-01" + }, + "disclosed": [ + "[]", + "age_over_18", + "birthdate" + ], + "status": { + "present": true, + "judged": true, + "mechanism": "status_list", + "uri": "https://issuer.example/status/pid/1", + "idx": 5, + "value": 0, + "name": "VALID" + } + } + }, + { + "nume": "NEGATIV: lista LOR pentru ALT uri (sub != uri-ul din jeton)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMS1hbHRhIiwiaWF0IjoxNzkyMjgxNjAwLCJleHAiOjE3OTIyODUyMDAsInN0YXR1c19saXN0Ijp7ImJpdHMiOjEsImxzdCI6ImVOcGpZQUFBQUFJQUFRIn19.SVVx1R0qyArp0nWD0PfwLBg63oZeoaRIZGNhPYdU4QG0yh3YasSZ_kIimjEW2hEz6NzH_HEW3Ci61a5Dze3nCA", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "sub .* is not the uri" + } + }, + { + "nume": "NEGATIV: lista LOR expirata", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjgxNjMwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.Kxsth2IkgDtbkwdxbG1tSGSNx_g0_sQNvwaZWjpggXwuv_TQdpqdAWQL9Io8zsOSwi4bSF569tZ35TvVfFNWBQ", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "status list: expired" + } + }, + { + "nume": "NEGATIV: verificatorul asteapta alt vct (urn:eudi:pid:2)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.mqBQYXpgRWu78YISD865GiYpBZcni3Ejpt440jL-LNV4kVtHcdBXR-_7XA2rhoPqbTC02MzLTf8MsFS4me0kAQ", + "expectedVct": "urn:eudi:pid:2", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "not the type expected" + } + }, + { + "nume": "NEGATIV: fara lista, la noi implicit (requireStatus:true): refuz numit; la ei disableStatusVerification: valid", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "was not judged" + } + }, + { + "nume": "fara lista, la noi cu requireStatus:false: valid, cu starea raportata nejudecata", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.fx0jsSAGfSyFzKcjxDT-r_vXqP2FxbuGaC-2RS7_oCtjej8hHDUi-V7rHKlWMkS56yvCcVnYJFWdcz8vr7FxAw", + "expectedVct": "urn:eudi:pid:1", + "optiuni": { + "requireStatus": false + }, + "asteptat": { + "valid": true, + "payload": { + "vct": "urn:eudi:pid:1", + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "nbf": 1792281600, + "exp": 1823817600, + "status": { + "status_list": { + "idx": 5, + "uri": "https://issuer.example/status/pid/1" + } + }, + "nationalities": [ + "RO" + ], + "issuing_authority": "Example Authority", + "issuing_country": "RO", + "cnf": { + "jwk": { + "crv": "Ed25519", + "x": "3IXTA1dXnHQJruWipvQEERs3ZM0a_thCsS3ZopDvamU", + "kty": "OKP" + } + }, + "age_over_18": true, + "birthdate": "1990-01-01" + }, + "disclosed": [ + "[]", + "age_over_18", + "birthdate" + ], + "status": { + "present": true, + "judged": false, + "mechanism": "status_list", + "uri": "https://issuer.example/status/pid/1", + "idx": 5 + } + } + }, + { + "nume": "NEGATIV: KB pentru alt aud", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "qwjKP3mAWl0rQJi-UunAZ_nAEJbLgc56-bc9IuVmV9s", + "kty": "OKP" + }, + "prezentare": "eyJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ2Y3QiOiJ1cm46ZXVkaTpwaWQ6MSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmxvci5leGFtcGxlIiwiaWF0IjoxNzkyMjgxNjAwLCJuYmYiOjE3OTIyODE2MDAsImV4cCI6MTgyMzgxNzYwMCwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6NSwidXJpIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS9zdGF0dXMvcGlkLzEifX0sIm5hdGlvbmFsaXRpZXMiOlt7Ii4uLiI6InlmQ0kwTmlLd21zMEVnVldvREU2d3l1VVIyN21RMXVHY1dSV2hzUVlsOWcifSx7Ii4uLiI6Inc1YnJ2M0NJLW1XT1V1SHAxMjEyR1R4OHlkSUNUUkpYS0JKdm5IMWhBNlEifV0sImlzc3VpbmdfYXV0aG9yaXR5IjoiRXhhbXBsZSBBdXRob3JpdHkiLCJpc3N1aW5nX2NvdW50cnkiOiJSTyIsImNuZiI6eyJqd2siOnsiY3J2IjoiRWQyNTUxOSIsIngiOiIzSVhUQTFkWG5IUUpydVdpcHZRRUVSczNaTTBhX3RoQ3NTM1pvcER2YW1VIiwia3R5IjoiT0tQIn19LCJfc2QiOlsiUE1WRGFGZ2FtYkpWX3BvTkJWR1hfbTNzWjFIRFpTT0FWbFJCbmUyZ0d6dyIsIlNhVTlYaXhrU21ENVZiU3RvZ042Ymh4ckVkR21KQWhfb0JFM3V5RFhULXMiLCJVLWFoTFlqdVl1ZnVzMXNDWVBITDBkNUhkYjlVNUpxUDJ4X0dMVklVaW93IiwiZVBCOFZNQ1ZPTGY4OVlTU1o0NGs2Q3lVLUdhRzRwM055cHVDU3h3cUJjOCIsImVnWVhkVGxzNXVTZmpFYVJSUWo1LUpCeHJKOXF2TjZPYTJNdDlHR3VmUzAiLCJndUpYclNEaktYaWg4NWlwaVBzeXdnUzQzZHB6NElHR1RfU292d0ZFdlpRIiwibFVxaFJtb29fVWdrcm1iTTVhSlU5NFNfVkt0VTJoNkRvNlRtcG9TX0xkdyJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.xE1r3QgOhiLHKuDuWAK51bmR9HicD9PYTMwHhRmfTDCwPdAjxUJZ6CzH_aYjvJ69mDnuYW2vrtTkGZl9DfwGCg~WyJjMTI0ZGMzYWVhYTNkNjEyIiwiYmlydGhkYXRlIiwiMTk5MC0wMS0wMSJd~WyIzZTkwZWUzMWE2YmZhODE1IiwiYWdlX292ZXJfMTgiLHRydWVd~WyI2MTQ5NGMyZmFhZjRhMGE5IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL290aGVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtdmMtZDc2ZDU5NmExYjdkIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRE1jbEh4QVZ0SkE2QXpZVGZDX0l1SnhQX28zMDVnUkx5ckxUS1owUWhkZyJ9.JKIQfTWlEvbo2fy-Hl93lPCBgbToTPQOYnI_ySU8MCX8zHiLlfheipxhQ8bN7ntWx-g_lCMTl-XgxlIdarGvAw", + "statusListJwt": "eyJhbGciOiJFZERTQSIsInR5cCI6InN0YXR1c2xpc3Qrand0In0.eyJzdWIiOiJodHRwczovL2lzc3Vlci5leGFtcGxlL3N0YXR1cy9waWQvMSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxNzkyMjg1MjAwLCJzdGF0dXNfbGlzdCI6eyJiaXRzIjoxLCJsc3QiOiJlTnBqWUFBQUFBSUFBUSJ9fQ.mqBQYXpgRWu78YISD865GiYpBZcni3Ejpt440jL-LNV4kVtHcdBXR-_7XA2rhoPqbTC02MzLTf8MsFS4me0kAQ", + "expectedVct": "urn:eudi:pid:1", + "optiuni": {}, + "asteptat": { + "valid": false, + "motiv": "made for" + } + } + ] +} diff --git a/identity/interop/fixturi-interop-sdjwt.json b/identity/interop/fixturi-interop-sdjwt.json new file mode 100644 index 0000000..5eee43b --- /dev/null +++ b/identity/interop/fixturi-interop-sdjwt.json @@ -0,0 +1,310 @@ +{ + "generat": "2026-10-18T06:12:16.195Z", + "unealta": "tools/aere-identity/interop/interop-sdjwt.mjs --scrie", + "nota": "AERE-SINTETIC: jetoane emise de @sd-jwt/core (semnate prin WebCrypto, verificate de jose) cu chei de PROBA nascute la generare; numai cheile publice sunt aici. Judecate offline de proba-sdjwt.mjs la ceasVerificare.", + "biblioteci": { + "@sd-jwt/core": "0.23.0", + "@sd-jwt/crypto-nodejs": "0.19.0", + "jose": "6.2.12", + "@owf/identity-common": "0.5.0", + "node": "v24.14.1" + }, + "ceas": 1792281600, + "ceasVerificare": 1792281660, + "audience": "https://verifier.example", + "nonce": "interop-c382c99bc280", + "cazuri": [ + { + "nume": "EdDSA: prezentare @sd-jwt/core cu dezvaluiri imbricate, element de lista, momeli si KB (fara typ)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyI2NjQxOGNlZWY4M2VkODY4Iiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~WyIzMjc5ZTM1NjI4ZDZlYTVjIiwiREUiXQ~WyI3ZTBkNmNkYTliMmFkYzc1IiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyJhYzBlZjNhZWU0N2QwZjlkIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~", + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.Rr9sBYmA9BEp-uSt_d4w854OLSM7S6Sm-L_UHPGTHwVLpY_hVmLilgbZ9KF-X6Mk29KSQEIanQKOW1dzGcQFAg", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": true, + "payload": { + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "exp": 1823817600, + "nationalities": [ + "RO" + ], + "cnf": { + "jwk": { + "crv": "Ed25519", + "x": "HFy0vzt3aXxDeMDn64cbX7z0uuCl8v2VAoEOO3dwndM", + "kty": "OKP" + } + }, + "age_over_18": true, + "address": { + "country": "RO", + "locality": "Cluj" + } + }, + "disclosed": [ + "[]", + "address", + "age_over_18", + "locality" + ] + } + }, + { + "nume": "ES256: prezentare @sd-jwt/core cu dezvaluiri imbricate, element de lista, momeli si KB (fara typ)", + "alg": "ES256", + "issuerJwk": { + "kty": "EC", + "x": "MwvcAG7Qwg-mknZRXu-JS7VHkZzVLlYjvXzYj4TeLPY", + "y": "fLuSX-6-_njH4b6GGbwwmkgPzD7nBZu04TzG0v0A1j8", + "crv": "P-256" + }, + "sdJwt": "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJ5Snp4elppdXBULVlER2szcUM3ejNoVmt1NmZtcUdHQnIxZkEyUHl4b2ZBIn0seyIuLi4iOiJaRXIyakxZdGhoWDhYTHdmTy1ISWtfMnRTNm1mRmwxeW9fRDU5NmFRaWVNIn1dLCJjbmYiOnsiandrIjp7Imt0eSI6IkVDIiwieCI6Ijh3cjJKX1RTdHVLZHo1LUlYQ3dIUGhSaGYwLVU5d3pWLXphd1J4R3FsQVEiLCJ5IjoieVRDeXhlYmtaQUNhM2dLR21MMjVzWjVQWmtuM2g0T0Jkb2FxLWdtc3owcyIsImNydiI6IlAtMjU2In19LCJfc2QiOlsiLW1ORUJ1MkVfUm90aUxEWW9aNWpRN05hUDhUMGZxOUhtOENUUG1GTmRzcyIsIjJqRDRrTWw5cDdwdkdJNW1ONGlnRzZpOGM3RmoxWVNlQ3pWSWpxMEYtY2siLCIzTmE1NUtBNzFPNUlHVW9mRHpSZXozY3B2bUVCUFh1X1pqZm5vdG9xbFd3IiwiRVA4a0p0NEVwUTZNTzhMZ2RJRDhFM0dvS1QzUUQzZ01RVjI3LXF1dEFVUSIsIkhxLTFtdmhJbi1EQjh1aTBaSEpNdlNYOTVpMjRCbDlZRWRjLURuXy00eDgiLCJSQkJMRnUxYVVGck9xMnpoRnJDOW9DNF9oN21BVnBKZ0NmcHZQYUFJV2NvIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.pVRO7rycFsVU67grJdAQy2sGCFG_8TeTDPWCN8BXoQ8S14D3CllLSMbHzzRKtV0ShLS3AIJ1y3H6IQbbKC5rcQ~WyI2N2Q5ZTc2Nzg5M2Y2MTNhIiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyIyZTQwZjQwNGY3MjRiNWFlIiwibG9jYWxpdHkiLCJDbHVqIl0~WyJlN2VjYmU0MjBjMWUyMzkwIiwiUk8iXQ~WyJmODI1MDM5YjBlNjhiMjVjIiwiREUiXQ~WyI3ZGE3MWU3Y2U3ZGZkNDg5IiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyIwMTM4MGYyMzBlZmVkN2I1IiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyI1NmUwZjk3MzlmYjhjN2NhIiwiYWdlX292ZXJfMTgiLHRydWVd~WyI1ZTg5ZGM2YzE4YTRhY2U3IiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiV0JFYmlSUXJmdzd5Z0o3dHMtWi1DOF93LUQ2N1hmTEVob2d6dDJFSDl3YyIsIm83SV9VRWpYaVlwaXhDUVRpaklINldaVldlZ3RzcF9GM3JWQU1CdXVEcFkiXX1d~", + "prezentare": "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJ5Snp4elppdXBULVlER2szcUM3ejNoVmt1NmZtcUdHQnIxZkEyUHl4b2ZBIn0seyIuLi4iOiJaRXIyakxZdGhoWDhYTHdmTy1ISWtfMnRTNm1mRmwxeW9fRDU5NmFRaWVNIn1dLCJjbmYiOnsiandrIjp7Imt0eSI6IkVDIiwieCI6Ijh3cjJKX1RTdHVLZHo1LUlYQ3dIUGhSaGYwLVU5d3pWLXphd1J4R3FsQVEiLCJ5IjoieVRDeXhlYmtaQUNhM2dLR21MMjVzWjVQWmtuM2g0T0Jkb2FxLWdtc3owcyIsImNydiI6IlAtMjU2In19LCJfc2QiOlsiLW1ORUJ1MkVfUm90aUxEWW9aNWpRN05hUDhUMGZxOUhtOENUUG1GTmRzcyIsIjJqRDRrTWw5cDdwdkdJNW1ONGlnRzZpOGM3RmoxWVNlQ3pWSWpxMEYtY2siLCIzTmE1NUtBNzFPNUlHVW9mRHpSZXozY3B2bUVCUFh1X1pqZm5vdG9xbFd3IiwiRVA4a0p0NEVwUTZNTzhMZ2RJRDhFM0dvS1QzUUQzZ01RVjI3LXF1dEFVUSIsIkhxLTFtdmhJbi1EQjh1aTBaSEpNdlNYOTVpMjRCbDlZRWRjLURuXy00eDgiLCJSQkJMRnUxYVVGck9xMnpoRnJDOW9DNF9oN21BVnBKZ0NmcHZQYUFJV2NvIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.pVRO7rycFsVU67grJdAQy2sGCFG_8TeTDPWCN8BXoQ8S14D3CllLSMbHzzRKtV0ShLS3AIJ1y3H6IQbbKC5rcQ~WyI1NmUwZjk3MzlmYjhjN2NhIiwiYWdlX292ZXJfMTgiLHRydWVd~WyI1ZTg5ZGM2YzE4YTRhY2U3IiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiV0JFYmlSUXJmdzd5Z0o3dHMtWi1DOF93LUQ2N1hmTEVob2d6dDJFSDl3YyIsIm83SV9VRWpYaVlwaXhDUVRpaklINldaVldlZ3RzcF9GM3JWQU1CdXVEcFkiXX1d~WyIyZTQwZjQwNGY3MjRiNWFlIiwibG9jYWxpdHkiLCJDbHVqIl0~WyJlN2VjYmU0MjBjMWUyMzkwIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiRms5NUlyM3d2cUV2ZzF0TnFZUHA5ZGNzOW5XY2tZc3ZkQkRTbnY1UE1EZyJ9.9q3SQVmhEiiaoFq36fHnuH-DBr7myT9ACMu1eY-3754X0KO-kT0E5VxKUUViVji5vVVV5Pb3cjTeUf0Ppu9X7w", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": true, + "payload": { + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "exp": 1823817600, + "nationalities": [ + "RO" + ], + "cnf": { + "jwk": { + "kty": "EC", + "x": "8wr2J_TStuKdz5-IXCwHPhRhf0-U9wzV-zawRxGqlAQ", + "y": "yTCyxebkZACa3gKGmL25sZ5PZkn3h4OBdoaq-gmsz0s", + "crv": "P-256" + } + }, + "address": { + "country": "RO", + "locality": "Cluj" + }, + "age_over_18": true + }, + "disclosed": [ + "[]", + "address", + "age_over_18", + "locality" + ] + } + }, + { + "nume": "ML-DSA-65: prezentare @sd-jwt/core cu dezvaluiri imbricate, element de lista, momeli si KB (fara typ)", + "alg": "ML-DSA-65", + "issuerJwk": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "4EW3YEtcEePmfItOC7r8wNICpSBTdXF6aHeTXBW3oQ-ISEoVcVubLhfVb1kMlqGVGSJ0wijbWn46NyosvQzaXaI16zvd9927oabHLfmyBGOyUvbOC5Jj7AUXEzn8OrdtcYvEtARw4r0FKnugy7uKDt4fyNhzrzMCJWEVGTw-ftaMho2-5kh7KYixaWxbQdPTmCgm3QqQk7v0clvVSx6mpJZB8sntXnwROL_NRUlKLWYJdB-4YSNdFzpH-oey7yR7VpnyyE3CMZIZbRuoMIGLbHUMw7R6Zg-C3HLGHAqrScfO3pQLNV2H7xRZ3N6wzAyRZQJrvGW8MalIa8v0VAU8ejuy7IgcyWn_1UEvL-cnv2b2_MGXiL_oYKjlsl1nyGi9DJcK7BRbuamJRUjG3fjTE3SnkRAy-yde4QWX6PGgxA35q5yqoOisong8pWH0RK02JP9tdwRvDbsTEVAGlWnQPUISGc9MFMM6ioF-jztv5hJfKx1yV3qwHaYOV1xeSRL-yM48RuoboRYNpNkslLf55cZrSzFGcNxztTnqtpZ4yP7j3PAcMgPqTCxDu_EEeFAJgp1POm4gxq7d6YkoN42ZAdiX8Uq2yJEBXGm9UaqSNqgtuulAJw90ENUnmaShijqWKeetnclk19qAtGGzbjNOcMx02hB5q-CUmdqPGAzsA5hY1YvbwGbIZewWuS9-QxR_XCPci1sR_XlJhQ7qa71an5y0Zahy8RfJ3hh2BiyN1xsDpP2PHxnbNxxL8OgllNdrM9cpfnc2eQQ1PiIfZaNrXsb4Juwbpte3jAJjzjRKO_7njLHF3SWVAhIxEQMUBdq1qLRIaZysw5FNvIBJ304fetFXGNK7YfCEXvpCoGPNnaT_WL7vu5u153-KzGSoJmVxY5J0bcrsZhkATliIYHyGGMei5XyHvxNtzogresuktQrUTg-zwNhgbz4KjmQMLbCcRoy7VEDzZ5gqhhx3rNuGjJDpUjQygok6VXOXEbZbZiDTPtOc8jEOk_0RVK2vkeaEIJS9eIzfkmPYNOTSchUTgbfUnRdIHwqxMzf_URTIFe8ZXgy0WyLYC8UhnOj8kMyUtNy7emgnCnaBjelgCr5X5rAc8YOwFsmAC09WY9IrMwc4sIs2JDAw24ZxXGFEWyUqiEzRUMUivKw3KsOxP-RJo2pI9Q3_0rnb6LnMpGpoB2gkCc0pM6NbTNMhlVGnaZGHfsJ6anUkXvsocc-CGRzMH3rzlb8BFVH9ejHLTfisp3vTLfyhgPgg1F5G19mdXN-AcpR6-AP4U_kEzNUe7l3WHLhrmjzDZ1GZG7wMnKfkN-nd0pnvhhwGE6EF4KGfshfP0rThVRI4TG3sTn3fumJQMR4YYGv10rJmPUrBeGqbnSv1bz3PcZo1v0aHegVGD6A5sBvqxZTZ6Ul0zrc6nMPK_gcJCOed0uDeetbdKXQhSwYIUdCnPnoKO8a4lqiyIaRQHjkTGDL4ADbvbzMruz1K_PM3YcCORmCfacW5xtsTQwsRyA3J6zEz3M_2neEiHDPaRR8XYKnjC4_sX1RgRAQ8EX_2N3qw6nKPaQLR4p_HSlrkalFv0sYUK-rcVB4XoWW2YMl0wCqA2U-ih5r78mxs9X9f0kOIG6QUKZQg7QcEWy6az-1bmyvcUP0Wur_MofFw5e05ZEdXXmMDderf9bOtRpOvWGP9WNJt5P1toRskMfVuF6FINh0d93I0ZNn0zs3Hjzm_1ADhQiYdXe6GvMl83zqfW9f-cEFlonsXvqyKmiQ6lrGq7bQfL5wtTRDYjgPSgqrfp561n53wIVcURD6eWptPDngSkVG3UJApJiSj9W5nRYGsV_m-wieJ0YukYNXfEkVeA1XF5IY_c8eeleGULKw9IRt1-Na-sFS7bQlN0-gh9lUK026khSCzYZQFMJWDiMa4tSj4DhddC9tsm8CfYzfSaQl-PFHK3jk2aHXfkgfZJeH3QZcPbMwjTUWIybp7TbfFg9tj30XlJ6vm6W5Y-ykMQtg_JeilJl-l56k1VbYRbsehTHBNXk4TF6Uv1sy6DqTzVwU-Ows7XZCM_KWelylsziDuy68vDaZWNNarqs2vJT9cPBRWHav8JB5vi4kRW5p4U7mzLh4Dqq9QXJBhFhjMT0nmSQaWZspo0Nd2c2JaqyaBNhgW-yfXFD48HNtmEXH_jHuQ4qXktA-p8nEL2zTsohSyO_OGZvyvZDUJjouc4srcbE78c8k3zR5omLKhahF5kpVKm63pXC1_dzpc_4rm9ULxDbPcfsby1McoSyDfEieublBWBPeDAKBgNpT_DkzgksXBdATe_9CNlM1nYhHXKsNhaxx74HaSGUl6OIMagmYYkW8yeM3fVIbtx89bpvgl4t6pdJh_avMlCOz-LXFGeZBnIFPZVyCoajwIh_le6sDlmdoH-MP-fgfuNWqo_YLSUOyV6-YW7LXLlnp4k8_YJ-y5Pitf1M-ocyVAZliqzen8rVvm7XfV3QKZ_pxZqMzFGAg-IkNnigBuUmc9rc4wMPDJVqfPynSFwtta2qcRYXiIitOMW_m2xSnqZucwiEYJl5pq4PzWipuglTiydJOObvD6SRg41BPBYLLE9P0" + }, + "sdJwt": "eyJhbGciOiJNTC1EU0EtNjUifQ.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJFY3g3OXIxX29BbDdEbl92V2lGb1dySl9yTU5NM19rUGprMFpIdS1CMWQ0In0seyIuLi4iOiJpSGh3dm5uVGh1ZlNFWlJYdEJ2SW1fakI2T0VqRzR1NHFFR3RIbUFOLVlnIn1dLCJjbmYiOnsiandrIjp7Imt0eSI6IkFLUCIsImFsZyI6Ik1MLURTQS02NSIsInB1YiI6IlZBTGJxMnB3RU94aG1DUjZIbmxFcFFBOFpiWVJrTUtrRHI4V1FCdjV4SVd6TzNqVzF5bzJHRmRMTUl1STBXZ0R0Q0x2bUlPSUFiU3lpOVNwRHRaMjhPalc0R0tqdGpydTVoTEkydFA2M0FnNU41UVd0T2dwSFczRW5DZVl4MEFhZlItTGFVeXhVVXNrNl9RTnVZZ2pLczA3QmY1LVFYX3R1d3RqZktobVZyQUJ2Tk1TbDFLa2N4Nlg5RzdHQWh0a2dPdEZuelViQ1dfNUFkR0dTSEdDb09SVndmZXRIQjZVWm9nMEh0V2t5MXVkZURYeEN3dGwtYV9ZYmdjMW02MTV1TDBZX3l2NlA4VzRuZWEyTy1vbWE2TThXaXI1ZkpkZWZremVoakoyLVNGNXI4ZWZXbUJXX2xNNk1LY2NVOXJSSG5GSHFzbTc2VjF5UUhIZmw0ajRIX1lPTWxlLTdlbDFUcDJvQ095ekU1aEZfeWlTaXlKNEFDcmFhTm4zckxFYXVkRG94ZmlXUlA0dW41eFFlU1ZxejU4YXVOX0N6OTdxOURUbVI4X2lPNmYzNnZ6Rzk1MmZUb3VhaTJBX2o5SW1TOUh1cGZEY1R2eDhGRUNyTnA0cnJrMlpFUGlKY3NPbmc5bVgyeFNuMFVMZktQQlItT2gxR1pWOHNCdVB1b3BxTlI3MEw2SFRaTmhjLU55Uk8zd1o0U1lMRlJBeFRtWi1HYmgweTZvVkVqdGlKOUlHMVhEVkF2NVBJazJmXzhwalo5UHFrbDIySE1Qd3ZZdUNMRXJHWnBVdFFub3YtX2VpeWhyM3pweWhUZlExOF9leFpIZUtBdm1HcTZKbzlLN3pkWVVxaUYxZkJMQ3dUN1B5RUNobm5IZTVxV1lrTVNJWjAwMjhfUVJ5SnhjWHlVS0VPU19ybjFUM182UVRtS2hTN3ZUaWdERVVLNmVFU21rbDJSNC1GaWQxaTdOaFktbmpnQnBDWEg2Y011emlVTDBIVUhUbDZvTTVJX1k0aXVnQ3BvdkMtc21jQmFWeU9nM1doQWktVjRIWVowZXhkNHlCRm5vUHRTaXF3UzMzclBIWTgtQnpVeWtKMkhTNkx5X3VnanJybnJhYkplN1hmTzcwTTRkR0FTdzlnVmFpUjgzbTNFWTlSLWlQdXRmNXNsOWRjcTBmd0g1b19WMEowYVdLREhPRDI1X3h3Tmd3SGphbWJqaXUyWXhEaGVoWDFRZkc3Y3plRS03ZWwzVnJmVDJ5TWF6REtZYXdwM3hUdW8xMkdLS0ZPTk1zZ3FQek5PelktZjJkVkVOY0k4TFAtaHM5VjVsQ3QtTjIzZmpQNnpPWUdDLU1hRUxNOXQ2WE1PNVIxT0ZJTHY4UWVKSksydFpsUTRDSlkyU1UyUXNfekVQLTVnOE5MMVg2Y3JZbnVzRXZicTQ4aWprV3Zta2FRNHJDa0gySmhmckN1c3RfcDJnUnlYSmhud0hsaVRFeTlfYTQ3TjJ6SlFOSlMzWDJxTGk2bTlQMDQ4UnF0Y0U3LVdZeWFFSG1xYTFYOGprSU93M1RMNTdueVJPU3BFSnFielJnODFiZjR2Mi1xUTZNNF9qa1k0X0J0ZEx4ZWduX3d6UVh4U2diTHktbnFLX1BaekhZUWpIcWdvQU1LUlZfN3BTZllyaUNQZV91aDkxcUdRZ1J5VUdwS2ZObHdZZDh2T1JtNnVLUlFQOW1YN0ctNE13M3lyTU13dkxKWHpIU0xyVWpzbXdQZmoydi1KYjMtZzN0SmM0aE0waXFFQmFVR24yU1V0ek44UjVGRUpOLV9UODRZMzQtTkFKRzkxUUxBS0JUcWdpMTRPZnhSWDlFRUMtRVZWZnRqekU1Tm5hMURZVENlZFNJSlFRdExGVENGZS1uejdxLXVEdWJzWDNMaV9ReWVxcjhaQXBaUEZXU1E3bFZmQXhVMFRHNk1PZkZvbS1iekFUaXA1d1pkV3pJal9PY1pMUUg5QjBmVEhWdW9qNHlTUGstNHdUUFBLcDlXVHo2SGdDenRpdjZTSkxWSmlZWEI4N01oX2FxczEyTHZVcnR2TTliNERWVzN1dnlTVWstY3ptR0xGNG05VGUxWjlXbllKNjY1UWNTZ0twUHAwQUpGRmMzYjRKdThlcFZTeFNZXzRRbkZYQzc5WnBDNDAwZ0pZTlRsVDRrMW4tVElwd3JybTN2S0M1bmJEaENYT3JXNlQ2Q0FNV3lLa1E1Vks2cnBaUG9CRmhPS2FCSWg2MmYwaWFzd0VTSXVtSEtoRlBaWnptcVo5dkhlMjFMa3FTMkNzXzhhUFh5VkdNTTdPUngyYUNnY3QzZENxbkJmMlB5QjNYR25teW1Cb3I5b3l4NVh1Rl8tWlhYQmZ1Zm93blNwcFNIbGhfUERKb3c1X1p4MFBzR0Jfank0cFNrSFdKR1hRLXF4aUhRLUJTRlZmc05oUzc1NHBHMFc5NGVLTXdzb3lDRzJhUXMyQlotamFNcW1vNzhkY1d6VURWeVFSWDVuSFNYV0lmYVN4c0tsQ2RwZkxLOVkwdjVtbnhvb1lVTGN0YU5ONWRoQWt3ZmJrdmdacmhzR3Q1ZWg3TV9kYlFmRE40LUp2Z0RLOWZPVUo3MXdvN084Q1lPVHNwY3l0VW4wMXZMZWdhOGtxeDlSOUQxdnRJR3U2bkRjVnJVejRWUjZzYzE5cVEwcG1EdU9LUlhOZU1KaVJNREtuUkFGTWFZOXhKOS1Zd0pRM3F4MHpuUTVfbndiY2wweVFTQS1EUFU5UHdkUndpRnNqdkhNZWc0WHlEX3R1M0FUR3lPeTUzNEpIbUgzR19Od3BWeU13X1d2TF9MTEE1X1hUaWl3R09sVFFvdWlKSm1CX0RpZlUtMHRPcElUWDlTZkRZZ3NoTkkxaXJubnlLclRjZ3FKYThha3pxTkgzWUVwbjJhbUZNV1JnMElXUUs3YUFXN1p3T3hvRG93MHFKYWNGMzNEN3BPVDgwSEk4WFFodlpkQ1FyakpaZTV0UEEzRjI3d3JWUEczTUc0SlRmYnpHbFZZcm9jaWZZcWtkWGlrWVc1andrTGlmR2NrRUg2LVF3VTJNSlpuT2xiNy1ndkJIZGd2WXNaVW13eHdPSjZ6cG1lLUpiWkwxVTY0bXJYTTlxVnpkMjlTSTRJV3E5ZFAyWVppcUx2WlhlQXBPekl3YTJZNXhQSHVaTmJBVWVfNGlqQnhrNUE2OHFYT0xYWFhQZzVuaXZKcWdjSWVxMXdtd0ZpSkxYS0NsSEluRDlWXzl4MjVvNS1vSzVOVFVpX2IyaGRnd0pGVVNxV1ZTM09DTWNheEFVMmRxWkJMU0lQS08wbHUzZHd6NFJfYjNrcjNpZmNYcEI5Ylk5TFVCWFJ0ckxYMHJONllEQ2czVzlWSFZ2R01XT2VJY0pDZkcxMkROUDRYejkxNDV0M2JRMmdFOWZiQ0x5bjlsc3JMWmgxV2ljIn19LCJfc2QiOlsiRWtUeUUybG5rQXItRmhDV1NBeUNyT0ZYX2MtV2dBRndERGp4TDNaeFAwSSIsIk1HQ0xNdk92WlRyRG9lNDJOc2x0THZHZlJ3ckp3X0JVbXM2UGFOZk5CVmMiLCJfZGhZbVBacXFXcUhqQ2cySThtMG5CNXVvRnlBSnp4UTUxVWl5YUs3OXJ3IiwiZm9iNWV0MFVxU2hPVlZZengtekhoZTNhbnVPZWJ1YzUydkl2WlZLazZUTSIsImZzSmI5YmZ6MlFhUnN0cm9SQVFjMmlYaXJMcTNsM2xWQWI4X0o5MDZXZXciLCJmeXFicTFab1h5SWpmOE9XMWNOX2dWdzgyelpWMWxqbmpINDBzay05OGxjIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.kzq5ApOKCkOg5J2OXBIRinyv6tU4EuUsbMa38s8lHLjqYB1CkB85DWHsnCxA7qCKDErRx_t2hQEL6ay2eYpCydIWhTkM5RGqZH94DW_MPz99Me2lRMy4MpHapCfdVL4iQPDQTLGCQO7R6pmmV-TD42RrZPsUEAzU7nEt1OnZt7DOTBmLIgDu-TTJEkhb-hRhlPav413FL7qkyFsYPiqLlHyQwC6AJ86OPIRXPRqSALiVodUPJ-steRRsBbx2zvlJoYI-2KJ3qSvAM0jZARk5GWH1yCv3NJGS4dx8jQGEcvqK6z63HwKyYs5zHDehZhf6dxyiX0LZEXQY8CwU1txL23o4e3hoHT-we9D4BWBi-ztNmG6dVnNcOKacA0dZsh8O0G5ZDZsBL9gSK2vQaIktWWzcFdgvB-k6wH-C0WQiVq1R3aK0nxxq_i11LblmGLjbbYleaFaFNqp0TWSq-yXzRNHW2gYz78aYFoz22Ty4O1G--7TUuj0FQUCyrQ14O7Di5Yv0FcqInw_Talrg_8ouxDXP5JAIhBHSrNLzJ4RO4467tVK3aT4Ig998tdHc316Jm4o6TqS8HYEqPDxfnlvUWy3EsMxEzo3q-fOJ4ju4Impd_sTLTV5ZzFbNv6J_eJXLW7Pe3B85tyRhVA7eY2iG3Q29OzvjvWawD8Ow3rE_Q7oBjU0q4njnKqTOOsBHjTmke3CEml0VbsLPZbrswmUCjwZglsgq_qOJDIsWmNLtpkfsTu7zlCXMBnNSDcK64cbqmEX8Bq9Q278j526LJOfmZrACzTsiNXiDgQZhPQEMSbnn0GfGs9Mc_ivEAB-ZVDVx6qRFagpJp7m7vyPbkasb3re4NBj94-K6tumcCEqYOZn2ECO8XLkOVnbOhQySioTYemGiEA71Yvg8kaawrCE2sGxDx3-g9hQt223xEgT0-w1DC-DpWpmKf1-v-sQo90A8pb53p6HJ3NqJJmcC9B14nHWZfZ0Hv5aJve_neD6c7viIsP4JcMDrW7eOlm6Pxs-AkD-4Ro0OHiOlP0r-kJTu_uiy_-H2uj9cLa5T115NXuCJ2uVIWh8Oj0cbnOYdxjd17Sx9yi7wUVCKylgxMaKLs-YqAiR9SLXs5ku3wAd0_saTmE_-gHzwZfSj3mzJ_uiIFRcQtNsfD3GwJwartf6jgaWY0gcSJhMUGSasbH8_NhXjoVAm-dGDjJdbnYqKEdL8pLQ0ZTkkk5cH96v1uQYeTLMFNAYipT_FvwWYAKWc-Uc5PaBipCrzvL9y_MshidEKTom1p-7scnMzDU6RcAA5Xeu-ocgxjqmMmSE5rDePrKi-Jd0bujdA3UlkwVtMZGE45C_WmcVhuWWdIEivOZp-FAmgv-cISdPMWRCdDFS9NL72uyyaMTIcuOD7C02zi749Xw1BybzoxVHcPGcmtWFDM4q_L7DrlYSO1T1v1cQJ8HdfBMvnOTpGToIfG9SCZmPh5R14wFdcqNr5QglC36De6vtkwDFaw1ASADmlm88uNb_hd16UvVjs8gf91WZIINGNk50Fu4BsFlJTWmy1ZnMKxVZOcGEJs0J_8eqbp25sBR1XtyKtyo45vdJPaLVQtsql3z3jKjoKLEE7J4n31flyYh-p_fShsfcJyw3CZbnhRYVWR-8MdnHDV4INh-rDKGkVsY4JtKQv_VjN78ARG1XPXaNO_2yMXICRWotKNzo4Jwx3btKHQhoM5zwHNdrF0p9ha_WZC960lvJ5XcWAeXTzI0WJP7LZHRzp7zc3iR-osVHhfMNuuy6-prrMdTqT_Pn6JURfCH5L9LEvXoeVXuTLDS_gECVWGrk9HqjFyqbsfftOgseFkH8ELExTQGI2zHCrcjHfdlBqMogj8kv-ya5GBk9DC7iR8REyrsuAKQzJI2FyImxGVxmKKoPNrqKgorKrTgbhHoxay8Mu3YPkWJfLNUYKkLVgRknQRRnu12cnB_noxFBDr83GrvXsmgwKadVe_SGrcB_FI6EIIQfBzHjeRWtLReK_nyfpKhpNUUMgw_wfmQHcde1wdrabw8yIaC5CrsD97U5C2jGNnzO8RTm-JNDsRWjduzXlBhxP2uoe9bRpe6-x2W6LG9o6gS4PIC4DnF6U6zxReBMurDXXOpFwJJhDM2FsZEg6bDHoIwlCVjs4eZX0WS5o2iagjYM5hIykwRZmP78jt_YEAo8isNR1U8Fh79mxMylaIx2TNenf9nj1OhFQp8W7tQ0cBEvvfUlwHIT4KC4yaAuslNX4Mc5BFOwoTiZ3M82hzab3vXowIgdWJxqXTSULVuKvD4-939pFlIVuMIVbaOLdrhXEmN5Rs3aFneEk6Qp7J11TMsXygzqrSYs5o8BNnR7GrOTT4RuGi3-At9fKMpEdln7mmsJ2owkU9DBfRmG6G29l831pfpOD1yCWX5bTwKl09Q-aYIoGYycpoXHm2dct055SO9CFXATPGXd_gPlPyklwdD_0V43Z_Kgm-AH8PRjKVeDgrLnI3skQNaEpiaXl5vV5nNunFCoj4fqb5HuxrcvYf0zcmf5PxVlvuBBhPcmCJSJQ7iYfEYN4Sw3sor3BGYDuOXO3CVnF6acawwvnNCLhMvKpC6PZGLx0-FyVtqJVVeLq4F4TiotNU-fNZffuIw4XYxQiNg1xKG2VvBVbwQ8738bNfhsxkZayqhNQTbJRYKmitVBsWTzhgCAwIBbxHvsNQDgk8GKU9nwYVyaMJUIod2jPuAatvA_39FPe3jC5UKpJe3-Kj9MvN_GlOXqh29Y5-PxWBdIYh7XzHCFM636Ljwte7PQ4IOr8VospDQE2w26cVl2F9xqJoYQB3CQlHWkNlmJXTGxwG9I1g_b2qr4UvueFwkdqNNP2Wg4RzvPWsRJEnrG13irYok7OfqTfZ1CTQRoeqQkHaroOBgW6bb2mTBE0vkK5d7DfaRdcFEFYOjfg520LwzOjyYhAuHstXh7Cd186QIISxKKxOC4fKsA3LgrPHUyVpb6f18InFi3f2OZauPt2EEckpADi1WiviopD4g0RzZ7syuwcmXybZeFRy8fi5hb0OrDvFusACn-o2JyCx-Cl2FkesRoXrO6Uw6PQnW6mYvugCj7ZRkapAGTLYrA0vXMbC0a2DBC6T-eLDZSZDDSfy7J_ZffTffRzth5Gs6j_LKO41FSgC-uxqeBoRihx1a5rh9K2fGRgYPCURHgv3KK93WAhcqzeCAOLt9tBGdNUQBV5_IMW_8RBOBaCFOEC2r_lCVpe1LijV4wYMC133u34AyI51JSJI6Z3V1FlZbKjY7KuvhWVINSrQ7nQIba6u5Ci3e3JbTMJLr7P8_UEM41-0475ts0tadjLrGEFo2aZe1ZwsfSjVfmjYeOtmCFgxjasWpUpIPthJoXdCd-Fu3beO5Jvl9FmFMqqsP9h_z81kQfDu8qi-_TrXWhiamwfpuETG-3nZTi8HqO1nAXPQ8sGNN65FbZrVHj6OOmVMVnNUToMFNsq9unEJZdZIfB_ymDdA3Ggo3T9JZmQ4elMeEJss_wzMwUJqjsbsvNWDzB-UBFXCIkTjht1KQ-CKFMTSvUdZK0jxuSmC3HFT-rMeasqnwp4J-tp28Hq_a7xVQoEvRBcr1yyNgdWdgYPnenUgPGlV8o_p2tEGkpWoozdaIuegqEUTvuKL8rUN6K2hRvcPaWvQe_YFK2oPPsJYse4a-lxUS_nWtLW5P9s6wTq3lhs744oo0kToMamstTYZ5z6qw86LeELrYVy__iRJpXINnZTwwlAOXF9-iuojINf7aNG5Tmj9vovpSiiHpwYQ9vyyJ6OuGoHPqE-zaQwduwdzQb_iBms2E78KOK0gRPyFzwfC9YGZwJBVRqrtbRZSrnWSA_81lp7P9vMnfDnw8nPpi-WuGz1QAW_7XQOpK2xJEHiDfVSQIQUu9-k--g09aFZ386RpAXtuJRNSijtjoucw6ay4Wt1wUuLI8aaTgVPQ4N67XpPMoZQIQ2LkWvQbh3-mHiAS8mXsnujSVqMyRbx1CNPmHvnWYG2MRw8ox90j6hBpIazSk2EY8Bp25e3m2pvdc3Ofyo9E-vYM_OopofS1GJzFFwYI_HYiy_aq1xp4_dhUOsIPhhq3pt5S92Q076mnQGbzz_t2OafEQvknXMeHpoeR4i-02Wmi7m6JzJE8Mz_Ycdqm2quC4VZT1Prm3zVFzAUxutRXhfZHurXuflgAU_LZnvB30MqzxH-J-CrrO7qW5fnpKGfsUkRY7UcjQEn3jykPz-UU_U58HRwCTZnSyIh5fpCc6OJDHju3DeVQ3Emv5sS6IRYQC53Sl7wITb9HvsWZmMuB0feh7W2UjH01ou8zPcKKkledX-Sxs3p_gYZJ3DO0t3o8gsiUmVpdXaF0-_wiOcoO1ddwNcAAAAAAAAAAAAAAAAAAw4XIiQq~WyJiMDRiZGVhNzI2NDQwY2M1Iiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyI2ZWUyZjQyMDU4NjI5ZDA4IiwibG9jYWxpdHkiLCJDbHVqIl0~WyIzMDRmMzljYzNhODY3YzliIiwiUk8iXQ~WyJmMmU4MjQzMjAwYTY4NmY2IiwiREUiXQ~WyIxZTBkNjFiMzMzYTNjYzg5IiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyJmYmFkZDY2OGZlNzQ0ODE2IiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyJiNDRlZWYzOTFmZWNhMGY4IiwiYWdlX292ZXJfMTgiLHRydWVd~WyIxNDQ0M2YzYjdmYTc1NjQzIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiWkwzYkJMeFItWklzLTZRZG0zYVBXeXRGTVJUNzdGSHJQcUlVUjBPYTRvYyIsIlp2ZkE0VGZDbkxIUDllcFFoRlg1dW1TbF9mTkhiVHoxcnpIUktDZDFaTU0iXX1d~", + "prezentare": "eyJhbGciOiJNTC1EU0EtNjUifQ.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJFY3g3OXIxX29BbDdEbl92V2lGb1dySl9yTU5NM19rUGprMFpIdS1CMWQ0In0seyIuLi4iOiJpSGh3dm5uVGh1ZlNFWlJYdEJ2SW1fakI2T0VqRzR1NHFFR3RIbUFOLVlnIn1dLCJjbmYiOnsiandrIjp7Imt0eSI6IkFLUCIsImFsZyI6Ik1MLURTQS02NSIsInB1YiI6IlZBTGJxMnB3RU94aG1DUjZIbmxFcFFBOFpiWVJrTUtrRHI4V1FCdjV4SVd6TzNqVzF5bzJHRmRMTUl1STBXZ0R0Q0x2bUlPSUFiU3lpOVNwRHRaMjhPalc0R0tqdGpydTVoTEkydFA2M0FnNU41UVd0T2dwSFczRW5DZVl4MEFhZlItTGFVeXhVVXNrNl9RTnVZZ2pLczA3QmY1LVFYX3R1d3RqZktobVZyQUJ2Tk1TbDFLa2N4Nlg5RzdHQWh0a2dPdEZuelViQ1dfNUFkR0dTSEdDb09SVndmZXRIQjZVWm9nMEh0V2t5MXVkZURYeEN3dGwtYV9ZYmdjMW02MTV1TDBZX3l2NlA4VzRuZWEyTy1vbWE2TThXaXI1ZkpkZWZremVoakoyLVNGNXI4ZWZXbUJXX2xNNk1LY2NVOXJSSG5GSHFzbTc2VjF5UUhIZmw0ajRIX1lPTWxlLTdlbDFUcDJvQ095ekU1aEZfeWlTaXlKNEFDcmFhTm4zckxFYXVkRG94ZmlXUlA0dW41eFFlU1ZxejU4YXVOX0N6OTdxOURUbVI4X2lPNmYzNnZ6Rzk1MmZUb3VhaTJBX2o5SW1TOUh1cGZEY1R2eDhGRUNyTnA0cnJrMlpFUGlKY3NPbmc5bVgyeFNuMFVMZktQQlItT2gxR1pWOHNCdVB1b3BxTlI3MEw2SFRaTmhjLU55Uk8zd1o0U1lMRlJBeFRtWi1HYmgweTZvVkVqdGlKOUlHMVhEVkF2NVBJazJmXzhwalo5UHFrbDIySE1Qd3ZZdUNMRXJHWnBVdFFub3YtX2VpeWhyM3pweWhUZlExOF9leFpIZUtBdm1HcTZKbzlLN3pkWVVxaUYxZkJMQ3dUN1B5RUNobm5IZTVxV1lrTVNJWjAwMjhfUVJ5SnhjWHlVS0VPU19ybjFUM182UVRtS2hTN3ZUaWdERVVLNmVFU21rbDJSNC1GaWQxaTdOaFktbmpnQnBDWEg2Y011emlVTDBIVUhUbDZvTTVJX1k0aXVnQ3BvdkMtc21jQmFWeU9nM1doQWktVjRIWVowZXhkNHlCRm5vUHRTaXF3UzMzclBIWTgtQnpVeWtKMkhTNkx5X3VnanJybnJhYkplN1hmTzcwTTRkR0FTdzlnVmFpUjgzbTNFWTlSLWlQdXRmNXNsOWRjcTBmd0g1b19WMEowYVdLREhPRDI1X3h3Tmd3SGphbWJqaXUyWXhEaGVoWDFRZkc3Y3plRS03ZWwzVnJmVDJ5TWF6REtZYXdwM3hUdW8xMkdLS0ZPTk1zZ3FQek5PelktZjJkVkVOY0k4TFAtaHM5VjVsQ3QtTjIzZmpQNnpPWUdDLU1hRUxNOXQ2WE1PNVIxT0ZJTHY4UWVKSksydFpsUTRDSlkyU1UyUXNfekVQLTVnOE5MMVg2Y3JZbnVzRXZicTQ4aWprV3Zta2FRNHJDa0gySmhmckN1c3RfcDJnUnlYSmhud0hsaVRFeTlfYTQ3TjJ6SlFOSlMzWDJxTGk2bTlQMDQ4UnF0Y0U3LVdZeWFFSG1xYTFYOGprSU93M1RMNTdueVJPU3BFSnFielJnODFiZjR2Mi1xUTZNNF9qa1k0X0J0ZEx4ZWduX3d6UVh4U2diTHktbnFLX1BaekhZUWpIcWdvQU1LUlZfN3BTZllyaUNQZV91aDkxcUdRZ1J5VUdwS2ZObHdZZDh2T1JtNnVLUlFQOW1YN0ctNE13M3lyTU13dkxKWHpIU0xyVWpzbXdQZmoydi1KYjMtZzN0SmM0aE0waXFFQmFVR24yU1V0ek44UjVGRUpOLV9UODRZMzQtTkFKRzkxUUxBS0JUcWdpMTRPZnhSWDlFRUMtRVZWZnRqekU1Tm5hMURZVENlZFNJSlFRdExGVENGZS1uejdxLXVEdWJzWDNMaV9ReWVxcjhaQXBaUEZXU1E3bFZmQXhVMFRHNk1PZkZvbS1iekFUaXA1d1pkV3pJal9PY1pMUUg5QjBmVEhWdW9qNHlTUGstNHdUUFBLcDlXVHo2SGdDenRpdjZTSkxWSmlZWEI4N01oX2FxczEyTHZVcnR2TTliNERWVzN1dnlTVWstY3ptR0xGNG05VGUxWjlXbllKNjY1UWNTZ0twUHAwQUpGRmMzYjRKdThlcFZTeFNZXzRRbkZYQzc5WnBDNDAwZ0pZTlRsVDRrMW4tVElwd3JybTN2S0M1bmJEaENYT3JXNlQ2Q0FNV3lLa1E1Vks2cnBaUG9CRmhPS2FCSWg2MmYwaWFzd0VTSXVtSEtoRlBaWnptcVo5dkhlMjFMa3FTMkNzXzhhUFh5VkdNTTdPUngyYUNnY3QzZENxbkJmMlB5QjNYR25teW1Cb3I5b3l4NVh1Rl8tWlhYQmZ1Zm93blNwcFNIbGhfUERKb3c1X1p4MFBzR0Jfank0cFNrSFdKR1hRLXF4aUhRLUJTRlZmc05oUzc1NHBHMFc5NGVLTXdzb3lDRzJhUXMyQlotamFNcW1vNzhkY1d6VURWeVFSWDVuSFNYV0lmYVN4c0tsQ2RwZkxLOVkwdjVtbnhvb1lVTGN0YU5ONWRoQWt3ZmJrdmdacmhzR3Q1ZWg3TV9kYlFmRE40LUp2Z0RLOWZPVUo3MXdvN084Q1lPVHNwY3l0VW4wMXZMZWdhOGtxeDlSOUQxdnRJR3U2bkRjVnJVejRWUjZzYzE5cVEwcG1EdU9LUlhOZU1KaVJNREtuUkFGTWFZOXhKOS1Zd0pRM3F4MHpuUTVfbndiY2wweVFTQS1EUFU5UHdkUndpRnNqdkhNZWc0WHlEX3R1M0FUR3lPeTUzNEpIbUgzR19Od3BWeU13X1d2TF9MTEE1X1hUaWl3R09sVFFvdWlKSm1CX0RpZlUtMHRPcElUWDlTZkRZZ3NoTkkxaXJubnlLclRjZ3FKYThha3pxTkgzWUVwbjJhbUZNV1JnMElXUUs3YUFXN1p3T3hvRG93MHFKYWNGMzNEN3BPVDgwSEk4WFFodlpkQ1FyakpaZTV0UEEzRjI3d3JWUEczTUc0SlRmYnpHbFZZcm9jaWZZcWtkWGlrWVc1andrTGlmR2NrRUg2LVF3VTJNSlpuT2xiNy1ndkJIZGd2WXNaVW13eHdPSjZ6cG1lLUpiWkwxVTY0bXJYTTlxVnpkMjlTSTRJV3E5ZFAyWVppcUx2WlhlQXBPekl3YTJZNXhQSHVaTmJBVWVfNGlqQnhrNUE2OHFYT0xYWFhQZzVuaXZKcWdjSWVxMXdtd0ZpSkxYS0NsSEluRDlWXzl4MjVvNS1vSzVOVFVpX2IyaGRnd0pGVVNxV1ZTM09DTWNheEFVMmRxWkJMU0lQS08wbHUzZHd6NFJfYjNrcjNpZmNYcEI5Ylk5TFVCWFJ0ckxYMHJONllEQ2czVzlWSFZ2R01XT2VJY0pDZkcxMkROUDRYejkxNDV0M2JRMmdFOWZiQ0x5bjlsc3JMWmgxV2ljIn19LCJfc2QiOlsiRWtUeUUybG5rQXItRmhDV1NBeUNyT0ZYX2MtV2dBRndERGp4TDNaeFAwSSIsIk1HQ0xNdk92WlRyRG9lNDJOc2x0THZHZlJ3ckp3X0JVbXM2UGFOZk5CVmMiLCJfZGhZbVBacXFXcUhqQ2cySThtMG5CNXVvRnlBSnp4UTUxVWl5YUs3OXJ3IiwiZm9iNWV0MFVxU2hPVlZZengtekhoZTNhbnVPZWJ1YzUydkl2WlZLazZUTSIsImZzSmI5YmZ6MlFhUnN0cm9SQVFjMmlYaXJMcTNsM2xWQWI4X0o5MDZXZXciLCJmeXFicTFab1h5SWpmOE9XMWNOX2dWdzgyelpWMWxqbmpINDBzay05OGxjIl0sIl9zZF9hbGciOiJzaGEtMjU2In0.kzq5ApOKCkOg5J2OXBIRinyv6tU4EuUsbMa38s8lHLjqYB1CkB85DWHsnCxA7qCKDErRx_t2hQEL6ay2eYpCydIWhTkM5RGqZH94DW_MPz99Me2lRMy4MpHapCfdVL4iQPDQTLGCQO7R6pmmV-TD42RrZPsUEAzU7nEt1OnZt7DOTBmLIgDu-TTJEkhb-hRhlPav413FL7qkyFsYPiqLlHyQwC6AJ86OPIRXPRqSALiVodUPJ-steRRsBbx2zvlJoYI-2KJ3qSvAM0jZARk5GWH1yCv3NJGS4dx8jQGEcvqK6z63HwKyYs5zHDehZhf6dxyiX0LZEXQY8CwU1txL23o4e3hoHT-we9D4BWBi-ztNmG6dVnNcOKacA0dZsh8O0G5ZDZsBL9gSK2vQaIktWWzcFdgvB-k6wH-C0WQiVq1R3aK0nxxq_i11LblmGLjbbYleaFaFNqp0TWSq-yXzRNHW2gYz78aYFoz22Ty4O1G--7TUuj0FQUCyrQ14O7Di5Yv0FcqInw_Talrg_8ouxDXP5JAIhBHSrNLzJ4RO4467tVK3aT4Ig998tdHc316Jm4o6TqS8HYEqPDxfnlvUWy3EsMxEzo3q-fOJ4ju4Impd_sTLTV5ZzFbNv6J_eJXLW7Pe3B85tyRhVA7eY2iG3Q29OzvjvWawD8Ow3rE_Q7oBjU0q4njnKqTOOsBHjTmke3CEml0VbsLPZbrswmUCjwZglsgq_qOJDIsWmNLtpkfsTu7zlCXMBnNSDcK64cbqmEX8Bq9Q278j526LJOfmZrACzTsiNXiDgQZhPQEMSbnn0GfGs9Mc_ivEAB-ZVDVx6qRFagpJp7m7vyPbkasb3re4NBj94-K6tumcCEqYOZn2ECO8XLkOVnbOhQySioTYemGiEA71Yvg8kaawrCE2sGxDx3-g9hQt223xEgT0-w1DC-DpWpmKf1-v-sQo90A8pb53p6HJ3NqJJmcC9B14nHWZfZ0Hv5aJve_neD6c7viIsP4JcMDrW7eOlm6Pxs-AkD-4Ro0OHiOlP0r-kJTu_uiy_-H2uj9cLa5T115NXuCJ2uVIWh8Oj0cbnOYdxjd17Sx9yi7wUVCKylgxMaKLs-YqAiR9SLXs5ku3wAd0_saTmE_-gHzwZfSj3mzJ_uiIFRcQtNsfD3GwJwartf6jgaWY0gcSJhMUGSasbH8_NhXjoVAm-dGDjJdbnYqKEdL8pLQ0ZTkkk5cH96v1uQYeTLMFNAYipT_FvwWYAKWc-Uc5PaBipCrzvL9y_MshidEKTom1p-7scnMzDU6RcAA5Xeu-ocgxjqmMmSE5rDePrKi-Jd0bujdA3UlkwVtMZGE45C_WmcVhuWWdIEivOZp-FAmgv-cISdPMWRCdDFS9NL72uyyaMTIcuOD7C02zi749Xw1BybzoxVHcPGcmtWFDM4q_L7DrlYSO1T1v1cQJ8HdfBMvnOTpGToIfG9SCZmPh5R14wFdcqNr5QglC36De6vtkwDFaw1ASADmlm88uNb_hd16UvVjs8gf91WZIINGNk50Fu4BsFlJTWmy1ZnMKxVZOcGEJs0J_8eqbp25sBR1XtyKtyo45vdJPaLVQtsql3z3jKjoKLEE7J4n31flyYh-p_fShsfcJyw3CZbnhRYVWR-8MdnHDV4INh-rDKGkVsY4JtKQv_VjN78ARG1XPXaNO_2yMXICRWotKNzo4Jwx3btKHQhoM5zwHNdrF0p9ha_WZC960lvJ5XcWAeXTzI0WJP7LZHRzp7zc3iR-osVHhfMNuuy6-prrMdTqT_Pn6JURfCH5L9LEvXoeVXuTLDS_gECVWGrk9HqjFyqbsfftOgseFkH8ELExTQGI2zHCrcjHfdlBqMogj8kv-ya5GBk9DC7iR8REyrsuAKQzJI2FyImxGVxmKKoPNrqKgorKrTgbhHoxay8Mu3YPkWJfLNUYKkLVgRknQRRnu12cnB_noxFBDr83GrvXsmgwKadVe_SGrcB_FI6EIIQfBzHjeRWtLReK_nyfpKhpNUUMgw_wfmQHcde1wdrabw8yIaC5CrsD97U5C2jGNnzO8RTm-JNDsRWjduzXlBhxP2uoe9bRpe6-x2W6LG9o6gS4PIC4DnF6U6zxReBMurDXXOpFwJJhDM2FsZEg6bDHoIwlCVjs4eZX0WS5o2iagjYM5hIykwRZmP78jt_YEAo8isNR1U8Fh79mxMylaIx2TNenf9nj1OhFQp8W7tQ0cBEvvfUlwHIT4KC4yaAuslNX4Mc5BFOwoTiZ3M82hzab3vXowIgdWJxqXTSULVuKvD4-939pFlIVuMIVbaOLdrhXEmN5Rs3aFneEk6Qp7J11TMsXygzqrSYs5o8BNnR7GrOTT4RuGi3-At9fKMpEdln7mmsJ2owkU9DBfRmG6G29l831pfpOD1yCWX5bTwKl09Q-aYIoGYycpoXHm2dct055SO9CFXATPGXd_gPlPyklwdD_0V43Z_Kgm-AH8PRjKVeDgrLnI3skQNaEpiaXl5vV5nNunFCoj4fqb5HuxrcvYf0zcmf5PxVlvuBBhPcmCJSJQ7iYfEYN4Sw3sor3BGYDuOXO3CVnF6acawwvnNCLhMvKpC6PZGLx0-FyVtqJVVeLq4F4TiotNU-fNZffuIw4XYxQiNg1xKG2VvBVbwQ8738bNfhsxkZayqhNQTbJRYKmitVBsWTzhgCAwIBbxHvsNQDgk8GKU9nwYVyaMJUIod2jPuAatvA_39FPe3jC5UKpJe3-Kj9MvN_GlOXqh29Y5-PxWBdIYh7XzHCFM636Ljwte7PQ4IOr8VospDQE2w26cVl2F9xqJoYQB3CQlHWkNlmJXTGxwG9I1g_b2qr4UvueFwkdqNNP2Wg4RzvPWsRJEnrG13irYok7OfqTfZ1CTQRoeqQkHaroOBgW6bb2mTBE0vkK5d7DfaRdcFEFYOjfg520LwzOjyYhAuHstXh7Cd186QIISxKKxOC4fKsA3LgrPHUyVpb6f18InFi3f2OZauPt2EEckpADi1WiviopD4g0RzZ7syuwcmXybZeFRy8fi5hb0OrDvFusACn-o2JyCx-Cl2FkesRoXrO6Uw6PQnW6mYvugCj7ZRkapAGTLYrA0vXMbC0a2DBC6T-eLDZSZDDSfy7J_ZffTffRzth5Gs6j_LKO41FSgC-uxqeBoRihx1a5rh9K2fGRgYPCURHgv3KK93WAhcqzeCAOLt9tBGdNUQBV5_IMW_8RBOBaCFOEC2r_lCVpe1LijV4wYMC133u34AyI51JSJI6Z3V1FlZbKjY7KuvhWVINSrQ7nQIba6u5Ci3e3JbTMJLr7P8_UEM41-0475ts0tadjLrGEFo2aZe1ZwsfSjVfmjYeOtmCFgxjasWpUpIPthJoXdCd-Fu3beO5Jvl9FmFMqqsP9h_z81kQfDu8qi-_TrXWhiamwfpuETG-3nZTi8HqO1nAXPQ8sGNN65FbZrVHj6OOmVMVnNUToMFNsq9unEJZdZIfB_ymDdA3Ggo3T9JZmQ4elMeEJss_wzMwUJqjsbsvNWDzB-UBFXCIkTjht1KQ-CKFMTSvUdZK0jxuSmC3HFT-rMeasqnwp4J-tp28Hq_a7xVQoEvRBcr1yyNgdWdgYPnenUgPGlV8o_p2tEGkpWoozdaIuegqEUTvuKL8rUN6K2hRvcPaWvQe_YFK2oPPsJYse4a-lxUS_nWtLW5P9s6wTq3lhs744oo0kToMamstTYZ5z6qw86LeELrYVy__iRJpXINnZTwwlAOXF9-iuojINf7aNG5Tmj9vovpSiiHpwYQ9vyyJ6OuGoHPqE-zaQwduwdzQb_iBms2E78KOK0gRPyFzwfC9YGZwJBVRqrtbRZSrnWSA_81lp7P9vMnfDnw8nPpi-WuGz1QAW_7XQOpK2xJEHiDfVSQIQUu9-k--g09aFZ386RpAXtuJRNSijtjoucw6ay4Wt1wUuLI8aaTgVPQ4N67XpPMoZQIQ2LkWvQbh3-mHiAS8mXsnujSVqMyRbx1CNPmHvnWYG2MRw8ox90j6hBpIazSk2EY8Bp25e3m2pvdc3Ofyo9E-vYM_OopofS1GJzFFwYI_HYiy_aq1xp4_dhUOsIPhhq3pt5S92Q076mnQGbzz_t2OafEQvknXMeHpoeR4i-02Wmi7m6JzJE8Mz_Ycdqm2quC4VZT1Prm3zVFzAUxutRXhfZHurXuflgAU_LZnvB30MqzxH-J-CrrO7qW5fnpKGfsUkRY7UcjQEn3jykPz-UU_U58HRwCTZnSyIh5fpCc6OJDHju3DeVQ3Emv5sS6IRYQC53Sl7wITb9HvsWZmMuB0feh7W2UjH01ou8zPcKKkledX-Sxs3p_gYZJ3DO0t3o8gsiUmVpdXaF0-_wiOcoO1ddwNcAAAAAAAAAAAAAAAAAAw4XIiQq~WyJiNDRlZWYzOTFmZWNhMGY4IiwiYWdlX292ZXJfMTgiLHRydWVd~WyIxNDQ0M2YzYjdmYTc1NjQzIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiWkwzYkJMeFItWklzLTZRZG0zYVBXeXRGTVJUNzdGSHJQcUlVUjBPYTRvYyIsIlp2ZkE0VGZDbkxIUDllcFFoRlg1dW1TbF9mTkhiVHoxcnpIUktDZDFaTU0iXX1d~WyI2ZWUyZjQyMDU4NjI5ZDA4IiwibG9jYWxpdHkiLCJDbHVqIl0~WyIzMDRmMzljYzNhODY3YzliIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJNTC1EU0EtNjUifQ.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoia3JnQlhnNjJRSXZmMWpPdDM2WU5XbDJwUXdIVWs1elJGVHVtS0puZWhkNCJ9.8Z2Ms4-p4o9gqQ34HBJ1V8IToO4QpsFaPi6-fNdY3Q3Rh3YScikx8c_NW2UjRxD7_XLiayZDyiGok0u4SCkjkW4iRBKoolXZ_TWsiH3TC9Yo53ZJPlKiMtGEAiO4Vh9_NsCQciiHA7D6RN-rLh3YFhlykAJMDZiwNRPBYbLuDrDIwGvsLjjjV3DQKI2Po41KxgdRnhoA1ao4O_uXCixIax4w8ijs_yEj9UkIsBYO6M2rBVPMrEJqEIUX1mi1SXyaPvgV-SSWhjevBFKvVzHFeiT3Qy1wr9XfJ5YlNj1XxxYXZNk1lvkJeRk9NP4NVRm6j7ghDfs7ZWXa_6GLB4tWsAXAwi8r-ll-OF0wm7lZbAHVyhH7mETzkb8DsWwJctYo3YdQjK_eCNlPKn4PyOqPfi3ZNWmWONQ0w6b3EVXSliicTguMIMYLg27wWVpVTqEz_WGwYFYMWSoSUtFwCy35sp155U9h3DaMpSGlxDpi8s2lwmoGEzSfXlJsrVs-7mENVDR-esc-7MF4g_2KLu3vnLxJ8prcAjFbNTGl__R5M1KdEQRinEWLFbiwN4egKLAl4IP1-6CGYVnTP0ReiIU0aGi2vMlq7GqkXMEJ5J8xsdacSZVnEO23r-MPSM8A-sdX3x8e-5CcbPxBRh2Xd7wZELo8SC4N_L-hOZfPKnQ6M-WG3pUvCyAmJ-ufb7MfSkGUuwIrTzcyOLi9hOY6ojVN50OQoSQRVzDQHZj8vIMZOIek2aq4J8Zktf1vksBQxmHcgknjhjdwc9C1IXgi4CSBuCdi1EJD0MvPF6AfsOwuhBclHQizK1RzFYt5aDofG73trkhbEC5xP_MuHhc11_R6id2OB-H6qAVwnGQ8VRdtaRn2bLu-Y43klK_mQTK4aCCh1F-nuVCv5oq5jPbEMwhrJzWEobgaAcZZgyzI4aBe84Q_QyXvH5jZizdyxQezK3BybaPJs1wv4cyrqmaGCjoJwnK5Rw1ff7x5d8P-WZdmQ75vUVWrkFhUkAg6i4ykjH855TN_bggLM060MBkpmC_UH_F2GsPXZ2cE5qf6EsFuK_FY-iQkDU6suUgxUiH2CNtiaREOGLTEVi0jqHcFTGDoImrIb8I7KL4h4p8q51t_KZ61c50bscD0vf6Mql9ZYZ2Q3vMOJ_38Rmt590Ok_XZKpqnX-Ngba4NOYZv5y2_MB-2Ss8aANViOIKtdKXnH3LpMTUiV4Qw-6mE4xao_SE0QzUwAdAS6fE_OIfMUdg75p_djILaTG3Dvh6uqNUFkJRiAyOeJqUqQTqF2nxFgC9Nu542n7jWKa9ZUwX4c7DGiIAf_WGlNDTKFDICfoPPj7bDIhKaS1rAHt0Nge_KRc5PlVsZOSUmuTXN5n5BFcKkIyom-W4hnrC-CBF34qPPpXpI-22_KWIoyF40ZlxFQKkAVZGCvZyIJh2zEqyMFQ6cKE2otZQDYz22ZbNgs3KOr3HXyqeV4_wxAfKEAn9gcBGApI8DF2qhDIeAH5I9pwS7obqsBy7r3I1dxGyAHaiKaAliaamie-4lRll6zyQK5BsKr7i93wyOQcuJFfjcgopw0RrMELIirYT27WrOIPUGnWDFJrlsiywBFGwnrHUfQxgYKOvO3liHhT47KPuTvZqAYaCSTLHfBFRbwQWh36uhxe_-hCBfB5c_n7PgcDS31FsQn5z_x8RJfHnxuzz4W9Gn0C_CYSQ-iXEcKP8tfhjkwEJToZLATnfh2Iq2UMQHvOMgyOLGJ9ioo5TmUp50kwhNRh4hnCiKITPNZmnHQ-jfwVvdwvM7FQ-ITmjTKe1PyfZCCZumeHIU7CfZUhfYVG50qgiRYYLCQVeJhr6KcIRE-v0v0IyHAq11eelGiLJ7JeyrH01HH_cP12DwuWT7ztVDuXW4TriLHOn64C366_s3Skwy4beZeInvp1_wWI44xTyhIZF494HmcQG1mp849J_HN8l6fneAm1wFHV1d8CtK1Q5HAYvQoAodJ2lNM68c0UiPcaI35HE3_Bw1ZJPutZhbCwLCiDIT4xBPEQSxPMexnEpVBSH9qvpSfVtZCBM3W8amyuPOacKbRnv3xIVtl4LEqrNRuIbpN5CfVSqilsR-hf6CQDpLFI7cR9-AstmKn6Tt1KJp71sX6S2zoh-l5wgoU8BeUFu4TfYMGDAEcdT2oGI4f3lllsuDKgmkFwofRT0JEJnd7EA9IcZUrNZeXhhS8cgYTEkdJXItvTJbx0gnuXKHQhNWKXEDWTkddwML7ADvenwqTdM5l9sNgISWU08qIsflz7lJIGEG7dtUiU3VJCHH6iEdRA4AeQUlUuM4EI_iEqRw71-kw_xD8SMcLA0km-4YN6ciO3APKqgswfkFPE1-Vs9jlPTAX3qurrYtTZf4b2T0Dbn9Y9TzZX8WJPvB1L2bWpTNi6ni_4BDYvvnPcT2OQfMuON5TOzvzd1nQXWGoBbDWK-a7I3PEmE4esWzIj2ghb-JWPdnlYH7gPT4zwzebCgTUgSM8lJgXLxxav74e233dol9VftftX_JbFurtq4jC25Sg1MKV68b5B9RJmm_Og9EBmlCuzyOqsBVV8TXb-JRf8IalJQJijz1PKhjgVgr45UpPv8pi42_CMtR_M8JWL82hn7YC5sX76zUr6Gw6h4e3Q0-YUZYn3s_GZy5qXVpqreHl19Aul-OW-fbtv_4zA9E7i2CYz19l4hm3r_YiOCXVVmMmewSPSsOcLb-1lXETbqfirYP-PlJRl9ghfMzGLg0RkS8Ld9gSMJcSJ6mtSAKzycN-dyw39pkQ359WhAshR-LgzAyBhTdPEflwP5CVzViWGwF1rykNvl0m89NOh8zpglJFvhIrcXcxZyMJJMsUk4bzB8FvJxwepSssWKRAuKH5rlbtWkyRSC15IrBqjhbTB9wDovTFRPKd6WhpNIIJ8RrnUGywwTQhnxf-zr4SVP86YQbYUgaeDCjIvlZajo6iyKXH7tcXDdd4LoO_jHRexPAgIXK3Apymh6OPqt3iDcVnAQ3o2Lr3dQQjNC4NXxqL1Mw5Lf3jJVWNO9usKQEl6qvF4THby71y8VBsd3GBMCgsy5y5N2lz6C1QkSt_xQ2bZ8ThmgPauEtDeX8o0rnLNFYtQITwr-sKU9hfVlxngCJ6u0JjVW3M6tTmkpSuWhpozYPtNcRPatIhjNjpeCYObDMZTJSnbB-hCZDvn76otuXalO0m71rQ42dnwbOf11VxVDMX7MKLOLsE2IuoN4ocMuyrIWCvYMvdRS3IC__yTJ5GuMbVymM4sIN_Bm0xP7Ulym9SctbAtWPSCNTq3CpuvjyWAKxEU5NniY-vlYedlJwRlx_J6rHTWqIgjgWm7y0NLs5gfgXQswWT2a6McafT2rpGcKM6leiKZTYzlGpC5Jq8_ciUhX2Y7U2MIMywLtgQdG0Jn_MKLtCIJIN9-klgAMahu7pO09ciMKf0tfb6wzw_um3XAMqKev55617tRQnQaqBZj2k5CORfE2SOOxlSS8ATbVtokyCwVt--SnoQFsNr7BTV8q_v_l2TKOcMoc85DMtsvhFfeJeTLTW-blJA0-TLlm5ToNBjf-K1aGUl_WWpnEg9U4Tc1z7N4GyLH46_TdG3FVws0pV19DghPZ-fjSTOlBfxzNJjQJZje8BtlSFNNs7BswSfp9Yp7qy35Oje3B-kahbZ6JXE97-fp5_N4yntOupwyXD7iTAqCc9LsxAZhBMa8_8ufqGCTPmrjcSnuEdsA_DYly35aTgssoD9dUqgOjDEJXGbhrdQIgloheqs-bj_X6s5t9ObCk7FfE-2BNDukWAc8YHue_la7gxDsRGZ69Yo6UPnwwSSW5dUwNnncDyoMGgwICR1ff-s7zqo6jZ1iTorRSZAznslHm1Djkwwqd3lNqW-tcU1Am7KisMnmbUhOY9pStIIldQXYJHcRotMTXq4Dpq9UxeEKXHITFq8MSPtAm2OP4g6VPKXy3lgnd4aEfiea8bLQZkJzeFhoGP8vzokl_q4novNgdFhXbx1Pj8yVdm7H9RpI64AzfzBiCofRAUoJW3OzZeD1w6VhXmf0FOwpAMLj4U1QYNF7TuCks5GDNk1DPRTg0OWqf8eqTnb8WPEfKYQUI-_ut2svO1cB4tSguU0miBYaYDNmwzFIavz2gbFTew9HHf8STvTi5MgwzKkA_kRAIZ7RBtRwUH5loy07dt2hM556ler3MA3iPKUriKHTcBNmmpCJWWSyW9nlP5HWeW9M8iDDFOP2pnNeJ1bNGNiWYBOtNEIq5jyKiutULRvB04mJgJcsdX5guz38QsOB6Aywv45JbnyViWHoEnzenjzEk6F0CE8TE6OoaLDWJeap7e91Clqe5q8y9klOj1hYmZxvOYFER1PgpSZm-fzAAAAAAAAAAAAAAAAAAAABw4VHigo", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": true, + "payload": { + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "exp": 1823817600, + "nationalities": [ + "RO" + ], + "cnf": { + "jwk": { + "kty": "AKP", + "alg": "ML-DSA-65", + "pub": "VALbq2pwEOxhmCR6HnlEpQA8ZbYRkMKkDr8WQBv5xIWzO3jW1yo2GFdLMIuI0WgDtCLvmIOIAbSyi9SpDtZ28OjW4GKjtjru5hLI2tP63Ag5N5QWtOgpHW3EnCeYx0AafR-LaUyxUUsk6_QNuYgjKs07Bf5-QX_tuwtjfKhmVrABvNMSl1Kkcx6X9G7GAhtkgOtFnzUbCW_5AdGGSHGCoORVwfetHB6UZog0HtWky1udeDXxCwtl-a_Ybgc1m615uL0Y_yv6P8W4nea2O-oma6M8Wir5fJdefkzehjJ2-SF5r8efWmBW_lM6MKccU9rRHnFHqsm76V1yQHHfl4j4H_YOMle-7el1Tp2oCOyzE5hF_yiSiyJ4ACraaNn3rLEaudDoxfiWRP4un5xQeSVqz58auN_Cz97q9DTmR8_iO6f36vzG952fTouai2A_j9ImS9HupfDcTvx8FECrNp4rrk2ZEPiJcsOng9mX2xSn0ULfKPBR-Oh1GZV8sBuPuopqNR70L6HTZNhc-NyRO3wZ4SYLFRAxTmZ-Gbh0y6oVEjtiJ9IG1XDVAv5PIk2f_8pjZ9Pqkl22HMPwvYuCLErGZpUtQnov-_eiyhr3zpyhTfQ18_exZHeKAvmGq6Jo9K7zdYUqiF1fBLCwT7PyEChnnHe5qWYkMSIZ0028_QRyJxcXyUKEOS_rn1T3_6QTmKhS7vTigDEUK6eESmkl2R4-Fid1i7NhY-njgBpCXH6cMuziUL0HUHTl6oM5I_Y4iugCpovC-smcBaVyOg3WhAi-V4HYZ0exd4yBFnoPtSiqwS33rPHY8-BzUykJ2HS6Ly_ugjrrnrabJe7XfO70M4dGASw9gVaiR83m3EY9R-iPutf5sl9dcq0fwH5o_V0J0aWKDHOD25_xwNgwHjambjiu2YxDhehX1QfG7czeE-7el3VrfT2yMazDKYawp3xTuo12GKKFONMsgqPzNOzY-f2dVENcI8LP-hs9V5lCt-N23fjP6zOYGC-MaELM9t6XMO5R1OFILv8QeJJK2tZlQ4CJY2SU2Qs_zEP-5g8NL1X6crYnusEvbq48ijkWvmkaQ4rCkH2JhfrCust_p2gRyXJhnwHliTEy9_a47N2zJQNJS3X2qLi6m9P048RqtcE7-WYyaEHmqa1X8jkIOw3TL57nyROSpEJqbzRg81bf4v2-qQ6M4_jkY4_BtdLxegn_wzQXxSgbLy-nqK_PZzHYQjHqgoAMKRV_7pSfYriCPe_uh91qGQgRyUGpKfNlwYd8vORm6uKRQP9mX7G-4Mw3yrMMwvLJXzHSLrUjsmwPfj2v-Jb3-g3tJc4hM0iqEBaUGn2SUtzN8R5FEJN-_T84Y34-NAJG91QLAKBTqgi14OfxRX9EEC-EVVftjzE5Nna1DYTCedSIJQQtLFTCFe-nz7q-uDubsX3Li_Qyeqr8ZApZPFWSQ7lVfAxU0TG6MOfFom-bzATip5wZdWzIj_OcZLQH9B0fTHVuoj4ySPk-4wTPPKp9WTz6HgCztiv6SJLVJiYXB87Mh_aqs12LvUrtvM9b4DVW3uvySUk-czmGLF4m9Te1Z9WnYJ665QcSgKpPp0AJFFc3b4Ju8epVSxSY_4QnFXC79ZpC400gJYNTlT4k1n-TIpwrrm3vKC5nbDhCXOrW6T6CAMWyKkQ5VK6rpZPoBFhOKaBIh62f0iaswESIumHKhFPZZzmqZ9vHe21LkqS2Cs_8aPXyVGMM7ORx2aCgct3dCqnBf2PyB3XGnmymBor9oyx5XuF_-ZXXBfufownSppSHlh_PDJow5_Zx0PsGB_jy4pSkHWJGXQ-qxiHQ-BSFVfsNhS754pG0W94eKMwsoyCG2aQs2BZ-jaMqmo78dcWzUDVyQRX5nHSXWIfaSxsKlCdpfLK9Y0v5mnxooYULctaNN5dhAkwfbkvgZrhsGt5eh7M_dbQfDN4-JvgDK9fOUJ71wo7O8CYOTspcytUn01vLega8kqx9R9D1vtIGu6nDcVrUz4VR6sc19qQ0pmDuOKRXNeMJiRMDKnRAFMaY9xJ9-YwJQ3qx0znQ5_nwbcl0yQSA-DPU9PwdRwiFsjvHMeg4XyD_tu3ATGyOy534JHmH3G_NwpVyMw_WvL_LLA5_XTiiwGOlTQouiJJmB_DifU-0tOpITX9SfDYgshNI1irnnyKrTcgqJa8akzqNH3YEpn2amFMWRg0IWQK7aAW7ZwOxoDow0qJacF33D7pOT80HI8XQhvZdCQrjJZe5tPA3F27wrVPG3MG4JTfbzGlVYrocifYqkdXikYW5jwkLifGckEH6-QwU2MJZnOlb7-gvBHdgvYsZUmwxwOJ6zpme-JbZL1U64mrXM9qVzd29SI4IWq9dP2YZiqLvZXeApOzIwa2Y5xPHuZNbAUe_4ijBxk5A68qXOLXXXPg5nivJqgcIeq1wmwFiJLXKClHInD9V_9x25o5-oK5NTUi_b2hdgwJFUSqWVS3OCMcaxAU2dqZBLSIPKO0lu3dwz4R_b3kr3ifcXpB9bY9LUBXRtrLX0rN6YDCg3W9VHVvGMWOeIcJCfG12DNP4Xz9145t3bQ2gE9fbCLyn9lsrLZh1Wic" + } + }, + "age_over_18": true, + "address": { + "country": "RO", + "locality": "Cluj" + } + }, + "disclosed": [ + "[]", + "address", + "age_over_18", + "locality" + ] + } + }, + { + "nume": "EdDSA: prezentare @sd-jwt/core cu typ example+sd-jwt (tipul implicit al verificatorului nostru)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "nE6yYyZSwKuaQaf0UWpjTfPKu4bRh65eOWSm1teOO0w", + "kty": "OKP" + }, + "sdJwt": "eyJ0eXAiOiJleGFtcGxlK3NkLWp3dCIsImFsZyI6IkVkRFNBIn0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJlM2dSeEkzMmRtQ0duMjR3SkxPY3lPMmpDcU40U3NQZFFYbkROSHU0Nkp3In0seyIuLi4iOiJrLUdyZVZWcWtIUFNWZGotdWxqMDQ5UFlYOHk5T0JsOV9DOFBjbmJFb0pBIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiZDBrY3VxS3FoQmp1MGM5cXRhOVhCNzdwY2x2Z085b01yQW9lVFhxaVJZMCIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIjhBYzFQZTItVUxYMElvR255dzJJT0g4Wk1WbVFEWHhyVEw5WTVLcUFwZDQiLCJBSW9VMDh0Z0hrYTBrYU1uT0RqS1ZKeXlQX3k1V1NyRGxQc3ZxZzVRZ0NFIiwiYjZTR09mSVZhQzJEaFhsUkFNZjVYT2pwZlJPYm5Bb3J6d1FqcjhRQ3ZCSSIsImx0T1Y0R0NIUzQwc2pHZ2tpZW5aVGJ2UGNsc0draGtlcUJxSS1jRi0xa2ciLCJtLVVzSlNuQjlnc3VSMjFNaXl6SGdSN3JvWUEtVG83YmNTSlFmUFhGUWhRIiwibzg2UnRhQTd4eXZrOWNCQ3NycE5nd3p4Mmg2RE1wdjc3aVJLUmFPUGxiOCJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.7hhpGxaCJG0GpqDOfHXECP22qYC10FBzZE-CVSWwueA16naH0RtCwQlHMhIXnvIdPNrDuPji_L4YGxG96zm4AA~WyI2Zjk0NjEzZDkzZjM2ZGFmIiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyIzMTZjOTQzMjM0ZTdhZGEwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyI0OGZlNDgwNmNkZTY2MDZkIiwiUk8iXQ~WyI1YWYwZWZhMjdlOGI3YTIwIiwiREUiXQ~WyIxZDkwNjllODY3ODQ3MDVjIiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyI0YTk1MzJjZWQ2OTkwNmY4IiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyIzYTE1ZmNhNGQ2MzE2OTNjIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiMzVlNzFjNTI1ODhkMTdiIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiOVJwNktjR3F0Tk1MdVF3QTFmTmEzSFZhM2ZLM2ZOTXBoQk44dnFKbVNRSSIsInlDendIVEFVSWVqZ0NKN0FqQlRvZkhWTGJ4VG9FcGNUelNucVB4d2diTGMiXX1d~", + "prezentare": "eyJ0eXAiOiJleGFtcGxlK3NkLWp3dCIsImFsZyI6IkVkRFNBIn0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJlM2dSeEkzMmRtQ0duMjR3SkxPY3lPMmpDcU40U3NQZFFYbkROSHU0Nkp3In0seyIuLi4iOiJrLUdyZVZWcWtIUFNWZGotdWxqMDQ5UFlYOHk5T0JsOV9DOFBjbmJFb0pBIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiZDBrY3VxS3FoQmp1MGM5cXRhOVhCNzdwY2x2Z085b01yQW9lVFhxaVJZMCIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIjhBYzFQZTItVUxYMElvR255dzJJT0g4Wk1WbVFEWHhyVEw5WTVLcUFwZDQiLCJBSW9VMDh0Z0hrYTBrYU1uT0RqS1ZKeXlQX3k1V1NyRGxQc3ZxZzVRZ0NFIiwiYjZTR09mSVZhQzJEaFhsUkFNZjVYT2pwZlJPYm5Bb3J6d1FqcjhRQ3ZCSSIsImx0T1Y0R0NIUzQwc2pHZ2tpZW5aVGJ2UGNsc0draGtlcUJxSS1jRi0xa2ciLCJtLVVzSlNuQjlnc3VSMjFNaXl6SGdSN3JvWUEtVG83YmNTSlFmUFhGUWhRIiwibzg2UnRhQTd4eXZrOWNCQ3NycE5nd3p4Mmg2RE1wdjc3aVJLUmFPUGxiOCJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.7hhpGxaCJG0GpqDOfHXECP22qYC10FBzZE-CVSWwueA16naH0RtCwQlHMhIXnvIdPNrDuPji_L4YGxG96zm4AA~WyIzYTE1ZmNhNGQ2MzE2OTNjIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiMzVlNzFjNTI1ODhkMTdiIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiOVJwNktjR3F0Tk1MdVF3QTFmTmEzSFZhM2ZLM2ZOTXBoQk44dnFKbVNRSSIsInlDendIVEFVSWVqZ0NKN0FqQlRvZkhWTGJ4VG9FcGNUelNucVB4d2diTGMiXX1d~WyIzMTZjOTQzMjM0ZTdhZGEwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyI0OGZlNDgwNmNkZTY2MDZkIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiMjl1UTR4Ul9RQVJXbUNId1JtbVRENDcwcGdmZGhnMTgwX08zc09mWDBOWSJ9.iCOcidDsT_n-KZteZtnt1-3oJ4v7FlZpk3g03wnCc-shcjIzBv9xh2X1ZLGJaHtxbF8oeJ3q5rUCV0TEr7o3Bw", + "optiuni": {}, + "asteptat": { + "valid": true, + "payload": { + "iss": "https://issuer.lor.example", + "iat": 1792281600, + "exp": 1823817600, + "nationalities": [ + "RO" + ], + "cnf": { + "jwk": { + "crv": "Ed25519", + "x": "d0kcuqKqhBju0c9qta9XB77pclvgO9oMrAoeTXqiRY0", + "kty": "OKP" + } + }, + "age_over_18": true, + "address": { + "country": "RO", + "locality": "Cluj" + } + }, + "disclosed": [ + "[]", + "address", + "age_over_18", + "locality" + ] + } + }, + { + "nume": "EdDSA: jetonul @sd-jwt/core cu _sd_alg sha-384 (la noi: refuzat, numai sha-256)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "AxyFfp5Ynr1Ag33qsjnaN0R_mILDj8J10x-1vPCEgl8", + "kty": "OKP" + }, + "sdJwt": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJUcURkRFVvX0pNa3NGT3J3Q3ZPS3JjajZaZXRWeC1qTkVHa0xhTVlGS0lZM3lmVDNkSzBWanlPRTBubWNESUZXIn0seyIuLi4iOiJWQ1RERXVkcUQxRHdlUTRfV1JFSHh5SWZFQzl1Z2hzODZKMGtYUEcwem5JUE1Sbm9vcnJYaVNhUTVVZXY5eFpSIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiaWhmNi1BVlhLdlpTTlo5bjZaU1ByWUtzTzZfNVdaQ3g2bHo4THRfM3FuYyIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIjZOT0luMkU4NEpUbkJlZWpmZ1FfN3otakZqWWM0aWZWVGI1Y1FxYjhZajh6ZFFiQlB2QnNpZnNuNXBvS3N1cGwiLCJCbXlmRDZ0cHRrZDMtSXo4RTVtdjhQWmN3UWJYLURsSHljVVFyLVliU0VRNlZlTzRCVGdYdkE2aFlIekY5YVNqIiwiQnZjelJTOFl0cU93bkVLNEk5UTgyelpLUUw1clh0SU9tOEdEZE5tYThoVE5wb0d5TnBmTW9RZW9CdWJEZHBtUyIsIkNscmFHR3BlYVJHR0JpLTlPcThpN2RrSEhpbjhzbGxaWkc3VWE5bVc2a2I5NmNFM0dqR21RRFdDX3lqY0hESksiLCJfUTF2VkQ3bW1sQ1IySXhpUDR0WGJKM3pqQ3VGWGNOUjJ2X2hYVldWak1DMHRweFlfRzc5dm15UGNCRk1CV1FLIiwiZ1g4TU55MWIxd3dBajQwSk5oVzl0Qk1ickMxbjdjcXJyWVVWTFJnOXZ1c2szaGdrM0RYSnF2T1FnZW1haUJYaCJdLCJfc2RfYWxnIjoic2hhLTM4NCJ9.AZsWqI-NY3-ce3xfH3Fjt1z7nsF2F6eQMaNVfZb7zhEk3OclAfWlZ2kA9XyeBvaFWSLuy695ktSU0MxaCGwnBQ~WyI3MTkxYWVjYTc2NzEyNmVmIiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyIwNzQ5Yjc5ZTVjMjVmY2RhIiwibG9jYWxpdHkiLCJDbHVqIl0~WyI4MTgwZTVjNDQyMzQyZjVlIiwiUk8iXQ~WyJiYWExZWUwMDQxMjk0NjQ2IiwiREUiXQ~WyIzZTljNzY0ODM1OGY0ZWI5IiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyIzOTAzZThjODYxZGYxMGJmIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyJiZDdmODdlMjljNjRmZmFjIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiYjBjZDkxMzg2ZWZkNGI1IiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiaFQwV0VOdUFJZE5PaUpfYUNMYnZQeG1YZmxHcEZqbTR2eTRvVTBCcUdOYkg0VnA3TW9rQ0VQb0JLWFBnSFM5QiIsInB0SzZTOUE1WlJzbnB0UWZ4QjBBZEdHbXc1YnFTalhkTjRvWkNJU0JLZjRUR0daVFJUUnlRWVdYYjlzeXROai0iXX1d~", + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJUcURkRFVvX0pNa3NGT3J3Q3ZPS3JjajZaZXRWeC1qTkVHa0xhTVlGS0lZM3lmVDNkSzBWanlPRTBubWNESUZXIn0seyIuLi4iOiJWQ1RERXVkcUQxRHdlUTRfV1JFSHh5SWZFQzl1Z2hzODZKMGtYUEcwem5JUE1Sbm9vcnJYaVNhUTVVZXY5eFpSIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiaWhmNi1BVlhLdlpTTlo5bjZaU1ByWUtzTzZfNVdaQ3g2bHo4THRfM3FuYyIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIjZOT0luMkU4NEpUbkJlZWpmZ1FfN3otakZqWWM0aWZWVGI1Y1FxYjhZajh6ZFFiQlB2QnNpZnNuNXBvS3N1cGwiLCJCbXlmRDZ0cHRrZDMtSXo4RTVtdjhQWmN3UWJYLURsSHljVVFyLVliU0VRNlZlTzRCVGdYdkE2aFlIekY5YVNqIiwiQnZjelJTOFl0cU93bkVLNEk5UTgyelpLUUw1clh0SU9tOEdEZE5tYThoVE5wb0d5TnBmTW9RZW9CdWJEZHBtUyIsIkNscmFHR3BlYVJHR0JpLTlPcThpN2RrSEhpbjhzbGxaWkc3VWE5bVc2a2I5NmNFM0dqR21RRFdDX3lqY0hESksiLCJfUTF2VkQ3bW1sQ1IySXhpUDR0WGJKM3pqQ3VGWGNOUjJ2X2hYVldWak1DMHRweFlfRzc5dm15UGNCRk1CV1FLIiwiZ1g4TU55MWIxd3dBajQwSk5oVzl0Qk1ickMxbjdjcXJyWVVWTFJnOXZ1c2szaGdrM0RYSnF2T1FnZW1haUJYaCJdLCJfc2RfYWxnIjoic2hhLTM4NCJ9.AZsWqI-NY3-ce3xfH3Fjt1z7nsF2F6eQMaNVfZb7zhEk3OclAfWlZ2kA9XyeBvaFWSLuy695ktSU0MxaCGwnBQ~WyJiZDdmODdlMjljNjRmZmFjIiwiYWdlX292ZXJfMTgiLHRydWVd~WyJiYjBjZDkxMzg2ZWZkNGI1IiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiaFQwV0VOdUFJZE5PaUpfYUNMYnZQeG1YZmxHcEZqbTR2eTRvVTBCcUdOYkg0VnA3TW9rQ0VQb0JLWFBnSFM5QiIsInB0SzZTOUE1WlJzbnB0UWZ4QjBBZEdHbXc1YnFTalhkTjRvWkNJU0JLZjRUR0daVFJUUnlRWVdYYjlzeXROai0iXX1d~WyIwNzQ5Yjc5ZTVjMjVmY2RhIiwibG9jYWxpdHkiLCJDbHVqIl0~WyI4MTgwZTVjNDQyMzQyZjVlIiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiTlFRdGRHdVc3QmRadWpQUjBRYWRaQ21PMERaSTY3ZDBBMFd4TEZrOTRSaE5KYkd4ZXJhcXM2WDBDalQ3NVEwaSJ9.7yJQbLknl6-Miy4ITnhBhHCWXpslFPhMZewEQyC3bl20cB6QEG6C1SQtl9X7RKe5u3CVCGyFmrydYQ-bSfA7Cg", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "not understood" + } + }, + { + "nume": "NEGATIV: dezvaluirea age_over_18 cu valoarea schimbata (fara KB)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLGZhbHNlXQ~", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "not referenced" + } + }, + { + "nume": "NEGATIV: KB pentru alt aud", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL290aGVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.NmNA2UuLcu2CkbufwjC4GcipNF9EwR5Di43bsRk-RXjPE-cWVS2eljbadOkZU1yQDkQH-yiYDh6e1fDsQXRYAg", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "made for" + } + }, + { + "nume": "NEGATIV: alg none", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "prezentare": "eyJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.~", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "not accepted" + } + }, + { + "nume": "NEGATIV: acelasi digest de doua ori in _sd (re-semnat de emitentul LOR)", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSIsIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiXSwiX3NkX2FsZyI6InNoYS0yNTYifQ.bnB_QWkrH4IGE4RkrBrwoy-sIS1hSL0f4azdh2DlZ-obGdZKFvz_w76VW_x2PEMKugH01HYgAnDGqHqt0cCLDg~WyI2NjQxOGNlZWY4M2VkODY4Iiwic3RyZWV0X2FkZHJlc3MiLCJTdHIuIEx1bmdhIDEiXQ~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~WyIzMjc5ZTM1NjI4ZDZlYTVjIiwiREUiXQ~WyI3ZTBkNmNkYTliMmFkYzc1IiwiZ2l2ZW5fbmFtZSIsIkFuYSJd~WyJhYzBlZjNhZWU0N2QwZjlkIiwiZmFtaWx5X25hbWUiLCJQb3AiXQ~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "more than once" + } + }, + { + "nume": "NEGATIV: KB semnat de alta cheie decat cnf.jwk", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~WyIwYTQwZTZjZDg0ZmJjNGU2IiwiUk8iXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.rEJpb_jkTpXEe0iDbhE8KNPo2LWzRwdaFg88pJzE7nUqSx16N7TxK-rcIabqavi1NsFbPdUcW2mkn604zjYWDg", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "key binding: the signature does not verify" + } + }, + { + "nume": "NEGATIV: o dezvaluire scoasa din prezentare dupa semnarea KB", + "alg": "EdDSA", + "issuerJwk": { + "crv": "Ed25519", + "x": "-aHX28vHzHZU6u5ottr9OKLK2dDhU3l50i21w_Ry7Zw", + "kty": "OKP" + }, + "prezentare": "eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5sb3IuZXhhbXBsZSIsImlhdCI6MTc5MjI4MTYwMCwiZXhwIjoxODIzODE3NjAwLCJuYXRpb25hbGl0aWVzIjpbeyIuLi4iOiJjVWJRWHNNaU9jTGxoTlNmaVo1MW5UaWdUaVRwY2xhQ1lsYy1Uc3JHWVhBIn0seyIuLi4iOiJSNjRmdGNLMW50Mnl1TktiVmJBRjg1M1dUelYyaWg3clRUS0NwNU00QmxnIn1dLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiSEZ5MHZ6dDNhWHhEZU1EbjY0Y2JYN3owdXVDbDh2MlZBb0VPTzNkd25kTSIsImt0eSI6Ik9LUCJ9fSwiX3NkIjpbIkNLdE5BaGFvTlMyY0h1U1hCeUJzclJHcTE2dmZBUTF6Tk1TUGs4ZktkTkkiLCJGQnlGeXlZWkUwMjdWU1NZeUVLTS03dUZMNTFSY09fdk9jUFdZWHVpU09vIiwiUGNEY2l0S0dJbm0wQmpBR0x5Q3ptaU52YU5aSGZZVl9GNmRWeUM1LWd1NCIsIlNyS3JyYk1wNWM2OG5FVnFmNmJ0VWFTYWwxV3dCc0J0OENJcUJHTGFTYmciLCJXajlCTkc4ZVhnWU1zd0tJVEhOd3kzQXdyV1hXVC1XMGRGbjFpSWdGdXRNIiwiblo0aUZuSlB2OTkyb2lGLVFJaFMwT1g5WDllM2FqODVKb0o0bnVzVU1jTSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.Pqsg-0U-7cVdQqkjJ7qDg6e9fQpCa-EbhRwR9PpWszZkAxterCEgzsYk0dtC-REgTCuSRew50ZuAQQmiwE18Aw~WyIzNjQxOGIzNjIzZDM2Zjc2IiwiYWdlX292ZXJfMTgiLHRydWVd~WyJjNTU0ODYyODA2MzVmZTRlIiwiYWRkcmVzcyIseyJjb3VudHJ5IjoiUk8iLCJfc2QiOlsiTGw0SnlHS2hCNFpZZGdkZy05LU5iTGZlaDVBQkdnYmRNVUpsZHNGVUJlOCIsIlpKc1NmZTVMWEFmVTQyYVBEMU9SdU1IblNqVWZ3NHVqeWZPdXhuaExDQ28iXX1d~WyJiNDhkMDc1YzExZGE2ZDAwIiwibG9jYWxpdHkiLCJDbHVqIl0~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJub25jZSI6ImludGVyb3AtYzM4MmM5OWJjMjgwIiwiaWF0IjoxNzkyMjgxNjAwLCJzZF9oYXNoIjoiM243Q1hEQmk2T2FRYmg0YUQ2R3lxaHZWWGF5YXhfZFJNdjNZeHNZME5mTSJ9.Rr9sBYmA9BEp-uSt_d4w854OLSM7S6Sm-L_UHPGTHwVLpY_hVmLilgbZ9KF-X6Mk29KSQEIanQKOW1dzGcQFAg", + "optiuni": { + "expectedTyp": null + }, + "asteptat": { + "valid": false, + "motiv": "sd_hash" + } + } + ] +} diff --git a/identity/interop/interop-sdjwt-vc.mjs b/identity/interop/interop-sdjwt-vc.mjs new file mode 100644 index 0000000..e352a92 --- /dev/null +++ b/identity/interop/interop-sdjwt-vc.mjs @@ -0,0 +1,202 @@ +#!/usr/bin/env node +// interop-sdjwt-vc.mjs: interoperarea SD-JWT VC (draft-ietf-oauth-sd-jwt-vc-19) si a listei de stare (Token Status List, +// draft-ietf-oauth-status-list-21) MASURATA in ambele sensuri intre sdjwt-vc.mjs (al nostru) si @sd-jwt/sd-jwt-vc (openwallet-foundation-labs), +// cu @owf/token-status-list pentru lista LOR de stare si jose ca motor JWS al partii straine (pista B, B9, 2026-10-18). +// node interop-sdjwt-vc.mjs --lab [--scrie] +// --scrie rescrie fixturi-interop-sdjwt-vc.json (credentialele si listele de stare ale LOR, chei publice de proba, versiuni) si +// rezultate-interop-sdjwt-vc.json, ca proba-sdjwt-vc.mjs sa le judece OFFLINE +// Iesire: 0 = fiecare rand a dat EXACT verdictele asteptate de la amandoua partile; 1 = divergent; 2 = NEMASURAT (bibliotecile lipsesc). +// Ceas FIX (CEAS), nicio cheie privata nu se tipareste sau se scrie (chei de proba nascute la rulare, AERE-SINTETIC). +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { createRequire } from 'node:module'; +import { pathToFileURL, fileURLToPath } from 'node:url'; +import * as I from '../identity.mjs'; +import * as J from '../sdjwt.mjs'; +import * as V from '../sdjwt-vc.mjs'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +const arg = (n) => { const i = process.argv.indexOf(n); return i === -1 ? null : (process.argv[i + 1] ?? null); }; +const LAB = arg('--lab') ?? process.env.AERE_SDJWT_LAB ?? null; +const SCRIE = process.argv.includes('--scrie'); +const CEAS = 1792281600, ACUM = CEAS + 60, LA = new Date(ACUM * 1000); +const AUD = 'https://verifier.example', NONCE = 'interop-vc-' + crypto.randomBytes(6).toString('hex'); +const VCT = 'urn:eudi:pid:1', URI = 'https://issuer.example/status/pid/1', IDX = 5, N = 16; +const b64u = (b) => Buffer.from(b).toString('base64url'); +const dec = (s) => JSON.parse(Buffer.from(s, 'base64url').toString('utf8')); +const sortat = (o) => (Array.isArray(o) ? o.map(sortat) : o && typeof o === 'object' ? Object.fromEntries(Object.keys(o).sort().map((k) => [k, sortat(o[k])])) : o); +const egal = (a, b) => JSON.stringify(sortat(a)) === JSON.stringify(sortat(b)); +const taie = (s, n = 110) => (s == null ? '' : String(s).replace(/\s+/g, ' ').slice(0, n)); + +async function main() { + if (!LAB || !fs.existsSync(path.join(LAB, 'node_modules'))) { console.log('NEMASURAT: laboratorul cu bibliotecile straine lipseste (--lab sau AERE_SDJWT_LAB)'); return 2; } + const req = createRequire(path.join(LAB, 'package.json')); + const modul = async (nume) => { let cale; try { cale = req.resolve(nume); } catch { return null; } const m = await import(pathToFileURL(cale).href); return m.digest || m.SDJwtVcInstance || m.compactVerify || m.StatusList ? m : (m.default ?? m); }; + const versiune = (nume) => { try { return JSON.parse(fs.readFileSync(path.join(LAB, 'node_modules', ...nume.split('/'), 'package.json'), 'utf8')).version; } catch { return null; } }; + const vc = await modul('@sd-jwt/sd-jwt-vc'), cn = await modul('@sd-jwt/crypto-nodejs'), jose = await modul('jose'), tsl = await modul('@owf/token-status-list'); + const lipsa = [['@sd-jwt/sd-jwt-vc', vc], ['@sd-jwt/crypto-nodejs', cn], ['jose', jose], ['@owf/token-status-list', tsl]].filter(([, m]) => !m).map(([n]) => n); + if (lipsa.length) { console.log('NEMASURAT: lipsesc din laborator: ' + lipsa.join(', ')); return 2; } + const biblioteci = { '@sd-jwt/sd-jwt-vc': versiune('@sd-jwt/sd-jwt-vc'), '@sd-jwt/core': versiune('@sd-jwt/core'), '@owf/token-status-list': versiune('@owf/token-status-list'), '@sd-jwt/crypto-nodejs': versiune('@sd-jwt/crypto-nodejs'), jose: versiune('jose'), node: process.version }; + console.log('biblioteci: ' + JSON.stringify(biblioteci)); + + // ---------------------------------------------------------------- partea LOR + const subtleParams = { EdDSA: { name: 'Ed25519' }, ES256: { name: 'ECDSA', hash: 'SHA-256' }, 'ML-DSA-65': { name: 'ML-DSA-65' } }; + async function cheiLor(alg) { const { publicKey, privateKey } = await jose.generateKeyPair(alg, { extractable: true }); const jwk = await jose.exportJWK(publicKey); if (alg === 'ML-DSA-65') jwk.alg = jwk.alg ?? 'ML-DSA-65'; return { publicKey, privateKey, jwk, alg }; } + const semnatorLor = (k) => async (data) => b64u(Buffer.from(await crypto.subtle.sign(subtleParams[k.alg], k.privateKey, Buffer.from(data, 'ascii')))); + let ultimaJose = ''; + async function verificatorJose(jwk, alg) { const key = await jose.importJWK(jwk, alg); return async (data, sig) => { try { await jose.compactVerify(data + '.' + sig, key, { algorithms: [alg] }); return true; } catch (e) { ultimaJose = e.message; return false; } }; } + const kbVerificatorJose = async (data, sig, payload) => { try { const h = dec(data.split('.')[0]); const key = await jose.importJWK(payload.cnf.jwk, payload.cnf.jwk.alg ?? h.alg); await jose.compactVerify(data + '.' + sig, key, { algorithms: [h.alg] }); return true; } catch (e) { ultimaJose = e.message; return false; } }; + const lor = (cfg) => new vc.SDJwtVcInstance({ hasher: cn.digest, saltGenerator: cn.generateSalt, hashAlg: 'sha-256', kbVerifier: kbVerificatorJose, ...cfg }); + async function lorVerifica(sd, { issuerJwk, alg, statusListJwt = null, optiuni = {} }) { + const inst = lor({ verifier: await verificatorJose(issuerJwk, alg), ...(statusListJwt != null ? { statusListFetcher: async () => statusListJwt } : {}) }); + try { const r = await inst.verify(sd, { currentDate: ACUM, keyBindingNonce: NONCE, expectedKeyBindingAudience: AUD, expectedVct: VCT, ...(statusListJwt == null ? { disableStatusVerification: true } : {}), ...optiuni }); return { valid: true, payload: r.payload, header: r.header, kb: r.kb ? r.kb.payload : null }; } catch (e) { return { valid: false, reason: e.message + (e.cause && e.cause.message ? ' <- ' + e.cause.message : '') + (/Signature/.test(e.message) && ultimaJose ? ' [jose: ' + ultimaJose + ']' : ''), code: e.code ?? null }; } + } + // lista LOR de stare: @owf/token-status-list + jose + async function listaLor(chei, statuses, bits = 1, { uri = URI, exp = CEAS + 3600 } = {}) { + const { header, payload } = tsl.createHeaderAndPayload(new tsl.StatusList(statuses, bits), { sub: uri, iat: CEAS, exp }, { alg: chei.alg, typ: 'statuslist+jwt' }); + return new jose.SignJWT(payload).setProtectedHeader(header).sign(chei.privateKey); + } + // ---------------------------------------------------------------- partea NOASTRA + function cheiNoi(alg) { + if (alg === 'ES256') { const k = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }); return { priv: k.privateKey, pub: k.publicKey, jwk: J.publicJwk(k.publicKey), alg }; } + const k = I.generateKeys(); return { priv: k, pub: k.public, jwk: J.publicJwk(k, alg), alg }; + } + const CL = { given_name: 'Ana', family_name: 'Pop', birthdate: '1990-01-01', age_over_18: true, nationalities: ['RO', 'DE'], address: { locality: 'Cluj', country: 'RO' }, issuing_authority: 'Example Authority', issuing_country: 'RO' }; + // status: null = credential FARA status (un `undefined` ar lua valoarea implicita a parametrului) + const noiEmite = ({ iss, hol, alg, status = { status_list: { idx: IDX, uri: URI } }, extra = {} }) => V.issueSdJwtVc({ issuer: iss.priv, holder: hol.pub, vct: VCT, claims: CL, disclosable: ['given_name', 'family_name', 'birthdate', 'age_over_18', 'address'], arrayDisclosable: ['nationalities'], iss: 'https://issuer.aere.example', iat: CEAS, nbf: CEAS, exp: CEAS + 365 * 86400, alg, holderAlg: hol.alg, decoys: 2, ...(status !== null ? { status } : {}), ...extra }); + const noiPrezinta = (sd, reveal, hol, extra = {}) => V.presentSdJwtVc({ sdJwt: sd, reveal, holder: hol.priv, holderAlg: hol.alg, audience: AUD, nonce: NONCE, iat: CEAS, ...extra }); + const noiVerifica = (sd, { issuerKey, alg, statusListJwt = null, optiuni = {} }) => V.verifySdJwtVc(sd, { issuerKey, issuerAlg: alg, audience: AUD, nonce: NONCE, now: LA, expectedVct: VCT, ...(statusListJwt != null ? { statusListJwt } : {}), ...optiuni }); + const listaNoi = (iss, statuses, bits = 1, extra = {}) => V.issueStatusListJwt({ issuer: iss.priv, alg: iss.alg, uri: URI, statuses, bits, iat: CEAS, exp: CEAS + 3600, ...extra }); + const toateValide = new Array(N).fill(0); + const revocat = toateValide.map((_, i) => (i === IDX ? 1 : 0)); + const suspendat = toateValide.map((_, i) => (i === IDX ? 2 : 0)); + + // ---------------------------------------------------------------- tabelul + const randuri = [], fixturi = []; let divergente = 0; + const fixtura = (f) => fixturi.push(f); + function rand({ sens, caz, noi, lor: l, asteptat, nota = '' }) { + const vN = noi.valid ? 'VALID' : 'REFUZ', vL = l.valid ? 'VALID' : 'REFUZ'; + const probleme = []; + if (vN !== asteptat.noi) probleme.push(`noi: ${vN} in loc de ${asteptat.noi} (${taie(noi.reason)})`); + if (vL !== asteptat.lor) probleme.push(`lor: ${vL} in loc de ${asteptat.lor} (${taie(l.reason)})`); + if (asteptat.motivNoi && !noi.valid && !asteptat.motivNoi.test(noi.reason || '')) probleme.push(`motivul nostru nu e cel asteptat: ${taie(noi.reason)}`); + if (asteptat.motivLor && !l.valid && !asteptat.motivLor.test(l.reason || '')) probleme.push(`motivul lor nu e cel asteptat: ${taie(l.reason)}`); + if (asteptat.continut && noi.valid && l.valid) { const m = asteptat.continut(noi, l); if (m) probleme.push(m); } + const ok = probleme.length === 0; if (!ok) divergente++; + randuri.push({ sens, caz, asteptat: `${asteptat.noi}/${asteptat.lor}`, noi: vN + (noi.valid ? '' : ': ' + taie(noi.reason)), lor: vL + (l.valid ? '' : ': ' + taie(l.reason)), ok, probleme, nota }); + console.log(` ${ok ? 'OK ' : 'DIVERGENT'} [${sens}] ${caz}\n noi: ${vN}${noi.valid ? '' : ' (' + taie(noi.reason, 130) + ')'}\n lor: ${vL}${l.valid ? '' : ' (' + taie(l.reason, 130) + ')'}${nota ? '\n nota: ' + nota : ''}${ok ? '' : '\n PROBLEME: ' + probleme.join('; ')}`); + } + const continutPid = (pn, pl) => { + const p = pn.payload; + if (p.vct !== VCT || p.birthdate !== '1990-01-01' || p.age_over_18 !== true || 'given_name' in p || !egal(p.nationalities, ['RO']) || !p.cnf) return 'payload-ul nostru nu e cel asteptat: ' + taie(JSON.stringify(p), 200); + if (!egal(pn.payload, pl.payload)) return 'payload-urile difera: noi ' + taie(JSON.stringify(sortat(pn.payload)), 160) + ' lor ' + taie(JSON.stringify(sortat(pl.payload)), 160); + return null; + }; + + // ================================================================ NOI -> LOR + const nl = {}; + for (const alg of ['EdDSA', 'ES256', 'ML-DSA-65']) { + const iss = cheiNoi(alg), hol = cheiNoi(alg); + const E = noiEmite({ iss, hol, alg }); + const p = noiPrezinta(E.sdJwt, ['birthdate', 'age_over_18', { element: 'RO', in: 'nationalities' }], hol); + const lista = listaNoi(iss, toateValide); + const noi = noiVerifica(p, { issuerKey: iss.jwk, alg, statusListJwt: lista }), l = await lorVerifica(p, { issuerJwk: iss.jwk, alg, statusListJwt: lista }); + rand({ sens: 'noi->lor', caz: `${alg}: SD-JWT VC (typ dc+sd-jwt, vct ${VCT}, status_list idx ${IDX}) + lista noastra de stare (toate 0), KB(aud, nonce)`, noi, lor: l, asteptat: { noi: 'VALID', lor: 'VALID', continut: (a, b) => continutPid(a, b) || (a.status && a.status.judged && a.status.value === 0 ? null : 'starea nu e judecata la noi: ' + JSON.stringify(a.status)) || (b.header && b.header.typ === 'dc+sd-jwt' ? null : 'typ-ul vazut de ei nu e dc+sd-jwt') } }); + nl[alg] = { iss, hol, E, p, lista }; + } + { + const { iss, hol, E, p } = nl.EdDSA; + const ambii = async (jeton, listaNoastra, optLor = {}, optNoi = {}) => [noiVerifica(jeton, { issuerKey: iss.jwk, alg: 'EdDSA', statusListJwt: listaNoastra, optiuni: optNoi }), await lorVerifica(jeton, { issuerJwk: iss.jwk, alg: 'EdDSA', statusListJwt: listaNoastra, optiuni: optLor })]; + let [n, l] = await ambii(p, listaNoi(iss, revocat)); + rand({ sens: 'noi->lor', caz: `NEGATIV: lista noastra cu indexul ${IDX} = 1 (INVALID, revocat)`, noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /status 1 \(INVALID\)/, motivLor: /Status is not valid/ } }); + [n, l] = await ambii(p, listaNoi(iss, suspendat, 2)); + rand({ sens: 'noi->lor', caz: `NEGATIV: lista noastra pe 2 biti cu indexul ${IDX} = 2 (SUSPENDED)`, noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /status 2 \(SUSPENDED\)/, motivLor: /Status is not valid/ } }); + [n, l] = await ambii(p, listaNoi(iss, toateValide, 8)); + rand({ sens: 'noi->lor', caz: 'lista noastra pe 8 biti, toate 0 (impachetarea pe mai multi biti citita de ei)', noi: n, lor: l, asteptat: { noi: 'VALID', lor: 'VALID' } }); + [n, l] = await ambii(p, listaNoi(iss, toateValide, 1, { uri: URI + '-alta' })); + rand({ sens: 'noi->lor', caz: 'NEGATIV: lista noastra publicata pentru ALT uri (sub != uri-ul din jeton)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /sub .* is not the uri/, motivLor: /sub|uri|Status List/i } }); + [n, l] = await ambii(p, null, {}, { requireStatus: false }); + rand({ sens: 'noi->lor', caz: 'fara lista: noi cu requireStatus:false (stare nejudecata, spusa), ei cu disableStatusVerification', noi: n, lor: l, asteptat: { noi: 'VALID', lor: 'VALID', continut: (a) => (a.status && a.status.present && !a.status.judged ? null : 'starea trebuia raportata prezenta si nejudecata: ' + JSON.stringify(a.status)) }, nota: 'la noi, implicit (requireStatus:true) acelasi credential e REFUZAT: ' + taie(noiVerifica(p, { issuerKey: iss.jwk, alg: 'EdDSA' }).reason, 90) }); + [n, l] = await ambii(p, listaNoi(iss, toateValide), { expectedVct: 'urn:eudi:pid:2' }, { expectedVct: 'urn:eudi:pid:2' }); + rand({ sens: 'noi->lor', caz: 'NEGATIV: verificatorul asteapta alt vct (urn:eudi:pid:2)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /not the type expected/, motivLor: /Invalid VCT/ } }); + const altAud = noiPrezinta(E.sdJwt, ['birthdate'], hol, { audience: 'https://other.example' }); + [n, l] = await ambii(altAud, listaNoi(iss, toateValide)); + rand({ sens: 'noi->lor', caz: 'NEGATIV: KB pentru alt aud', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /made for/, motivLor: /Invalid Key Binding audience/ } }); + // un credential fara status: valid la amandoi, fara lista + const faraStatus = noiEmite({ iss, hol, alg: 'EdDSA', status: null }); + [n, l] = await ambii(noiPrezinta(faraStatus.sdJwt, ['birthdate'], hol), null); + rand({ sens: 'noi->lor', caz: 'credential FARA status (nu numeste nicio lista): valid fara lista', noi: n, lor: l, asteptat: { noi: 'VALID', lor: 'VALID', continut: (a) => (a.status && !a.status.present ? null : 'status trebuia absent') } }); + // emitentul nostru refuza sa faca vct dezvaluibil (s.2.2.2.3); al lor la fel ("Cannot disclose protected field") + let mNoi = null; try { V.issueSdJwtVc({ issuer: iss.priv, holder: hol.pub, vct: VCT, iss: 'x', iat: CEAS, claims: { a: 1 }, disclosable: ['vct'] }); } catch (e) { mNoi = e.message; } + let mLor = null; try { await lor({ signer: semnatorLor(await cheiLor('EdDSA')), signAlg: 'EdDSA' }).issue({ vct: VCT, iss: 'x', iat: CEAS, a: 1 }, { _sd: ['vct'] }); } catch (e) { mLor = e.message; } + rand({ sens: 'noi->lor', caz: 'EMITERE: vct cerut dezvaluibil, refuzat de amandoi emitentii (s.2.2.2.3)', noi: { valid: !mNoi, reason: mNoi }, lor: { valid: !mLor, reason: mLor }, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /may not be selectively disclosed/, motivLor: /Cannot disclose protected field/ } }); + } + + // ================================================================ LOR -> NOI + const claimsLor = { vct: VCT, iss: 'https://issuer.lor.example', iat: CEAS, nbf: CEAS, exp: CEAS + 365 * 86400, status: { status_list: { idx: IDX, uri: URI } }, given_name: 'Ana', family_name: 'Pop', birthdate: '1990-01-01', age_over_18: true, nationalities: ['RO', 'DE'], address: { locality: 'Cluj', country: 'RO' }, issuing_authority: 'Example Authority', issuing_country: 'RO' }; + const frameLor = { _sd: ['given_name', 'family_name', 'birthdate', 'age_over_18', 'address'], nationalities: { _sd: [0, 1] }, _sd_decoy: 2 }; + const prezFrame = { birthdate: true, age_over_18: true, nationalities: { 0: true } }; + const lorEmitePrezinta = async (alg, claims = claimsLor) => { + const iss = await cheiLor(alg), hol = await cheiLor(alg); + const inst = lor({ signer: semnatorLor(iss), signAlg: alg, kbSigner: semnatorLor(hol), kbSignAlg: alg }); + const sd = await inst.issue({ ...claims, cnf: { jwk: hol.jwk } }, frameLor); + const p = await inst.present(sd, prezFrame, { kb: { payload: { aud: AUD, nonce: NONCE, iat: CEAS } } }); + return { iss, hol, sd, p }; + }; + const ln = {}; + for (const alg of ['EdDSA', 'ES256', 'ML-DSA-65']) { + const r = await lorEmitePrezinta(alg); + const lista = await listaLor(r.iss, toateValide); + const noi = noiVerifica(r.p, { issuerKey: r.iss.jwk, alg, statusListJwt: lista }), l = await lorVerifica(r.p, { issuerJwk: r.iss.jwk, alg, statusListJwt: lista }); + const antet = dec(r.sd.split('.')[0]); + rand({ sens: 'lor->noi', caz: `${alg}: SD-JWT VC al LOR (typ ${antet.typ}, status_list idx ${IDX}) + lista LOR de stare (@owf/token-status-list, toate 0), KB(aud, nonce); tipul implicit al nostru`, noi, lor: l, asteptat: { noi: 'VALID', lor: 'VALID', continut: (a, b) => continutPid(a, b) || (a.status && a.status.judged && a.status.value === 0 ? null : 'starea nu e judecata la noi: ' + JSON.stringify(a.status)) || (antet.typ === 'dc+sd-jwt' ? null : 'typ-ul lor nu e dc+sd-jwt: ' + antet.typ) } }); + ln[alg] = { ...r, lista }; + if (noi.valid) fixtura({ nume: `${alg}: SD-JWT VC @sd-jwt/sd-jwt-vc cu lista de stare @owf/token-status-list (toate 0)`, alg, issuerJwk: r.iss.jwk, sdJwt: r.sd, prezentare: r.p, statusListJwt: lista, expectedVct: VCT, optiuni: {}, asteptat: { valid: true, payload: noi.payload, disclosed: [...noi.disclosed].sort(), status: noi.status } }); + } + { + const { iss, hol, sd, p } = ln.EdDSA; + const neg = async (nume, { jeton = p, lista, motivNoi, motivLor, optNoi = {}, optLor = {}, asteptatNoi = 'REFUZ', asteptatLor = 'REFUZ', nota, fix = true }) => { + const n = noiVerifica(jeton, { issuerKey: iss.jwk, alg: 'EdDSA', statusListJwt: lista, optiuni: optNoi }), l = await lorVerifica(jeton, { issuerJwk: iss.jwk, alg: 'EdDSA', statusListJwt: lista, optiuni: optLor }); + rand({ sens: 'lor->noi', caz: nume, noi: n, lor: l, asteptat: { noi: asteptatNoi, lor: asteptatLor, motivNoi, motivLor }, nota }); + if (fix && (n.valid ? asteptatNoi === 'VALID' : asteptatNoi === 'REFUZ' && (!motivNoi || motivNoi.test(n.reason)))) fixtura({ nume, alg: 'EdDSA', issuerJwk: iss.jwk, prezentare: jeton, ...(lista != null ? { statusListJwt: lista } : {}), expectedVct: optNoi.expectedVct ?? VCT, optiuni: Object.fromEntries(Object.entries(optNoi).filter(([k]) => k !== 'expectedVct')), asteptat: n.valid ? { valid: true, payload: n.payload, disclosed: [...n.disclosed].sort(), status: n.status } : { valid: false, motiv: motivNoi.source } }); + }; + await neg(`NEGATIV: lista LOR cu indexul ${IDX} = 1 (INVALID)`, { lista: await listaLor(iss, revocat), motivNoi: /status 1 \(INVALID\)/, motivLor: /Status is not valid/ }); + await neg(`NEGATIV: lista LOR pe 2 biti cu indexul ${IDX} = 2 (SUSPENDED)`, { lista: await listaLor(iss, suspendat, 2), motivNoi: /status 2 \(SUSPENDED\)/, motivLor: /Status is not valid/ }); + await neg('lista LOR pe 8 biti, toate 0 (impachetarea lor pe mai multi biti citita de noi)', { lista: await listaLor(iss, toateValide, 8), asteptatNoi: 'VALID', asteptatLor: 'VALID' }); + // controlul pozitiv al impachetarii: o lista LOR cu stari diferite pe fiecare index, citita de noi index cu index + const amestec = [0, 1, 2, 3, 0, 1, 2, 3, 3, 2, 1, 0]; + const lAmestec = await listaLor(iss, amestec, 2); + const citit = V.readStatusListJwt(lAmestec, { key: iss.jwk, alg: 'EdDSA', uri: URI, now: LA }); + const citite = citit.ok ? amestec.map((_, i) => citit.statusAt(i)) : null; + rand({ sens: 'lor->noi', caz: 'IMPACHETARE: lista LOR pe 2 biti cu 12 stari amestecate, citite de noi index cu index', noi: { valid: citit.ok && egal(citite, amestec), reason: citit.ok ? 'citit ' + JSON.stringify(citite) : citit.reason }, lor: { valid: true }, asteptat: { noi: 'VALID', lor: 'VALID' }, nota: 'citit: ' + JSON.stringify(citite) + ' = scris: ' + JSON.stringify(amestec) }); + const lNoiAmestec = V.issueStatusListJwt({ issuer: cheiNoi('EdDSA').priv, uri: URI, statuses: amestec, bits: 2, iat: CEAS }); + const lorCitit = amestec.map((_, i) => tsl.getListFromStatusListJWT(lNoiAmestec).getStatus(i)); + rand({ sens: 'noi->lor', caz: 'IMPACHETARE: lista NOASTRA pe 2 biti cu 12 stari amestecate, citite de ei index cu index', noi: { valid: true }, lor: { valid: egal(lorCitit, amestec), reason: 'citit ' + JSON.stringify(lorCitit) }, asteptat: { noi: 'VALID', lor: 'VALID' }, nota: 'citit: ' + JSON.stringify(lorCitit) + ' = scris: ' + JSON.stringify(amestec) }); + await neg('NEGATIV: lista LOR pentru ALT uri (sub != uri-ul din jeton)', { lista: await listaLor(iss, toateValide, 1, { uri: URI + '-alta' }), motivNoi: /sub .* is not the uri/, motivLor: /sub|uri|Status List/i }); + await neg('NEGATIV: lista LOR expirata', { lista: await listaLor(iss, toateValide, 1, { exp: CEAS + 30 }), motivNoi: /status list: expired/, motivLor: /expired|exp/i }); + await neg('NEGATIV: verificatorul asteapta alt vct (urn:eudi:pid:2)', { lista: await listaLor(iss, toateValide), optNoi: { expectedVct: 'urn:eudi:pid:2' }, optLor: { expectedVct: 'urn:eudi:pid:2' }, motivNoi: /not the type expected/, motivLor: /Invalid VCT/ }); + await neg('NEGATIV: fara lista, la noi implicit (requireStatus:true): refuz numit; la ei disableStatusVerification: valid', { lista: null, motivNoi: /was not judged/, asteptatLor: 'VALID', nota: 'politica: noi nu dam VALID pe o stare nejudecata fara ca verificatorul sa o ceara explicit (requireStatus:false); ei lasa decizia pe disableStatusVerification' }); + await neg('fara lista, la noi cu requireStatus:false: valid, cu starea raportata nejudecata', { lista: null, optNoi: { requireStatus: false }, asteptatNoi: 'VALID', asteptatLor: 'VALID' }); + const altAud = await lor({ kbSigner: semnatorLor(hol), kbSignAlg: 'EdDSA' }).present(sd, prezFrame, { kb: { payload: { aud: 'https://other.example', nonce: NONCE, iat: CEAS } } }); + await neg('NEGATIV: KB pentru alt aud', { jeton: altAud, lista: await listaLor(iss, toateValide), motivNoi: /made for/, motivLor: /Invalid Key Binding audience/ }); + // un credential LOR fara vct: la noi refuzat (vct REQUIRED, s.2.2.2.3); la ei cu expectedVct refuzat + const { vct: _v, ...faraVct } = claimsLor; + const fv = await lorEmitePrezinta('EdDSA', faraVct); + const nFv = noiVerifica(fv.p, { issuerKey: fv.iss.jwk, alg: 'EdDSA', statusListJwt: await listaLor(fv.iss, toateValide) }), lFv = await lorVerifica(fv.p, { issuerJwk: fv.iss.jwk, alg: 'EdDSA', statusListJwt: await listaLor(fv.iss, toateValide) }); + rand({ sens: 'lor->noi', caz: 'NEGATIV: SD-JWT VC al LOR FARA vct (emitentul lor il lasa afara)', noi: nFv, lor: lFv, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /vct is required/, motivLor: /Invalid VCT/ }, nota: 'al lor: SDJwtVcInstance.issue nu cere vct; verificatorul lor il refuza numai daca i se da expectedVct' }); + const lFvFaraAsteptare = await lorVerifica(fv.p, { issuerJwk: fv.iss.jwk, alg: 'EdDSA', statusListJwt: await listaLor(fv.iss, toateValide), optiuni: { expectedVct: undefined } }); + rand({ sens: 'lor->noi', caz: 'DIFERENTA: acelasi SD-JWT VC fara vct, verificatorul LOR fara expectedVct', noi: nFv, lor: lFvFaraAsteptare, asteptat: { noi: 'REFUZ', lor: 'VALID' }, nota: 'al lor: fara expectedVct nu cere vct deloc; la noi expectedVct e obligatoriu si vct e cerut in jeton (s.2.2.2.3 REQUIRED)' }); + } + + const ok = randuri.filter((r) => r.ok).length; + console.log(`\ninterop-sdjwt-vc: ${ok}/${randuri.length} randuri cu verdictele asteptate de amandoua partile${divergente ? `, ${divergente} DIVERGENTE` : ''}`); + if (SCRIE) { + const generat = new Date().toISOString(); + fs.writeFileSync(path.join(AICI, 'fixturi-interop-sdjwt-vc.json'), JSON.stringify({ generat, unealta: 'tools/aere-identity/interop/interop-sdjwt-vc.mjs --scrie', nota: 'AERE-SINTETIC: credentiale emise de @sd-jwt/sd-jwt-vc si liste de stare de @owf/token-status-list (semnate prin WebCrypto/jose) cu chei de PROBA nascute la generare; numai cheile publice sunt aici. Judecate offline de proba-sdjwt-vc.mjs la ceasVerificare.', biblioteci, ceas: CEAS, ceasVerificare: ACUM, audience: AUD, nonce: NONCE, vct: VCT, cazuri: fixturi }, null, 1) + '\n'); + fs.writeFileSync(path.join(AICI, 'rezultate-interop-sdjwt-vc.json'), JSON.stringify({ generat, biblioteci, ceas: CEAS, randuri: randuri.map(({ sens, caz, asteptat, noi, lor, ok, nota }) => ({ sens, caz, asteptat, noi, lor, ok, nota })) }, null, 1) + '\n'); + console.log(`scrise: fixturi-interop-sdjwt-vc.json (${fixturi.length} cazuri), rezultate-interop-sdjwt-vc.json (${randuri.length} randuri)`); + } + return divergente ? 1 : 0; +} +main().then((c) => { process.exitCode = c; }, (e) => { console.log('STRICAT: ' + (e.stack || e)); process.exitCode = 2; }); diff --git a/identity/interop/interop-sdjwt.mjs b/identity/interop/interop-sdjwt.mjs new file mode 100644 index 0000000..5a55d6c --- /dev/null +++ b/identity/interop/interop-sdjwt.mjs @@ -0,0 +1,247 @@ +#!/usr/bin/env node +// interop-sdjwt.mjs: interoperarea SD-JWT (IETF RFC 9901) MASURATA in AMBELE sensuri intre sdjwt.mjs (al nostru) si @sd-jwt/core +// (openwallet-foundation-labs/identity-common-ts), cu jose ca motor JWS al partii straine si @sd-jwt/crypto-nodejs ca hasher/sare a ei +// (pista B, B9, 2026-10-18). Bibliotecile straine NU sunt in depozit si nu intra in modulul public: se dau prin `--lab ` (dosarul cu +// `node_modules`, in afara depozitului) sau AERE_SDJWT_LAB; lipsa lor e 2 NEMASURAT, pe nume. +// node interop-sdjwt.mjs --lab [--scrie] +// --scrie rescrie fixturi-interop-sdjwt.json (jetoanele LOR, cu cheile lor PUBLICE de proba si versiunile bibliotecii) si +// rezultate-interop-sdjwt.json (tabelul), ca proba-sdjwt.mjs sa le judece OFFLINE, fara biblioteca +// Iesire: 0 = fiecare rand a dat EXACT verdictele asteptate de la amandoua partile; 1 = cel putin un rand divergent; 2 = NEMASURAT. +// Ceasul e FIX (CEAS), ca fixturile sa ramana judecabile: jetoanele au iat = CEAS, exp = CEAS + 1 an, KB iat = CEAS; verificarea e la CEAS + 60 s. +// Nicio cheie privata nu se tipareste si nu se scrie: cheile de proba se nasc la rulare (AERE-SINTETIC) si mor cu procesul. +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { createRequire } from 'node:module'; +import { pathToFileURL, fileURLToPath } from 'node:url'; +import * as I from '../identity.mjs'; +import * as J from '../sdjwt.mjs'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +const arg = (n) => { const i = process.argv.indexOf(n); return i === -1 ? null : (process.argv[i + 1] ?? null); }; +const LAB = arg('--lab') ?? process.env.AERE_SDJWT_LAB ?? null; +const SCRIE = process.argv.includes('--scrie'); +const CEAS = 1792281600; // 2026-10-18T00:00:00Z +const ACUM = CEAS + 60; // ceasul verificatorului +const AUD = 'https://verifier.example', NONCE = 'interop-' + crypto.randomBytes(6).toString('hex'); +const b64u = (b) => Buffer.from(b).toString('base64url'); +const dec = (s) => JSON.parse(Buffer.from(s, 'base64url').toString('utf8')); +const sortat = (o) => (Array.isArray(o) ? o.map(sortat) : o && typeof o === 'object' ? Object.fromEntries(Object.keys(o).sort().map((k) => [k, sortat(o[k])])) : o); +const egal = (a, b) => JSON.stringify(sortat(a)) === JSON.stringify(sortat(b)); +const taie = (s, n = 90) => (s == null ? '' : String(s).replace(/\s+/g, ' ').slice(0, n)); + +async function main() { + if (!LAB || !fs.existsSync(path.join(LAB, 'node_modules'))) { console.log('NEMASURAT: laboratorul cu bibliotecile straine lipseste (--lab sau AERE_SDJWT_LAB)'); return 2; } + const req = createRequire(path.join(LAB, 'package.json')); + const modul = async (nume) => { let cale; try { cale = req.resolve(nume); } catch { return null; } const m = await import(pathToFileURL(cale).href); return m.digest || m.SDJwtInstance || m.compactVerify ? m : (m.default ?? m); }; + const versiune = (nume) => { try { return JSON.parse(fs.readFileSync(path.join(LAB, 'node_modules', ...nume.split('/'), 'package.json'), 'utf8')).version; } catch { return null; } }; + const core = await modul('@sd-jwt/core'), cn = await modul('@sd-jwt/crypto-nodejs'), jose = await modul('jose'); + const lipsa = [['@sd-jwt/core', core], ['@sd-jwt/crypto-nodejs', cn], ['jose', jose]].filter(([, m]) => !m).map(([n]) => n); + if (lipsa.length) { console.log('NEMASURAT: lipsesc din laborator: ' + lipsa.join(', ') + ' (npm install acolo, nu in depozit)'); return 2; } + const biblioteci = { '@sd-jwt/core': versiune('@sd-jwt/core'), '@sd-jwt/crypto-nodejs': versiune('@sd-jwt/crypto-nodejs'), jose: versiune('jose'), '@owf/identity-common': versiune('@owf/identity-common'), node: process.version }; + console.log('biblioteci: ' + JSON.stringify(biblioteci)); + + // ---------------------------------------------------------------- partea LOR: chei WebCrypto prin jose, semnare WebCrypto, verificare jose + const subtleParams = { EdDSA: { name: 'Ed25519' }, ES256: { name: 'ECDSA', hash: 'SHA-256' }, 'ML-DSA-65': { name: 'ML-DSA-65' } }; + async function cheiLor(alg) { + const { publicKey, privateKey } = await jose.generateKeyPair(alg, { extractable: true }); + const jwk = await jose.exportJWK(publicKey); if (alg === 'ML-DSA-65') jwk.alg = jwk.alg ?? 'ML-DSA-65'; + return { publicKey, privateKey, jwk, alg }; + } + const semnatorLor = (k) => async (data) => b64u(Buffer.from(await crypto.subtle.sign(subtleParams[k.alg], k.privateKey, Buffer.from(data, 'ascii')))); + let ultimaJose = ''; + async function verificatorJose(jwk, alg) { + const key = await jose.importJWK(jwk, alg); + return async (data, sig) => { try { await jose.compactVerify(data + '.' + sig, key, { algorithms: [alg] }); return true; } catch (e) { ultimaJose = e.message; return false; } }; + } + const kbVerificatorJose = async (data, sig, payload) => { + try { const h = dec(data.split('.')[0]); const key = await jose.importJWK(payload.cnf.jwk, payload.cnf.jwk.alg ?? h.alg); await jose.compactVerify(data + '.' + sig, key, { algorithms: [h.alg] }); return true; } catch (e) { ultimaJose = e.message; return false; } + }; + const lor = (cfg) => new core.SDJwtInstance({ hasher: cn.digest, saltGenerator: cn.generateSalt, hashAlg: 'sha-256', kbVerifier: kbVerificatorJose, ...cfg }); + async function lorVerifica(sd, { issuerJwk, alg, optiuni = {} }) { + const inst = lor({ verifier: await verificatorJose(issuerJwk, alg) }); + try { const r = await inst.verify(sd, { currentDate: ACUM, ...optiuni }); return { valid: true, payload: r.payload, kb: r.kb ? r.kb.payload : null }; } catch (e) { return { valid: false, reason: e.message + (/Signature/.test(e.message) && ultimaJose ? ' [jose: ' + ultimaJose + ']' : ''), code: e.code ?? null }; } + } + async function lorEmite({ chei, holder, claims, frame, header, hashAlg }) { + const inst = lor({ signer: semnatorLor(chei), signAlg: chei.alg, ...(hashAlg ? { hashAlg } : {}) }); + return inst.issue({ ...claims, cnf: { jwk: holder.jwk } }, frame, header ? { header } : undefined); + } + async function lorPrezinta(sd, frame, { holder, aud = AUD, nonce = NONCE }) { + const inst = lor({ kbSigner: semnatorLor(holder), kbSignAlg: holder.alg }); + return inst.present(sd, frame, { kb: { payload: { aud, nonce, iat: CEAS } } }); + } + // ---------------------------------------------------------------- partea NOASTRA + const LA = new Date(ACUM * 1000); + const noiVerifica = (sd, { issuerKey, alg, optiuni = {} }) => J.verifySdJwt(sd, { issuerKey, issuerAlg: alg, audience: AUD, nonce: NONCE, now: LA, ...optiuni }); + const CL = { given_name: 'Ana', family_name: 'Pop', age_over_18: true, nationalities: ['RO', 'DE'], address: { street_address: 'Str. Lunga 1', locality: 'Cluj', country: 'RO' } }; + function cheiNoi(alg) { + if (alg === 'ES256') { const k = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }); return { priv: k.privateKey, pub: k.publicKey, jwk: J.publicJwk(k.publicKey), alg }; } + const k = I.generateKeys(); return { priv: k, pub: k.public, jwk: J.publicJwk(k, alg), alg }; + } + const noiEmite = ({ iss, hol, alg, extra = {} }) => J.issueSdJwt({ issuer: iss.priv, holder: hol.pub, claims: CL, disclosable: ['given_name', 'family_name', 'age_over_18'], arrayDisclosable: ['nationalities'], iss: 'https://issuer.aere.example', iat: CEAS, exp: CEAS + 365 * 86400, alg, holderAlg: hol.alg, decoys: 2, ...extra }); + const noiPrezinta = (sd, reveal, hol, extra = {}) => J.presentSdJwt({ sdJwt: sd, reveal, holder: hol.priv, holderAlg: hol.alg, audience: AUD, nonce: NONCE, iat: CEAS, ...extra }); + const jwtDin = (antet, corp, k) => { const cap = b64u(JSON.stringify(antet)) + '.' + b64u(JSON.stringify(corp)); const date = Buffer.from(cap, 'ascii'); return cap + '.' + b64u(antet.alg === 'ES256' ? crypto.sign('sha256', date, { key: k, dsaEncoding: 'ieee-p1363' }) : crypto.sign(null, date, k)); }; + const sha = (d) => crypto.createHash('sha256').update(d).digest('base64url'); + + // ---------------------------------------------------------------- randurile tabelului + const randuri = [], fixturi = []; + let divergente = 0; + // asteptat: { noi: 'VALID'|'REFUZ', lor: 'VALID'|'REFUZ', motivNoi?: RegExp, motivLor?: RegExp, continut?: (payloadNoi, payloadLor) => string|null } + function rand({ sens, caz, noi, lor: l, asteptat, nota = '' }) { + const vN = noi.valid ? 'VALID' : 'REFUZ', vL = l.valid ? 'VALID' : 'REFUZ'; + const probleme = []; + if (vN !== asteptat.noi) probleme.push(`noi: ${vN} in loc de ${asteptat.noi} (${taie(noi.reason)})`); + if (vL !== asteptat.lor) probleme.push(`lor: ${vL} in loc de ${asteptat.lor} (${taie(l.reason)})`); + if (asteptat.motivNoi && !noi.valid && !asteptat.motivNoi.test(noi.reason || '')) probleme.push(`motivul nostru nu e cel asteptat: ${taie(noi.reason)}`); + if (asteptat.motivLor && !l.valid && !asteptat.motivLor.test(l.reason || '')) probleme.push(`motivul lor nu e cel asteptat: ${taie(l.reason)}`); + if (asteptat.continut && noi.valid && l.valid) { const m = asteptat.continut(noi.payload, l.payload); if (m) probleme.push(m); } + const ok = probleme.length === 0; if (!ok) divergente++; + randuri.push({ sens, caz, asteptat: `${asteptat.noi}/${asteptat.lor}`, noi: vN + (noi.valid ? '' : ': ' + taie(noi.reason, 110)), lor: vL + (l.valid ? '' : ': ' + taie(l.reason, 110)), ok, probleme, nota }); + console.log(` ${ok ? 'OK ' : 'DIVERGENT'} [${sens}] ${caz}\n noi: ${vN}${noi.valid ? '' : ' (' + taie(noi.reason, 120) + ')'}\n lor: ${vL}${l.valid ? '' : ' (' + taie(l.reason, 120) + ')'}${nota ? '\n nota: ' + nota : ''}${ok ? '' : '\n PROBLEME: ' + probleme.join('; ')}`); + } + const fixtura = (f) => fixturi.push(f); + + // ================================================================ sensul NOI -> LOR (emitem si prezentam noi, verifica @sd-jwt/core) + const noiLor = async (alg) => { + const iss = cheiNoi(alg), hol = cheiNoi(alg); + const E = noiEmite({ iss, hol, alg }); + const p = noiPrezinta(E.sdJwt, ['age_over_18', { element: 'RO', in: 'nationalities' }], hol); + const noi = noiVerifica(p, { issuerKey: iss.jwk, alg }), lorR = await lorVerifica(p, { issuerJwk: iss.jwk, alg, optiuni: { keyBindingNonce: NONCE, expectedKeyBindingAudience: AUD } }); + rand({ sens: 'noi->lor', caz: `${alg}: prezentare cu age_over_18 + nationalities[RO], 2 momeli, KB(aud, nonce)`, noi, lor: lorR, asteptat: { noi: 'VALID', lor: 'VALID', continut: (pn, pl) => { + if (!pl || pl.age_over_18 !== true || 'given_name' in pl || !egal(pl.nationalities, ['RO']) || !egal(pl.address, CL.address) || pl.iss !== 'https://issuer.aere.example') return 'payload-ul lor nu e cel asteptat: ' + taie(JSON.stringify(pl), 200); + if (!egal(pn, pl)) return 'payload-urile difera: noi ' + taie(JSON.stringify(sortat(pn)), 150) + ' lor ' + taie(JSON.stringify(sortat(pl)), 150); + return null; } } }); + return { iss, hol, E, p }; + }; + const nl = { EdDSA: await noiLor('EdDSA'), ES256: await noiLor('ES256'), 'ML-DSA-65': await noiLor('ML-DSA-65') }; + { // negative, sensul noi->lor: jetonul nostru stricat de noi, refuzat de AMANDOUA partile, cu motivul + const { iss, hol, E, p } = nl.EdDSA; + const verifAmbii = async (sd, optLor = {}) => [noiVerifica(sd, { issuerKey: iss.jwk, alg: 'EdDSA' }), await lorVerifica(sd, { issuerJwk: iss.jwk, alg: 'EdDSA', optiuni: { keyBindingNonce: NONCE, expectedKeyBindingAudience: AUD, ...optLor } })]; + // (a) o dezvaluire cu valoarea schimbata + const parti = noiPrezinta(E.sdJwt, ['given_name'], hol).split('~'); const c = dec(parti[1]); c[2] = 'Maria'; + let [n, l] = await verifAmbii([parti[0], b64u(JSON.stringify(c)), ''].join('~'), { keyBindingNonce: undefined }); + rand({ sens: 'noi->lor', caz: 'NEGATIV: dezvaluirea given_name cu valoarea schimbata (fara KB)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /not referenced/, motivLor: /Unreferenced disclosure/ } }); + // (b) KB facut pentru alt verificator + const altAud = noiPrezinta(E.sdJwt, ['age_over_18'], hol, { audience: 'https://other.example' }); + [n, l] = await verifAmbii(altAud); + rand({ sens: 'noi->lor', caz: 'NEGATIV: KB pentru alt aud (verificatorul cere al lui)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /made for/, motivLor: /Invalid Key Binding audience/ } }); + const lFaraAud = await lorVerifica(altAud, { issuerJwk: iss.jwk, alg: 'EdDSA', optiuni: { keyBindingNonce: NONCE } }); + rand({ sens: 'noi->lor', caz: 'DIFERENTA: acelasi KB pentru alt aud, cand verificatorul LOR nu da expectedKeyBindingAudience', noi: n, lor: lFaraAud, asteptat: { noi: 'REFUZ', lor: 'VALID' }, nota: 'al lor: @sd-jwt/core compara aud-ul KB numai daca i se cere (RFC 9901 s.7.3 pasul 5.f cere legarea de verificator); la noi aud si nonce sunt cerute mereu' }); + // (c) alg none + const corp = dec(E.sdJwt.split('~')[0].split('.')[1]); + const none = b64u(JSON.stringify({ alg: 'none', typ: J.TYP })) + '.' + b64u(JSON.stringify(corp)) + '.' + '~'; + [n, l] = await verifAmbii(none, { keyBindingNonce: undefined }); + rand({ sens: 'noi->lor', caz: 'NEGATIV: alg none', noi: { ...n, valid: n.valid }, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /not accepted/, motivLor: /"none" is not allowed/ } }); + // (d) acelasi digest de doua ori in _sd (jeton facut de mana, semnat cu cheia noastra) + const d = b64u(JSON.stringify(['salt-1', 'a', 1])), dg = sha(d); + const dublu = jwtDin({ alg: 'EdDSA', typ: J.TYP }, { _sd: [dg, dg], _sd_alg: 'sha-256', iss: 'x', iat: CEAS, exp: CEAS + 1000 }, iss.priv.privat.ed25519) + '~' + d + '~'; + [n, l] = await verifAmbii(dublu, { keyBindingNonce: undefined }); + rand({ sens: 'noi->lor', caz: 'NEGATIV: acelasi digest de doua ori in _sd', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /more than once/, motivLor: /Duplicate digest/ } }); + // (e) KB semnat de alta cheie decat cnf.jwk + const strain = cheiNoi('EdDSA'); + [n, l] = await verifAmbii(noiPrezinta(E.sdJwt, ['age_over_18'], strain)); + rand({ sens: 'noi->lor', caz: 'NEGATIV: KB semnat de alta cheie decat cnf.jwk', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /key binding: the signature does not verify/, motivLor: /Invalid JWT Signature/ } }); + // (f) _sd_alg imbricat (jeton facut de mana) + const imb = jwtDin({ alg: 'EdDSA', typ: J.TYP }, { iss: 'x', iat: CEAS, exp: CEAS + 1000, _sd_alg: 'sha-256', meta: { _sd_alg: 'sha-256', note: 1 } }, iss.priv.privat.ed25519) + '~'; + [n, l] = await verifAmbii(imb, { keyBindingNonce: undefined }); + rand({ sens: 'noi->lor', caz: 'NEGATIV: _sd_alg imbricat (RFC 9901 s.4.1.1 MUST NOT)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi: /_sd_alg below the top level/, motivLor: /Nested _sd_alg/ }, nota: 'reparat la noi pe 2026-10-18: pana atunci _sd_alg imbricat era pastrat ca afirmatie' }); + // (g) prezentarea cu KB, dar verificatorul LOR fara nonce: KB-ul nu e judecat deloc + const lFaraNonce = await lorVerifica(p, { issuerJwk: iss.jwk, alg: 'EdDSA', optiuni: {} }); + rand({ sens: 'noi->lor', caz: 'DIFERENTA: prezentarea cu KB, verificatorul LOR fara keyBindingNonce (si fara cerinta de KB)', noi: J.verifySdJwt(p, { issuerKey: iss.jwk, now: LA }), lor: lFaraNonce, asteptat: { noi: 'REFUZ', lor: 'VALID' }, nota: 'al lor: fara keyBindingNonce @sd-jwt/core nu judeca KB-ul prezent si nu il cere; la noi fara aud+nonce o prezentare cu KB e refuzata (RFC 9901 s.7.3)' }); + // (h) typ: al nostru e explicit (aere+sd-jwt); ei nu verifica typ-ul (RFC 9901 s.9.11 RECOMMENDED pentru verificatori) + const tipJwt = jwtDin({ alg: 'EdDSA', typ: 'JWT' }, corp, iss.priv.privat.ed25519) + '~'; + [n, l] = await verifAmbii(tipJwt, { keyBindingNonce: undefined }); + rand({ sens: 'noi->lor', caz: 'DIFERENTA: jetonul emitentului cu typ JWT (ne-explicit)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'VALID', motivNoi: /typ/ }, nota: 'al lor: @sd-jwt/core nu verifica typ-ul jetonului emitentului; RFC 9901 s.9.11 RECOMANDA ca verificatorii sa il verifice; la noi expectedTyp:null il lasa' }); + } + + // ================================================================ sensul LOR -> NOI (emite si prezinta @sd-jwt/core, verificam noi) + const claimsLor = { iss: 'https://issuer.lor.example', iat: CEAS, exp: CEAS + 365 * 86400, given_name: 'Ana', family_name: 'Pop', age_over_18: true, nationalities: ['RO', 'DE'], address: { street_address: 'Str. Lunga 1', locality: 'Cluj', country: 'RO' } }; + const frameLor = { _sd: ['given_name', 'family_name', 'age_over_18', 'address'], address: { _sd: ['street_address', 'locality'] }, nationalities: { _sd: [0, 1] }, _sd_decoy: 2 }; + const prezFrame = { age_over_18: true, address: { locality: true }, nationalities: { 0: true } }; + const asteptatLorNoi = (pl, issJwk) => { + if (pl.age_over_18 !== true || 'given_name' in pl || 'family_name' in pl) return 'afirmatiile ascunse/aratate nu sunt cele asteptate: ' + taie(JSON.stringify(pl), 200); + if (!egal(pl.address, { locality: 'Cluj', country: 'RO' }) || !egal(pl.nationalities, ['RO'])) return 'dezvaluirile imbricate/de lista nu sunt cele asteptate: ' + taie(JSON.stringify(pl), 200); + if (pl.iss !== 'https://issuer.lor.example' || !pl.cnf || !pl.cnf.jwk) return 'iss/cnf lipsesc'; + return null; + }; + const lorNoi = async (alg, { header, hashAlg, nume } = {}) => { + const iss = await cheiLor(alg), hol = await cheiLor(alg); + const sd = await lorEmite({ chei: iss, holder: hol, claims: claimsLor, frame: frameLor, header, hashAlg }); + const p = await lorPrezinta(sd, prezFrame, { holder: hol }); + const lorR = await lorVerifica(p, { issuerJwk: iss.jwk, alg, optiuni: { keyBindingNonce: NONCE, expectedKeyBindingAudience: AUD } }); + const optiuni = header ? {} : { expectedTyp: null }; + const noi = noiVerifica(p, { issuerKey: iss.jwk, alg, optiuni }); + return { iss, hol, sd, p, lorR, noi, optiuni }; + }; + const ln = {}; + for (const alg of ['EdDSA', 'ES256', 'ML-DSA-65']) { + const r = await lorNoi(alg); + ln[alg] = r; + rand({ sens: 'lor->noi', caz: `${alg}: dezvaluiri imbricate (address.locality), element de lista (nationalities[0]), 2 momeli, KB(aud, nonce); verificat cu expectedTyp:null`, noi: r.noi, lor: r.lorR, asteptat: { noi: 'VALID', lor: 'VALID', continut: (pn, pl) => asteptatLorNoi(pn) || (egal(pn, pl) ? null : 'payload-urile difera: noi ' + taie(JSON.stringify(sortat(pn)), 150) + ' lor ' + taie(JSON.stringify(sortat(pl)), 150)) } }); + if (r.noi.valid) fixtura({ nume: `${alg}: prezentare @sd-jwt/core cu dezvaluiri imbricate, element de lista, momeli si KB (fara typ)`, alg, issuerJwk: r.iss.jwk, sdJwt: r.sd, prezentare: r.p, optiuni: r.optiuni, asteptat: { valid: true, payload: r.noi.payload, disclosed: [...r.noi.disclosed].sort() } }); + } + { // typ-ul: jetonul LOR implicit nu are typ; cu header {typ} explicit, verificatorul nostru implicit il primeste + const r = ln.EdDSA; + const implicitTyp = noiVerifica(r.p, { issuerKey: r.iss.jwk, alg: 'EdDSA' }); + rand({ sens: 'lor->noi', caz: 'DIFERENTA: acelasi jeton LOR, verificat cu tipul implicit cerut de noi (orice ...+sd-jwt)', noi: implicitTyp, lor: r.lorR, asteptat: { noi: 'REFUZ', lor: 'VALID', motivNoi: /typ/ }, nota: 'al lor: SDJwtInstance nu pune typ implicit (SDJwtVcInstance pune dc+sd-jwt); RFC 9901 s.9.11: tipul explicit e RECOMMENDED; la noi se primeste cu expectedTyp:null sau cu typ dat la emitere' }); + const antetLor = dec(r.sd.split('.')[0]); if ('typ' in antetLor) throw new Error('presupunerea "core nu pune typ" e falsa: ' + JSON.stringify(antetLor)); + const t = await lorNoi('EdDSA', { header: { typ: 'example+sd-jwt' } }); + rand({ sens: 'lor->noi', caz: 'EdDSA: jetonul LOR emis cu header typ example+sd-jwt, verificat cu tipul implicit al nostru', noi: t.noi, lor: t.lorR, asteptat: { noi: 'VALID', lor: 'VALID', continut: (pn) => asteptatLorNoi(pn) } }); + if (t.noi.valid) fixtura({ nume: 'EdDSA: prezentare @sd-jwt/core cu typ example+sd-jwt (tipul implicit al verificatorului nostru)', alg: 'EdDSA', issuerJwk: t.iss.jwk, sdJwt: t.sd, prezentare: t.p, optiuni: {}, asteptat: { valid: true, payload: t.noi.payload, disclosed: [...t.noi.disclosed].sort() } }); + // _sd_alg sha-384: ei il emit, noi il refuzam (RFC 9901 s.4.1.1: sha-256 MUST; restul e politica) + const s3 = await lorNoi('EdDSA', { hashAlg: 'sha-384' }); + rand({ sens: 'lor->noi', caz: 'DIFERENTA: jetonul LOR cu _sd_alg sha-384', noi: s3.noi, lor: s3.lorR, asteptat: { noi: 'REFUZ', lor: 'VALID', motivNoi: /not understood/ }, nota: 'a noastra, dinadins: verificatorul nostru stie numai sha-256 (RFC 9901 s.4.1.1: sha-256 MUST be supported; alte functii sunt politica); @sd-jwt/core accepta lista IANA fara formele trunchiate' }); + if (!s3.noi.valid) fixtura({ nume: 'EdDSA: jetonul @sd-jwt/core cu _sd_alg sha-384 (la noi: refuzat, numai sha-256)', alg: 'EdDSA', issuerJwk: s3.iss.jwk, sdJwt: s3.sd, prezentare: s3.p, optiuni: { expectedTyp: null }, asteptat: { valid: false, motiv: 'not understood' } }); + // sarea: cati biti de entropie pune generatorul LOR de sare, fata de al nostru (RFC 9901 s.9.3: RECOMMENDED minim 128 de biti) + const sareLor = dec(r.sd.split('~')[1])[0], sareNoi = dec(nl.EdDSA.E.sdJwt.split('~')[1])[0]; + const bitiLor = /^[0-9a-f]+$/.test(sareLor) ? sareLor.length * 4 : Buffer.from(sareLor, 'base64url').length * 8, bitiNoi = Buffer.from(sareNoi, 'base64url').length * 8; + rand({ sens: 'lor->noi', caz: `DIFERENTA: sarea dezvaluirii: lor ${sareLor.length} caractere (${bitiLor} biti), noi ${sareNoi.length} caractere (${bitiNoi} biti)`, noi: { valid: bitiNoi >= 128 }, lor: { valid: bitiLor >= 128, reason: `${bitiLor} biti sub cei 128 RECOMANDATI (RFC 9901 s.9.3)` }, asteptat: { noi: 'VALID', lor: bitiLor >= 128 ? 'VALID' : 'REFUZ' }, nota: 'al lor: generateSalt(16) din @sd-jwt/crypto-nodejs da 16 caractere hexa = 64 de biti; generatorul de sare e injectabil, deci un emitent poate pune unul de 128 de biti; verificatorii nu judeca lungimea sarii' }); + } + { // negative, sensul lor->noi: jetonul LOR stricat, refuzat de AMANDOUA partile, cu motivul; fiecare intra in fixturi cu motivul nostru + const { iss, hol, sd, p } = ln.EdDSA; + const ambii = async (jeton, optLor = { keyBindingNonce: NONCE, expectedKeyBindingAudience: AUD }) => [noiVerifica(jeton, { issuerKey: iss.jwk, alg: 'EdDSA', optiuni: { expectedTyp: null } }), await lorVerifica(jeton, { issuerJwk: iss.jwk, alg: 'EdDSA', optiuni: optLor })]; + const neg = async (nume, jeton, motivNoi, motivLor, optLor) => { + const [n, l] = await ambii(jeton, optLor); + rand({ sens: 'lor->noi', caz: 'NEGATIV: ' + nume, noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: 'REFUZ', motivNoi, motivLor } }); + if (!n.valid && motivNoi.test(n.reason)) fixtura({ nume: 'NEGATIV: ' + nume, alg: 'EdDSA', issuerJwk: iss.jwk, prezentare: jeton, optiuni: { expectedTyp: null }, asteptat: { valid: false, motiv: motivNoi.source } }); + }; + // (a) valoarea unei dezvaluiri schimbata, in prezentarea LOR (fara KB ca sa nu cada intai pe sd_hash) + const pFaraKb = await lor({}).present(sd, { age_over_18: true }); + const parti = pFaraKb.split('~'); const c = dec(parti[1]); c[2] = false; + await neg('dezvaluirea age_over_18 cu valoarea schimbata (fara KB)', [parti[0], b64u(JSON.stringify(c)), ''].join('~'), /not referenced/, /Unreferenced disclosure/, {}); + // (b) KB pentru alt aud + await neg('KB pentru alt aud', await lorPrezinta(sd, prezFrame, { holder: hol, aud: 'https://other.example' }), /made for/, /Invalid Key Binding audience/); + // (c) alg none peste payload-ul LOR + const corpLor = dec(sd.split('~')[0].split('.')[1]); + await neg('alg none', b64u(JSON.stringify({ alg: 'none' })) + '.' + b64u(JSON.stringify(corpLor)) + '.' + '~', /not accepted/, /"none" is not allowed/, {}); + // (d) acelasi digest de doua ori: payload-ul LOR cu primul digest din _sd dublat, re-semnat de semnatorul LOR + const dublu = { ...corpLor, _sd: [...corpLor._sd, corpLor._sd[0]] }; + const capD = b64u(JSON.stringify(dec(sd.split('.')[0]))) + '.' + b64u(JSON.stringify(dublu)); + await neg('acelasi digest de doua ori in _sd (re-semnat de emitentul LOR)', capD + '.' + await semnatorLor(iss)(capD) + '~' + sd.split('~').slice(1).join('~'), /more than once/, /Duplicate digest/, {}); + // (e) KB semnat de alta cheie decat cnf.jwk + await neg('KB semnat de alta cheie decat cnf.jwk', await lorPrezinta(sd, prezFrame, { holder: await cheiLor('EdDSA') }), /key binding: the signature does not verify/, /Invalid JWT Signature/); + // (f) o dezvaluire scoasa dupa semnarea KB + const pp = p.split('~'); const kb = pp.pop(); const scoasa = [...pp.slice(0, -1), kb].join('~'); + await neg('o dezvaluire scoasa din prezentare dupa semnarea KB', scoasa, /sd_hash/, /sd_hash/); + } + { // sigiliul post-cuantic in ambele sensuri a fost in randurile ML-DSA-65 de mai sus; aici, ce NU merge: cheia ML-DSA-65 fara `alg` in JWK + const r = ln['ML-DSA-65']; + const faraAlg = { ...r.iss.jwk }; delete faraAlg.alg; + const n = noiVerifica(r.p, { issuerKey: faraAlg, alg: 'ML-DSA-65', optiuni: { expectedTyp: null } }); + let l; try { await jose.importJWK(faraAlg, 'ML-DSA-65'); l = { valid: true }; } catch (e) { l = { valid: false, reason: 'jose.importJWK: ' + e.message }; } + rand({ sens: 'lor->noi', caz: 'ML-DSA-65: cheia AKP FARA parametrul alg (RFC 9964 s.3 il cere)', noi: n, lor: l, asteptat: { noi: 'REFUZ', lor: l.valid ? 'VALID' : 'REFUZ' }, nota: 'masurat: ' + (l.valid ? 'jose o primeste cu alg dat la import' : 'jose o refuza') + '; node:crypto refuza JWK-ul AKP fara alg: ' + taie(n.reason, 80) }); + } + + // ---------------------------------------------------------------- rezumat si fisiere + const ok = randuri.filter((r) => r.ok).length; + console.log(`\ninterop-sdjwt: ${ok}/${randuri.length} randuri cu verdictele asteptate de amandoua partile${divergente ? `, ${divergente} DIVERGENTE` : ''}`); + if (SCRIE) { + const generat = new Date().toISOString(); + const F = { generat, unealta: 'tools/aere-identity/interop/interop-sdjwt.mjs --scrie', nota: 'AERE-SINTETIC: jetoane emise de @sd-jwt/core (semnate prin WebCrypto, verificate de jose) cu chei de PROBA nascute la generare; numai cheile publice sunt aici. Judecate offline de proba-sdjwt.mjs la ceasVerificare.', biblioteci, ceas: CEAS, ceasVerificare: ACUM, audience: AUD, nonce: NONCE, cazuri: fixturi }; + fs.writeFileSync(path.join(AICI, 'fixturi-interop-sdjwt.json'), JSON.stringify(F, null, 1) + '\n'); + fs.writeFileSync(path.join(AICI, 'rezultate-interop-sdjwt.json'), JSON.stringify({ generat, biblioteci, ceas: CEAS, randuri: randuri.map(({ sens, caz, asteptat, noi, lor, ok, nota }) => ({ sens, caz, asteptat, noi, lor, ok, nota })) }, null, 1) + '\n'); + console.log(`scrise: fixturi-interop-sdjwt.json (${fixturi.length} cazuri), rezultate-interop-sdjwt.json (${randuri.length} randuri)`); + } + return divergente ? 1 : 0; +} +main().then((c) => { process.exitCode = c; }, (e) => { console.log('STRICAT: ' + (e.stack || e)); process.exitCode = 2; }); diff --git a/identity/interop/rezultate-interop-sdjwt-vc.json b/identity/interop/rezultate-interop-sdjwt-vc.json new file mode 100644 index 0000000..a0a4b79 --- /dev/null +++ b/identity/interop/rezultate-interop-sdjwt-vc.json @@ -0,0 +1,266 @@ +{ + "generat": "2026-10-18T06:18:52.552Z", + "biblioteci": { + "@sd-jwt/sd-jwt-vc": "0.23.0", + "@sd-jwt/core": "0.23.0", + "@owf/token-status-list": "0.5.0", + "@sd-jwt/crypto-nodejs": "0.19.0", + "jose": "6.2.12", + "node": "v24.14.1" + }, + "ceas": 1792281600, + "randuri": [ + { + "sens": "noi->lor", + "caz": "EdDSA: SD-JWT VC (typ dc+sd-jwt, vct urn:eudi:pid:1, status_list idx 5) + lista noastra de stare (toate 0), KB(aud, nonce)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "ES256: SD-JWT VC (typ dc+sd-jwt, vct urn:eudi:pid:1, status_list idx 5) + lista noastra de stare (toate 0), KB(aud, nonce)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "ML-DSA-65: SD-JWT VC (typ dc+sd-jwt, vct urn:eudi:pid:1, status_list idx 5) + lista noastra de stare (toate 0), KB(aud, nonce)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: lista noastra cu indexul 5 = 1 (INVALID, revocat)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status 1 (INVALID) in https://issuer.example/status/pid/1 at index 5", + "lor": "REFUZ: Status is not valid", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: lista noastra pe 2 biti cu indexul 5 = 2 (SUSPENDED)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status 2 (SUSPENDED) in https://issuer.example/status/pid/1 at index 5", + "lor": "REFUZ: Status is not valid", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "lista noastra pe 8 biti, toate 0 (impachetarea pe mai multi biti citita de ei)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: lista noastra publicata pentru ALT uri (sub != uri-ul din jeton)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status list: sub \"https://issuer.example/status/pid/1-alta\" is not the uri referenced (https://issuer.example/", + "lor": "REFUZ: The subject claim 'https://issuer.example/status/pid/1-alta' must be equal to the uri 'https://issuer.example/", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "fara lista: noi cu requireStatus:false (stare nejudecata, spusa), ei cu disableStatusVerification", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "la noi, implicit (requireStatus:true) acelasi credential e REFUZAT: the credential names a status (status_list) that was not judged: give statusListJwt fetche" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: verificatorul asteapta alt vct (urn:eudi:pid:2)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: vct \"urn:eudi:pid:1\" is not the type expected (urn:eudi:pid:2)", + "lor": "REFUZ: Verify Error: Invalid VCT", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: KB pentru alt aud", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: made for https://other.example, not https://verifier.example", + "lor": "REFUZ: Verify Error: Invalid Key Binding audience", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "credential FARA status (nu numeste nicio lista): valid fara lista", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "EMITERE: vct cerut dezvaluibil, refuzat de amandoi emitentii (s.2.2.2.3)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: sd-jwt-vc: vct may not be selectively disclosed (s.2.2.2.3)", + "lor": "REFUZ: Cannot disclose protected field", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "EdDSA: SD-JWT VC al LOR (typ dc+sd-jwt, status_list idx 5) + lista LOR de stare (@owf/token-status-list, toate 0), KB(aud, nonce); tipul implicit al nostru", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "ES256: SD-JWT VC al LOR (typ dc+sd-jwt, status_list idx 5) + lista LOR de stare (@owf/token-status-list, toate 0), KB(aud, nonce); tipul implicit al nostru", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "ML-DSA-65: SD-JWT VC al LOR (typ dc+sd-jwt, status_list idx 5) + lista LOR de stare (@owf/token-status-list, toate 0), KB(aud, nonce); tipul implicit al nostru", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: lista LOR cu indexul 5 = 1 (INVALID)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status 1 (INVALID) in https://issuer.example/status/pid/1 at index 5", + "lor": "REFUZ: Status is not valid", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: lista LOR pe 2 biti cu indexul 5 = 2 (SUSPENDED)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status 2 (SUSPENDED) in https://issuer.example/status/pid/1 at index 5", + "lor": "REFUZ: Status is not valid", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "lista LOR pe 8 biti, toate 0 (impachetarea lor pe mai multi biti citita de noi)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "IMPACHETARE: lista LOR pe 2 biti cu 12 stari amestecate, citite de noi index cu index", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "citit: [0,1,2,3,0,1,2,3,3,2,1,0] = scris: [0,1,2,3,0,1,2,3,3,2,1,0]" + }, + { + "sens": "noi->lor", + "caz": "IMPACHETARE: lista NOASTRA pe 2 biti cu 12 stari amestecate, citite de ei index cu index", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "citit: [0,1,2,3,0,1,2,3,3,2,1,0] = scris: [0,1,2,3,0,1,2,3,3,2,1,0]" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: lista LOR pentru ALT uri (sub != uri-ul din jeton)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status list: sub \"https://issuer.example/status/pid/1-alta\" is not the uri referenced (https://issuer.example/", + "lor": "REFUZ: The subject claim 'https://issuer.example/status/pid/1-alta' must be equal to the uri 'https://issuer.example/", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: lista LOR expirata", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: status list: expired at 1792281630", + "lor": "REFUZ: Status List JWT verification failed: Verify Error: JWT is expired <- Verify Error: JWT is expired", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: verificatorul asteapta alt vct (urn:eudi:pid:2)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: vct \"urn:eudi:pid:1\" is not the type expected (urn:eudi:pid:2)", + "lor": "REFUZ: Verify Error: Invalid VCT", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: fara lista, la noi implicit (requireStatus:true): refuz numit; la ei disableStatusVerification: valid", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: the credential names a status (status_list) that was not judged: give statusListJwt fetched from https://issue", + "lor": "VALID", + "ok": true, + "nota": "politica: noi nu dam VALID pe o stare nejudecata fara ca verificatorul sa o ceara explicit (requireStatus:false); ei lasa decizia pe disableStatusVerification" + }, + { + "sens": "lor->noi", + "caz": "fara lista, la noi cu requireStatus:false: valid, cu starea raportata nejudecata", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: KB pentru alt aud", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: made for https://other.example, not https://verifier.example", + "lor": "REFUZ: Verify Error: Invalid Key Binding audience", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: SD-JWT VC al LOR FARA vct (emitentul lor il lasa afara)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: vct is required and the payload has none (draft-ietf-oauth-sd-jwt-vc s.2.2.2.3)", + "lor": "REFUZ: Verify Error: Invalid VCT", + "ok": true, + "nota": "al lor: SDJwtVcInstance.issue nu cere vct; verificatorul lor il refuza numai daca i se da expectedVct" + }, + { + "sens": "lor->noi", + "caz": "DIFERENTA: acelasi SD-JWT VC fara vct, verificatorul LOR fara expectedVct", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: vct is required and the payload has none (draft-ietf-oauth-sd-jwt-vc s.2.2.2.3)", + "lor": "VALID", + "ok": true, + "nota": "al lor: fara expectedVct nu cere vct deloc; la noi expectedVct e obligatoriu si vct e cerut in jeton (s.2.2.2.3 REQUIRED)" + } + ] +} diff --git a/identity/interop/rezultate-interop-sdjwt.json b/identity/interop/rezultate-interop-sdjwt.json new file mode 100644 index 0000000..7b11d76 --- /dev/null +++ b/identity/interop/rezultate-interop-sdjwt.json @@ -0,0 +1,247 @@ +{ + "generat": "2026-10-18T06:12:16.195Z", + "biblioteci": { + "@sd-jwt/core": "0.23.0", + "@sd-jwt/crypto-nodejs": "0.19.0", + "jose": "6.2.12", + "@owf/identity-common": "0.5.0", + "node": "v24.14.1" + }, + "ceas": 1792281600, + "randuri": [ + { + "sens": "noi->lor", + "caz": "EdDSA: prezentare cu age_over_18 + nationalities[RO], 2 momeli, KB(aud, nonce)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "ES256: prezentare cu age_over_18 + nationalities[RO], 2 momeli, KB(aud, nonce)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "ML-DSA-65: prezentare cu age_over_18 + nationalities[RO], 2 momeli, KB(aud, nonce)", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: dezvaluirea given_name cu valoarea schimbata (fara KB)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: a disclosure is not referenced by any digest of the issuer-signed JWT", + "lor": "REFUZ: Unreferenced disclosure(s) detected in SD-JWT", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: KB pentru alt aud (verificatorul cere al lui)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: made for https://other.example, not https://verifier.example", + "lor": "REFUZ: Verify Error: Invalid Key Binding audience", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "DIFERENTA: acelasi KB pentru alt aud, cand verificatorul LOR nu da expectedKeyBindingAudience", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: key binding: made for https://other.example, not https://verifier.example", + "lor": "VALID", + "ok": true, + "nota": "al lor: @sd-jwt/core compara aud-ul KB numai daca i se cere (RFC 9901 s.7.3 pasul 5.f cere legarea de verificator); la noi aud si nonce sunt cerute mereu" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: alg none", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: alg \"none\" is not accepted (accepted: ES256, EdDSA, Ed25519, ML-DSA-65; never none)", + "lor": "REFUZ: Verify Error: alg \"none\" is not allowed", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: acelasi digest de doua ori in _sd", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: the digest eq6hf8ZFjgcT.. appears more than once", + "lor": "REFUZ: Duplicate digest found in SD-JWT payload", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: KB semnat de alta cheie decat cnf.jwk", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: the signature does not verify with the key given", + "lor": "REFUZ: Verify Error: Invalid JWT Signature [jose: signature verification failed]", + "ok": true, + "nota": "" + }, + { + "sens": "noi->lor", + "caz": "NEGATIV: _sd_alg imbricat (RFC 9901 s.4.1.1 MUST NOT)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: _sd_alg below the top level of the payload (RFC 9901 s.4.1.1)", + "lor": "REFUZ: Nested _sd_alg is not allowed", + "ok": true, + "nota": "reparat la noi pe 2026-10-18: pana atunci _sd_alg imbricat era pastrat ca afirmatie" + }, + { + "sens": "noi->lor", + "caz": "DIFERENTA: prezentarea cu KB, verificatorul LOR fara keyBindingNonce (si fara cerinta de KB)", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: the verifier must give its audience and nonce to judge a key binding (RFC 9901 s.7.3)", + "lor": "VALID", + "ok": true, + "nota": "al lor: fara keyBindingNonce @sd-jwt/core nu judeca KB-ul prezent si nu il cere; la noi fara aud+nonce o prezentare cu KB e refuzata (RFC 9901 s.7.3)" + }, + { + "sens": "noi->lor", + "caz": "DIFERENTA: jetonul emitentului cu typ JWT (ne-explicit)", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: typ \"JWT\" is not the type expected (an explicit ...+sd-jwt)", + "lor": "VALID", + "ok": true, + "nota": "al lor: @sd-jwt/core nu verifica typ-ul jetonului emitentului; RFC 9901 s.9.11 RECOMANDA ca verificatorii sa il verifice; la noi expectedTyp:null il lasa" + }, + { + "sens": "lor->noi", + "caz": "EdDSA: dezvaluiri imbricate (address.locality), element de lista (nationalities[0]), 2 momeli, KB(aud, nonce); verificat cu expectedTyp:null", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "ES256: dezvaluiri imbricate (address.locality), element de lista (nationalities[0]), 2 momeli, KB(aud, nonce); verificat cu expectedTyp:null", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "ML-DSA-65: dezvaluiri imbricate (address.locality), element de lista (nationalities[0]), 2 momeli, KB(aud, nonce); verificat cu expectedTyp:null", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "DIFERENTA: acelasi jeton LOR, verificat cu tipul implicit cerut de noi (orice ...+sd-jwt)", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: typ undefined is not the type expected (an explicit ...+sd-jwt)", + "lor": "VALID", + "ok": true, + "nota": "al lor: SDJwtInstance nu pune typ implicit (SDJwtVcInstance pune dc+sd-jwt); RFC 9901 s.9.11: tipul explicit e RECOMMENDED; la noi se primeste cu expectedTyp:null sau cu typ dat la emitere" + }, + { + "sens": "lor->noi", + "caz": "EdDSA: jetonul LOR emis cu header typ example+sd-jwt, verificat cu tipul implicit al nostru", + "asteptat": "VALID/VALID", + "noi": "VALID", + "lor": "VALID", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "DIFERENTA: jetonul LOR cu _sd_alg sha-384", + "asteptat": "REFUZ/VALID", + "noi": "REFUZ: _sd_alg \"sha-384\" is not understood (only sha-256)", + "lor": "VALID", + "ok": true, + "nota": "a noastra, dinadins: verificatorul nostru stie numai sha-256 (RFC 9901 s.4.1.1: sha-256 MUST be supported; alte functii sunt politica); @sd-jwt/core accepta lista IANA fara formele trunchiate" + }, + { + "sens": "lor->noi", + "caz": "DIFERENTA: sarea dezvaluirii: lor 16 caractere (64 biti), noi 22 caractere (128 biti)", + "asteptat": "VALID/REFUZ", + "noi": "VALID", + "lor": "REFUZ: 64 biti sub cei 128 RECOMANDATI (RFC 9901 s.9.3)", + "ok": true, + "nota": "al lor: generateSalt(16) din @sd-jwt/crypto-nodejs da 16 caractere hexa = 64 de biti; generatorul de sare e injectabil, deci un emitent poate pune unul de 128 de biti; verificatorii nu judeca lungimea sarii" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: dezvaluirea age_over_18 cu valoarea schimbata (fara KB)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: a disclosure is not referenced by any digest of the issuer-signed JWT", + "lor": "REFUZ: Unreferenced disclosure(s) detected in SD-JWT", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: KB pentru alt aud", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: made for https://other.example, not https://verifier.example", + "lor": "REFUZ: Verify Error: Invalid Key Binding audience", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: alg none", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: alg \"none\" is not accepted (accepted: ES256, EdDSA, Ed25519, ML-DSA-65; never none)", + "lor": "REFUZ: Verify Error: alg \"none\" is not allowed", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: acelasi digest de doua ori in _sd (re-semnat de emitentul LOR)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: the digest CKtNAhaoNS2c.. appears more than once", + "lor": "REFUZ: Duplicate digest found in SD-JWT payload", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: KB semnat de alta cheie decat cnf.jwk", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: the signature does not verify with the key given", + "lor": "REFUZ: Verify Error: Invalid JWT Signature [jose: signature verification failed]", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "NEGATIV: o dezvaluire scoasa din prezentare dupa semnarea KB", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: key binding: sd_hash is not the hash of what was presented", + "lor": "REFUZ: Invalid sd_hash in Key Binding JWT", + "ok": true, + "nota": "" + }, + { + "sens": "lor->noi", + "caz": "ML-DSA-65: cheia AKP FARA parametrul alg (RFC 9964 s.3 il cere)", + "asteptat": "REFUZ/REFUZ", + "noi": "REFUZ: The property 'key.alg' must be one of: 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87'. Received undefined", + "lor": "REFUZ: jose.importJWK: missing \"alg\" (Algorithm) Parameter value", + "ok": true, + "nota": "masurat: jose o refuza; node:crypto refuza JWK-ul AKP fara alg: The property 'key.alg' must be one of: 'ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87'. Re" + } + ] +} diff --git a/identity/proba-sdjwt-vc.mjs b/identity/proba-sdjwt-vc.mjs new file mode 100644 index 0000000..efe8d84 --- /dev/null +++ b/identity/proba-sdjwt-vc.mjs @@ -0,0 +1,152 @@ +// Proba SD-JWT VC (sdjwt-vc.mjs): profilul draft-ietf-oauth-sd-jwt-vc-19 peste sdjwt.mjs, lista de stare (Token Status List, +// draft-ietf-oauth-status-list-21), si fixturile de interoperare DERIVATE din iesirea reala a bibliotecilor straine +// (@sd-jwt/sd-jwt-vc + @owf/token-status-list, scrise de interop/interop-sdjwt-vc.mjs --scrie), judecate offline. Fiecare refuz e o proba numita. +// node proba-sdjwt-vc.mjs iesire 0 = toate cum trebuia +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import zlib from 'node:zlib'; +import os from 'node:os'; +import { spawnSync } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import * as I from './identity.mjs'; +import * as J from './sdjwt.mjs'; +import * as V from './sdjwt-vc.mjs'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +let treceri = 0; const esecuri = []; +function test(nume, fn) { try { fn(); treceri++; console.log(' OK ' + nume); } catch (e) { esecuri.push(nume); console.log(' RAU ' + nume + ' -- ' + (e.message || e)); } } +const cere = (c, m) => { if (!c) throw new Error(m); }; +const sortat = (o) => (Array.isArray(o) ? o.map(sortat) : o && typeof o === 'object' ? Object.fromEntries(Object.keys(o).sort().map((k) => [k, sortat(o[k])])) : o); +const egal = (a, b) => JSON.stringify(sortat(a)) === JSON.stringify(sortat(b)); +const b64u = (x) => Buffer.from(x).toString('base64url'); +const refuz = (r, re) => !r.valid && re.test(r.reason); +const NOW = 1792281600, LA = new Date((NOW + 60) * 1000); +const iss = I.generateKeys(), hol = I.generateKeys(), strain = I.generateKeys(); +const AUD = 'https://rp.example', NONCE = 'n-' + crypto.randomBytes(4).toString('hex'); +const VCT = 'urn:eudi:pid:1', URI = 'https://issuer.example/status/pid/1', IDX = 5; +const CL = { given_name: 'Ana', family_name: 'Pop', birthdate: '1990-01-01', age_over_18: true, nationalities: ['RO', 'DE'], address: { locality: 'Cluj', country: 'RO' }, issuing_authority: 'Example Authority', issuing_country: 'RO' }; +const emite = (o = {}) => V.issueSdJwtVc({ issuer: iss, holder: hol, vct: VCT, claims: CL, disclosable: ['given_name', 'family_name', 'birthdate', 'age_over_18', 'address'], arrayDisclosable: ['nationalities'], iss: 'https://issuer.example', iat: NOW, nbf: NOW, exp: NOW + 365 * 86400, status: { status_list: { idx: IDX, uri: URI } }, decoys: 2, ...o }); +const arata = (sd, reveal, o = {}) => V.presentSdJwtVc({ sdJwt: sd, reveal, holder: hol, audience: AUD, nonce: NONCE, iat: NOW, ...o }); +const judeca = (p, o = {}) => V.verifySdJwtVc(p, { issuerKey: iss, audience: AUD, nonce: NONCE, now: LA, expectedVct: VCT, ...o }); +const lista = (statuses, bits = 1, o = {}) => V.issueStatusListJwt({ issuer: iss, uri: URI, statuses, bits, iat: NOW, exp: NOW + 3600, ...o }); +const TOATE0 = new Array(16).fill(0), REVOCAT = TOATE0.map((_, i) => (i === IDX ? 1 : 0)), SUSPENDAT = TOATE0.map((_, i) => (i === IDX ? 2 : 0)); +const jwtDin = (antet, corp, cheie) => { const cap = b64u(JSON.stringify(antet)) + '.' + b64u(JSON.stringify(corp)); return cap + '.' + b64u(crypto.sign(null, Buffer.from(cap), cheie)); }; +const E = emite(), P = arata(E.sdJwt, ['birthdate', 'age_over_18', { element: 'RO', in: 'nationalities' }]); + +test('PROFIL: emitere SD-JWT VC (typ dc+sd-jwt, vct, iss, cnf, nbf/exp, status) si verificare cu lista de stare (toate 0): VALID, starea judecata 0, numai ce s-a aratat', () => { + const h = JSON.parse(Buffer.from(E.sdJwt.split('.')[0], 'base64url').toString('utf8')); cere(h.typ === 'dc+sd-jwt' && h.alg === 'EdDSA', JSON.stringify(h)); + const r = judeca(P, { statusListJwt: lista(TOATE0) }); + cere(r.valid, r.reason); + cere(r.vct === VCT && r.payload.vct === VCT && r.payload.iss === 'https://issuer.example' && r.payload.cnf && r.payload.nbf === NOW && r.payload.exp === NOW + 365 * 86400, JSON.stringify(Object.keys(r.payload))); + cere(r.payload.birthdate === '1990-01-01' && r.payload.age_over_18 === true && !('given_name' in r.payload) && !('address' in r.payload) && egal(r.payload.nationalities, ['RO']) && r.payload.issuing_country === 'RO', JSON.stringify(r.payload)); + cere(egal(r.status, { present: true, judged: true, mechanism: 'status_list', uri: URI, idx: IDX, value: 0, name: 'VALID' }), JSON.stringify(r.status)); + cere(r.keyBinding && r.keyBinding.aud === AUD && r.keyBinding.nonce === NONCE, JSON.stringify(r.keyBinding)); +}); +test('PROFIL vct: verificatorul fara expectedVct -> refuzat; alt vct asteptat -> refuzat; lista de vct-uri acceptate -> primit; jeton fara vct -> refuzat (s.2.2.2.3 REQUIRED)', () => { + cere(refuz(V.verifySdJwtVc(P, { issuerKey: iss, audience: AUD, nonce: NONCE, now: LA, statusListJwt: lista(TOATE0) }), /must name the vct/), 'fara expectedVct a trecut'); + cere(refuz(judeca(P, { expectedVct: 'urn:eudi:pid:2', statusListJwt: lista(TOATE0) }), /not the type expected/), 'alt vct a trecut'); + cere(judeca(P, { expectedVct: ['urn:eudi:pid:2', VCT], statusListJwt: lista(TOATE0) }).valid, 'lista de vct-uri refuzata'); + const faraVct = J.issueSdJwt({ issuer: iss, holder: hol, claims: { a: 1 }, iss: 'x', iat: NOW, exp: NOW + 100, typ: 'dc+sd-jwt' }); + cere(refuz(judeca(arata(faraVct.sdJwt, [])), /vct is required/), 'fara vct a trecut'); +}); +test('PROFIL typ: un SD-JWT cu vct dar typ aere+sd-jwt -> refuzat de verificatorul VC (dc+sd-jwt cerut); application/dc+sd-jwt -> primit (RFC 7515 s.4.1.9)', () => { + const alt = J.issueSdJwt({ issuer: iss, holder: hol, claims: { vct: VCT, a: 1 }, iss: 'x', iat: NOW, exp: NOW + 100 }); + cere(refuz(judeca(arata(alt.sdJwt, [])), /typ/), 'typ aere+sd-jwt a trecut drept VC'); + const pre = J.issueSdJwt({ issuer: iss, holder: hol, claims: { vct: VCT, a: 1 }, iss: 'x', iat: NOW, exp: NOW + 100, typ: 'application/dc+sd-jwt' }); + const r = judeca(arata(pre.sdJwt, [])); cere(r.valid, 'application/dc+sd-jwt refuzat: ' + r.reason); +}); +test('PROFIL s.2.2.2.3: emitentul refuza vct/status/iss/exp/cnf dezvaluibile, vct lipsa, status stricat; verificatorul refuza o dezvaluire numita vct sau status', () => { + const incearca = (o) => { try { V.issueSdJwtVc({ issuer: iss, holder: hol, vct: VCT, iss: 'x', iat: NOW, claims: { a: 1, sub: 's' }, ...o }); return null; } catch (e) { return e.message; } }; + for (const n of ['vct', 'status', 'iss', 'exp', 'cnf', 'vct#integrity']) cere(/may not be selectively disclosed/.test(incearca({ disclosable: [n] }) || ''), n + ' dezvaluibil emis'); + cere(/vct is required/.test(incearca({ vct: undefined }) || ''), 'vct lipsa emis'); + cere(/vct is required/.test(incearca({ vct: '' }) || ''), 'vct gol emis'); + cere(/status\.status_list/.test(incearca({ status: { status_list: { idx: -1, uri: URI } } }) || ''), 'idx negativ emis'); + cere(/set by the profile/.test(incearca({ claims: { vct: 'alt' } }) || ''), 'vct dat in claims emis'); + cere(incearca({ disclosable: ['sub'] }) === null, 'sub dezvaluibil refuzat (s.2.2.2.3 il lasa)'); + // verificatorul: o dezvaluire numita status / vct, facuta de mana si semnata de emitent + const fa = (nume, val) => { const d = b64u(JSON.stringify(['s1', nume, val])); const dg = crypto.createHash('sha256').update(d).digest('base64url'); + return jwtDin({ alg: 'EdDSA', typ: 'dc+sd-jwt' }, { vct: VCT, iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', _sd: [dg] }, iss.privat.ed25519) + '~' + d + '~'; }; + cere(refuz(judeca(fa('status', { status_list: { idx: 1, uri: URI } }), { requireKeyBinding: false }), /status was selectively disclosed/), 'status dezvaluit a trecut'); + const dv = b64u(JSON.stringify(['s1', 'nationalities', ['RO']])), dgv = crypto.createHash('sha256').update(dv).digest('base64url'); + const bun = jwtDin({ alg: 'EdDSA', typ: 'dc+sd-jwt' }, { vct: VCT, iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', _sd: [dgv] }, iss.privat.ed25519) + '~' + dv + '~'; + cere(judeca(bun, { requireKeyBinding: false }).valid, 'martorul (o dezvaluire obisnuita) refuzat'); +}); +test('STARE: lista lipsa -> refuzat implicit (requireStatus, cu uri-ul de adus in motiv); requireStatus:false -> VALID cu starea prezenta si nejudecata; credential fara status -> VALID fara lista', () => { + const r = judeca(P); cere(refuz(r, /was not judged/) && r.reason.includes(URI) && r.status && r.status.present && !r.status.judged, r.reason + ' ' + JSON.stringify(r.status)); + const r2 = judeca(P, { requireStatus: false }); cere(r2.valid && egal(r2.status, { present: true, judged: false, mechanism: 'status_list', uri: URI, idx: IDX }), r2.reason + ' ' + JSON.stringify(r2.status)); + const F = emite({ status: undefined }); const r3 = judeca(arata(F.sdJwt, ['birthdate'])); cere(r3.valid && egal(r3.status, { present: false, judged: false }), r3.reason + ' ' + JSON.stringify(r3.status)); + // un mecanism de stare pe care nu il stim: prezent, nejudecat + const alt = jwtDin({ alg: 'EdDSA', typ: 'dc+sd-jwt' }, { vct: VCT, iss: 'x', exp: NOW + 100, status: { identifier_list: { id: '1', uri: URI } } }, iss.privat.ed25519) + '~'; + const r4 = judeca(alt, { requireKeyBinding: false }); cere(refuz(r4, /was not judged/) && r4.status.mechanism === 'identifier_list', r4.reason); + cere(judeca(alt, { requireKeyBinding: false, requireStatus: false }).valid, 'mecanismul necunoscut cu requireStatus:false refuzat'); +}); +test('STARE: revocat (1) -> refuzat; suspendat (2, pe 2 biti) -> refuzat; stare 3 (a aplicatiei) -> refuzat; 1, 2, 4 si 8 biti citite index cu index (impachetarea: scris = citit)', () => { + cere(refuz(judeca(P, { statusListJwt: lista(REVOCAT) }), /status 1 \(INVALID\) in .* at index 5/), 'revocat a trecut'); + cere(refuz(judeca(P, { statusListJwt: lista(SUSPENDAT, 2) }), /status 2 \(SUSPENDED\)/), 'suspendat a trecut'); + cere(refuz(judeca(P, { statusListJwt: lista(TOATE0.map((_, i) => (i === IDX ? 3 : 0)), 2) }), /status 3 \(application-specific\)/), 'starea 3 a trecut'); + for (const [bits, st] of [[1, [1, 0, 1, 1, 0, 0, 0, 1, 1, 0]], [2, [0, 1, 2, 3, 0, 1, 2, 3, 3, 2, 1, 0]], [4, [1, 2, 3, 15, 0, 9]], [8, [0, 1, 2, 3, 255, 7, 0, 1]]]) { + const r = V.readStatusListJwt(lista(st, bits), { key: iss, uri: URI, now: LA }); + cere(r.ok && r.bits === bits, bits + ' biti: ' + r.reason); + cere(egal(st.map((_, i) => r.statusAt(i)), st), bits + ' biti: citit ' + JSON.stringify(st.map((_, i) => r.statusAt(i))) + ' scris ' + JSON.stringify(st)); + cere(r.statusAt(r.entries) === null && r.statusAt(-1) === null, bits + ' biti: dincolo de lista'); + } + // forma de pe fir, octet cu octet: 2 biti, starile [1,2,3,0] -> primul octet = 1 | 2<<2 | 3<<4 | 0<<6 = 0b00111001 = 0x39 (status-list-21 s.4.1) + const j = lista([1, 2, 3, 0], 2); const corp = JSON.parse(Buffer.from(j.split('.')[1], 'base64url').toString('utf8')); + const oct = zlib.inflateSync(Buffer.from(corp.status_list.lst, 'base64url')); + cere(oct.length === 1 && oct[0] === 0x39 && corp.status_list.bits === 2 && corp.sub === URI && corp.iat === NOW, 'octetul: ' + oct.toString('hex')); +}); +test('STARE: lista pentru alt uri (sub), expirata, semnata de alta cheie, cu typ JWT, fara iat, cu bits 3, index dincolo de lista -> refuzate; cheia listei poate fi alta decat a emitentului', () => { + cere(refuz(judeca(P, { statusListJwt: lista(TOATE0, 1, { uri: URI + 'x' }) }), /status list: sub .* is not the uri referenced/), 'alt uri a trecut'); + cere(refuz(judeca(P, { statusListJwt: lista(TOATE0, 1, { exp: NOW + 30 }) }), /status list: expired at/), 'expirata a trecut'); + cere(refuz(judeca(P, { statusListJwt: V.issueStatusListJwt({ issuer: strain, uri: URI, statuses: TOATE0, iat: NOW }) }), /status list: the signature does not verify/), 'alta cheie a trecut'); + cere(judeca(P, { statusListJwt: V.issueStatusListJwt({ issuer: strain, uri: URI, statuses: TOATE0, iat: NOW }), statusListKey: strain }).valid, 'cheia listei data separat refuzata'); + const corp = JSON.parse(Buffer.from(lista(TOATE0).split('.')[1], 'base64url').toString('utf8')); + cere(refuz(judeca(P, { statusListJwt: jwtDin({ alg: 'EdDSA', typ: 'JWT' }, corp, iss.privat.ed25519) }), /status list: typ/), 'typ JWT a trecut'); + const { iat: _i, ...faraIat } = corp; + cere(refuz(judeca(P, { statusListJwt: jwtDin({ alg: 'EdDSA', typ: 'statuslist+jwt' }, faraIat, iss.privat.ed25519) }), /status list: iat is required/), 'fara iat a trecut'); + cere(refuz(judeca(P, { statusListJwt: jwtDin({ alg: 'EdDSA', typ: 'statuslist+jwt' }, { ...corp, status_list: { ...corp.status_list, bits: 3 } }, iss.privat.ed25519) }), /status list: status_list must be/), 'bits 3 a trecut'); + cere(refuz(judeca(P, { statusListJwt: jwtDin({ alg: 'EdDSA', typ: 'statuslist+jwt' }, { ...corp, iat: NOW + 600 }, iss.privat.ed25519) }), /status list: issued in the future/), 'iat in viitor a trecut'); + const scurta = V.issueStatusListJwt({ issuer: iss, uri: URI, statuses: [0, 0, 0, 0], bits: 8, iat: NOW }); + cere(refuz(judeca(P, { statusListJwt: scurta }), /index 5 is beyond the list \(4 entries\)/), 'index dincolo a trecut'); + let m = null; try { V.issueStatusListJwt({ issuer: iss, uri: URI, statuses: [0, 2], bits: 1, iat: NOW }); } catch (e) { m = e.message; } cere(/below 2\^1/.test(m || ''), 'starea 2 pe 1 bit emisa'); +}); +test('POST-CUANTIC: credential ML-DSA-65 cu lista de stare semnata ML-DSA-65 -> VALID; aceeasi lista judecata cu cheia Ed25519 -> refuzata', () => { + const M = emite({ alg: 'ML-DSA-65', holderAlg: 'ML-DSA-65' }); + const p = arata(M.sdJwt, ['birthdate'], { holderAlg: 'ML-DSA-65' }); + const l = V.issueStatusListJwt({ issuer: iss, alg: 'ML-DSA-65', uri: URI, statuses: TOATE0, iat: NOW }); + const r = judeca(p, { issuerAlg: 'ML-DSA-65', statusListJwt: l }); cere(r.valid && r.alg === 'ML-DSA-65' && r.status.judged, r.reason); + cere(refuz(judeca(p, { issuerAlg: 'ML-DSA-65', statusListJwt: l, statusListAlg: 'EdDSA' }), /status list: .*does not match|status list: signed with/), 'lista ML-DSA-65 judecata cu Ed25519 a trecut'); +}); +const FX = path.join(AICI, 'interop', 'fixturi-interop-sdjwt-vc.json'); +const F = fs.existsSync(FX) ? JSON.parse(fs.readFileSync(FX, 'utf8')) : null; +test(`INTEROP (fixturi @sd-jwt/sd-jwt-vc ${F ? F.biblioteci['@sd-jwt/sd-jwt-vc'] : '?'} + @owf/token-status-list ${F ? F.biblioteci['@owf/token-status-list'] : '?'}, generate ${F ? F.generat.slice(0, 10) : '?'}): fiecare credential si lista de stare a LOR da, offline, verdictul inregistrat`, () => { + cere(F && Array.isArray(F.cazuri) && F.cazuri.length >= 8, 'fixturile lipsesc sau sunt prea putine (ruleaza interop/interop-sdjwt-vc.mjs --lab ... --scrie)'); + const la = new Date(F.ceasVerificare * 1000); + let valide = 0, refuzate = 0; + for (const c of F.cazuri) { + const r = V.verifySdJwtVc(c.prezentare, { issuerKey: c.issuerJwk, issuerAlg: c.alg, audience: F.audience, nonce: F.nonce, now: la, expectedVct: c.expectedVct, ...(c.statusListJwt ? { statusListJwt: c.statusListJwt } : {}), ...(c.optiuni || {}) }); + if (c.asteptat.valid) { + cere(r.valid, c.nume + ': ' + r.reason); + cere(egal(r.payload, c.asteptat.payload) && egal([...r.disclosed].sort(), c.asteptat.disclosed) && egal(r.status, c.asteptat.status), c.nume + ': rezultatul difera de cel inregistrat: ' + JSON.stringify(r.payload).slice(0, 200)); + valide++; + } else { cere(refuz(r, new RegExp(c.asteptat.motiv)), c.nume + ': asteptat refuz /' + c.asteptat.motiv + '/, primit ' + (r.valid ? 'VALID' : r.reason)); refuzate++; } + } + cere(valide >= 3 && refuzate >= 4, `prea putine cazuri: ${valide} valide, ${refuzate} refuzate`); + const algs = new Set(F.cazuri.filter((c) => c.asteptat.valid).map((c) => c.alg)); cere(algs.has('EdDSA') && algs.has('ES256') && algs.has('ML-DSA-65'), 'lipsesc algoritmi din cazurile valide: ' + [...algs]); +}); +test('linia de comanda: verify-sdjwt-vc -> 0 VALID cu lista, 1 INVALID cu lista revocata, 1 fara lista, 0 cu --status-not-required, 2 fara --expected-vct', () => { + const T = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-sdjwt-vc-cli-')); + try { + fs.writeFileSync(path.join(T, 'p.txt'), P); fs.writeFileSync(path.join(T, 'k.json'), JSON.stringify(iss.public)); + fs.writeFileSync(path.join(T, 'l0.txt'), lista(TOATE0)); fs.writeFileSync(path.join(T, 'l1.txt'), lista(REVOCAT)); + const run = (...a) => spawnSync(process.execPath, [path.join(AICI, 'identity-cli.mjs'), 'verify-sdjwt-vc', '--sd-jwt', 'p.txt', '--issuer-key', 'k.json', '--audience', AUD, '--nonce', NONCE, '--at', LA.toISOString().replace(/\.\d{3}Z$/, 'Z'), ...a], { cwd: T, encoding: 'utf8' }); + const a = run('--expected-vct', VCT, '--status-list', 'l0.txt', '--json'); cere(a.status === 0 && JSON.parse(a.stdout).valid === true && JSON.parse(a.stdout).status.value === 0, 'valid: ' + a.status + ' ' + a.stdout.slice(0, 200) + a.stderr); + const b = run('--expected-vct', VCT, '--status-list', 'l1.txt'); cere(b.status === 1 && /INVALID: status 1/.test(b.stdout), 'revocat: ' + b.status + ' ' + b.stdout); + const c = run('--expected-vct', VCT); cere(c.status === 1 && /was not judged/.test(c.stdout), 'fara lista: ' + c.status + ' ' + c.stdout); + const d = run('--expected-vct', VCT, '--status-not-required'); cere(d.status === 0 && /status not judged/.test(d.stdout), 'status-not-required: ' + d.status + ' ' + d.stdout); + const e = run(); cere(e.status === 2 && /expected-vct/.test(e.stderr), 'fara vct: ' + e.status + ' ' + e.stderr); + } finally { fs.rmSync(T, { recursive: true, force: true }); } +}); +console.log(`\naere-sd-jwt-vc: ${treceri}/${treceri + esecuri.length} cum trebuia`); +process.exitCode = esecuri.length ? 1 : 0; diff --git a/identity/proba-sdjwt.mjs b/identity/proba-sdjwt.mjs index c9b1ca7..2ff0b7a 100644 --- a/identity/proba-sdjwt.mjs +++ b/identity/proba-sdjwt.mjs @@ -178,12 +178,12 @@ test('REVIZUIRE: tipul jetonului: un KB-JWT sau un JWT cu typ JWT dat drept jeto cere(bun.valid && bun.issuerChecked, 'emitentul asteptat refuzat'); cere(refuz(J.verifySdJwt(arata(E.sdJwt, ['age_over_18']), { issuerKey: iss, audience: AUD, nonce: NONCE, now: LA, expectedIssuer: 'https://altul.example' }), /issued by/), 'alt emitent a trecut'); }); -test('REVIZUIRE: crit (orice forma), base64url necanonic al semnaturii, KB expirat sau inca nevalabil (nbf) -> refuzate; _sd_alg imbricat ramane afirmatie', () => { - const corp = { iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', meta: { _sd_alg: 'x', note: 1 } }; +test('REVIZUIRE: crit (orice forma), base64url necanonic al semnaturii, KB expirat sau inca nevalabil (nbf) -> refuzate', () => { + const corp = { iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', meta: { note: 1 } }; for (const crit of [[], 'b64', ['b64']]) cere(refuz(J.verifySdJwt(jwtDin({ alg: 'EdDSA', typ: J.TYP, crit, b64: false }, corp, iss.privat.ed25519) + '~', { issuerKey: iss, requireKeyBinding: false, now: LA }), /crit/), 'crit ' + JSON.stringify(crit)); const j = jwtDin({ alg: 'EdDSA', typ: J.TYP }, corp, iss.privat.ed25519); const r = J.verifySdJwt(j + '~', { issuerKey: iss, requireKeyBinding: false, now: LA }); - cere(r.valid && r.payload.meta._sd_alg === 'x' && !('_sd_alg' in r.payload), '_sd_alg imbricat: ' + JSON.stringify(r.payload)); + cere(r.valid && r.payload.meta.note === 1 && !('_sd_alg' in r.payload), 'martorul: ' + JSON.stringify(r.payload)); const ALF = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; const u = j[j.length - 1], alt = ALF[ALF.indexOf(u) ^ 1]; const nec = j.slice(0, -1) + alt; @@ -202,6 +202,48 @@ test('REVIZUIRE: crit (orice forma), base64url necanonic al semnaturii, KB expir cere(refuz(judeca(baza + kbNbf('maine')), /key binding: not valid before/), 'KB cu nbf necitibil a trecut'); }); +// 2026-10-18, din interoperarea cu @sd-jwt/core 0.23.0 (care refuza _sd_alg imbricat): RFC 9901 s.4.1.1 "It MUST NOT be used in any object +// nested within the payload"; pana atunci il pastram ca afirmatie. Si RFC 7515 s.4.1.9: typ-ul "application/x+sd-jwt" e acelasi cu "x+sd-jwt". +test('INTEROP: _sd_alg imbricat (in clar sau intr-o valoare dezvaluita) -> refuzat (RFC 9901 s.4.1.1); o dezvaluire numita _sd_alg -> refuzata; typ cu prefixul application/ -> acelasi tip (RFC 7515 s.4.1.9)', () => { + const cap = (corp, typ = J.TYP) => jwtDin({ alg: 'EdDSA', typ }, corp, iss.privat.ed25519); + const o = { issuerKey: iss, requireKeyBinding: false, now: LA }; + cere(refuz(J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', meta: { _sd_alg: 'x', note: 1 } }) + '~', o), /_sd_alg below the top level/), 'imbricat in clar a trecut'); + const dIm = b64u(JSON.stringify(['s1', 'meta', { _sd_alg: 'sha-256', note: 1 }])), dgIm = crypto.createHash('sha256').update(dIm).digest('base64url'); + cere(refuz(J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', _sd: [dgIm] }) + '~' + dIm + '~', o), /_sd_alg below the top level/), 'imbricat in valoarea dezvaluita a trecut'); + const dAlg = b64u(JSON.stringify(['s2', '_sd_alg', 'sha-512'])), dgAlg = crypto.createHash('sha256').update(dAlg).digest('base64url'); + cere(refuz(J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100, _sd: [dgAlg] }) + '~' + dAlg + '~', o), /may not name _sd_alg/), 'dezvaluirea _sd_alg a trecut'); + const martor = J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', meta: { note: 1 } }) + '~', o); cere(martor.valid, 'martorul fara _sd_alg imbricat: ' + martor.reason); + const pre = J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100 }, 'application/aere+sd-jwt') + '~', o); cere(pre.valid, 'application/aere+sd-jwt refuzat implicit: ' + pre.reason); + cere(J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100 }, 'application/aere+sd-jwt') + '~', { ...o, expectedTyp: 'aere+sd-jwt' }).valid, 'application/aere+sd-jwt refuzat fata de aere+sd-jwt cerut'); + cere(refuz(J.verifySdJwt(cap({ iss: 'x', exp: NOW + 100 }, 'application/JWT') + '~', o), /typ/), 'application/JWT a trecut drept SD-JWT'); + let m = null; try { J.issueSdJwt({ issuer: iss, holder: hol, claims: { a: 1 }, iss: 'x', iat: NOW, typ: 'JWT' }); } catch (e) { m = e.message; } cere(/explicit SD-JWT type/.test(m || ''), 'emiterea cu typ JWT a tacut'); +}); + +// 2026-10-18: interoperarea cu o biblioteca straina, DERIVATA din iesirea ei reala: interop/interop-sdjwt.mjs --scrie (cu bibliotecile intr-un +// laborator din afara depozitului) a scris jetoanele emise si prezentate de @sd-jwt/core (semnate prin WebCrypto, verificate de jose), cu +// cheile lor publice de proba; aici se judeca offline, la ceasul inregistrat, si trebuie sa dea exact verdictul inregistrat +const FX = path.join(AICI, 'interop', 'fixturi-interop-sdjwt.json'); +const F2 = fs.existsSync(FX) ? JSON.parse(fs.readFileSync(FX, 'utf8')) : null; +test(`INTEROP (fixturi @sd-jwt/core ${F2 ? F2.biblioteci['@sd-jwt/core'] : '?'} + jose ${F2 ? F2.biblioteci.jose : '?'}, generate ${F2 ? F2.generat.slice(0, 10) : '?'}): fiecare jeton al LOR (EdDSA, ES256, ML-DSA-65; dezvaluiri imbricate, de lista, momeli, KB) da offline verdictul inregistrat`, () => { + cere(F2 && Array.isArray(F2.cazuri) && F2.cazuri.length >= 8, 'fixturile lipsesc sau sunt prea putine (ruleaza interop/interop-sdjwt.mjs --lab ... --scrie)'); + const la = new Date(F2.ceasVerificare * 1000); + let valide = 0, refuzate = 0; + for (const c of F2.cazuri) { + const r = J.verifySdJwt(c.prezentare, { issuerKey: c.issuerJwk, issuerAlg: c.alg, audience: F2.audience, nonce: F2.nonce, now: la, ...(c.optiuni || {}) }); + if (c.asteptat.valid) { + cere(r.valid, c.nume + ': ' + r.reason); + cere(egal(r.payload, c.asteptat.payload) && egal([...r.disclosed].sort(), c.asteptat.disclosed), c.nume + ': rezultatul difera de cel inregistrat: ' + JSON.stringify(r.payload).slice(0, 200)); + cere(r.payload.address && r.payload.address.locality === 'Cluj' && !('street_address' in r.payload.address) && egal(r.payload.nationalities, ['RO']) && !('given_name' in r.payload), c.nume + ': dezvaluirile imbricate/de lista nu sunt cele asteptate'); + valide++; + } else { cere(refuz(r, new RegExp(c.asteptat.motiv)), c.nume + ': asteptat refuz /' + c.asteptat.motiv + '/, primit ' + (r.valid ? 'VALID' : r.reason)); refuzate++; } + } + cere(valide >= 4 && refuzate >= 6, `prea putine cazuri: ${valide} valide, ${refuzate} refuzate`); + const algs = new Set(F2.cazuri.filter((c) => c.asteptat.valid).map((c) => c.alg)); cere(algs.has('EdDSA') && algs.has('ES256') && algs.has('ML-DSA-65'), 'lipsesc algoritmi din cazurile valide: ' + [...algs]); + // jetonul LOR fara typ e refuzat de tipul implicit al nostru (RFC 9901 s.9.11 RECOMMENDED): al doilea verdict al aceluiasi jeton + const faraTyp = F2.cazuri.find((c) => c.optiuni && c.optiuni.expectedTyp === null && c.asteptat.valid); + cere(faraTyp && refuz(J.verifySdJwt(faraTyp.prezentare, { issuerKey: faraTyp.issuerJwk, issuerAlg: faraTyp.alg, audience: F2.audience, nonce: F2.nonce, now: la }), /typ/), 'jetonul lor fara typ a trecut de tipul implicit'); +}); + test('linia de comanda: verify-sdjwt pe prezentarea RFC 9901 s.5.2 -> 0 VALID la momentul ei (--at), 1 INVALID acum (KB vechi); o cheie privata -> 2', () => { const T = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-sdjwt-cli-')); try { diff --git a/identity/sdjwt-vc.mjs b/identity/sdjwt-vc.mjs new file mode 100644 index 0000000..b2f1acf --- /dev/null +++ b/identity/sdjwt-vc.mjs @@ -0,0 +1,152 @@ +// AERE Identity, SD-JWT VC: profilul "SD-JWT-based Verifiable Digital Credentials" (draft-ietf-oauth-sd-jwt-vc-19, 31 august 2026; la +// IESG, "Waiting for AD Go-Ahead", NU inca RFC) peste sdjwt.mjs (RFC 9901). Strat subtire, fara dependinte (pista B, B9, 2026-10-18). +// +// CE FACE: +// issueSdJwtVc un SD-JWT VC: typ "dc+sd-jwt" (s.2.2.1), `vct` obligatoriu (s.2.2.2.3), `iss`, `cnf.jwk`, `iat`/`exp`/`nbf`, `status` +// optional (Token Status List, draft-ietf-oauth-status-list-21, s.2.2.2.3 si HAIP 1.0 s.6.1), `vct#integrity` optional; +// afirmatiile pe care s.2.2.2.3 le vrea in clar nu pot fi facute dezvaluibile +// verifySdJwtVc verifySdJwt cu typ dc+sd-jwt cerut, apoi: `vct` prezent si EGAL cu cel asteptat de verificator (un verificator care nu +// numeste tipul pe care il vrea primeste orice credential); nicio afirmatie din s.2.2.2.3 dezvaluita selectiv; `status` +// judecat dintr-un Status List Token dat de verificator (offline), si NEjudecat = refuz, daca verificatorul nu spune altfel +// issueStatusListJwt un Status List Token in forma JWT (typ statuslist+jwt, sub = URI-ul listei, iat, exp, ttl, status_list {bits, lst}: +// octetii starilor impachetati de la bitul cel mai putin semnificativ, DEFLATE in container ZLIB, base64url) +// readStatusListJwt il citeste si il verifica (semnatura cu cheia data, typ, sub = URI-ul cerut, iat, exp) si da starea unui index +// +// REGULILE NUMITE (pentru suita de conformitate tools/aere-conformance): un refuz al lui verifySdJwtVc numeste regula lui (`rule`): una +// din REGULI de aici, sau una a lui sdjwt.mjs cand refuzul vine de acolo; fiecare verificare poarta /*PAZA:*/ pe conditia ei buna. +// +// CE NU FACE: nu aduce nimic de pe internet (nici metadatele de tip ale lui `vct`, s.5, nici lista de stare: verificatorul le aduce si le da, +// ca `--status-list` la credentialul AERE); nu rezolva cheia emitentului din `iss` (s.2.5: JWT VC Issuer Metadata sau x5c): cheia e intrarea +// verificatorului, niciodata din jeton; nu e mdoc (ISO/IEC 18013-5, CBOR/COSE): formatul de proximitate al ARF e alt format, nefacut aici. +import zlib from 'node:zlib'; +import { issueSdJwt, presentSdJwt, verifySdJwt, publicJwk, verifyJws, signJws, privateKeyOf, ALGS } from './sdjwt.mjs'; + +export const TYP_VC = 'dc+sd-jwt'; +export const TYP_STATUS_LIST = 'statuslist+jwt'; +// draft-ietf-oauth-sd-jwt-vc-19 s.2.2.2.3: "MUST NOT be included in Disclosures and therefore MUST NOT be selectively disclosed" +export const NEDEZVALUIBILE = ['iss', 'nbf', 'exp', 'cnf', 'vct', 'vct#integrity', 'aka_vcts', 'status']; +// draft-ietf-oauth-status-list-21 s.7: tipurile de stare inregistrate; 0x03 si 0x0C..0x0F sunt ale aplicatiei +export const STARI = { 0: 'VALID', 1: 'INVALID', 2: 'SUSPENDED' }; +export const MAX_LISTA_OCTETI = 1 << 24; +/** regulile proprii ale profilului (cele ale lui sdjwt.mjs trec prin verifySdJwt si isi pastreaza numele) */ +export const REGULI = ['vct-expected', 'vct', 'vct-mismatch', 'disclosed-protected', 'form', 'status-list', 'status-index', 'status-revoked', 'status-unjudged']; +const obiect = (x) => x !== null && typeof x === 'object' && !Array.isArray(x); +const b64u = (b) => Buffer.from(b).toString('base64url'); +export { presentSdJwt as presentSdJwtVc }; + +// forma referintei de stare din jeton (status-list-21 s.6.1): { status_list: { idx: intreg >= 0, uri: sir } }; null = buna, altfel motivul +function formaReferintei(ref) { + if (!obiect(ref)) return 'status_list is not an object'; + if (!Number.isInteger(ref.idx) || ref.idx < 0) return 'idx is not a non-negative integer'; + if (typeof ref.uri !== 'string' || !ref.uri) return 'uri is not a string'; + return null; +} + +/** + * @param {{vct:string, vctIntegrity?:string, status?:{status_list:{idx:number, uri:string}}, claims?:object, disclosable?:string[], + * arrayDisclosable?:string[], issuer, holder, iss:string, iat?:number, exp?:number|null, nbf?:number, alg?, holderAlg?, decoys?:number}} o + * Restul optiunilor sunt ale lui issueSdJwt. `vct`, `status`, `vct#integrity` se dau aici, nu in `claims`, si nu pot fi dezvaluibile. + */ +export function issueSdJwtVc({ vct, vctIntegrity, status, claims = {}, disclosable = [], arrayDisclosable = [], ...rest }) { + if (typeof vct !== 'string' || !vct) throw new Error('sd-jwt-vc: vct is required (a case-sensitive string; draft-ietf-oauth-sd-jwt-vc s.2.2.2.3)'); + if (!obiect(claims)) throw new Error('sd-jwt-vc: claims must be an object'); + for (const n of NEDEZVALUIBILE) if (Object.hasOwn(claims, n)) throw new Error(`sd-jwt-vc: ${n} is set by the profile, not given among the claims`); + for (const n of [...disclosable, ...arrayDisclosable]) if (NEDEZVALUIBILE.includes(n)) throw new Error(`sd-jwt-vc: ${n} may not be selectively disclosed (s.2.2.2.3)`); + if (status !== undefined) { + if (!obiect(status) || !Object.hasOwn(status, 'status_list')) throw new Error('sd-jwt-vc: status must be { status_list: { idx, uri } } (Token Status List)'); + const e = formaReferintei(status.status_list); if (e) throw new Error('sd-jwt-vc: status.status_list: ' + e); + } + if (vctIntegrity != null && (typeof vctIntegrity !== 'string' || !/^sha(256|384|512)-[A-Za-z0-9+/=]+/.test(vctIntegrity))) throw new Error('sd-jwt-vc: vct#integrity is an "integrity metadata" string (sha256-)'); + const toate = { vct, ...(vctIntegrity != null ? { 'vct#integrity': vctIntegrity } : {}), ...(status !== undefined ? { status } : {}), ...claims }; + return issueSdJwt({ ...rest, claims: toate, disclosable, arrayDisclosable, typ: TYP_VC }); +} + +/** + * Status List Token (draft-ietf-oauth-status-list-21 s.5, forma JWT). statuses: starea fiecarui index (0 VALID, 1 INVALID, 2 SUSPENDED, ...), + * fiecare sub 2^bits; bits din {1, 2, 4, 8}. Impachetarea (s.4.1): indexul i sta la octetul floor(i*bits/8), de la bitul (i*bits) mod 8, adica + * de la bitul cel mai putin semnificativ catre cel mai semnificativ. lst = base64url(ZLIB(DEFLATE(octeti))). + */ +export function issueStatusListJwt({ issuer, alg = 'EdDSA', uri, statuses, bits = 1, iat = Math.floor(Date.now() / 1000), exp, ttl, aggregationUri }) { + if (!ALGS.includes(alg)) throw new Error('status-list: unknown alg'); + if (typeof uri !== 'string' || !uri) throw new Error('status-list: uri (the sub of the token) is required'); + if (![1, 2, 4, 8].includes(bits)) throw new Error('status-list: bits is 1, 2, 4 or 8'); + if (!Array.isArray(statuses) || !statuses.length || !statuses.every((s) => Number.isInteger(s) && s >= 0 && s < 2 ** bits)) throw new Error(`status-list: statuses is a non-empty list of integers below 2^${bits}`); + const octeti = Buffer.alloc(Math.ceil(statuses.length * bits / 8)); + statuses.forEach((s, i) => { octeti[Math.floor(i * bits / 8)] |= s << ((i * bits) % 8); }); + const lst = b64u(zlib.deflateSync(octeti, { level: 9 })); + const corp = { sub: uri, iat, ...(exp != null ? { exp } : {}), ...(ttl != null ? { ttl } : {}), status_list: { bits, lst, ...(aggregationUri ? { aggregation_uri: aggregationUri } : {}) } }; + return signJws({ alg, typ: TYP_STATUS_LIST }, corp, privateKeyOf(issuer, alg)); +} + +/** + * Citeste si verifica un Status List Token JWT cu cheia DATA (a emitentului listei; de obicei emitentul credentialului), pentru URI-ul cerut. + * Intoarce { ok, reason, entries, bits, statusAt(idx) -> 0..2^bits-1 sau null (dincolo de lista), payload }. Toate verificarile de aici + * sunt regula `status-list` a profilului. + */ +export function readStatusListJwt(jwt, { key, alg = 'EdDSA', uri, now = new Date(), clockSkewS = 60 } = {}) { + const nu = (reason) => ({ ok: false, reason, entries: 0, bits: 0, statusAt: () => null, payload: null }); + const motiv = (e) => String((e && e.message) || e).replace(/^sd-jwt: /, ''); + // semnatura, typ-ul si potrivirea alg/cheie le judeca verifyJws (o lista semnata ML-DSA-65 judecata cu cheia Ed25519 cade acolo: "does not match") + let corp = {}; + try { ({ corp } = verifyJws(jwt, publicJwk(key, alg), { typ: TYP_STATUS_LIST })); } catch (e) { if (!(false /*PAZA:status-list*/)) return nu(motiv(e)); } + if (!(typeof uri === 'string' && !!uri /*PAZA:status-list*/)) return nu('the verifier must give the uri the list was fetched for'); + if (!(corp.sub === uri /*PAZA:status-list*/)) return nu(`sub ${JSON.stringify(corp.sub)} is not the uri referenced (${uri})`); + const acum = Math.floor(new Date(now).getTime() / 1000); + if (!(Number.isFinite(corp.iat) /*PAZA:status-list*/)) return nu('iat is required (status-list s.5.1)'); + if (!(corp.iat - clockSkewS <= acum /*PAZA:status-list*/)) return nu(`issued in the future (${corp.iat})`); + if (!(corp.exp === undefined || (Number.isFinite(corp.exp) && acum < corp.exp) /*PAZA:status-list*/)) return nu(`expired at ${corp.exp}`); + const sl = corp.status_list; + if (!(obiect(sl) && [1, 2, 4, 8].includes(sl.bits) && typeof sl.lst === 'string' /*PAZA:status-list*/)) return nu('status_list must be { bits: 1|2|4|8, lst: base64url }'); + let octeti = Buffer.alloc(0); + try { + if (!/^[A-Za-z0-9_-]+$/.test(sl.lst)) throw new Error('lst is not base64url'); + octeti = zlib.inflateSync(Buffer.from(sl.lst, 'base64url'), { maxOutputLength: MAX_LISTA_OCTETI }); + } catch (e) { if (!(false /*PAZA:status-list*/)) return nu('lst cannot be inflated: ' + String(e.message || e).slice(0, 80)); } + const bits = obiect(sl) && [1, 2, 4, 8].includes(sl.bits) ? sl.bits : 1, entries = Math.floor(octeti.length * 8 / bits); + const statusAt = (idx) => (Number.isInteger(idx) && idx >= 0 && idx < entries ? (octeti[Math.floor(idx * bits / 8)] >> ((idx * bits) % 8)) & ((1 << bits) - 1) : null); + return { ok: true, reason: '', entries, bits, statusAt, payload: corp }; +} + +/** + * @param {string} token SD-JWT VC sau SD-JWT VC+KB, serializarea compacta + * @param {{expectedVct:string|string[], statusListJwt?:string, statusListKey?, statusListAlg?, requireStatus?:boolean, expectedTyp?:string} & import('./sdjwt.mjs').VerifyOptions} o + * expectedVct e CERUT. statusListJwt: Status List Token-ul adus de verificator pentru URI-ul din jeton (cheia lui: statusListKey, implicit + * cheia emitentului). requireStatus (implicit true): un `status` prezent si nejudecat e refuz, nu "nerevocat". + * Intoarce rezultatul lui verifySdJwt plus { vct, status: { present, judged, mechanism?, uri?, idx?, value?, name? } }; `rule` numeste + * regula care a refuzat (a profilului sau a lui sdjwt.mjs), null cand e valid. + */ +export function verifySdJwtVc(token, { expectedVct, statusListJwt = null, statusListKey = null, statusListAlg = null, requireStatus = true, expectedTyp = TYP_VC, ...o } = {}) { + const refuz = (rule, reason, extra = {}) => ({ valid: false, rule, reason, payload: null, disclosed: [], keyBinding: null, vct: null, status: null, ...extra }); + const vcts = Array.isArray(expectedVct) ? expectedVct : expectedVct == null ? null : [expectedVct]; + if (!(Array.isArray(vcts) && vcts.length > 0 && vcts.every((v) => typeof v === 'string' && !!v) /*PAZA:vct-expected*/)) return refuz('vct-expected', 'the verifier must name the vct it expects (expectedVct)'); + const tipuri = Array.isArray(vcts) ? vcts : []; + const r = verifySdJwt(token, { ...o, expectedTyp }); + if (!r.valid) return { ...r, vct: null, status: null }; + const p = r.payload; + if (!(typeof p.vct === 'string' && !!p.vct /*PAZA:vct*/)) return refuz('vct', 'vct is required and the payload has none (draft-ietf-oauth-sd-jwt-vc s.2.2.2.3)'); + if (!(tipuri.includes(p.vct) /*PAZA:vct-mismatch*/)) return refuz('vct-mismatch', `vct ${JSON.stringify(p.vct)} is not the type expected (${tipuri.join(', ')})`); + const dez = r.disclosed.filter((n) => NEDEZVALUIBILE.includes(n)); + if (!(dez.length === 0 /*PAZA:disclosed-protected*/)) return refuz('disclosed-protected', `${dez[0]} was selectively disclosed; an SD-JWT VC carries it in the clear (s.2.2.2.3)`); + if (!(p['vct#integrity'] === undefined || typeof p['vct#integrity'] === 'string' /*PAZA:form*/)) return refuz('form', 'vct#integrity is not a string'); + let status = { present: false, judged: false }; + if (p.status !== undefined) { + if (!(obiect(p.status) /*PAZA:form*/)) return refuz('form', 'status is not an object'); + const ref = obiect(p.status) ? p.status.status_list : undefined; + status = { present: true, judged: false, mechanism: ref !== undefined ? 'status_list' : (Object.keys(obiect(p.status) ? p.status : {}).join(',') || 'none') }; + if (ref !== undefined) { + const e = formaReferintei(ref); + if (!(e === null /*PAZA:form*/)) return refuz('form', 'status.status_list: ' + e); + status.uri = ref.uri; status.idx = ref.idx; + if (statusListJwt != null) { + const l = readStatusListJwt(statusListJwt, { key: statusListKey ?? o.issuerKey, alg: statusListAlg ?? o.issuerAlg ?? 'EdDSA', uri: ref.uri, now: o.now, clockSkewS: o.clockSkewS }); + if (!(l.ok /*PAZA:status-list*/)) return refuz('status-list', 'status list: ' + l.reason, { vct: p.vct, status }); + const v = l.statusAt(ref.idx); + if (!(v !== null /*PAZA:status-index*/)) return refuz('status-index', `status list: index ${ref.idx} is beyond the list (${l.entries} entries)`, { vct: p.vct, status }); + status.judged = true; status.value = v; status.name = STARI[v] ?? 'application-specific'; + if (!(v === 0 /*PAZA:status-revoked*/)) return refuz('status-revoked', `status ${v} (${status.name}) in ${ref.uri} at index ${ref.idx}`, { vct: p.vct, status }); + } + } + if (!(status.judged || !requireStatus /*PAZA:status-unjudged*/)) return refuz('status-unjudged', `the credential names a status (${status.mechanism}) that was not judged: give statusListJwt fetched from ${status.uri ?? 'the issuer'}, or set requireStatus:false`, { vct: p.vct, status }); + } + return { ...r, vct: p.vct, status }; +} diff --git a/identity/sdjwt.mjs b/identity/sdjwt.mjs index f39c6fd..d3f59bc 100644 --- a/identity/sdjwt.mjs +++ b/identity/sdjwt.mjs @@ -1,6 +1,6 @@ // AERE Identity, SD-JWT (IETF RFC 9901, noiembrie 2025): acelasi emitent si acelasi detinator ca in identity.mjs, in formatul standardului -// (roadmap master punctul 12, "interoperare SD-JWT"; pista B, 2026-09-30). Judecat pe vectorii standardului (RFC 9901 s.5 si A.5), NU -// contra altei biblioteci SD-JWT: interoperarea cu o implementare straina e NEMASURATA (spus in README). +// (roadmap master punctul 12, "interoperare SD-JWT"; pista B, 2026-09-30). Judecat pe vectorii standardului (RFC 9901 s.5 si A.5) si, din +// 2026-10-18, contra @sd-jwt/core in ambele sensuri (interop/interop-sdjwt.mjs; fixturile lor, judecate offline, in proba-sdjwt.mjs). // // CE FACE: // issueSdJwt emitentul face un SD-JWT in serializarea compacta: JWT semnat de emitent, cu digesturile afirmatiilor dezvaluibile in `_sd` @@ -11,9 +11,9 @@ // nonce-ul lui CERUTE cand exista (sau se cere) Key Binding, cu `exp` cerut, cu tipul explicit al jetonului verificat // // ALGORITMII (JWS): ES256 (P-256, cel din exemplele RFC 9901), EdDSA / Ed25519 (RFC 8037) si ML-DSA-65 (post-cuantic; numele si forma -// cheii JWK "AKP" dupa draftul IETF draft-ietf-cose-dilithium, NU inca un standard publicat). Un emitent AERE semneaza cu cheia lui Ed25519 -// (algoritm inregistrat, cunoscut bibliotecilor JOSE) sau cu cheia ML-DSA-65 (numai pentru verificatorii care stiu numele din draft); o -// semnatura hibrida in acelasi jeton ar cere serializarea JSON generala a JWS si nu e facuta aici. +// cheii JWK "AKP" din RFC 9964, mai 2026). Un emitent AERE semneaza cu cheia lui Ed25519 (algoritm cunoscut tuturor bibliotecilor JOSE) +// sau cu cheia ML-DSA-65 (masurat 2026-10-18: jose 6.2.12 pe Node 24 o semneaza si o verifica); o semnatura hibrida in acelasi jeton ar +// cere serializarea JSON generala a JWS si nu e facuta aici. // // Revizuirea adversariala din 2026-09-30 (inainte de publicare) a gasit si s-au reparat: emitentul semna structura SD-JWT venita in valorile // afirmatiilor (`_sd`, `{"...": d}`), deci detinatorul putea dezvalui afirmatii pe care emitentul nu le-a vazut; prezentarea arata un element @@ -21,25 +21,34 @@ // implicit (un KB-JWT trecea drept jeton de emitent); o cheie publica Node nu era primita; exp/nbf ale KB, `crit` stricat, base64url // necanonic si `_sd_alg` imbricat. Fiecare are proba lui in proba-sdjwt.mjs si plantarea lui in control-negativ-sdjwt.mjs. // -// CE NU FACE: nu e SD-JWT VC (nu cere `vct` si nu verifica metadatele de tip ale emitentului); nu citeste liste de stare in jeton (pentru -// revocare, credentialul AERE din identity.mjs are lista lui); nu dezvaluie recursiv la emitere (verificarea stie dezvaluiri recursive). +// REGULILE NUMITE (2026-10-18, pentru suita de conformitate tools/aere-conformance): fiecare refuz al lui verifySdJwt numeste regula lui +// (`rule`), din lista REGULI; fiecare verificare a unei reguli poarta marcajul /*PAZA:*/ pe conditia ei BUNA, pe care controlul +// negativ al suitei o face adevarata intr-o copie. Verificatorul se opreste la primul refuz (un SD-JWT invalid nu se mai citeste mai departe). +// +// CE NU FACE: nu e SD-JWT VC (profilul e sdjwt-vc.mjs); nu citeste liste de stare in jeton (sdjwt-vc.mjs citeste Token Status List); nu +// dezvaluie recursiv la emitere (verificarea stie dezvaluiri recursive). import crypto from 'node:crypto'; const b64u = (b) => Buffer.from(b).toString('base64url'); -// base64url CANONIC: decodat si recodat trebuie sa dea acelasi text (altfel aceeasi semnatura are mai multe scrieri, si un depozit de -// reluari care tine sirul jetonului e ocolit schimbatnd bitii nefolositi ai ultimului caracter) -const dinB64u = (s, ce) => { - if (typeof s !== 'string' || !/^[A-Za-z0-9_-]*$/.test(s)) throw new Error(`sd-jwt: ${ce} is not base64url`); - const b = Buffer.from(s, 'base64url'); - if (b.toString('base64url') !== s) throw new Error(`sd-jwt: ${ce} is not canonical base64url`); - return b; -}; -const jsonB64u = (s, ce) => { let o; try { o = JSON.parse(dinB64u(s, ce).toString('utf8')); } catch (e) { throw new Error(/canonical/.test(e.message) ? e.message : `sd-jwt: ${ce} is not base64url JSON`); } return o; }; -const sha256b64u = (s) => crypto.createHash('sha256').update(Buffer.from(s, 'ascii')).digest('base64url'); -const obiect = (x) => x !== null && typeof x === 'object' && !Array.isArray(x); export const ALGS = ['ES256', 'EdDSA', 'Ed25519', 'ML-DSA-65']; export const TYP = 'aere+sd-jwt'; const AERE_ALG = 'ed25519+ml-dsa-65'; +/** regulile pe care le poate numi un refuz al lui verifySdJwt (ordinea e cea a verificarii; `form` si pentru ceasul verificatorului) */ +export const REGULI = ['form', 'alg', 'typ', 'crit', 'key', 'signature', 'issuer', 'sd-alg', 'disclosure-form', 'disclosure-twice', 'digest-twice', + 'disclosure-name', 'claim-conflict', 'unreferenced', 'time', 'kb-context', 'kb-required', 'kb-cnf', 'kb-claims', 'kb-audience', 'kb-nonce', 'kb-freshness', 'kb-sd-hash']; +class Refuz extends Error { constructor(rule, message) { super(message); this.rule = rule; } } +const nu = (rule, msg) => { if (!REGULI.includes(rule)) throw new Error('sd-jwt: undeclared rule ' + rule); return new Refuz(rule, 'sd-jwt: ' + msg); }; +// base64url CANONIC: decodat si recodat trebuie sa dea acelasi text (altfel aceeasi semnatura are mai multe scrieri, si un depozit de +// reluari care tine sirul jetonului e ocolit schimbatnd bitii nefolositi ai ultimului caracter) +const dinB64u = (s, ce) => { + if (!(typeof s === 'string' && /^[A-Za-z0-9_-]*$/.test(s) /*PAZA:form*/)) throw nu('form', `${ce} is not base64url`); + const b = Buffer.from(s, 'base64url'); + if (!(b.toString('base64url') === s /*PAZA:form*/)) throw nu('form', `${ce} is not canonical base64url`); + return b; +}; +const jsonB64u = (s, ce) => { let o; try { o = JSON.parse(dinB64u(s, ce).toString('utf8')); } catch (e) { throw e instanceof Refuz ? e : nu('form', `${ce} is not base64url JSON`); } return o; }; +const sha256b64u = (s) => crypto.createHash('sha256').update(Buffer.from(s, 'ascii')).digest('base64url'); +const obiect = (x) => x !== null && typeof x === 'object' && !Array.isArray(x); // ---------------------------------------------------------------- chei JWK si semnaturi JWS /** @@ -52,12 +61,12 @@ export function publicJwk(k, alg = 'EdDSA') { else if (obiect(k) && k.alg === AERE_ALG && typeof k.ed25519 === 'string') k = crypto.createPublicKey({ key: Buffer.from(ml ? k.mldsa65 : k.ed25519, 'base64'), format: 'der', type: 'spki' }); if (k instanceof crypto.KeyObject) return (k.type === 'public' ? k : crypto.createPublicKey(k)).export({ format: 'jwk' }); if (obiect(k) && k.kty) return k; - throw new Error('sd-jwt: not a key (a JWK, a Node key object, or AERE identity keys)'); + throw nu('key', 'not a key (a JWK, a Node key object, or AERE identity keys)'); } function cheiePublica(jwk) { - if (!obiect(jwk) || !['EC', 'OKP', 'AKP'].includes(jwk.kty)) throw new Error('sd-jwt: the key is not an EC, OKP or AKP JWK'); - if ('d' in jwk || 'priv' in jwk) throw new Error('sd-jwt: a private JWK was given where a public key belongs'); - return crypto.createPublicKey({ key: jwk, format: 'jwk' }); + if (!(obiect(jwk) && ['EC', 'OKP', 'AKP'].includes(jwk.kty) /*PAZA:key*/)) throw nu('key', 'the key is not an EC, OKP or AKP JWK'); + if (!(!('d' in jwk) && !('priv' in jwk) /*PAZA:key*/)) throw nu('key', 'a private JWK was given where a public key belongs'); + try { return crypto.createPublicKey({ key: jwk, format: 'jwk' }); } catch (e) { throw nu('key', 'the key cannot be read: ' + String(e.message || e).slice(0, 120)); } } // algoritmul trebuie sa fie al cheii: un jeton nu alege el cu ce se verifica (atacul de confuzie a algoritmului, RFC 8725 s.2.1) function potriveste(alg, key) { @@ -67,27 +76,31 @@ function potriveste(alg, key) { if (alg === 'ML-DSA-65') return t === 'ml-dsa-65'; return false; } -// tipul: un sir exact; sau `undefined` = orice tip explicit de SD-JWT ("...+sd-jwt" sau "sd-jwt"); sau null = orice, in afara de kb+jwt +// tipul: un sir exact; sau `undefined` = orice tip explicit de SD-JWT ("...+sd-jwt" sau "sd-jwt"); sau null = orice, in afara de kb+jwt. +// RFC 7515 s.4.1.9: un typ fara "/" se citeste ca si cum ar avea prefixul "application/", deci "application/dc+sd-jwt" si "dc+sd-jwt" sunt +// acelasi tip (2026-10-18, la interoperare: bibliotecile JOSE scriu oricare din cele doua forme) +const faraPrefix = (t) => (typeof t === 'string' && t.startsWith('application/') && !t.slice(12).includes('/') ? t.slice(12) : t); function tipBun(typ, cerut) { - if (cerut === undefined) return typeof typ === 'string' && /(^|\+)sd-jwt$/.test(typ); - if (cerut === null) return typ !== 'kb+jwt'; - return typ === cerut; + const t = faraPrefix(typ); + if (cerut === undefined) return typeof t === 'string' && /(^|\+)sd-jwt$/.test(t); + if (cerut === null) return t !== 'kb+jwt'; + return t === faraPrefix(cerut); } function verificaJws(jws, jwk, { typ } = {}) { const parti = String(jws).split('.'); - if (parti.length !== 3) throw new Error('sd-jwt: a JWS has three parts'); + if (!(parti.length === 3 /*PAZA:form*/)) throw nu('form', 'a JWS has three parts'); const antet = jsonB64u(parti[0], 'the JWS header'), corp = jsonB64u(parti[1], 'the JWS payload'); - if (!obiect(antet) || !obiect(corp)) throw new Error('sd-jwt: the JWS header and payload must be objects'); - if (!ALGS.includes(antet.alg)) throw new Error(`sd-jwt: alg ${JSON.stringify(antet.alg)} is not accepted (accepted: ${ALGS.join(', ')}; never none)`); - if (!tipBun(antet.typ, typ)) throw new Error(`sd-jwt: typ ${JSON.stringify(antet.typ)} is not the type expected (${typ === undefined ? 'an explicit ...+sd-jwt' : typ === null ? 'anything but kb+jwt' : typ})`); + if (!(obiect(antet) && obiect(corp) /*PAZA:form*/)) throw nu('form', 'the JWS header and payload must be objects'); + if (!(ALGS.includes(antet.alg) /*PAZA:alg*/)) throw nu('alg', `alg ${JSON.stringify(antet.alg)} is not accepted (accepted: ${ALGS.join(', ')}; never none)`); + if (!(tipBun(antet.typ, typ) /*PAZA:typ*/)) throw nu('typ', `typ ${JSON.stringify(antet.typ)} is not the type expected (${typ === undefined ? 'an explicit ...+sd-jwt' : typ === null ? 'anything but kb+jwt' : typ})`); // `crit` numeste parametri pe care verificatorul TREBUIE sa-i inteleaga; nu intelegem niciunul, deci orice `crit` (bun sau stricat) e refuz - if (Object.hasOwn(antet, 'crit')) throw new Error('sd-jwt: critical header parameters (crit) are not understood'); + if (!(!Object.hasOwn(antet, 'crit') /*PAZA:crit*/)) throw nu('crit', 'critical header parameters (crit) are not understood'); const key = cheiePublica(jwk); - if (!potriveste(antet.alg, key)) throw new Error(`sd-jwt: alg ${antet.alg} does not match the ${key.asymmetricKeyType} key given`); + if (!(potriveste(antet.alg, key) /*PAZA:key*/)) throw nu('key', `alg ${antet.alg} does not match the ${key.asymmetricKeyType} key given`); const date = Buffer.from(parti[0] + '.' + parti[1], 'ascii'), sig = dinB64u(parti[2], 'the JWS signature'); let ok = false; try { ok = antet.alg === 'ES256' ? sig.length === 64 && crypto.verify('sha256', date, { key, dsaEncoding: 'ieee-p1363' }, sig) : crypto.verify(null, date, key, sig); } catch { ok = false; } - if (!ok) throw new Error('sd-jwt: the signature does not verify with the key given'); + if (!(ok /*PAZA:signature*/)) throw nu('signature', 'the signature does not verify with the key given'); return { antet, corp }; } function semneazaJws(antet, corp, priv) { @@ -97,6 +110,8 @@ function semneazaJws(antet, corp, priv) { return cap + '.' + b64u(sig); } const cheiePrivata = (k, alg) => (k && k.privat ? (alg === 'ML-DSA-65' ? k.privat.mldsa65 : k.privat.ed25519) : k); +// pentru profilurile de deasupra (sdjwt-vc.mjs: Status List Token), ca semnatura JWS sa se faca intr-un singur loc +export { verificaJws as verifyJws, semneazaJws as signJws, cheiePrivata as privateKeyOf }; // structura SD-JWT intr-o valoare: o cheie `_sd`/`_sd_alg` intr-un obiect sau un element {"...": x} intr-o lista, oriunde in adancime function areStructuraSd(v) { const stiva = [v]; @@ -111,15 +126,17 @@ function areStructuraSd(v) { // ---------------------------------------------------------------- emitere si prezentare /** * @param {{issuer, claims:object, disclosable?:string[], arrayDisclosable?:string[], holder, iss:string, iat?:number, exp?:number|null, nbf?:number, - * alg?:'EdDSA'|'ML-DSA-65'|'ES256', holderAlg?:'EdDSA'|'ML-DSA-65'|'ES256', decoys?:number}} o + * alg?:'EdDSA'|'ML-DSA-65'|'ES256', holderAlg?:'EdDSA'|'ML-DSA-65'|'ES256', decoys?:number, typ?:string}} o * issuer: chei AERE sau KeyObject privat. holder: cheia PUBLICA a detinatorului (sau cheile lui AERE). disclosable: numele afirmatiilor de * sus dezvaluibile; arrayDisclosable: listele de sus ale caror ELEMENTE sunt dezvaluibile una cate una. exp implicit: un an de la iat - * (null: fara exp, pe care verifySdJwt il refuza implicit). Intoarce { sdJwt, disclosures:[{name, value, disclosure}] }. + * (null: fara exp, pe care verifySdJwt il refuza implicit). typ: tipul explicit al jetonului (implicit TYP; un profil ca SD-JWT VC isi + * pune al lui, "dc+sd-jwt"; RFC 9901 s.9.11). Intoarce { sdJwt, disclosures:[{name, value, disclosure}] }. */ -export function issueSdJwt({ issuer, claims, disclosable = [], arrayDisclosable = [], holder, iss, iat = Math.floor(Date.now() / 1000), exp, nbf, alg = 'EdDSA', holderAlg = 'EdDSA', decoys = 0 }) { +export function issueSdJwt({ issuer, claims, disclosable = [], arrayDisclosable = [], holder, iss, iat = Math.floor(Date.now() / 1000), exp, nbf, alg = 'EdDSA', holderAlg = 'EdDSA', decoys = 0, typ = TYP }) { if (!obiect(claims)) throw new Error('sd-jwt: claims must be an object'); if (typeof iss !== 'string' || !iss) throw new Error('sd-jwt: iss is required'); if (!ALGS.includes(alg) || !ALGS.includes(holderAlg)) throw new Error('sd-jwt: unknown alg'); + if (!tipBun(typ, undefined)) throw new Error('sd-jwt: typ must be an explicit SD-JWT type ("...+sd-jwt", RFC 9901 s.9.11)'); // RFC 9901 s.4.1 (regula 7 a emitentului): emitentul nu semneaza digesturi pe care nu le-a facut el; o valoare care poarta deja `_sd`, // `_sd_alg` sau un element {"...": d} ar lasa detinatorul sa dezvaluie afirmatii nevazute de emitent if (areStructuraSd(claims)) throw new Error('sd-jwt: a claim value carries SD-JWT structure (_sd, _sd_alg or a {"...": digest} element) or a __proto__ key; the issuer signs only digests it made'); @@ -139,7 +156,7 @@ export function issueSdJwt({ issuer, claims, disclosable = [], arrayDisclosable const e = exp === undefined ? iat + 365 * 86400 : exp; if (e != null) corp.exp = e; if (nbf != null) corp.nbf = nbf; corp.cnf = { jwk: publicJwk(holder, holderAlg) }; - const jwt = semneazaJws({ alg, typ: TYP }, corp, cheiePrivata(issuer, alg)); + const jwt = semneazaJws({ alg, typ }, corp, cheiePrivata(issuer, alg)); return { sdJwt: jwt + '~' + dez.map((x) => x.disclosure + '~').join(''), disclosures: dez }; } @@ -183,35 +200,40 @@ export function presentSdJwt({ sdJwt, reveal = [], holder, holderAlg = 'EdDSA', * now?:Date, maxAgeS?:number, clockSkewS?:number, expectedTyp?:string|null}} o * issuerKey: cheia EMITENTULUI data de verificator (JWK, KeyObject, cheile AERE ale emitentului); niciodata din jeton. audience si nonce * sunt ale verificatorului si se CER cand exista (sau se cere) Key Binding. expectedTyp: implicit orice tip explicit "...+sd-jwt". - * Intoarce { valid, reason, payload, disclosed:[nume], issuer, issuerChecked, keyBinding:{aud, nonce, iat, alg}|null }. + * Intoarce { valid, rule, reason, payload, disclosed:[nume], issuer, issuerChecked, keyBinding:{aud, nonce, iat, alg}|null }; `rule` e + * regula (din REGULI) care a refuzat, null cand e valid. */ export function verifySdJwt(sdJwt, { issuerKey, issuerAlg = 'EdDSA', expectedIssuer = null, audience = null, nonce = null, requireKeyBinding = true, requireExp = true, now = new Date(), maxAgeS = 300, clockSkewS = 60, expectedTyp } = {}) { - const refuz = (reason) => ({ valid: false, reason, payload: null, disclosed: [], keyBinding: null }); + const refuz = (rule, reason) => ({ valid: false, rule, reason, payload: null, disclosed: [], keyBinding: null }); + const motiv = (e) => String((e && e.message) || e).replace(/^sd-jwt: /, ''); + const regula = (e) => (e instanceof Refuz ? e.rule : 'form'); try { - if (typeof sdJwt !== 'string' || !sdJwt.includes('~')) return refuz('not an SD-JWT (no ~)'); + if (!(typeof sdJwt === 'string' && sdJwt.includes('~') /*PAZA:form*/)) return refuz('form', 'not an SD-JWT (no ~)'); + // ceasul verificatorului: un `now` care nu e un timp ar lasa toate comparatiile de timp sa treaca (NaN nu e mai mare decat nimic) + const acum = Math.floor(new Date(now).getTime() / 1000); + if (!(Number.isFinite(acum) /*PAZA:form*/)) return refuz('form', 'the verifier clock (now) is not a time'); const parti = sdJwt.split('~'); const jwt = parti[0], kb = parti[parti.length - 1], dez = parti.slice(1, -1); - if (dez.some((d) => d === '')) return refuz('an empty disclosure between two ~'); + if (!(!dez.some((d) => d === '') /*PAZA:form*/)) return refuz('form', 'an empty disclosure between two ~'); // RFC 9901 s.7.3 pasul 5: publicul si nonce-ul verificatorului se compara; fara ele, o prezentare facuta pentru altul ar trece - if ((requireKeyBinding || kb !== '') && (typeof audience !== 'string' || !audience || typeof nonce !== 'string' || !nonce)) { - return refuz('the verifier must give its audience and nonce to judge a key binding (RFC 9901 s.7.3)'); - } + const context = typeof audience === 'string' && !!audience && typeof nonce === 'string' && !!nonce; + if (!(!(requireKeyBinding || kb !== '') || context /*PAZA:kb-context*/)) return refuz('kb-context', 'the verifier must give its audience and nonce to judge a key binding (RFC 9901 s.7.3)'); // 2. JWT-ul emitentului const { antet, corp } = verificaJws(jwt, publicJwk(issuerKey, issuerAlg), { typ: expectedTyp }); - if (expectedIssuer != null && corp.iss !== expectedIssuer) return refuz(`issued by ${JSON.stringify(corp.iss)}, not ${expectedIssuer}`); + if (!(expectedIssuer == null || corp.iss === expectedIssuer /*PAZA:issuer*/)) return refuz('issuer', `issued by ${JSON.stringify(corp.iss)}, not ${expectedIssuer}`); const alg = corp._sd_alg === undefined ? 'sha-256' : corp._sd_alg; - if (alg !== 'sha-256') return refuz(`_sd_alg ${JSON.stringify(corp._sd_alg)} is not understood (only sha-256)`); + if (!(alg === 'sha-256' /*PAZA:sd-alg*/)) return refuz('sd-alg', `_sd_alg ${JSON.stringify(corp._sd_alg)} is not understood (only sha-256)`); // 3. dezvaluirile: digest -> continut const dupaDigest = new Map(); for (const d of dez) { const dg = sha256b64u(d); - if (dupaDigest.has(dg)) return refuz('the same disclosure is given twice'); - let c; try { c = JSON.parse(dinB64u(d, 'a disclosure').toString('utf8')); } catch { return refuz('a disclosure is not base64url JSON'); } - if (!Array.isArray(c) || (c.length !== 2 && c.length !== 3) || typeof c[0] !== 'string') return refuz('a disclosure is not [salt, name, value] or [salt, value]'); + if (!(!dupaDigest.has(dg) /*PAZA:disclosure-twice*/)) return refuz('disclosure-twice', 'the same disclosure is given twice'); + let c; try { c = JSON.parse(dinB64u(d, 'a disclosure').toString('utf8')); } catch { if (!(false /*PAZA:disclosure-form*/)) return refuz('disclosure-form', 'a disclosure is not base64url JSON'); continue; } + if (!(Array.isArray(c) && (c.length === 2 || c.length === 3) && typeof c[0] === 'string' /*PAZA:disclosure-form*/)) return refuz('disclosure-form', 'a disclosure is not [salt, name, value] or [salt, value]'); dupaDigest.set(dg, c); } const vazute = new Set(), folosite = new Set(); - const vezi = (dg) => { if (vazute.has(dg)) throw new Error('the digest ' + dg.slice(0, 12) + '.. appears more than once'); vazute.add(dg); }; + const vezi = (dg) => { if (!(!vazute.has(dg) /*PAZA:digest-twice*/)) throw nu('digest-twice', 'the digest ' + dg.slice(0, 12) + '.. appears more than once'); vazute.add(dg); }; const proceseaza = (x, sus = false) => { if (Array.isArray(x)) { const out = []; @@ -220,7 +242,7 @@ export function verifySdJwt(sdJwt, { issuerKey, issuerAlg = 'EdDSA', expectedIss vezi(e['...']); const c = dupaDigest.get(e['...']); if (!c) continue; // nedezvaluit: elementul se scoate - if (c.length !== 2) throw new Error('an array element disclosure must be [salt, value]'); + if (!(c.length === 2 /*PAZA:disclosure-form*/)) throw nu('disclosure-form', 'an array element disclosure must be [salt, value]'); folosite.add(e['...']); out.push(proceseaza(c[1])); } else out.push(proceseaza(e)); } @@ -229,55 +251,62 @@ export function verifySdJwt(sdJwt, { issuerKey, issuerAlg = 'EdDSA', expectedIss if (!obiect(x)) return x; // JSON.parse face din "__proto__" o proprietate proprie, iar `out[k] = v` pe un obiect obisnuit i-ar schimba PROTOTIPUL (afirmatii // mostenite, nevazute de Object.keys); o afirmatie cu numele asta, in clar sau intr-o valoare dezvaluita, se refuza - if (Object.hasOwn(x, '__proto__')) throw new Error('a claim may not be named __proto__'); + if (!(!Object.hasOwn(x, '__proto__') /*PAZA:disclosure-name*/)) throw nu('disclosure-name', 'a claim may not be named __proto__'); const out = {}; - // `_sd_alg` se scoate NUMAI de sus (RFC 9901 s.7.1 pasul 3.f); mai jos e o afirmatie ca oricare - for (const [k, v] of Object.entries(x)) if (k !== '_sd' && !(sus && k === '_sd_alg')) out[k] = proceseaza(v); + // `_sd_alg` se scoate de sus (RFC 9901 s.7.1 pasul 3.f). Mai jos NU are voie sa existe: "It MUST NOT be used in any object nested + // within the payload" (s.4.1.1), deci un jeton care il poarta imbricat (in clar sau intr-o valoare dezvaluita) nu e un SD-JWT valid. + // Pana pe 2026-10-18 era pastrat ca o afirmatie oarecare; la interoperare, @sd-jwt/core 0.23.0 il refuza, si textul s.4.1.1 ii da dreptate. + for (const [k, v] of Object.entries(x)) { + if (k === '_sd') continue; + if (k === '_sd_alg') { if (!(sus /*PAZA:sd-alg*/)) throw nu('sd-alg', '_sd_alg below the top level of the payload (RFC 9901 s.4.1.1)'); continue; } + out[k] = proceseaza(v); + } if (x._sd !== undefined) { - if (!Array.isArray(x._sd) || !x._sd.every((s) => typeof s === 'string')) throw new Error('_sd is not a list of strings'); + if (!(Array.isArray(x._sd) && x._sd.every((s) => typeof s === 'string') /*PAZA:disclosure-form*/)) throw nu('disclosure-form', '_sd is not a list of strings'); for (const dg of x._sd) { vezi(dg); const c = dupaDigest.get(dg); if (!c) continue; - if (c.length !== 3 || typeof c[1] !== 'string') throw new Error('an object property disclosure must be [salt, name, value]'); - if (c[1] === '_sd' || c[1] === '...' || c[1] === '__proto__') throw new Error(`a disclosure may not name ${c[1]}`); - if (Object.hasOwn(out, c[1])) throw new Error(`the disclosed claim ${c[1]} already exists at its level`); + if (!(c.length === 3 && typeof c[1] === 'string' /*PAZA:disclosure-form*/)) throw nu('disclosure-form', 'an object property disclosure must be [salt, name, value]'); + // `_sd_alg` dezvaluit: s.7.1 l-ar insera (3.c.ii.4) si apoi l-ar scoate (3.f); refuzam in loc sa il scoatem in tacere, ca lista + // `disclosed` sa nu numeasca o afirmatie pe care payload-ul procesat nu o poarta (la fel face si @sd-jwt/core 0.23.0) + if (!(c[1] !== '_sd' && c[1] !== '...' && c[1] !== '_sd_alg' && c[1] !== '__proto__' /*PAZA:disclosure-name*/)) throw nu('disclosure-name', `a disclosure may not name ${c[1]}`); + if (!(!Object.hasOwn(out, c[1]) /*PAZA:claim-conflict*/)) throw nu('claim-conflict', `the disclosed claim ${c[1]} already exists at its level`); folosite.add(dg); out[c[1]] = proceseaza(c[2]); } } return out; }; let payload; - try { payload = proceseaza(corp, true); } catch (e) { return refuz(e.message); } + try { payload = proceseaza(corp, true); } catch (e) { return refuz(regula(e), motiv(e)); } // 5. o dezvaluire nelegata de niciun digest = refuz - if (folosite.size !== dupaDigest.size) return refuz('a disclosure is not referenced by any digest of the issuer-signed JWT'); + if (!(folosite.size === dupaDigest.size /*PAZA:unreferenced*/)) return refuz('unreferenced', 'a disclosure is not referenced by any digest of the issuer-signed JWT'); const disclosed = [...dupaDigest.entries()].map(([, c]) => (c.length === 3 ? c[1] : '[]')); // 6. valabilitatea pe ceasul verificatorului (exp cerut si fara toleranta; nbf si iat cu toleranta numai pe inceput, ca identity.mjs) - const acum = Math.floor(new Date(now).getTime() / 1000); - for (const k of ['exp', 'nbf', 'iat']) if (payload[k] !== undefined && !Number.isFinite(payload[k])) return refuz(`${k} is not a number`); - if (requireExp && payload.exp === undefined) return refuz('exp is required and the processed payload has none (RFC 9901 s.9.7)'); - if (payload.exp !== undefined && acum >= payload.exp) return refuz(`expired at ${payload.exp}`); - if (payload.nbf !== undefined && payload.nbf - clockSkewS > acum) return refuz(`not valid before ${payload.nbf}`); - if (payload.iat !== undefined && payload.iat - clockSkewS > acum) return refuz(`issued in the future (${payload.iat})`); - const rez = { valid: true, reason: '', payload, disclosed, issuer: corp.iss, issuerChecked: expectedIssuer != null, alg: antet.alg }; + for (const k of ['exp', 'nbf', 'iat']) if (!(payload[k] === undefined || Number.isFinite(payload[k]) /*PAZA:time*/)) return refuz('time', `${k} is not a number`); + if (!(!requireExp || payload.exp !== undefined /*PAZA:time*/)) return refuz('time', 'exp is required and the processed payload has none (RFC 9901 s.9.7)'); + if (!(payload.exp === undefined || acum < payload.exp /*PAZA:time*/)) return refuz('time', `expired at ${payload.exp}`); + if (!(payload.nbf === undefined || payload.nbf - clockSkewS <= acum /*PAZA:time*/)) return refuz('time', `not valid before ${payload.nbf}`); + if (!(payload.iat === undefined || payload.iat - clockSkewS <= acum /*PAZA:time*/)) return refuz('time', `issued in the future (${payload.iat})`); + const rez = { valid: true, rule: null, reason: '', payload, disclosed, issuer: corp.iss, issuerChecked: expectedIssuer != null, alg: antet.alg }; // s.7.3: Key Binding JWT if (kb === '') { - if (requireKeyBinding) return refuz('key binding is required and the SD-JWT has none (it ends with ~)'); + if (!(!requireKeyBinding /*PAZA:kb-required*/)) return refuz('kb-required', 'key binding is required and the SD-JWT has none (it ends with ~)'); return { ...rez, keyBinding: null }; } - if (!obiect(payload.cnf) || !obiect(payload.cnf.jwk)) return refuz('a key binding JWT is given but the SD-JWT names no holder key (cnf.jwk)'); + if (!(obiect(payload.cnf) && obiect(payload.cnf.jwk) /*PAZA:kb-cnf*/)) return refuz('kb-cnf', 'a key binding JWT is given but the SD-JWT names no holder key (cnf.jwk)'); let k; - try { k = verificaJws(kb, payload.cnf.jwk, { typ: 'kb+jwt' }); } catch (e) { return refuz('key binding: ' + e.message.replace(/^sd-jwt: /, '')); } + try { k = verificaJws(kb, payload.cnf.jwk, { typ: 'kb+jwt' }); } catch (e) { return refuz(regula(e), 'key binding: ' + motiv(e)); } const K = k.corp; - if (typeof K.nonce !== 'string' || typeof K.aud !== 'string' || !Number.isFinite(K.iat) || typeof K.sd_hash !== 'string') return refuz('key binding: aud, nonce, iat and sd_hash are required'); - if (K.aud !== audience) return refuz(`key binding: made for ${K.aud}, not ${audience}`); - if (K.nonce !== nonce) return refuz('key binding: another nonce'); - if (Math.abs(acum - K.iat) > maxAgeS) return refuz(`key binding: made at ${K.iat}, outside ${maxAgeS} s of this clock`); + if (!(typeof K.nonce === 'string' && typeof K.aud === 'string' && Number.isFinite(K.iat) && typeof K.sd_hash === 'string' /*PAZA:kb-claims*/)) return refuz('kb-claims', 'key binding: aud, nonce, iat and sd_hash are required'); + if (!(K.aud === audience /*PAZA:kb-audience*/)) return refuz('kb-audience', `key binding: made for ${K.aud}, not ${audience}`); + if (!(K.nonce === nonce /*PAZA:kb-nonce*/)) return refuz('kb-nonce', 'key binding: another nonce'); + if (!(Math.abs(acum - K.iat) <= maxAgeS /*PAZA:kb-freshness*/)) return refuz('kb-freshness', `key binding: made at ${K.iat}, outside ${maxAgeS} s of this clock`); // RFC 9901 s.7.3 pasul 5.h: si exp/nbf ale KB-JWT, daca le poarta (RFC 7519) - if (K.exp !== undefined && (!Number.isFinite(K.exp) || acum >= K.exp)) return refuz(`key binding: expired at ${K.exp}`); - if (K.nbf !== undefined && (!Number.isFinite(K.nbf) || K.nbf - clockSkewS > acum)) return refuz(`key binding: not valid before ${K.nbf}`); + if (!(K.exp === undefined || (Number.isFinite(K.exp) && acum < K.exp) /*PAZA:kb-freshness*/)) return refuz('kb-freshness', `key binding: expired at ${K.exp}`); + if (!(K.nbf === undefined || (Number.isFinite(K.nbf) && K.nbf - clockSkewS <= acum) /*PAZA:kb-freshness*/)) return refuz('kb-freshness', `key binding: not valid before ${K.nbf}`); const baza = sdJwt.slice(0, sdJwt.length - kb.length); - if (sha256b64u(baza) !== K.sd_hash) return refuz('key binding: sd_hash is not the hash of what was presented'); + if (!(sha256b64u(baza) === K.sd_hash /*PAZA:kb-sd-hash*/)) return refuz('kb-sd-hash', 'key binding: sd_hash is not the hash of what was presented'); return { ...rez, keyBinding: { aud: K.aud, nonce: K.nonce, iat: K.iat, alg: k.antet.alg } }; - } catch (e) { return refuz(String(e.message || e).replace(/^sd-jwt: /, '')); } + } catch (e) { return refuz(regula(e), motiv(e)); } }