@sphereon/ssi-sdk.sd-jwt 0.34.1-feature.merge.crypto.extensions.modules.39 → 0.34.1-fix.103

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.cjs CHANGED
@@ -37,16 +37,19 @@ __export(index_exports, {
37
37
  createIntegrity: () => createIntegrity,
38
38
  extractHashFromIntegrity: () => extractHashFromIntegrity,
39
39
  fetchUrlWithErrorHandling: () => fetchUrlWithErrorHandling,
40
+ getIssuerFromSdJwt: () => getIssuerFromSdJwt,
41
+ isSdjwtVcPayload: () => isSdjwtVcPayload,
42
+ isVcdm2SdJwt: () => isVcdm2SdJwt,
43
+ isVcdm2SdJwtPayload: () => isVcdm2SdJwtPayload,
40
44
  sdJwtPluginContextMethods: () => sdJwtPluginContextMethods,
41
45
  validateIntegrity: () => validateIntegrity
42
46
  });
43
47
  module.exports = __toCommonJS(index_exports);
44
48
 
45
49
  // src/action-handler.ts
46
- var import_core = require("@sd-jwt/core");
47
- var import_sd_jwt_vc = require("@sd-jwt/sd-jwt-vc");
50
+ var import_core2 = require("@sd-jwt/core");
51
+ var import_sd_jwt_vc2 = require("@sd-jwt/sd-jwt-vc");
48
52
  var import_ssi_sdk_ext2 = require("@sphereon/ssi-sdk-ext.key-utils");
49
- var import_utils = require("@veramo/utils");
50
53
  var import_debug = __toESM(require("debug"), 1);
51
54
 
52
55
  // src/defaultCallbacks.ts
@@ -122,8 +125,189 @@ function assertValidTypeMetadata(metadata, vct) {
122
125
  }
123
126
  }
124
127
  __name(assertValidTypeMetadata, "assertValidTypeMetadata");
128
+ function isVcdm2SdJwtPayload(payload) {
129
+ return "type" in payload && Array.isArray(payload.type) && payload.type.includes("VerifiableCredential") && "@context" in payload && (typeof payload["@context"] === "string" && payload["@context"].length > 0 || Array.isArray(payload["@context"]) && payload["@context"].length > 0 && payload["@context"].includes("https://www.w3.org/ns/credentials/v2"));
130
+ }
131
+ __name(isVcdm2SdJwtPayload, "isVcdm2SdJwtPayload");
132
+ function isSdjwtVcPayload(payload) {
133
+ return !isVcdm2SdJwtPayload(payload) && "vct" in payload && typeof payload.vct === "string";
134
+ }
135
+ __name(isSdjwtVcPayload, "isSdjwtVcPayload");
136
+ function getIssuerFromSdJwt(payload) {
137
+ let issuer;
138
+ if (isSdjwtVcPayload(payload) || "iss" in payload) {
139
+ issuer = payload.iss;
140
+ } else if (isVcdm2SdJwtPayload(payload) || "issuer" in payload && payload.issuer) {
141
+ issuer = typeof payload.issuer === "string" ? payload.issuer : payload.issuer?.id;
142
+ }
143
+ if (!issuer) {
144
+ throw new Error("No issuer (iss or VCDM 2 issuer) found in SD-JWT or no VCDM2 SD-JWT or SD-JWT VC");
145
+ }
146
+ return issuer;
147
+ }
148
+ __name(getIssuerFromSdJwt, "getIssuerFromSdJwt");
149
+
150
+ // src/sdJwtVcdm2Instance.ts
151
+ var import_core = require("@sd-jwt/core");
152
+ var import_utils = require("@sd-jwt/utils");
153
+ var import_sd_jwt_vc = require("@sd-jwt/sd-jwt-vc");
154
+
155
+ // src/types.ts
156
+ var import_ssi_sdk = require("@sphereon/ssi-sdk.agent-config");
157
+ var sdJwtPluginContextMethods = [
158
+ "createSdJwtVc",
159
+ "createSdJwtPresentation",
160
+ "verifySdJwtVc",
161
+ "verifySdJwtPresentation"
162
+ ];
163
+ function contextHasSDJwtPlugin(context) {
164
+ return (0, import_ssi_sdk.contextHasPlugin)(context, "verifySdJwtVc");
165
+ }
166
+ __name(contextHasSDJwtPlugin, "contextHasSDJwtPlugin");
167
+ function isVcdm2SdJwt(type) {
168
+ return type === "vc+sd-jwt" || type === "vp+sd-jwt";
169
+ }
170
+ __name(isVcdm2SdJwt, "isVcdm2SdJwt");
171
+
172
+ // src/sdJwtVcdm2Instance.ts
173
+ var SDJwtVcdmInstanceFactory = class {
174
+ static {
175
+ __name(this, "SDJwtVcdmInstanceFactory");
176
+ }
177
+ static create(type, config) {
178
+ if (isVcdm2SdJwt(type)) {
179
+ return new SDJwtVcdm2Instance(config);
180
+ }
181
+ return new import_sd_jwt_vc.SDJwtVcInstance(config);
182
+ }
183
+ };
184
+ var SDJwtVcdm2Instance = class extends import_core.SDJwtInstance {
185
+ static {
186
+ __name(this, "SDJwtVcdm2Instance");
187
+ }
188
+ /**
189
+ * The type of the SD-JWT VCDM2 set in the header.typ field.
190
+ */
191
+ static type = "vc+sd-jwt";
192
+ userConfig = {};
193
+ constructor(userConfig) {
194
+ super(userConfig);
195
+ if (userConfig) {
196
+ this.userConfig = userConfig;
197
+ }
198
+ }
199
+ /**
200
+ * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
201
+ * @param disclosureFrame
202
+ */
203
+ validateReservedFields(disclosureFrame) {
204
+ if (disclosureFrame?._sd && Array.isArray(disclosureFrame._sd) && disclosureFrame._sd.length > 0) {
205
+ const reservedNames = [
206
+ "iss",
207
+ "nbf",
208
+ "exp",
209
+ "cnf",
210
+ "@context",
211
+ "type",
212
+ "credentialStatus",
213
+ "credentialSchema",
214
+ "relatedResource"
215
+ ];
216
+ const reservedNamesInDisclosureFrame = disclosureFrame._sd.filter((key) => reservedNames.includes(key));
217
+ if (reservedNamesInDisclosureFrame.length > 0) {
218
+ throw new import_utils.SDJWTException(`Cannot disclose protected field(s): ${reservedNamesInDisclosureFrame.join(", ")}`);
219
+ }
220
+ }
221
+ }
222
+ /**
223
+ * Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
224
+ * @param encodedSDJwt
225
+ * @param options
226
+ */
227
+ async verify(encodedSDJwt, options) {
228
+ const result = await super.verify(encodedSDJwt, options).then((res) => {
229
+ return {
230
+ payload: res.payload,
231
+ header: res.header,
232
+ kb: res.kb
233
+ };
234
+ });
235
+ return result;
236
+ }
237
+ /**
238
+ * Validates the integrity of the response if the integrity is passed. If the integrity does not match, an error is thrown.
239
+ * @param integrity
240
+ * @param response
241
+ */
242
+ async validateIntegrity(response, url, integrity) {
243
+ if (integrity) {
244
+ const arrayBuffer = await response.arrayBuffer();
245
+ const alg = integrity.split("-")[0];
246
+ const hashBuffer = await this.userConfig.hasher(arrayBuffer, alg);
247
+ const integrityHash = integrity.split("-")[1];
248
+ const hash = Array.from(new Uint8Array(hashBuffer)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
249
+ if (hash !== integrityHash) {
250
+ throw new Error(`Integrity check for ${url} failed: is ${hash}, but expected ${integrityHash}`);
251
+ }
252
+ }
253
+ }
254
+ /**
255
+ * Fetches the content from the url with a timeout of 10 seconds.
256
+ * @param url
257
+ * @param integrity
258
+ * @returns
259
+ */
260
+ async fetch(url, integrity) {
261
+ try {
262
+ const response = await fetch(url, {
263
+ signal: AbortSignal.timeout(this.userConfig.timeout ?? 1e4)
264
+ });
265
+ if (!response.ok) {
266
+ const errorText = await response.text();
267
+ return Promise.reject(new Error(`Error fetching ${url}: ${response.status} ${response.statusText} - ${errorText}`));
268
+ }
269
+ await this.validateIntegrity(response.clone(), url, integrity);
270
+ return response.json();
271
+ } catch (error) {
272
+ if (error.name === "TimeoutError") {
273
+ throw new Error(`Request to ${url} timed out`);
274
+ }
275
+ throw error;
276
+ }
277
+ }
278
+ async issue(payload, disclosureFrame, options) {
279
+ if (payload.iss && !payload.issuer) {
280
+ payload.issuer = {
281
+ id: payload.iss
282
+ };
283
+ delete payload.iss;
284
+ }
285
+ if (payload.nbf && !payload.validFrom) {
286
+ payload.validFrom = toVcdm2Date(payload.nbf);
287
+ delete payload.nbf;
288
+ }
289
+ if (payload.exp && !payload.validUntil) {
290
+ payload.validUntil = toVcdm2Date(payload.exp);
291
+ delete payload.exp;
292
+ }
293
+ if (payload.sub && !Array.isArray(payload.credentialSubject) && !payload.credentialSubject.id) {
294
+ payload.credentialSubject.id = payload.sub;
295
+ delete payload.sub;
296
+ }
297
+ return super.issue(payload, disclosureFrame, options);
298
+ }
299
+ };
300
+ function toVcdm2Date(value) {
301
+ const num = typeof value === "string" ? Number(value) : value;
302
+ if (!Number.isFinite(num)) {
303
+ throw new import_utils.SDJWTException(`Invalid numeric date: ${value}`);
304
+ }
305
+ return new Date(num * 1e3).toISOString();
306
+ }
307
+ __name(toVcdm2Date, "toVcdm2Date");
125
308
 
126
309
  // src/action-handler.ts
310
+ var u8a = __toESM(require("uint8arrays"), 1);
127
311
  var debug = (0, import_debug.default)("@sphereon/ssi-sdk.sd-jwt");
128
312
  var SDJwtPlugin = class {
129
313
  static {
@@ -193,7 +377,11 @@ var SDJwtPlugin = class {
193
377
  * @returns A signed SD-JWT credential.
194
378
  */
195
379
  async createSdJwtVc(args, context) {
196
- const issuer = args.credentialPayload.iss;
380
+ const payload = args.credentialPayload;
381
+ const isVcdm2 = isVcdm2SdJwtPayload(payload);
382
+ const isSdJwtVc = isSdjwtVcPayload(payload);
383
+ const type = args.type ?? (isVcdm2 ? "vc+sd-jwt" : "dc+sd-jwt");
384
+ const issuer = getIssuerFromSdJwt(args.credentialPayload);
197
385
  if (!issuer) {
198
386
  throw new Error("credential.issuer must not be empty");
199
387
  }
@@ -201,24 +389,46 @@ var SDJwtPlugin = class {
201
389
  identifier: issuer,
202
390
  resolution: args.resolution
203
391
  }, context);
204
- const sdjwt = new import_sd_jwt_vc.SDJwtVcInstance({
392
+ const signAlg = alg ?? signingKey?.alg ?? "ES256";
393
+ const hashAlg = /(\d{3})$/.test(signAlg) ? `sha-${signAlg.slice(-3)}` : "sha-256";
394
+ const sdjwt = SDJwtVcdmInstanceFactory.create(type, {
395
+ omitTyp: true,
205
396
  signer,
206
397
  hasher: this.registeredImplementations.hasher,
207
398
  saltGenerator: this.registeredImplementations.saltGenerator,
208
- signAlg: alg ?? "ES256",
209
- hashAlg: "sha-256"
399
+ signAlg,
400
+ hashAlg
210
401
  });
211
- const credential = await sdjwt.issue(args.credentialPayload, args.disclosureFrame, {
212
- header: {
213
- ...signingKey?.key.kid !== void 0 && {
214
- kid: signingKey.key.kid
215
- },
216
- ...signingKey?.key.x5c !== void 0 && {
217
- x5c: signingKey.key.x5c
218
- }
402
+ const header = {
403
+ ...signingKey?.key.kid !== void 0 && {
404
+ kid: signingKey.key.kid
405
+ },
406
+ ...signingKey?.key.x5c !== void 0 && {
407
+ x5c: signingKey.key.x5c
408
+ },
409
+ ...type && {
410
+ typ: type
219
411
  }
220
- });
412
+ };
413
+ let credential;
414
+ if (isVcdm2) {
415
+ credential = await sdjwt.issue(
416
+ payload,
417
+ // @ts-ignore
418
+ args.disclosureFrame,
419
+ {
420
+ header
421
+ }
422
+ );
423
+ } else if (isSdJwtVc) {
424
+ credential = await sdjwt.issue(payload, args.disclosureFrame, {
425
+ header
426
+ });
427
+ } else {
428
+ return Promise.reject(new Error(`invalid_argument: credential '${type}' type is not supported`));
429
+ }
221
430
  return {
431
+ type,
222
432
  credential
223
433
  };
224
434
  }
@@ -344,7 +554,8 @@ var SDJwtPlugin = class {
344
554
  * @returns A signed SD-JWT presentation.
345
555
  */
346
556
  async createSdJwtPresentation(args, context) {
347
- const cred = await import_core.SDJwt.fromEncode(args.presentation, this.registeredImplementations.hasher);
557
+ const type = args.type ?? "dc+sd-jwt";
558
+ const cred = await import_core2.SDJwt.fromEncode(args.presentation, this.registeredImplementations.hasher);
348
559
  const claims = await cred.getClaims(this.registeredImplementations.hasher);
349
560
  let holder;
350
561
  if (args.holder) {
@@ -364,8 +575,9 @@ var SDJwtPlugin = class {
364
575
  const { alg, signer } = await this.getSignerForIdentifier({
365
576
  identifier: holder
366
577
  }, context);
367
- const sdjwt = new import_sd_jwt_vc.SDJwtVcInstance({
368
- hasher: this.registeredImplementations.hasher ?? defaultGenerateDigest,
578
+ const sdjwt = SDJwtVcdmInstanceFactory.create(type, {
579
+ omitTyp: true,
580
+ hasher: this.registeredImplementations.hasher,
369
581
  saltGenerator: this.registeredImplementations.saltGenerator,
370
582
  kbSigner: signer,
371
583
  kbSignAlg: alg ?? "ES256"
@@ -374,6 +586,7 @@ var SDJwtPlugin = class {
374
586
  kb: args.kb
375
587
  });
376
588
  return {
589
+ type,
377
590
  presentation
378
591
  };
379
592
  }
@@ -384,13 +597,18 @@ var SDJwtPlugin = class {
384
597
  * @returns
385
598
  */
386
599
  async verifySdJwtVc(args, context) {
387
- const verifier = /* @__PURE__ */ __name(async (data, signature) => this.verify(sdjwt, context, data, signature), "verifier");
388
- const sdjwt = new import_sd_jwt_vc.SDJwtVcInstance({
600
+ const verifier = /* @__PURE__ */ __name(async (data, signature) => this.verifyCallbackImpl(sdjwt, context, data, signature), "verifier");
601
+ const cred = await import_core2.SDJwt.fromEncode(args.credential, this.registeredImplementations.hasher);
602
+ const type = isVcdm2SdJwtPayload(cred.jwt?.payload) ? "vc+sd-jwt" : "dc+sd-jwt";
603
+ const sdjwt = SDJwtVcdmInstanceFactory.create(type, {
389
604
  verifier,
390
605
  hasher: this.registeredImplementations.hasher ?? defaultGenerateDigest
391
606
  });
392
- const { header = {}, payload, kb } = await sdjwt.verify(args.credential);
607
+ const { header = {}, payload, kb } = await sdjwt.verify(args.credential, {
608
+ skewSeconds: 60 * 60 * 24 * 5
609
+ });
393
610
  return {
611
+ type,
394
612
  header,
395
613
  payload,
396
614
  kb
@@ -405,7 +623,7 @@ var SDJwtPlugin = class {
405
623
  * @param payload - The payload of the SD-JWT
406
624
  * @returns
407
625
  */
408
- verifyKb(sdjwt, context, data, signature, payload) {
626
+ verifyKb(context, data, signature, payload) {
409
627
  if (!payload.cnf) {
410
628
  throw Error("other method than cnf is not supported yet");
411
629
  }
@@ -419,9 +637,10 @@ var SDJwtPlugin = class {
419
637
  * @param signature - The signature
420
638
  * @returns
421
639
  */
422
- async verify(sdjwt, context, data, signature, opts) {
640
+ async verifyCallbackImpl(sdjwt, context, data, signature, opts) {
423
641
  const decodedVC = await sdjwt.decode(`${data}.${signature}`);
424
- const issuer = decodedVC.jwt.payload.iss;
642
+ const payload = decodedVC.jwt.payload;
643
+ const issuer = getIssuerFromSdJwt(payload);
425
644
  const header = decodedVC.jwt.header;
426
645
  const x5c = header?.x5c;
427
646
  let jwk = header.jwk;
@@ -487,14 +706,18 @@ var SDJwtPlugin = class {
487
706
  */
488
707
  async verifySdJwtPresentation(args, context) {
489
708
  let sdjwt;
490
- const verifier = /* @__PURE__ */ __name(async (data, signature) => this.verify(sdjwt, context, data, signature), "verifier");
491
- const verifierKb = /* @__PURE__ */ __name(async (data, signature, payload) => this.verifyKb(sdjwt, context, data, signature, payload), "verifierKb");
492
- sdjwt = new import_sd_jwt_vc.SDJwtVcInstance({
709
+ const verifier = /* @__PURE__ */ __name(async (data, signature) => this.verifyCallbackImpl(sdjwt, context, data, signature), "verifier");
710
+ const verifierKb = /* @__PURE__ */ __name(async (data, signature, payload) => this.verifyKb(context, data, signature, payload), "verifierKb");
711
+ sdjwt = new import_sd_jwt_vc2.SDJwtVcInstance({
493
712
  verifier,
494
713
  hasher: this.registeredImplementations.hasher,
495
714
  kbVerifier: verifierKb
496
715
  });
497
- return sdjwt.verify(args.presentation, args.requiredClaimKeys, args.kb);
716
+ const verifierOpts = {
717
+ requiredClaimKeys: args.requiredClaimKeys,
718
+ keyBindingNonce: args.keyBindingNonce
719
+ };
720
+ return sdjwt.verify(args.presentation, verifierOpts);
498
721
  }
499
722
  /**
500
723
  * Fetch and validate Type Metadata.
@@ -565,7 +788,7 @@ var SDJwtPlugin = class {
565
788
  return payload.cnf.jwk;
566
789
  } else if (payload.cnf !== void 0 && "kid" in payload.cnf && typeof payload.cnf.kid === "string" && payload.cnf.kid.startsWith("did:jwk:")) {
567
790
  const encoded = this.extractBase64FromDIDJwk(payload.cnf.kid);
568
- const decoded = (0, import_utils.decodeBase64url)(encoded);
791
+ const decoded = u8a.toString(u8a.fromString(encoded, "base64url"), "utf-8");
569
792
  const jwt = JSON.parse(decoded);
570
793
  return jwt;
571
794
  }
@@ -579,17 +802,4 @@ var SDJwtPlugin = class {
579
802
  return parts[2].split("#")[0];
580
803
  }
581
804
  };
582
-
583
- // src/types.ts
584
- var import_ssi_sdk = require("@sphereon/ssi-sdk.agent-config");
585
- var sdJwtPluginContextMethods = [
586
- "createSdJwtVc",
587
- "createSdJwtPresentation",
588
- "verifySdJwtVc",
589
- "verifySdJwtPresentation"
590
- ];
591
- function contextHasSDJwtPlugin(context) {
592
- return (0, import_ssi_sdk.contextHasPlugin)(context, "verifySdJwtVc");
593
- }
594
- __name(contextHasSDJwtPlugin, "contextHasSDJwtPlugin");
595
805
  //# sourceMappingURL=index.cjs.map