@openeudi/openid4vp 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import 'reflect-metadata';
2
- import { X509Certificate, SubjectKeyIdentifierExtension, X509Certificates, BasicConstraintsExtension, KeyUsagesExtension, KeyUsageFlags as KeyUsageFlags$1, AuthorityKeyIdentifierExtension, SubjectAlternativeNameExtension, ExtendedKeyUsageExtension, Name as Name$1 } from '@peculiar/x509';
2
+ import { X509Certificate, SubjectKeyIdentifierExtension, BasicConstraintsExtension, KeyUsagesExtension, KeyUsageFlags as KeyUsageFlags$1, ExtendedKeyUsageExtension, AuthorityKeyIdentifierExtension, SubjectAlternativeNameExtension, Name as Name$1 } from '@peculiar/x509';
3
3
  import { v4 } from 'uuid';
4
4
  import { SignJWT, importX509, decodeProtectedHeader, jwtVerify, importJWK, compactDecrypt } from 'jose';
5
5
  import { Encoder, Tag } from 'cbor-x';
@@ -24,7 +24,7 @@ var init_reflect_polyfill = __esm({
24
24
  });
25
25
 
26
26
  // src/errors.ts
27
- var InvalidSignatureError, ExpiredCredentialError, UnsupportedFormatError, MalformedCredentialError, NonceValidationError, HaipValidationError, OpenID4VPError, TrustAnchorNotFoundError, CertificateChainError, RevokedCertificateError, RevocationCheckFailedError, LotlFetchError, LotlSignatureError, LotlConfigurationError, SignedRequestBuildError, UnsupportedJweError, DecryptionFailedError, MissingDecryptionKeyError, MissingVerifierEncryptionKeyError, MultipleCredentialsNotSupportedError;
27
+ var InvalidSignatureError, ExpiredCredentialError, UnsupportedFormatError, MalformedCredentialError, NonceValidationError, HaipValidationError, OpenID4VPError, TrustAnchorNotFoundError, CertificateChainError, RevokedCertificateError, RevocationCheckFailedError, LotlFetchError, LotlSignatureError, LotlConfigurationError, SignedRequestBuildError, UnsupportedJweError, DecryptionFailedError, MissingDecryptionKeyError, MissingVerifierEncryptionKeyError, MultipleCredentialsNotSupportedError, GuardedFetchError;
28
28
  var init_errors = __esm({
29
29
  "src/errors.ts"() {
30
30
  init_reflect_polyfill();
@@ -171,6 +171,16 @@ var init_errors = __esm({
171
171
  this.presentationCount = presentationCount;
172
172
  }
173
173
  };
174
+ GuardedFetchError = class extends OpenID4VPError {
175
+ code = "guarded_fetch_rejected";
176
+ reason;
177
+ url;
178
+ constructor(reason, message, options) {
179
+ super(message, { cause: options.cause });
180
+ this.reason = reason;
181
+ this.url = options.url;
182
+ }
183
+ };
174
184
  }
175
185
  });
176
186
 
@@ -6567,7 +6577,7 @@ function dnIsUnder(childDn, subtreeDn) {
6567
6577
  }
6568
6578
  return true;
6569
6579
  }
6570
- var NAME_CONSTRAINTS_OID, DEFAULT_ALGORITHMS, ChainBuilder;
6580
+ var NAME_CONSTRAINTS_OID, ISO_18013_5_DS_EKU, DEFAULT_MAX_CHAIN_LENGTH, DEFAULT_MAX_SIGNATURE_CHECKS, searchAborts, DEFAULT_ALGORITHMS, ChainBuilder;
6571
6581
  var init_ChainBuilder = __esm({
6572
6582
  "src/trust/ChainBuilder.ts"() {
6573
6583
  init_reflect_polyfill();
@@ -6576,6 +6586,10 @@ var init_ChainBuilder = __esm({
6576
6586
  init_errors();
6577
6587
  init_x509_utils();
6578
6588
  NAME_CONSTRAINTS_OID = "2.5.29.30";
6589
+ ISO_18013_5_DS_EKU = "1.0.18013.5.1.2";
6590
+ DEFAULT_MAX_CHAIN_LENGTH = 5;
6591
+ DEFAULT_MAX_SIGNATURE_CHECKS = 32;
6592
+ searchAborts = /* @__PURE__ */ new WeakSet();
6579
6593
  DEFAULT_ALGORITHMS = [
6580
6594
  "ES256",
6581
6595
  "ES384",
@@ -6598,62 +6612,130 @@ var init_ChainBuilder = __esm({
6598
6612
  * optionally using additional intermediates. Returns the ordered chain
6599
6613
  * (leaf → anchor). Throws `CertificateChainError` on any validation
6600
6614
  * failure.
6615
+ *
6616
+ * Trust is by presence in the anchor set and is established ONLY by (a) the
6617
+ * leaf being byte-identical to an anchor, or (b) a verified signature by an
6618
+ * anchor's key on the last certificate of the path. Subject/Issuer DN
6619
+ * equality is used to select candidates, never to conclude trust
6620
+ * (GHSA-4c2f-96cf-f5fc).
6621
+ *
6622
+ * The search is depth-first and backtracks: when several intermediates share
6623
+ * a Subject DN — a re-issued certificate next to its expired predecessor, or
6624
+ * cross-signed copies under different roots — a candidate that fails a check
6625
+ * or leads nowhere does not end the search. The result therefore does not
6626
+ * depend on the order of `intermediates`. Work is bounded by
6627
+ * `maxChainLength` and `maxSignatureChecks`.
6601
6628
  */
6602
- async build(leaf, anchors, intermediates = []) {
6603
- const errors = [];
6629
+ async build(leaf, anchors, intermediates = [], context = {}) {
6630
+ const search = {
6631
+ remaining: this.opts.maxSignatureChecks ?? DEFAULT_MAX_SIGNATURE_CHECKS
6632
+ };
6633
+ let lastFailure;
6604
6634
  for (const anchor of anchors) {
6635
+ search.specific = void 0;
6636
+ search.fallback = void 0;
6605
6637
  try {
6606
- return await this.tryBuild(leaf, anchor, intermediates);
6638
+ const chain = await this.tryBuild(leaf, anchor, intermediates, context, search);
6639
+ if (chain) return chain;
6640
+ lastFailure = search.specific ?? search.fallback;
6607
6641
  } catch (err) {
6608
- errors.push(err);
6642
+ if (searchAborts.has(err)) throw err;
6643
+ lastFailure = err;
6609
6644
  }
6610
6645
  }
6611
- const last = errors[errors.length - 1];
6612
- if (last instanceof CertificateChainError) throw last;
6646
+ if (lastFailure instanceof CertificateChainError) throw lastFailure;
6613
6647
  throw new CertificateChainError("no valid chain to any anchor", {
6614
6648
  reason: "signature",
6615
- cause: last
6649
+ cause: lastFailure
6616
6650
  });
6617
6651
  }
6618
- async tryBuild(leaf, anchor, intermediates) {
6619
- this.checkPerCert(leaf);
6620
- this.checkLeafKeyUsage(leaf);
6621
- const chain = [leaf];
6622
- let current = leaf;
6623
- const pool = new X509Certificates(intermediates);
6624
- let nonLeafDepth = 0;
6625
- while (current.subject !== anchor.subject) {
6626
- const issuer = pool.find((c) => c.subject === current.issuer);
6627
- if (!issuer) {
6628
- if (current.issuer !== anchor.subject) {
6629
- throw new CertificateChainError(`no issuer certificate found for ${current.subject}`, {
6630
- reason: "signature"
6631
- });
6632
- }
6633
- this.checkPerCert(anchor);
6634
- this.checkCaAndPathLen(anchor, nonLeafDepth);
6635
- this.checkAkiSkiMatch(current, anchor);
6636
- await this.verifySignature(current, anchor);
6637
- chain.push(anchor);
6638
- this.checkNameConstraints(leaf, chain.slice(1));
6639
- return chain;
6652
+ /** Search for a path from `leaf` that closes at `anchor`. */
6653
+ async tryBuild(leaf, anchor, intermediates, context, search) {
6654
+ this.checkPerCert(leaf, context);
6655
+ if (certificatesEqual(leaf, anchor)) {
6656
+ this.checkLeafKeyUsage(leaf, "generic");
6657
+ return [leaf];
6658
+ }
6659
+ const profile = this.opts.profile ?? "generic";
6660
+ this.checkLeafKeyUsage(leaf, profile);
6661
+ this.checkLeafExtendedKeyUsage(leaf, profile);
6662
+ const pool = intermediates.filter(
6663
+ (c) => !certificatesEqual(c, anchor) && !certificatesEqual(c, leaf)
6664
+ );
6665
+ return this.extendPath([leaf], anchor, pool, context, search);
6666
+ }
6667
+ /**
6668
+ * Try to complete `chain` (leaf first) to `anchor`. Returns the completed
6669
+ * chain, or `undefined` when no extension of this prefix works — failures
6670
+ * are recorded on `search` so the caller can report the most specific one.
6671
+ * Throws only to abandon the whole search (signature budget exhausted).
6672
+ */
6673
+ async extendPath(chain, anchor, pool, context, search) {
6674
+ const leaf = chain[0];
6675
+ const current = chain[chain.length - 1];
6676
+ const maxLength = this.opts.maxChainLength ?? DEFAULT_MAX_CHAIN_LENGTH;
6677
+ if (chain.length + 1 > maxLength) {
6678
+ search.specific = new CertificateChainError(
6679
+ `chain from ${leaf.subject} exceeds the maximum length of ${maxLength} certificates`,
6680
+ { reason: "path_length" }
6681
+ );
6682
+ return void 0;
6683
+ }
6684
+ const nonLeafDepth = chain.length - 1;
6685
+ if (current.issuer === anchor.subject) {
6686
+ try {
6687
+ await this.closeAtAnchor(current, anchor, nonLeafDepth, context, search);
6688
+ const closed = [...chain, anchor];
6689
+ this.checkNameConstraints(leaf, closed.slice(1));
6690
+ return closed;
6691
+ } catch (err) {
6692
+ if (searchAborts.has(err)) throw err;
6693
+ search.specific = err;
6640
6694
  }
6641
- this.checkPerCert(issuer);
6642
- this.checkCaAndPathLen(issuer, nonLeafDepth);
6643
- this.checkAkiSkiMatch(current, issuer);
6644
- await this.verifySignature(current, issuer);
6645
- chain.push(issuer);
6646
- current = issuer;
6647
- nonLeafDepth += 1;
6648
- }
6649
- if (!certificatesEqual(current, anchor)) {
6650
- throw new CertificateChainError(
6651
- `certificate ${current.subject} shares the trust anchor's Subject DN but is not the anchor (no signature closure)`,
6652
- { reason: "signature" }
6695
+ }
6696
+ const candidates = pool.filter(
6697
+ (c) => c.subject === current.issuer && !chain.some((x) => certificatesEqual(x, c))
6698
+ );
6699
+ let verified = 0;
6700
+ for (const candidate of candidates) {
6701
+ if (!await this.signatureVerifies(current, candidate, search)) continue;
6702
+ verified++;
6703
+ try {
6704
+ this.checkPerCert(candidate, context);
6705
+ this.checkCaAndPathLen(candidate, nonLeafDepth);
6706
+ this.checkAkiSkiMatch(current, candidate);
6707
+ } catch (err) {
6708
+ search.specific = err;
6709
+ continue;
6710
+ }
6711
+ const found = await this.extendPath([...chain, candidate], anchor, pool, context, search);
6712
+ if (found) return found;
6713
+ }
6714
+ search.fallback = new CertificateChainError(
6715
+ candidates.length > 0 && verified === 0 ? `signature verification failed for ${current.subject}` : `no issuer certificate found for ${current.subject}`,
6716
+ { reason: "signature" }
6717
+ );
6718
+ return void 0;
6719
+ }
6720
+ async closeAtAnchor(current, anchor, nonLeafDepth, context, search) {
6721
+ this.checkPerCert(anchor, context);
6722
+ this.checkCaAndPathLen(anchor, nonLeafDepth);
6723
+ this.checkAkiSkiMatch(current, anchor);
6724
+ this.spendSignatureCheck(search);
6725
+ await this.verifySignature(current, anchor);
6726
+ }
6727
+ /** Charge one signature verification to the search, or abandon it. */
6728
+ spendSignatureCheck(search) {
6729
+ if (search.remaining <= 0) {
6730
+ const limit = this.opts.maxSignatureChecks ?? DEFAULT_MAX_SIGNATURE_CHECKS;
6731
+ const err = new CertificateChainError(
6732
+ `certificate path search exceeded ${limit} signature checks`,
6733
+ { reason: "path_length" }
6653
6734
  );
6735
+ searchAborts.add(err);
6736
+ throw err;
6654
6737
  }
6655
- this.checkNameConstraints(leaf, chain.slice(1));
6656
- return chain;
6738
+ search.remaining--;
6657
6739
  }
6658
6740
  /**
6659
6741
  * Enforce nameConstraints asserted by any CA above the leaf against the
@@ -6702,7 +6784,7 @@ var init_ChainBuilder = __esm({
6702
6784
  }
6703
6785
  }
6704
6786
  checkCaAndPathLen(cert, nonLeafDepth) {
6705
- this.checkCaKeyUsage(cert);
6787
+ this.checkCaKeyUsage(cert, this.opts.profile ?? "generic");
6706
6788
  const bc = cert.getExtension(BasicConstraintsExtension);
6707
6789
  if (!bc || !bc.ca) {
6708
6790
  throw new CertificateChainError(
@@ -6717,9 +6799,17 @@ var init_ChainBuilder = __esm({
6717
6799
  );
6718
6800
  }
6719
6801
  }
6720
- checkLeafKeyUsage(leaf) {
6802
+ checkLeafKeyUsage(leaf, profile) {
6721
6803
  const ext = leaf.getExtension(KeyUsagesExtension);
6722
- if (!ext) return;
6804
+ if (!ext) {
6805
+ if (profile === "iso18013-5") {
6806
+ throw new CertificateChainError(
6807
+ `document signer ${leaf.subject} has no keyUsage extension (ISO 18013-5 requires digitalSignature)`,
6808
+ { reason: "key_usage" }
6809
+ );
6810
+ }
6811
+ return;
6812
+ }
6723
6813
  if ((ext.usages & KeyUsageFlags$1.digitalSignature) === 0) {
6724
6814
  throw new CertificateChainError(
6725
6815
  `leaf ${leaf.subject} does not assert digitalSignature key usage`,
@@ -6727,9 +6817,28 @@ var init_ChainBuilder = __esm({
6727
6817
  );
6728
6818
  }
6729
6819
  }
6730
- checkCaKeyUsage(cert) {
6820
+ checkLeafExtendedKeyUsage(leaf, profile) {
6821
+ if (profile !== "iso18013-5") return;
6822
+ const ext = leaf.getExtension(ExtendedKeyUsageExtension);
6823
+ const usages = (ext?.usages ?? []).map(String);
6824
+ if (!usages.includes(ISO_18013_5_DS_EKU)) {
6825
+ throw new CertificateChainError(
6826
+ `document signer ${leaf.subject} lacks extended key usage ${ISO_18013_5_DS_EKU} (id-mdl-kp-mdlDS)`,
6827
+ { reason: "extended_key_usage" }
6828
+ );
6829
+ }
6830
+ }
6831
+ checkCaKeyUsage(cert, profile) {
6731
6832
  const ext = cert.getExtension(KeyUsagesExtension);
6732
- if (!ext) return;
6833
+ if (!ext) {
6834
+ if (profile === "iso18013-5") {
6835
+ throw new CertificateChainError(
6836
+ `CA ${cert.subject} has no keyUsage extension (ISO 18013-5 requires keyCertSign)`,
6837
+ { reason: "key_usage" }
6838
+ );
6839
+ }
6840
+ return;
6841
+ }
6733
6842
  if ((ext.usages & KeyUsageFlags$1.keyCertSign) === 0) {
6734
6843
  throw new CertificateChainError(
6735
6844
  `CA ${cert.subject} does not assert keyCertSign key usage`,
@@ -6750,30 +6859,46 @@ var init_ChainBuilder = __esm({
6750
6859
  );
6751
6860
  }
6752
6861
  }
6862
+ /**
6863
+ * Signature check used to select among DN-matching candidates. Never throws
6864
+ * on a bad signature; throws only when the search budget is exhausted.
6865
+ */
6866
+ async signatureVerifies(child, issuer, search) {
6867
+ this.spendSignatureCheck(search);
6868
+ try {
6869
+ return await child.verify({ publicKey: issuer.publicKey, signatureOnly: true });
6870
+ } catch {
6871
+ return false;
6872
+ }
6873
+ }
6753
6874
  async verifySignature(child, issuer) {
6754
6875
  const ok = await child.verify({ publicKey: issuer.publicKey, signatureOnly: true });
6755
6876
  if (!ok) {
6756
6877
  throw new CertificateChainError(`signature verification failed for ${child.subject}`, { reason: "signature" });
6757
6878
  }
6758
6879
  }
6759
- checkPerCert(cert) {
6760
- this.checkValidity(cert);
6880
+ checkPerCert(cert, context = {}) {
6881
+ const now = (this.opts.now ?? (() => /* @__PURE__ */ new Date()))();
6882
+ this.checkValidity(cert, now, "");
6883
+ if (context.issuedAt) {
6884
+ this.checkValidity(cert, context.issuedAt, ` at issuance time ${context.issuedAt.toISOString()}`);
6885
+ }
6761
6886
  this.checkAlgorithm(cert);
6762
6887
  }
6763
- checkValidity(cert) {
6764
- const now = (this.opts.now ?? (() => /* @__PURE__ */ new Date()))().getTime();
6888
+ checkValidity(cert, at, label) {
6889
+ const time = at.getTime();
6765
6890
  const skewMs = (this.opts.clockSkewTolerance ?? 60) * 1e3;
6766
6891
  const notBefore = cert.notBefore.getTime();
6767
6892
  const notAfter = cert.notAfter.getTime();
6768
- if (now + skewMs < notBefore) {
6893
+ if (time + skewMs < notBefore) {
6769
6894
  throw new CertificateChainError(
6770
- `certificate ${cert.subject} not yet valid (notBefore=${cert.notBefore.toISOString()})`,
6895
+ `certificate ${cert.subject} not yet valid${label} (notBefore=${cert.notBefore.toISOString()})`,
6771
6896
  { reason: "validity" }
6772
6897
  );
6773
6898
  }
6774
- if (now - skewMs > notAfter) {
6899
+ if (time - skewMs > notAfter) {
6775
6900
  throw new CertificateChainError(
6776
- `certificate ${cert.subject} expired (notAfter=${cert.notAfter.toISOString()})`,
6901
+ `certificate ${cert.subject} expired${label} (notAfter=${cert.notAfter.toISOString()})`,
6777
6902
  { reason: "validity" }
6778
6903
  );
6779
6904
  }
@@ -6820,6 +6945,349 @@ var init_ecdsa_util = __esm({
6820
6945
  }
6821
6946
  });
6822
6947
 
6948
+ // src/http/ip-address.ts
6949
+ function parseIPv4(input) {
6950
+ const parts = input.split(".");
6951
+ if (parts.length !== 4) return void 0;
6952
+ const bytes = [];
6953
+ for (const part of parts) {
6954
+ if (!/^\d{1,3}$/.test(part)) return void 0;
6955
+ const value = Number(part);
6956
+ if (value > 255) return void 0;
6957
+ bytes.push(value);
6958
+ }
6959
+ return bytes;
6960
+ }
6961
+ function parseIPv6(input) {
6962
+ const address = input.split("%")[0];
6963
+ if (!address.includes(":")) return void 0;
6964
+ let head = address;
6965
+ let embeddedV4;
6966
+ const lastColon = address.lastIndexOf(":");
6967
+ const tail = address.slice(lastColon + 1);
6968
+ if (tail.includes(".")) {
6969
+ embeddedV4 = parseIPv4(tail);
6970
+ if (!embeddedV4) return void 0;
6971
+ head = address.slice(0, lastColon + 1) + "0:0";
6972
+ }
6973
+ const doubleColon = head.split("::");
6974
+ if (doubleColon.length > 2) return void 0;
6975
+ const toGroups = (s) => s === "" ? [] : s.split(":");
6976
+ const left = toGroups(doubleColon[0]);
6977
+ const right = doubleColon.length === 2 ? toGroups(doubleColon[1]) : [];
6978
+ const missing = 8 - left.length - right.length;
6979
+ if (doubleColon.length === 2 ? missing < 1 : missing !== 0) return void 0;
6980
+ const groups = [...left, ...Array(doubleColon.length === 2 ? missing : 0).fill("0"), ...right];
6981
+ const bytes = [];
6982
+ for (const group of groups) {
6983
+ if (!/^[0-9a-fA-F]{1,4}$/.test(group)) return void 0;
6984
+ const value = parseInt(group, 16);
6985
+ bytes.push(value >> 8, value & 255);
6986
+ }
6987
+ if (embeddedV4) bytes.splice(12, 4, ...embeddedV4);
6988
+ return bytes;
6989
+ }
6990
+ function inPrefix(bytes, prefix, bits) {
6991
+ for (let i = 0; i < bits; i++) {
6992
+ const byte = i >> 3;
6993
+ const mask = 128 >> (i & 7);
6994
+ if ((bytes[byte] & mask) !== ((prefix[byte] ?? 0) & mask)) return false;
6995
+ }
6996
+ return true;
6997
+ }
6998
+ function isPublicV4(bytes) {
6999
+ return !BLOCKED_V4.some(([prefix, bits]) => inPrefix(bytes, prefix, bits));
7000
+ }
7001
+ function isPublicV6(bytes) {
7002
+ const first10Zero = bytes.slice(0, 10).every((b) => b === 0);
7003
+ if (first10Zero && bytes[10] === 0 && bytes[11] === 0) {
7004
+ const v4 = bytes.slice(12);
7005
+ if (v4.slice(0, 3).every((b) => b === 0)) return false;
7006
+ return isPublicV4(v4);
7007
+ }
7008
+ if (first10Zero && bytes[10] === 255 && bytes[11] === 255) return isPublicV4(bytes.slice(12));
7009
+ if (inPrefix(bytes, [0, 100, 255, 155], 96)) return isPublicV4(bytes.slice(12));
7010
+ if (inPrefix(bytes, [32, 2], 16)) return isPublicV4(bytes.slice(2, 6));
7011
+ return !BLOCKED_V6.some(([prefix, bits]) => inPrefix(bytes, prefix, bits));
7012
+ }
7013
+ function isPublicIpAddress(ip) {
7014
+ const v4 = parseIPv4(ip);
7015
+ if (v4) return isPublicV4(v4);
7016
+ const v6 = parseIPv6(ip);
7017
+ if (v6) return isPublicV6(v6);
7018
+ return false;
7019
+ }
7020
+ function isIpLiteral(host) {
7021
+ return parseIPv4(host) !== void 0 || parseIPv6(host) !== void 0;
7022
+ }
7023
+ var BLOCKED_V4, BLOCKED_V6;
7024
+ var init_ip_address = __esm({
7025
+ "src/http/ip-address.ts"() {
7026
+ init_reflect_polyfill();
7027
+ BLOCKED_V4 = [
7028
+ [[0, 0, 0, 0], 8],
7029
+ [[10, 0, 0, 0], 8],
7030
+ [[100, 64, 0, 0], 10],
7031
+ [[127, 0, 0, 0], 8],
7032
+ [[169, 254, 0, 0], 16],
7033
+ [[172, 16, 0, 0], 12],
7034
+ [[192, 0, 0, 0], 24],
7035
+ [[192, 0, 2, 0], 24],
7036
+ [[192, 88, 99, 0], 24],
7037
+ [[192, 168, 0, 0], 16],
7038
+ [[198, 18, 0, 0], 15],
7039
+ [[198, 51, 100, 0], 24],
7040
+ [[203, 0, 113, 0], 24],
7041
+ [[224, 0, 0, 0], 4],
7042
+ [[240, 0, 0, 0], 4]
7043
+ ];
7044
+ BLOCKED_V6 = [
7045
+ [[1, 0], 64],
7046
+ // 100::/64 discard-only
7047
+ [[32, 1, 0, 0], 32],
7048
+ // 2001::/32 Teredo (embeds an obfuscated IPv4)
7049
+ [[32, 1, 13, 184], 32],
7050
+ // 2001:db8::/32 documentation
7051
+ [[252], 7],
7052
+ // fc00::/7 unique local (incl. fd00:ec2::254 metadata)
7053
+ [[254, 128], 10],
7054
+ // fe80::/10 link-local
7055
+ [[254, 192], 10],
7056
+ // fec0::/10 deprecated site-local
7057
+ [[255], 8]
7058
+ // ff00::/8 multicast
7059
+ ];
7060
+ }
7061
+ });
7062
+
7063
+ // src/http/guarded-fetch.ts
7064
+ function loadDns() {
7065
+ dnsModule ??= (async () => {
7066
+ try {
7067
+ const specifier = "node:dns";
7068
+ const mod = await import(
7069
+ /* webpackIgnore: true */
7070
+ /* @vite-ignore */
7071
+ specifier
7072
+ );
7073
+ return mod.promises ?? mod.default?.promises;
7074
+ } catch {
7075
+ return void 0;
7076
+ }
7077
+ })();
7078
+ return dnsModule;
7079
+ }
7080
+ function toError(err) {
7081
+ return err instanceof Error ? err : new Error(String(err));
7082
+ }
7083
+ function createGuardedFetcher(options = {}) {
7084
+ const allowHttp = options.allowHttp ?? false;
7085
+ const allowPrivate = options.allowPrivateNetworks ?? false;
7086
+ const maxRedirects = options.maxRedirects ?? GUARDED_FETCH_DEFAULTS.maxRedirects;
7087
+ const timeoutMs = options.timeoutMs ?? GUARDED_FETCH_DEFAULTS.timeoutMs;
7088
+ const maxBytes = options.maxResponseBytes ?? GUARDED_FETCH_DEFAULTS.maxResponseBytes;
7089
+ const lookup = options.lookup ?? defaultLookup;
7090
+ const transport = options.fetch ?? ((url, init) => globalThis.fetch(url, init));
7091
+ return async (input, init = {}) => {
7092
+ const controller = new AbortController();
7093
+ const timer = setTimeout(() => {
7094
+ controller.abort(
7095
+ new GuardedFetchError("timeout", `request to ${input} exceeded ${timeoutMs} ms`, { url: input })
7096
+ );
7097
+ }, timeoutMs);
7098
+ const callerSignal = init.signal ?? void 0;
7099
+ const onCallerAbort = () => controller.abort(callerSignal?.reason);
7100
+ if (callerSignal?.aborted) onCallerAbort();
7101
+ else callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
7102
+ const aborted = new Promise((_, reject) => {
7103
+ const fail = () => reject(toError(controller.signal.reason));
7104
+ if (controller.signal.aborted) fail();
7105
+ else controller.signal.addEventListener("abort", fail, { once: true });
7106
+ });
7107
+ aborted.catch(() => {
7108
+ });
7109
+ const race = (p) => Promise.race([p, aborted]);
7110
+ try {
7111
+ let url = await race(validateTarget(input, void 0));
7112
+ let method = (init.method ?? "GET").toUpperCase();
7113
+ let body = init.body;
7114
+ const headers = new Headers(init.headers);
7115
+ for (let hop = 0; ; hop++) {
7116
+ const response = await race(
7117
+ transport(url.href, { ...init, method, body, headers, redirect: "manual", signal: controller.signal })
7118
+ );
7119
+ if (response.type === "opaqueredirect") {
7120
+ throw new GuardedFetchError(
7121
+ "invalid_redirect",
7122
+ `redirect from ${url.href} cannot be inspected by this transport`,
7123
+ { url: url.href }
7124
+ );
7125
+ }
7126
+ if (!REDIRECT_STATUSES.has(response.status)) {
7127
+ const bytes = await readBounded(response, url.href, maxBytes, race);
7128
+ return new Response(NULL_BODY_STATUSES.has(response.status) ? null : bytes, {
7129
+ status: response.status,
7130
+ statusText: response.statusText,
7131
+ headers: response.headers
7132
+ });
7133
+ }
7134
+ await response.body?.cancel().catch(() => {
7135
+ });
7136
+ if (hop >= maxRedirects) {
7137
+ throw new GuardedFetchError(
7138
+ "too_many_redirects",
7139
+ `more than ${maxRedirects} redirects starting at ${input}`,
7140
+ { url: url.href }
7141
+ );
7142
+ }
7143
+ const location = response.headers.get("location");
7144
+ if (!location) {
7145
+ throw new GuardedFetchError(
7146
+ "invalid_redirect",
7147
+ `HTTP ${response.status} from ${url.href} has no Location header`,
7148
+ { url: url.href }
7149
+ );
7150
+ }
7151
+ let next;
7152
+ try {
7153
+ next = new URL(location, url);
7154
+ } catch (err) {
7155
+ throw new GuardedFetchError("invalid_redirect", `unparseable Location from ${url.href}`, {
7156
+ url: url.href,
7157
+ cause: toError(err)
7158
+ });
7159
+ }
7160
+ const nextUrl = await race(validateTarget(next.href, url));
7161
+ if (response.status === 303 || (response.status === 301 || response.status === 302) && method === "POST") {
7162
+ if (method !== "HEAD") method = "GET";
7163
+ body = void 0;
7164
+ for (const h of BODY_HEADERS) headers.delete(h);
7165
+ }
7166
+ if (nextUrl.origin !== url.origin) {
7167
+ for (const h of CROSS_ORIGIN_STRIPPED_HEADERS) headers.delete(h);
7168
+ }
7169
+ url = nextUrl;
7170
+ }
7171
+ } catch (err) {
7172
+ if (controller.signal.aborted) throw toError(controller.signal.reason);
7173
+ throw err;
7174
+ } finally {
7175
+ clearTimeout(timer);
7176
+ callerSignal?.removeEventListener("abort", onCallerAbort);
7177
+ }
7178
+ };
7179
+ async function validateTarget(raw, previous) {
7180
+ let url;
7181
+ try {
7182
+ url = new URL(raw);
7183
+ } catch (err) {
7184
+ throw new GuardedFetchError("invalid_url", `not an absolute URL: ${raw}`, { url: raw, cause: toError(err) });
7185
+ }
7186
+ if (url.protocol !== "https:" && !(allowHttp && url.protocol === "http:")) {
7187
+ throw new GuardedFetchError("insecure_scheme", `refusing ${url.protocol} URL ${url.href}: HTTPS is required`, {
7188
+ url: url.href
7189
+ });
7190
+ }
7191
+ if (previous?.protocol === "https:" && url.protocol !== "https:") {
7192
+ throw new GuardedFetchError("insecure_scheme", `refusing https -> http redirect to ${url.href}`, {
7193
+ url: url.href
7194
+ });
7195
+ }
7196
+ if (allowPrivate) return url;
7197
+ const host = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
7198
+ if (host === "localhost" || host.endsWith(".localhost")) {
7199
+ throw new GuardedFetchError("private_address", `refusing loopback host ${host}`, { url: url.href });
7200
+ }
7201
+ if (isIpLiteral(host)) {
7202
+ if (!isPublicIpAddress(host)) {
7203
+ throw new GuardedFetchError("private_address", `refusing non-public address ${host}`, { url: url.href });
7204
+ }
7205
+ return url;
7206
+ }
7207
+ let addresses;
7208
+ try {
7209
+ addresses = await lookup(host);
7210
+ } catch (err) {
7211
+ throw new GuardedFetchError("dns_resolution_failed", `could not resolve ${host}`, {
7212
+ url: url.href,
7213
+ cause: toError(err)
7214
+ });
7215
+ }
7216
+ if (addresses === void 0) return url;
7217
+ if (addresses.length === 0) {
7218
+ throw new GuardedFetchError("dns_resolution_failed", `${host} resolved to no addresses`, {
7219
+ url: url.href
7220
+ });
7221
+ }
7222
+ const blocked = addresses.find((a) => !isPublicIpAddress(a));
7223
+ if (blocked !== void 0) {
7224
+ throw new GuardedFetchError("private_address", `${host} resolves to non-public address ${blocked}`, {
7225
+ url: url.href
7226
+ });
7227
+ }
7228
+ return url;
7229
+ }
7230
+ }
7231
+ async function readBounded(response, url, maxBytes, race) {
7232
+ const tooLarge = () => new GuardedFetchError("response_too_large", `response from ${url} exceeds ${maxBytes} bytes`, { url });
7233
+ const declared = response.headers.get("content-length");
7234
+ if (declared !== null && Number(declared) > maxBytes) {
7235
+ await response.body?.cancel().catch(() => {
7236
+ });
7237
+ throw tooLarge();
7238
+ }
7239
+ if (!response.body) return null;
7240
+ const reader = response.body.getReader();
7241
+ const chunks = [];
7242
+ let total = 0;
7243
+ try {
7244
+ for (; ; ) {
7245
+ const { done, value } = await race(reader.read());
7246
+ if (done) break;
7247
+ total += value.byteLength;
7248
+ if (total > maxBytes) throw tooLarge();
7249
+ chunks.push(value);
7250
+ }
7251
+ } catch (err) {
7252
+ reader.cancel().catch(() => {
7253
+ });
7254
+ throw err;
7255
+ }
7256
+ const out = new Uint8Array(new ArrayBuffer(total));
7257
+ let offset = 0;
7258
+ for (const chunk of chunks) {
7259
+ out.set(chunk, offset);
7260
+ offset += chunk.byteLength;
7261
+ }
7262
+ return out;
7263
+ }
7264
+ function createDefaultTrustFetcher() {
7265
+ return createGuardedFetcher({ allowHttp: true });
7266
+ }
7267
+ var GUARDED_FETCH_DEFAULTS, REDIRECT_STATUSES, NULL_BODY_STATUSES, CROSS_ORIGIN_STRIPPED_HEADERS, BODY_HEADERS, dnsModule, defaultLookup;
7268
+ var init_guarded_fetch = __esm({
7269
+ "src/http/guarded-fetch.ts"() {
7270
+ init_reflect_polyfill();
7271
+ init_errors();
7272
+ init_ip_address();
7273
+ GUARDED_FETCH_DEFAULTS = {
7274
+ maxRedirects: 3,
7275
+ timeoutMs: 15e3,
7276
+ maxResponseBytes: 16 * 1024 * 1024
7277
+ };
7278
+ REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
7279
+ NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
7280
+ CROSS_ORIGIN_STRIPPED_HEADERS = ["authorization", "cookie", "proxy-authorization"];
7281
+ BODY_HEADERS = ["content-type", "content-length", "content-encoding", "content-language", "content-location"];
7282
+ defaultLookup = async (hostname) => {
7283
+ const dns = await loadDns();
7284
+ if (!dns) return void 0;
7285
+ const records = await dns.lookup(hostname, { all: true, verbatim: true });
7286
+ return records.map((r) => r.address);
7287
+ };
7288
+ }
7289
+ });
7290
+
6823
7291
  // src/trust/CrlFetcher.ts
6824
7292
  function normalizeCrl(parsed, der) {
6825
7293
  const thisUpdate = parsed.tbsCertList.thisUpdate.getTime();
@@ -6855,11 +7323,12 @@ var init_CrlFetcher = __esm({
6855
7323
  init_es2015();
6856
7324
  init_es20152();
6857
7325
  init_ecdsa_util();
7326
+ init_guarded_fetch();
6858
7327
  CrlFetcher = class {
6859
7328
  fetcher;
6860
7329
  cache;
6861
7330
  constructor(opts = {}) {
6862
- this.fetcher = opts.fetcher ?? globalThis.fetch.bind(globalThis);
7331
+ this.fetcher = opts.fetcher ?? createDefaultTrustFetcher();
6863
7332
  this.cache = opts.cache;
6864
7333
  }
6865
7334
  async fetchAndParse(url) {
@@ -7591,12 +8060,13 @@ var init_OcspClient = __esm({
7591
8060
  init_es20152();
7592
8061
  init_ChainBuilder();
7593
8062
  init_ecdsa_util();
8063
+ init_guarded_fetch();
7594
8064
  DEFAULT_MAX_RESPONSE_AGE_MS = 7 * 24 * 3600 * 1e3;
7595
8065
  OcspClient = class {
7596
8066
  fetcher;
7597
8067
  cache;
7598
8068
  constructor(opts = {}) {
7599
- this.fetcher = opts.fetcher ?? globalThis.fetch.bind(globalThis);
8069
+ this.fetcher = opts.fetcher ?? createDefaultTrustFetcher();
7600
8070
  this.cache = opts.cache;
7601
8071
  }
7602
8072
  /**
@@ -8062,7 +8532,9 @@ var init_ProvenanceResolver = __esm({
8062
8532
  // src/trust/TrustEvaluator.ts
8063
8533
  var TrustEvaluator_exports = {};
8064
8534
  __export(TrustEvaluator_exports, {
8065
- TrustEvaluator: () => TrustEvaluator
8535
+ MAX_CREDENTIAL_CERTIFICATES: () => MAX_CREDENTIAL_CERTIFICATES,
8536
+ TrustEvaluator: () => TrustEvaluator,
8537
+ evaluateCredentialIssuer: () => evaluateCredentialIssuer
8066
8538
  });
8067
8539
  function deriveHint(leaf) {
8068
8540
  const aki = leaf.getExtension(AuthorityKeyIdentifierExtension);
@@ -8073,6 +8545,13 @@ function deriveHint(leaf) {
8073
8545
  aki: akiBytes
8074
8546
  };
8075
8547
  }
8548
+ function deriveSelfHint(cert) {
8549
+ const skiHex = getSkiHex(cert);
8550
+ return {
8551
+ issuer: cert.subject,
8552
+ aki: skiHex ? hexToBytes(skiHex) : void 0
8553
+ };
8554
+ }
8076
8555
  function hexToBytes(s) {
8077
8556
  const clean = s.replace(/[^0-9a-f]/gi, "");
8078
8557
  const out = new Uint8Array(clean.length / 2);
@@ -8104,7 +8583,31 @@ async function resolveProvenance(store, anchor) {
8104
8583
  return void 0;
8105
8584
  }
8106
8585
  }
8107
- var TrustEvaluator;
8586
+ async function evaluateCredentialIssuer(input) {
8587
+ const [signerDer, ...rest] = input.chain;
8588
+ if (!signerDer) {
8589
+ throw new MalformedCredentialError("Missing issuer certificate");
8590
+ }
8591
+ if (input.chain.length > MAX_CREDENTIAL_CERTIFICATES) {
8592
+ throw new MalformedCredentialError(
8593
+ `x5c/x5chain carries ${input.chain.length} certificates; at most ${MAX_CREDENTIAL_CERTIFICATES} are accepted`
8594
+ );
8595
+ }
8596
+ const parse = (bytes, position) => {
8597
+ try {
8598
+ return new X509Certificate(bytes);
8599
+ } catch (err) {
8600
+ throw new MalformedCredentialError(
8601
+ `Invalid certificate at x5c/x5chain position ${position}: ${err.message}`
8602
+ );
8603
+ }
8604
+ };
8605
+ const leaf = parse(signerDer, 0);
8606
+ const intermediates = rest.map((bytes, i) => parse(bytes, i + 1));
8607
+ const { chain, issuedAt, ...evaluatorOptions } = input;
8608
+ return new TrustEvaluator(evaluatorOptions).evaluate(leaf, { intermediates, issuedAt });
8609
+ }
8610
+ var TrustEvaluator, MAX_CREDENTIAL_CERTIFICATES;
8108
8611
  var init_TrustEvaluator = __esm({
8109
8612
  "src/trust/TrustEvaluator.ts"() {
8110
8613
  init_reflect_polyfill();
@@ -8130,13 +8633,10 @@ var init_TrustEvaluator = __esm({
8130
8633
  revocationChecker;
8131
8634
  async evaluate(leaf, context = {}) {
8132
8635
  const hint = deriveHint(leaf);
8133
- const seen = /* @__PURE__ */ new Set();
8134
8636
  const anchors = [];
8135
8637
  const pushUnique = (batch) => {
8136
8638
  for (const a of batch) {
8137
- const key = a.certificate.serialNumber;
8138
- if (seen.has(key)) continue;
8139
- seen.add(key);
8639
+ if (anchors.some((x) => certificatesEqual(x.certificate, a.certificate))) continue;
8140
8640
  anchors.push(a);
8141
8641
  }
8142
8642
  };
@@ -8144,6 +8644,7 @@ var init_TrustEvaluator = __esm({
8144
8644
  for (const inter of context.intermediates ?? []) {
8145
8645
  pushUnique(await this.trustStore.getAnchors(deriveHint(inter)));
8146
8646
  }
8647
+ pushUnique(await this.trustStore.getAnchors(deriveSelfHint(leaf)));
8147
8648
  if (anchors.length === 0) {
8148
8649
  throw new TrustAnchorNotFoundError(
8149
8650
  `no trust anchor for issuer=${hint.issuer ?? "(none)"}`
@@ -8153,7 +8654,8 @@ var init_TrustEvaluator = __esm({
8153
8654
  const chain = await this.chainBuilder.build(
8154
8655
  leaf,
8155
8656
  anchorCerts,
8156
- context.intermediates ?? []
8657
+ context.intermediates ?? [],
8658
+ { issuedAt: context.issuedAt }
8157
8659
  );
8158
8660
  const terminusCert = chain[chain.length - 1];
8159
8661
  const anchor = anchors.find(
@@ -8193,6 +8695,7 @@ var init_TrustEvaluator = __esm({
8193
8695
  };
8194
8696
  }
8195
8697
  };
8698
+ MAX_CREDENTIAL_CERTIFICATES = 10;
8196
8699
  }
8197
8700
  });
8198
8701
 
@@ -8984,6 +9487,14 @@ function bytesEqual3(a, b) {
8984
9487
  }
8985
9488
  return true;
8986
9489
  }
9490
+ function peekMsoSigned(payload) {
9491
+ try {
9492
+ const signed = decodeMso(payload).validityInfo.signed;
9493
+ return Number.isFinite(signed.getTime()) ? signed : void 0;
9494
+ } catch {
9495
+ return void 0;
9496
+ }
9497
+ }
8987
9498
  function derToPem(der) {
8988
9499
  let binary = "";
8989
9500
  for (const b of der) binary += String.fromCharCode(b);
@@ -9144,17 +9655,17 @@ var MdocParser = class {
9144
9655
  }
9145
9656
  let trustResult;
9146
9657
  if (options.trustStore) {
9147
- const { TrustEvaluator: TrustEvaluator2 } = await Promise.resolve().then(() => (init_TrustEvaluator(), TrustEvaluator_exports));
9148
- const evaluator = new TrustEvaluator2({
9658
+ const { evaluateCredentialIssuer: evaluateCredentialIssuer2 } = await Promise.resolve().then(() => (init_TrustEvaluator(), TrustEvaluator_exports));
9659
+ trustResult = await evaluateCredentialIssuer2({
9660
+ chain: cose.x5chain,
9661
+ profile: "iso18013-5",
9662
+ issuedAt: peekMsoSigned(cose.payload),
9149
9663
  trustStore: options.trustStore,
9150
9664
  revocationPolicy: options.revocationPolicy ?? "skip",
9151
9665
  fetcher: options.fetcher,
9152
9666
  cache: options.cache,
9153
9667
  clockSkewTolerance: options.clockSkewTolerance
9154
9668
  });
9155
- const { X509Certificate: X509Certificate9 } = await import('@peculiar/x509');
9156
- const leaf = new X509Certificate9(issuerCertBytes);
9157
- trustResult = await evaluator.evaluate(leaf);
9158
9669
  } else {
9159
9670
  if (options.trustedCertificates.length === 0) {
9160
9671
  if (options.skipTrustCheck !== true) {
@@ -9303,6 +9814,13 @@ var MdocParser = class {
9303
9814
  init_reflect_polyfill();
9304
9815
  init_errors();
9305
9816
  var DEFAULT_ALLOWED_ALGORITHMS2 = ["ES256", "ES384", "ES512"];
9817
+ var SD_JWT_VC_TYP = "dc+sd-jwt";
9818
+ var LEGACY_SD_JWT_VC_TYP = "vc+sd-jwt";
9819
+ function normalizeTyp(typ) {
9820
+ if (typeof typ !== "string") return void 0;
9821
+ const lower = typ.toLowerCase();
9822
+ return lower.startsWith("application/") ? lower.slice("application/".length) : lower;
9823
+ }
9306
9824
  var sha256Hasher = async (data, _alg) => {
9307
9825
  const encoder2 = new TextEncoder();
9308
9826
  const input = typeof data === "string" ? encoder2.encode(data) : data;
@@ -9415,6 +9933,18 @@ var SdJwtParser = class {
9415
9933
  if (typeof alg !== "string" || !allowedAlgorithms.includes(alg)) {
9416
9934
  return invalidResult(`Unsupported algorithm: ${alg}`);
9417
9935
  }
9936
+ const typ = normalizeTyp(header.typ);
9937
+ if (typ === LEGACY_SD_JWT_VC_TYP) {
9938
+ if (options.allowLegacyVcSdJwtTyp !== true) {
9939
+ return invalidResult(
9940
+ `Legacy SD-JWT VC typ '${LEGACY_SD_JWT_VC_TYP}' is not accepted (removed in draft-ietf-oauth-sd-jwt-vc-19; expected '${SD_JWT_VC_TYP}'). Set allowLegacyVcSdJwtTyp to accept it during migration.`
9941
+ );
9942
+ }
9943
+ } else if (typ !== SD_JWT_VC_TYP) {
9944
+ return invalidResult(
9945
+ `Unsupported SD-JWT VC typ: ${header.typ === void 0 ? "(missing)" : String(header.typ)} (expected '${SD_JWT_VC_TYP}')`
9946
+ );
9947
+ }
9418
9948
  const x5cArray = header.x5c;
9419
9949
  const hasX5c = Array.isArray(x5cArray) && x5cArray.length > 0 && typeof x5cArray[0] === "string";
9420
9950
  let issuerKey;
@@ -9484,17 +10014,22 @@ var SdJwtParser = class {
9484
10014
  };
9485
10015
  let trustResult;
9486
10016
  if (issuerCertBytes === void 0) ; else if (options.trustStore) {
9487
- const { TrustEvaluator: TrustEvaluator2 } = await Promise.resolve().then(() => (init_TrustEvaluator(), TrustEvaluator_exports));
9488
- const evaluator = new TrustEvaluator2({
10017
+ const { evaluateCredentialIssuer: evaluateCredentialIssuer2 } = await Promise.resolve().then(() => (init_TrustEvaluator(), TrustEvaluator_exports));
10018
+ const x5cRest = x5cArray.slice(1);
10019
+ if (!x5cRest.every((entry) => typeof entry === "string")) {
10020
+ throw new MalformedCredentialError("x5c entries must be base64 strings");
10021
+ }
10022
+ const iat = payload["iat"];
10023
+ trustResult = await evaluateCredentialIssuer2({
10024
+ chain: [issuerCertBytes, ...x5cRest.map((entry) => base64ToBytes(entry))],
10025
+ profile: "generic",
10026
+ issuedAt: typeof iat === "number" && Number.isFinite(iat) ? new Date(iat * 1e3) : void 0,
9489
10027
  trustStore: options.trustStore,
9490
10028
  revocationPolicy: options.revocationPolicy ?? "skip",
9491
10029
  fetcher: options.fetcher,
9492
10030
  cache: options.cache,
9493
10031
  clockSkewTolerance: options.clockSkewTolerance
9494
10032
  });
9495
- const { X509Certificate: X509Certificate9 } = await import('@peculiar/x509');
9496
- const leaf = new X509Certificate9(issuerCertBytes);
9497
- trustResult = await evaluator.evaluate(leaf);
9498
10033
  } else {
9499
10034
  if (options.trustedCertificates.length === 0) {
9500
10035
  if (options.skipTrustCheck !== true) {
@@ -9930,6 +10465,9 @@ var InMemoryCache = class {
9930
10465
  }
9931
10466
  };
9932
10467
 
10468
+ // src/index.ts
10469
+ init_guarded_fetch();
10470
+
9933
10471
  // src/trust/index.ts
9934
10472
  init_reflect_polyfill();
9935
10473
 
@@ -9977,14 +10515,10 @@ var CompositeTrustStore = class {
9977
10515
  const results = await Promise.all(
9978
10516
  this.stores.map((store) => store.getAnchors(hint))
9979
10517
  );
9980
- const seen = /* @__PURE__ */ new Set();
9981
10518
  const out = [];
9982
10519
  for (const batch of results) {
9983
10520
  for (const anchor of batch) {
9984
- const ski = getSkiHex(anchor.certificate);
9985
- const key = ski ?? anchor.certificate.serialNumber;
9986
- if (seen.has(key)) continue;
9987
- seen.add(key);
10521
+ if (out.some((a) => certificatesEqual(a.certificate, anchor.certificate))) continue;
9988
10522
  out.push(anchor);
9989
10523
  }
9990
10524
  }
@@ -10078,11 +10612,12 @@ var EU_LOTL_SIGNING_ANCHORS = Object.freeze(
10078
10612
  // src/trust/LotlFetcher.ts
10079
10613
  init_reflect_polyfill();
10080
10614
  init_errors();
10615
+ init_guarded_fetch();
10081
10616
  var XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#";
10082
10617
  var LotlFetcher = class {
10083
10618
  fetcher;
10084
10619
  constructor(opts = {}) {
10085
- this.fetcher = opts.fetcher ?? globalThis.fetch.bind(globalThis);
10620
+ this.fetcher = opts.fetcher ?? createDefaultTrustFetcher();
10086
10621
  }
10087
10622
  async fetchSigned(url, signingAnchors) {
10088
10623
  assertCryptoEngineRegistered();
@@ -10544,7 +11079,7 @@ function equalBytes(a, b) {
10544
11079
 
10545
11080
  // src/index.ts
10546
11081
  init_errors();
10547
- var VERSION = "0.12.0";
11082
+ var VERSION = "0.13.0";
10548
11083
  /*! Bundled license information:
10549
11084
 
10550
11085
  pvtsutils/build/index.es.js:
@@ -10614,6 +11149,6 @@ asn1js/build/index.es.js:
10614
11149
  *)
10615
11150
  */
10616
11151
 
10617
- export { CertificateChainError, CompositeTrustStore, DecryptionFailedError, ExpiredCredentialError, HAIP_DOCTYPE_NAMESPACES, HaipValidationError, InMemoryCache, InvalidSignatureError, LotlConfigurationError, LotlFetchError, LotlSignatureError, LotlTrustStore, MalformedCredentialError, MdocParser, MissingDecryptionKeyError, MissingVerifierEncryptionKeyError, MultipleCredentialsNotSupportedError, NonceValidationError, OpenID4VPError, RevocationCheckFailedError, RevokedCertificateError, SdJwtParser, SignedRequestBuildError, StaticTrustStore, TrustAnchorNotFoundError, UnsupportedFormatError, UnsupportedJweError, VERSION, buildCredentialSetQuery, buildHaipQuery, buildOid4vpSessionTranscript, buildOpenID4VPHandoverSessionTranscript, createAuthorizationRequest, createSignedAuthorizationRequest, decryptAuthorizationResponse, isHaipQuery, parsePresentation, validateCredentialSetQuery, validateHaipQuery, verifyAuthorizationResponse, verifyPresentation };
11152
+ export { CertificateChainError, CompositeTrustStore, DecryptionFailedError, ExpiredCredentialError, GUARDED_FETCH_DEFAULTS, GuardedFetchError, HAIP_DOCTYPE_NAMESPACES, HaipValidationError, InMemoryCache, InvalidSignatureError, LotlConfigurationError, LotlFetchError, LotlSignatureError, LotlTrustStore, MalformedCredentialError, MdocParser, MissingDecryptionKeyError, MissingVerifierEncryptionKeyError, MultipleCredentialsNotSupportedError, NonceValidationError, OpenID4VPError, RevocationCheckFailedError, RevokedCertificateError, SdJwtParser, SignedRequestBuildError, StaticTrustStore, TrustAnchorNotFoundError, UnsupportedFormatError, UnsupportedJweError, VERSION, buildCredentialSetQuery, buildHaipQuery, buildOid4vpSessionTranscript, buildOpenID4VPHandoverSessionTranscript, createAuthorizationRequest, createGuardedFetcher, createSignedAuthorizationRequest, decryptAuthorizationResponse, isHaipQuery, parsePresentation, validateCredentialSetQuery, validateHaipQuery, verifyAuthorizationResponse, verifyPresentation };
10618
11153
  //# sourceMappingURL=index.js.map
10619
11154
  //# sourceMappingURL=index.js.map