@sd-jwt/core 0.20.1-next.5 → 0.20.1-next.7

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.mjs CHANGED
@@ -56,6 +56,8 @@ var SD_LIST_KEY = "...";
56
56
  var SD_DIGEST = "_sd";
57
57
  var SD_DECOY = "_sd_decoy";
58
58
  var KB_JWT_TYP = "kb+jwt";
59
+ var encodePathSegment = (segment) => segment.replace(/~/g, "~0").replace(/\./g, "~1");
60
+ var encodePath = (segments) => segments.map(encodePathSegment).join(".");
59
61
  var IANA_HASH_ALGORITHMS = [
60
62
  "sha-256",
61
63
  "sha-256-128",
@@ -75,6 +77,19 @@ var IANA_HASH_ALGORITHMS = [
75
77
  "k12-256",
76
78
  "k12-512"
77
79
  ];
80
+ var DEFAULT_SECURE_HASH_ALGORITHMS = [
81
+ "sha-256",
82
+ "sha-384",
83
+ "sha-512",
84
+ "sha3-256",
85
+ "sha3-384",
86
+ "sha3-512",
87
+ "blake2s-256",
88
+ "blake2b-256",
89
+ "blake2b-512",
90
+ "k12-256",
91
+ "k12-512"
92
+ ];
78
93
 
79
94
  // src/utils/base64url.ts
80
95
  import {
@@ -117,6 +132,12 @@ var decodeBase64urlJsonStrict = (encoded, errorMessage) => {
117
132
  // src/utils/disclosure.ts
118
133
  var Disclosure = class _Disclosure {
119
134
  constructor(data, _meta) {
135
+ if (!Array.isArray(data) || data.length !== 2 && data.length !== 3) {
136
+ throw new SDJWTException("Invalid disclosure data");
137
+ }
138
+ if (typeof data[0] !== "string") {
139
+ throw new SDJWTException("Invalid disclosure salt");
140
+ }
120
141
  this._digest = _meta == null ? void 0 : _meta.digest;
121
142
  this._encoded = _meta == null ? void 0 : _meta.encoded;
122
143
  if (data.length === 2) {
@@ -125,12 +146,19 @@ var Disclosure = class _Disclosure {
125
146
  return;
126
147
  }
127
148
  if (data.length === 3) {
149
+ if (typeof data[1] !== "string") {
150
+ throw new SDJWTException("Invalid disclosure claim name");
151
+ }
152
+ if (data[1] === SD_DIGEST || data[1] === SD_LIST_KEY) {
153
+ throw new SDJWTException(
154
+ `Reserved disclosure claim name "${data[1]}" is not allowed`
155
+ );
156
+ }
128
157
  this.salt = data[0];
129
158
  this.key = data[1];
130
159
  this.value = data[2];
131
160
  return;
132
161
  }
133
- throw new SDJWTException("Invalid disclosure data");
134
162
  }
135
163
  // We need to digest of the original encoded data.
136
164
  // After decode process, we use JSON.stringify to encode the data.
@@ -204,10 +232,7 @@ var decodeJwt = (jwt) => {
204
232
  var splitSdJwt = (sdjwt) => {
205
233
  const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
206
234
  if (encodedDisclosures.length === 0) {
207
- return {
208
- jwt: encodedJwt,
209
- disclosures: []
210
- };
235
+ throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
211
236
  }
212
237
  const encodedKeyBindingJwt = encodedDisclosures.pop();
213
238
  return {
@@ -220,10 +245,7 @@ var decodeSdJwt = (sdjwt, hasher) => __async(null, null, function* () {
220
245
  const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
221
246
  const jwt = decodeJwt(encodedJwt);
222
247
  if (encodedDisclosures.length === 0) {
223
- return {
224
- jwt,
225
- disclosures: []
226
- };
248
+ throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
227
249
  }
228
250
  const encodedKeyBindingJwt = encodedDisclosures.pop();
229
251
  const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
@@ -243,10 +265,7 @@ var decodeSdJwtSync = (sdjwt, hasher) => {
243
265
  const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
244
266
  const jwt = decodeJwt(encodedJwt);
245
267
  if (encodedDisclosures.length === 0) {
246
- return {
247
- jwt,
248
- disclosures: []
249
- };
268
+ throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
250
269
  }
251
270
  const encodedKeyBindingJwt = encodedDisclosures.pop();
252
271
  const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
@@ -275,7 +294,10 @@ var unpackArray = (arr, map, prefix = "", seenDigests) => {
275
294
  arr.forEach((item, idx) => {
276
295
  if (isRecord(item)) {
277
296
  const hash = item[SD_LIST_KEY];
278
- if (typeof hash === "string") {
297
+ if (SD_LIST_KEY in item) {
298
+ if (Object.keys(item).length !== 1 || typeof hash !== "string") {
299
+ throw new SDJWTException("Invalid array disclosure placeholder");
300
+ }
279
301
  if (seenDigests) {
280
302
  if (seenDigests.has(hash)) {
281
303
  throw new SDJWTException(
@@ -286,6 +308,11 @@ var unpackArray = (arr, map, prefix = "", seenDigests) => {
286
308
  }
287
309
  const disclosed = map[hash];
288
310
  if (disclosed) {
311
+ if (typeof disclosed.key === "string") {
312
+ throw new SDJWTException(
313
+ "Object-property disclosure cannot be used as an array element"
314
+ );
315
+ }
289
316
  const presentKey = prefix ? `${prefix}.${idx}` : `${idx}`;
290
317
  keys[presentKey] = hash;
291
318
  const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
@@ -328,8 +355,12 @@ var unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
328
355
  }
329
356
  const record = obj;
330
357
  for (const key in record) {
358
+ if (prefix && key === "_sd_alg") {
359
+ throw new SDJWTException("Nested _sd_alg is not allowed");
360
+ }
331
361
  if (key !== SD_DIGEST && key !== SD_LIST_KEY && typeof record[key] === "object") {
332
- const newKey = prefix ? `${prefix}.${key}` : key;
362
+ const escapedKey = encodePathSegment(key);
363
+ const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
333
364
  const { unpackedObj: unpackedObj2, disclosureKeymap: disclosureKeys } = unpackObjInternal(record[key], map, newKey, seenDigests);
334
365
  record[key] = unpackedObj2;
335
366
  Object.assign(keys, disclosureKeys);
@@ -337,7 +368,12 @@ var unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
337
368
  }
338
369
  const _a = record, { _sd } = _a, payload = __objRest(_a, ["_sd"]);
339
370
  const claims = {};
340
- if (_sd) {
371
+ if (_sd !== void 0) {
372
+ if (!Array.isArray(_sd) || !_sd.every((hash) => typeof hash === "string")) {
373
+ throw new SDJWTException(
374
+ "Invalid _sd claim: expected array of strings"
375
+ );
376
+ }
341
377
  for (const hash of _sd) {
342
378
  if (seenDigests) {
343
379
  if (seenDigests.has(hash)) {
@@ -348,13 +384,24 @@ var unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
348
384
  seenDigests.add(hash);
349
385
  }
350
386
  const disclosed = map[hash];
351
- if (disclosed == null ? void 0 : disclosed.key) {
387
+ if (disclosed) {
388
+ if (typeof disclosed.key !== "string") {
389
+ throw new SDJWTException(
390
+ "Array disclosure cannot be used as an object property"
391
+ );
392
+ }
352
393
  if (disclosed.key in payload) {
353
394
  throw new SDJWTException(
354
395
  `Disclosed claim name "${disclosed.key}" conflicts with existing payload key`
355
396
  );
356
397
  }
357
- const presentKey = prefix ? `${prefix}.${disclosed.key}` : disclosed.key;
398
+ if (disclosed.key in claims) {
399
+ throw new SDJWTException(
400
+ `Disclosed claim name "${disclosed.key}" conflicts with another disclosure`
401
+ );
402
+ }
403
+ const escapedKey = encodePathSegment(disclosed.key);
404
+ const presentKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
358
405
  keys[presentKey] = hash;
359
406
  const { unpackedObj: unpackedObj2, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
360
407
  claims[disclosed.key] = unpackedObj2;
@@ -372,6 +419,9 @@ var createHashMapping = (disclosures, hash) => __async(null, null, function* ()
372
419
  for (let i = 0; i < disclosures.length; i++) {
373
420
  const disclosure = disclosures[i];
374
421
  const digest = yield disclosure.digest(hash);
422
+ if (digest in map) {
423
+ throw new SDJWTException("Duplicate disclosure digest detected");
424
+ }
375
425
  map[digest] = disclosure;
376
426
  }
377
427
  return map;
@@ -381,20 +431,29 @@ var createHashMappingSync = (disclosures, hash) => {
381
431
  for (let i = 0; i < disclosures.length; i++) {
382
432
  const disclosure = disclosures[i];
383
433
  const digest = disclosure.digestSync(hash);
434
+ if (digest in map) {
435
+ throw new SDJWTException("Duplicate disclosure digest detected");
436
+ }
384
437
  map[digest] = disclosure;
385
438
  }
386
439
  return map;
387
440
  };
388
- var getSDAlgAndPayload = (SdJwtPayload) => {
441
+ var getSDAlgAndPayload = (SdJwtPayload, allowedAlgorithms = DEFAULT_SECURE_HASH_ALGORITHMS) => {
389
442
  const _a = SdJwtPayload, { _sd_alg } = _a, payload = __objRest(_a, ["_sd_alg"]);
390
- if (typeof _sd_alg !== "string") {
443
+ if (_sd_alg === void 0) {
391
444
  return { _sd_alg: "sha-256", payload };
392
445
  }
446
+ if (typeof _sd_alg !== "string") {
447
+ throw new SDJWTException("Invalid _sd_alg: expected string");
448
+ }
393
449
  if (!IANA_HASH_ALGORITHMS.includes(
394
450
  _sd_alg
395
451
  )) {
396
452
  throw new SDJWTException(`Invalid _sd_alg: ${_sd_alg}`);
397
453
  }
454
+ if (!allowedAlgorithms.includes(_sd_alg)) {
455
+ throw new SDJWTException(`Disallowed _sd_alg: ${_sd_alg}`);
456
+ }
398
457
  return { _sd_alg, payload };
399
458
  };
400
459
  var unpack = (SdJwtPayload, disclosures, hasher) => __async(null, null, function* () {
@@ -503,6 +562,14 @@ var GeneralJSON = class _GeneralJSON {
503
562
  if (!json.signatures[0]) {
504
563
  throw new SDJWTException("Invalid JSON");
505
564
  }
565
+ for (let index = 1; index < json.signatures.length; index++) {
566
+ const header = json.signatures[index].header;
567
+ if (header && ("disclosures" in header || "kb_jwt" in header)) {
568
+ throw new SDJWTException(
569
+ "disclosures and kb_jwt MUST only appear in the first unprotected header"
570
+ );
571
+ }
572
+ }
506
573
  const disclosures = (_b = (_a = json.signatures[0].header) == null ? void 0 : _a.disclosures) != null ? _b : [];
507
574
  const kb_jwt = (_c = json.signatures[0].header) == null ? void 0 : _c.kb_jwt;
508
575
  return new _GeneralJSON({
@@ -575,6 +642,49 @@ var GeneralJSON = class _GeneralJSON {
575
642
  };
576
643
 
577
644
  // src/jwt.ts
645
+ var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
646
+ var validateNumericDate = (payload, claim) => {
647
+ const value = payload[claim];
648
+ if (value === void 0) return void 0;
649
+ if (typeof value !== "number" || !Number.isFinite(value)) {
650
+ throw new SDJWTException(`Verify Error: JWT ${claim} must be a number`);
651
+ }
652
+ return value;
653
+ };
654
+ var getAudiences = (audience) => {
655
+ if (typeof audience === "string") return [audience];
656
+ if (isStringArray(audience)) return audience;
657
+ return void 0;
658
+ };
659
+ var validateAudience = (payload, expectedAudience) => {
660
+ if (expectedAudience === void 0) return;
661
+ const expectedAudiences = Array.isArray(expectedAudience) ? expectedAudience : [expectedAudience];
662
+ const audiences = getAudiences(payload.aud);
663
+ if (!audiences || !expectedAudiences.some((expected) => audiences.includes(expected))) {
664
+ throw new SDJWTException("Verify Error: Invalid audience");
665
+ }
666
+ };
667
+ var validateJwtPayload = (payload, options) => {
668
+ var _a;
669
+ if (!payload) {
670
+ throw new SDJWTException("Verify Error: JWT payload is missing");
671
+ }
672
+ const skew = (options == null ? void 0 : options.skewSeconds) ? options.skewSeconds : 0;
673
+ const currentDate = (_a = options == null ? void 0 : options.currentDate) != null ? _a : Math.floor(Date.now() / 1e3);
674
+ const iat = validateNumericDate(payload, "iat");
675
+ const nbf = validateNumericDate(payload, "nbf");
676
+ const exp = validateNumericDate(payload, "exp");
677
+ if (iat !== void 0 && iat - skew > currentDate) {
678
+ throw new SDJWTException("Verify Error: JWT is not yet valid");
679
+ }
680
+ if (nbf !== void 0 && nbf - skew > currentDate) {
681
+ throw new SDJWTException("Verify Error: JWT is not yet valid");
682
+ }
683
+ if (exp !== void 0 && exp + skew <= currentDate) {
684
+ throw new SDJWTException("Verify Error: JWT is expired");
685
+ }
686
+ validateAudience(payload, options == null ? void 0 : options.expectedAudience);
687
+ };
578
688
  var Jwt = class _Jwt {
579
689
  constructor(data) {
580
690
  this.header = data == null ? void 0 : data.header;
@@ -625,6 +735,9 @@ var Jwt = class _Jwt {
625
735
  }
626
736
  sign(signer) {
627
737
  return __async(this, null, function* () {
738
+ if (!this.header || this.header.alg === "none") {
739
+ throw new SDJWTException('Sign Error: alg "none" is not allowed');
740
+ }
628
741
  const data = this.getUnsignedToken();
629
742
  this.signature = yield signer(data);
630
743
  return this.encodeJwt();
@@ -653,20 +766,16 @@ var Jwt = class _Jwt {
653
766
  */
654
767
  verify(verifier, options) {
655
768
  return __async(this, null, function* () {
656
- var _a, _b, _c, _d;
657
- const skew = (options == null ? void 0 : options.skewSeconds) ? options.skewSeconds : 0;
658
- const currentDate = (_a = options == null ? void 0 : options.currentDate) != null ? _a : Math.floor(Date.now() / 1e3);
659
- const iat = (_b = this.payload) == null ? void 0 : _b.iat;
660
- const nbf = (_c = this.payload) == null ? void 0 : _c.nbf;
661
- const exp = (_d = this.payload) == null ? void 0 : _d.exp;
662
- if (typeof iat === "number" && iat - skew > currentDate) {
663
- throw new SDJWTException("Verify Error: JWT is not yet valid");
769
+ var _a;
770
+ const alg = (_a = this.header) == null ? void 0 : _a.alg;
771
+ if (typeof alg !== "string" || alg === "none") {
772
+ throw new SDJWTException('Verify Error: alg "none" is not allowed');
664
773
  }
665
- if (typeof nbf === "number" && nbf - skew > currentDate) {
666
- throw new SDJWTException("Verify Error: JWT is not yet valid");
774
+ if ((options == null ? void 0 : options.allowedIssuerAlgorithms) && !options.allowedIssuerAlgorithms.includes(alg)) {
775
+ throw new SDJWTException(`Verify Error: Disallowed alg ${alg}`);
667
776
  }
668
- if (typeof exp === "number" && exp + skew < currentDate) {
669
- throw new SDJWTException("Verify Error: JWT is expired");
777
+ if (!(options == null ? void 0 : options.skipJwtClaimValidation)) {
778
+ validateJwtPayload(this.payload, options);
670
779
  }
671
780
  if (!this.signature) {
672
781
  throw new SDJWTException("Verify Error: no signature in JWT");
@@ -687,16 +796,31 @@ var KBJwt = class _KBJwt extends Jwt {
687
796
  // the type unknown is not good, but we don't know at this point how to get the public key of the signer, this is defined in the kbVerifier
688
797
  verifyKB(values) {
689
798
  return __async(this, null, function* () {
799
+ var _a, _b, _c, _d;
690
800
  if (!this.header || !this.payload || !this.signature) {
691
801
  throw new SDJWTException("Verify Error: Invalid JWT");
692
802
  }
693
- if (!this.header.alg || this.header.alg === "none" || !this.header.typ || this.header.typ !== KB_JWT_TYP || !this.payload.iat || !this.payload.aud || !this.payload.nonce || // this is for backward compatibility with version 06
694
- !(this.payload.sd_hash || "_sd_hash" in this.payload && this.payload._sd_hash)) {
803
+ if (typeof this.header.alg !== "string" || this.header.alg === "none" || typeof this.header.typ !== "string" || this.header.typ !== KB_JWT_TYP || typeof this.payload.iat !== "number" || typeof this.payload.aud !== "string" || typeof this.payload.nonce !== "string" || typeof this.payload.sd_hash !== "string" || this.payload.sd_hash.length === 0) {
695
804
  throw new SDJWTException("Invalid Key Binding Jwt");
696
805
  }
697
806
  if (this.payload.nonce !== values.nonce) {
698
807
  throw new SDJWTException("Verify Error: Invalid Nonce");
699
808
  }
809
+ if (((_a = values.options) == null ? void 0 : _a.expectedKeyBindingAudience) !== void 0) {
810
+ const expectedAudiences = Array.isArray(
811
+ values.options.expectedKeyBindingAudience
812
+ ) ? values.options.expectedKeyBindingAudience : [values.options.expectedKeyBindingAudience];
813
+ if (!expectedAudiences.includes(this.payload.aud)) {
814
+ throw new SDJWTException("Verify Error: Invalid Key Binding audience");
815
+ }
816
+ }
817
+ if (((_b = values.options) == null ? void 0 : _b.keyBindingMaxAgeSeconds) !== void 0) {
818
+ const currentDate = (_c = values.options.currentDate) != null ? _c : Math.floor(Date.now() / 1e3);
819
+ const skew = (_d = values.options.skewSeconds) != null ? _d : 0;
820
+ if (this.payload.iat + values.options.keyBindingMaxAgeSeconds + skew < currentDate) {
821
+ throw new SDJWTException("Verify Error: Key Binding JWT is too old");
822
+ }
823
+ }
700
824
  yield this.verify(
701
825
  (data, sig) => values.verifier(data, sig, values.payload),
702
826
  values.options
@@ -772,16 +896,17 @@ var presentSync = (sdJwt, presentFrame, hasher) => {
772
896
  kbJwt != null ? kbJwt : ""
773
897
  ].join(SD_SEPARATOR);
774
898
  };
775
- var transformPresentationFrame = (obj, prefix = "") => {
899
+ var transformPresentationFrame = (obj, prefix = []) => {
776
900
  return Object.entries(obj).reduce((acc, [key, value]) => {
777
- const newPrefix = prefix ? `${prefix}.${key}` : key;
901
+ const newPrefix = [...prefix, key];
902
+ const encodedPrefix = encodePath(newPrefix);
778
903
  if (typeof value === "boolean") {
779
904
  if (value) {
780
- acc.push(newPrefix);
905
+ acc.push(encodedPrefix);
781
906
  }
782
907
  } else if (typeof value === "object" && value !== null) {
783
908
  acc.push(
784
- newPrefix,
909
+ encodedPrefix,
785
910
  ...transformPresentationFrame(
786
911
  value,
787
912
  newPrefix
@@ -832,6 +957,23 @@ var selectDisclosures = (payload, disclosures, presentationFrame) => {
832
957
  };
833
958
 
834
959
  // src/sdjwt.ts
960
+ var createDisclosureSalt = (saltGenerator, seenSalts) => __async(null, null, function* () {
961
+ const salt = yield saltGenerator(16);
962
+ if (typeof salt !== "string") {
963
+ throw new SDJWTException("SaltGenerator must return a string");
964
+ }
965
+ if (seenSalts.has(salt)) {
966
+ throw new SDJWTException("Duplicate disclosure salt detected");
967
+ }
968
+ seenSalts.add(salt);
969
+ return salt;
970
+ });
971
+ var addDisclosureDigest = (digest, seenDigests) => {
972
+ if (seenDigests.has(digest)) {
973
+ throw new SDJWTException("Duplicate disclosure digest detected");
974
+ }
975
+ seenDigests.add(digest);
976
+ };
835
977
  var SDJwt = class _SDJwt {
836
978
  constructor(data) {
837
979
  this.jwt = data == null ? void 0 : data.jwt;
@@ -841,16 +983,13 @@ var SDJwt = class _SDJwt {
841
983
  static decodeSDJwt(sdjwt, hasher) {
842
984
  return __async(this, null, function* () {
843
985
  const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
986
+ if (encodedDisclosures.length === 0) {
987
+ throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
988
+ }
844
989
  const jwt = Jwt.fromEncode(encodedJwt);
845
990
  if (!jwt.payload) {
846
991
  throw new Error("Payload is undefined on the JWT. Invalid state reached");
847
992
  }
848
- if (encodedDisclosures.length === 0) {
849
- return {
850
- jwt,
851
- disclosures: []
852
- };
853
- }
854
993
  const encodedKeyBindingJwt = encodedDisclosures.pop();
855
994
  const kbJwt = encodedKeyBindingJwt ? KBJwt.fromKBEncode(encodedKeyBindingJwt) : void 0;
856
995
  const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
@@ -964,7 +1103,8 @@ var listKeys = (obj, prefix = "") => {
964
1103
  const keys = [];
965
1104
  for (const key in obj) {
966
1105
  if (obj[key] === void 0) continue;
967
- const newKey = prefix ? `${prefix}.${key}` : key;
1106
+ const escapedKey = encodePathSegment(key);
1107
+ const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
968
1108
  keys.push(newKey);
969
1109
  const value = obj[key];
970
1110
  if (value && typeof value === "object") {
@@ -973,7 +1113,7 @@ var listKeys = (obj, prefix = "") => {
973
1113
  }
974
1114
  return keys;
975
1115
  };
976
- var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null, function* () {
1116
+ var pack = (_0, _1, _2, _3, ..._4) => __async(null, [_0, _1, _2, _3, ..._4], function* (claims, disclosureFrame, hash, saltGenerator, seenSalts = /* @__PURE__ */ new Set(), seenDigests = /* @__PURE__ */ new Set()) {
977
1117
  var _a, _b;
978
1118
  if (!disclosureFrame) {
979
1119
  return {
@@ -994,7 +1134,9 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
994
1134
  claims[idx],
995
1135
  disclosureFrame[idx],
996
1136
  hash,
997
- saltGenerator
1137
+ saltGenerator,
1138
+ seenSalts,
1139
+ seenDigests
998
1140
  );
999
1141
  recursivePackedClaims2[idx] = packed.packedClaims;
1000
1142
  disclosures2.push(...packed.disclosures);
@@ -1003,9 +1145,10 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
1003
1145
  for (let i = 0; i < claims.length; i++) {
1004
1146
  const claim = recursivePackedClaims2[i] ? recursivePackedClaims2[i] : claims[i];
1005
1147
  if (sd.includes(i)) {
1006
- const salt = yield saltGenerator(16);
1148
+ const salt = yield createDisclosureSalt(saltGenerator, seenSalts);
1007
1149
  const disclosure = new Disclosure([salt, claim]);
1008
1150
  const digest = yield disclosure.digest(hash);
1151
+ addDisclosureDigest(digest, seenDigests);
1009
1152
  packedClaims2.push({ [SD_LIST_KEY]: digest });
1010
1153
  disclosures2.push(disclosure);
1011
1154
  } else {
@@ -1014,6 +1157,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
1014
1157
  }
1015
1158
  for (let j = 0; j < decoyCount; j++) {
1016
1159
  const decoyDigest = yield createDecoy(hash, saltGenerator);
1160
+ addDisclosureDigest(decoyDigest, seenDigests);
1017
1161
  packedClaims2.push({ [SD_LIST_KEY]: decoyDigest });
1018
1162
  }
1019
1163
  return { packedClaims: packedClaims2, disclosures: disclosures2 };
@@ -1028,7 +1172,9 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
1028
1172
  claims[key],
1029
1173
  disclosureFrame[key],
1030
1174
  hash,
1031
- saltGenerator
1175
+ saltGenerator,
1176
+ seenSalts,
1177
+ seenDigests
1032
1178
  );
1033
1179
  recursivePackedClaims[key] = packed.packedClaims;
1034
1180
  disclosures.push(...packed.disclosures);
@@ -1038,9 +1184,10 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
1038
1184
  for (const key in claims) {
1039
1185
  const claim = recursivePackedClaims[key] ? recursivePackedClaims[key] : claims[key];
1040
1186
  if (sd.includes(key)) {
1041
- const salt = yield saltGenerator(16);
1187
+ const salt = yield createDisclosureSalt(saltGenerator, seenSalts);
1042
1188
  const disclosure = new Disclosure([salt, key, claim]);
1043
1189
  const digest = yield disclosure.digest(hash);
1190
+ addDisclosureDigest(digest, seenDigests);
1044
1191
  _sd.push(digest);
1045
1192
  disclosures.push(disclosure);
1046
1193
  } else {
@@ -1049,6 +1196,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
1049
1196
  }
1050
1197
  for (let j = 0; j < decoyCount; j++) {
1051
1198
  const decoyDigest = yield createDecoy(hash, saltGenerator);
1199
+ addDisclosureDigest(decoyDigest, seenDigests);
1052
1200
  _sd.push(decoyDigest);
1053
1201
  }
1054
1202
  if (_sd.length > 0) {
@@ -1078,12 +1226,19 @@ function validateReservedFieldsInternal(payload) {
1078
1226
  var _SDJwtInstance = class _SDJwtInstance {
1079
1227
  constructor(userConfig) {
1080
1228
  this.userConfig = {};
1229
+ var _a;
1081
1230
  if (userConfig) {
1082
1231
  if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
1083
1232
  throw new SDJWTException(
1084
1233
  `Invalid hash algorithm: ${userConfig.hashAlg}`
1085
1234
  );
1086
1235
  }
1236
+ const allowedDisclosureHashAlgorithms = (_a = userConfig.allowedDisclosureHashAlgorithms) != null ? _a : DEFAULT_SECURE_HASH_ALGORITHMS;
1237
+ if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) {
1238
+ throw new SDJWTException(
1239
+ `Disallowed hash algorithm: ${userConfig.hashAlg}`
1240
+ );
1241
+ }
1087
1242
  this.userConfig = userConfig;
1088
1243
  }
1089
1244
  }
@@ -1126,7 +1281,7 @@ var _SDJwtInstance = class _SDJwtInstance {
1126
1281
  }
1127
1282
  issue(payload, disclosureFrame, options) {
1128
1283
  return __async(this, null, function* () {
1129
- var _a, _b;
1284
+ var _a, _b, _c;
1130
1285
  if (!this.userConfig.hasher) {
1131
1286
  throw new SDJWTException("Hasher not found");
1132
1287
  }
@@ -1136,10 +1291,17 @@ var _SDJwtInstance = class _SDJwtInstance {
1136
1291
  if (!this.userConfig.signAlg) {
1137
1292
  throw new SDJWTException("sign alogrithm not specified");
1138
1293
  }
1294
+ if (this.userConfig.signAlg === "none") {
1295
+ throw new SDJWTException('sign algorithm "none" is not allowed');
1296
+ }
1139
1297
  this.validateReservedFields(payload);
1140
1298
  this.validateDisclosureFrame(disclosureFrame);
1141
1299
  const hasher = this.userConfig.hasher;
1142
1300
  const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : _SDJwtInstance.DEFAULT_hashAlg;
1301
+ const allowedDisclosureHashAlgorithms = (_b = this.userConfig.allowedDisclosureHashAlgorithms) != null ? _b : DEFAULT_SECURE_HASH_ALGORITHMS;
1302
+ if (!allowedDisclosureHashAlgorithms.includes(hashAlg)) {
1303
+ throw new SDJWTException(`Disallowed hash algorithm: ${hashAlg}`);
1304
+ }
1143
1305
  const { packedClaims, disclosures } = yield pack(
1144
1306
  payload,
1145
1307
  disclosureFrame,
@@ -1147,7 +1309,7 @@ var _SDJwtInstance = class _SDJwtInstance {
1147
1309
  this.userConfig.saltGenerator
1148
1310
  );
1149
1311
  const alg = this.userConfig.signAlg;
1150
- const OptionHeader = (_b = options == null ? void 0 : options.header) != null ? _b : {};
1312
+ const OptionHeader = (_c = options == null ? void 0 : options.header) != null ? _c : {};
1151
1313
  const CustomHeader = this.userConfig.omitTyp ? OptionHeader : __spreadValues({ typ: this.type }, OptionHeader);
1152
1314
  const header = __spreadProps(__spreadValues({}, CustomHeader), { alg });
1153
1315
  const jwt = new Jwt({
@@ -1183,6 +1345,9 @@ var _SDJwtInstance = class _SDJwtInstance {
1183
1345
  }
1184
1346
  const hasher = this.userConfig.hasher;
1185
1347
  const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1348
+ if (sdjwt.kbJwt) {
1349
+ throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1350
+ }
1186
1351
  if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
1187
1352
  const presentSdJwtWithoutKb = yield sdjwt.present(
1188
1353
  presentationFrame,
@@ -1325,10 +1490,13 @@ var _SDJwtInstance = class _SDJwtInstance {
1325
1490
  }
1326
1491
  if (sdjwt == null ? void 0 : sdjwt.jwt) {
1327
1492
  try {
1328
- const result = yield this.VerifyJwt(sdjwt.jwt, options);
1493
+ const result = yield this.VerifyJwt(sdjwt.jwt, __spreadProps(__spreadValues({}, options), {
1494
+ skipJwtClaimValidation: true
1495
+ }));
1329
1496
  header = result.header;
1330
1497
  const claims = yield sdjwt.getClaims(hasher);
1331
1498
  payload = claims;
1499
+ validateJwtPayload(payload, options);
1332
1500
  } catch (e) {
1333
1501
  const error = ensureError(e);
1334
1502
  const code = exceptionToCode(error);
@@ -1454,9 +1622,12 @@ var _SDJwtInstance = class _SDJwtInstance {
1454
1622
  if (!sdjwt.jwt) {
1455
1623
  throw new SDJWTException("Invalid SD JWT");
1456
1624
  }
1457
- const verifiedPayloads = yield this.VerifyJwt(sdjwt.jwt, options);
1625
+ const verifiedPayloads = yield this.VerifyJwt(sdjwt.jwt, __spreadProps(__spreadValues({}, options), {
1626
+ skipJwtClaimValidation: true
1627
+ }));
1458
1628
  const claims = yield sdjwt.getClaims(hasher);
1459
1629
  validateReservedFieldsInternal(claims);
1630
+ validateJwtPayload(claims, options);
1460
1631
  return { payload: claims, header: verifiedPayloads.header };
1461
1632
  });
1462
1633
  }
@@ -1511,12 +1682,19 @@ var SDJwtInstance = _SDJwtInstance;
1511
1682
  var SDJwtGeneralJSONInstance = class {
1512
1683
  constructor(userConfig) {
1513
1684
  this.userConfig = {};
1685
+ var _a;
1514
1686
  if (userConfig) {
1515
1687
  if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
1516
1688
  throw new SDJWTException(
1517
1689
  `Invalid hash algorithm: ${userConfig.hashAlg}`
1518
1690
  );
1519
1691
  }
1692
+ const allowedDisclosureHashAlgorithms = (_a = userConfig.allowedDisclosureHashAlgorithms) != null ? _a : DEFAULT_SECURE_HASH_ALGORITHMS;
1693
+ if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) {
1694
+ throw new SDJWTException(
1695
+ `Disallowed hash algorithm: ${userConfig.hashAlg}`
1696
+ );
1697
+ }
1520
1698
  this.userConfig = userConfig;
1521
1699
  }
1522
1700
  }
@@ -1610,6 +1788,9 @@ var SDJwtGeneralJSONInstance = class {
1610
1788
  const hasher = this.userConfig.hasher;
1611
1789
  const encodedSDJwt = generalJSON.toEncoded(0);
1612
1790
  const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1791
+ if (sdjwt.kbJwt) {
1792
+ throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1793
+ }
1613
1794
  if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
1614
1795
  const disclosures = yield sdjwt.getPresentDisclosures(
1615
1796
  presentationFrame,
@@ -1649,7 +1830,7 @@ var SDJwtGeneralJSONInstance = class {
1649
1830
  throw new SDJWTException("Hasher not found");
1650
1831
  }
1651
1832
  const hasher = this.userConfig.hasher;
1652
- const { payload, headers } = yield this.validate(generalJSON);
1833
+ const { payload, headers } = yield this.validate(generalJSON, options);
1653
1834
  const encodedSDJwt = generalJSON.toEncoded(0);
1654
1835
  const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
1655
1836
  if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) {
@@ -1715,7 +1896,7 @@ var SDJwtGeneralJSONInstance = class {
1715
1896
  }
1716
1897
  // This function is for validating the SD JWT
1717
1898
  // Just checking signature and return its the claims
1718
- validate(generalJSON) {
1899
+ validate(generalJSON, options) {
1719
1900
  return __async(this, null, function* () {
1720
1901
  if (!this.userConfig.hasher) {
1721
1902
  throw new SDJWTException("Hasher not found");
@@ -1731,9 +1912,21 @@ var SDJwtGeneralJSONInstance = class {
1731
1912
  const { protected: encodedHeader, signature } = s;
1732
1913
  const verified2 = yield verifier(
1733
1914
  `${encodedHeader}.${payload}`,
1734
- signature
1915
+ signature,
1916
+ __spreadProps(__spreadValues({}, options), { skipJwtClaimValidation: true })
1917
+ );
1918
+ const header = decodeBase64urlJsonStrict(
1919
+ encodedHeader,
1920
+ "Invalid JWT"
1735
1921
  );
1736
- const header = decodeBase64urlJsonStrict(encodedHeader, "Invalid JWT");
1922
+ if (typeof header.alg !== "string" || header.alg === "none") {
1923
+ throw new SDJWTException('Verify Error: alg "none" is not allowed');
1924
+ }
1925
+ if ((options == null ? void 0 : options.allowedIssuerAlgorithms) && !options.allowedIssuerAlgorithms.includes(header.alg)) {
1926
+ throw new SDJWTException(
1927
+ `Verify Error: Disallowed alg ${header.alg}`
1928
+ );
1929
+ }
1737
1930
  return { verified: verified2, header };
1738
1931
  }))
1739
1932
  );
@@ -1748,6 +1941,7 @@ var SDJwtGeneralJSONInstance = class {
1748
1941
  }
1749
1942
  const claims = yield sdjwt.getClaims(hasher);
1750
1943
  validateReservedFieldsInternal(claims);
1944
+ validateJwtPayload(claims, options);
1751
1945
  return { payload: claims, headers: results.map((r) => r.header) };
1752
1946
  });
1753
1947
  }
@@ -1793,6 +1987,7 @@ var SDJwtGeneralJSONInstance = class {
1793
1987
  };
1794
1988
  SDJwtGeneralJSONInstance.DEFAULT_hashAlg = "sha-256";
1795
1989
  export {
1990
+ DEFAULT_SECURE_HASH_ALGORITHMS,
1796
1991
  Disclosure,
1797
1992
  FlattenJSON,
1798
1993
  GeneralJSON,
@@ -1818,6 +2013,8 @@ export {
1818
2013
  decodeJwt,
1819
2014
  decodeSdJwt,
1820
2015
  decodeSdJwtSync,
2016
+ encodePath,
2017
+ encodePathSegment,
1821
2018
  ensureError,
1822
2019
  getClaims,
1823
2020
  getClaimsSync,
@@ -1834,5 +2031,6 @@ export {
1834
2031
  uint8ArrayToBase64Url,
1835
2032
  unpack,
1836
2033
  unpackObj,
1837
- unpackSync
2034
+ unpackSync,
2035
+ validateJwtPayload
1838
2036
  };