@sphereon/ssi-sdk.sd-jwt 0.34.1-next.7 → 0.34.1-next.85

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