@sd-jwt/core 0.3.2-next.75 → 0.3.2-next.94
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/README.md +1 -38
- package/dist/index.d.mts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +49 -6
- package/dist/index.mjs +52 -10
- package/package.json +6 -6
- package/src/index.ts +74 -10
- package/src/sdjwt.ts +3 -0
- package/src/test/index.spec.ts +101 -21
- package/test/app-e2e.spec.ts +7 -6
package/README.md
CHANGED
|
@@ -32,44 +32,7 @@ Ensure you have Node.js installed as a prerequisite.
|
|
|
32
32
|
|
|
33
33
|
### Usage
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```jsx
|
|
38
|
-
import { DisclosureFrame } from '@sd-jwt/core';
|
|
39
|
-
|
|
40
|
-
// Issuer defines the claims object with the user's information
|
|
41
|
-
const claims = {
|
|
42
|
-
firstname: 'John',
|
|
43
|
-
lastname: 'Doe',
|
|
44
|
-
ssn: '123-45-6789',
|
|
45
|
-
id: '1234',
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Issuer defines the disclosure frame to specify which claims can be disclosed/undisclosed
|
|
49
|
-
const disclosureFrame: DisclosureFrame<typeof claims> = {
|
|
50
|
-
_sd: ['firstname', 'lastname', 'ssn'],
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// Issuer issues a signed JWT credential with the specified claims and disclosure frame
|
|
54
|
-
// returns an encoded JWT
|
|
55
|
-
const credential = await sdjwt.issue(claims, disclosureFrame);
|
|
56
|
-
|
|
57
|
-
// Holder may validate the credential from the issuer
|
|
58
|
-
const valid = await sdjwt.validate(credential);
|
|
59
|
-
|
|
60
|
-
// Holder defines the presentation frame to specify which claims should be presented
|
|
61
|
-
// The list of presented claims must be a subset of the disclosed claims
|
|
62
|
-
const presentationFrame = ['firstname', 'ssn'];
|
|
63
|
-
|
|
64
|
-
// Holder creates a presentation using the issued credential and the presentation frame
|
|
65
|
-
// returns an encoded SD JWT.
|
|
66
|
-
const presentation = await sdjwt.present(credential, presentationFrame);
|
|
67
|
-
|
|
68
|
-
// Verifier can verify the presentation using the Issuer's public key
|
|
69
|
-
const verified = await sdjwt.verify(presentation);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Check out more details in our [documentation](https://github.com/openwallet-foundation-labs/sd-jwt-js/tree/next/docs) or [examples](https://github.com/openwallet-foundation-labs/sd-jwt-js/tree/next/examples)
|
|
35
|
+
This library can not be used on it's own, it is a dependency for other implementations like `@sd-jwt/sd-jwt-vc`.
|
|
73
36
|
|
|
74
37
|
### Dependencies
|
|
75
38
|
|
package/dist/index.d.mts
CHANGED
|
@@ -66,16 +66,19 @@ declare const pack: <T extends Record<string, unknown>>(claims: T, disclosureFra
|
|
|
66
66
|
|
|
67
67
|
declare const createDecoy: (hash: HasherAndAlg, saltGenerator: SaltGenerator) => Promise<string>;
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
type SdJwtPayload = Record<string, unknown>;
|
|
70
|
+
declare abstract class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
|
|
71
|
+
protected abstract type: string;
|
|
70
72
|
static DEFAULT_hashAlg: string;
|
|
71
73
|
private userConfig;
|
|
72
74
|
constructor(userConfig?: SDJWTConfig);
|
|
73
75
|
private createKBJwt;
|
|
74
76
|
private SignJwt;
|
|
75
77
|
private VerifyJwt;
|
|
76
|
-
issue<Payload extends
|
|
78
|
+
issue<Payload extends ExtendedPayload>(payload: Payload, disclosureFrame?: DisclosureFrame<Payload>, options?: {
|
|
77
79
|
header?: object;
|
|
78
80
|
}): Promise<SDJWTCompact>;
|
|
81
|
+
protected abstract validateReservedFields<T extends ExtendedPayload>(disclosureFrame: DisclosureFrame<T>): void;
|
|
79
82
|
present(encodedSDJwt: string, presentationKeys?: string[], options?: {
|
|
80
83
|
kb?: KBOptions;
|
|
81
84
|
}): Promise<SDJWTCompact>;
|
|
@@ -91,6 +94,7 @@ declare class SDJwtInstance {
|
|
|
91
94
|
header: _sd_jwt_types.kbHeader;
|
|
92
95
|
};
|
|
93
96
|
}>;
|
|
97
|
+
private calculateSDHash;
|
|
94
98
|
validate(encodedSDJwt: string): Promise<{
|
|
95
99
|
payload: unknown;
|
|
96
100
|
header: Record<string, unknown>;
|
|
@@ -103,4 +107,4 @@ declare class SDJwtInstance {
|
|
|
103
107
|
getClaims(endcodedSDJwt: SDJWTCompact): Promise<unknown>;
|
|
104
108
|
}
|
|
105
109
|
|
|
106
|
-
export { Jwt, type JwtData, KBJwt, SDJwt, type SDJwtData, SDJwtInstance, createDecoy, listKeys, pack };
|
|
110
|
+
export { Jwt, type JwtData, KBJwt, SDJwt, type SDJwtData, SDJwtInstance, type SdJwtPayload, createDecoy, listKeys, pack };
|
package/dist/index.d.ts
CHANGED
|
@@ -66,16 +66,19 @@ declare const pack: <T extends Record<string, unknown>>(claims: T, disclosureFra
|
|
|
66
66
|
|
|
67
67
|
declare const createDecoy: (hash: HasherAndAlg, saltGenerator: SaltGenerator) => Promise<string>;
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
type SdJwtPayload = Record<string, unknown>;
|
|
70
|
+
declare abstract class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
|
|
71
|
+
protected abstract type: string;
|
|
70
72
|
static DEFAULT_hashAlg: string;
|
|
71
73
|
private userConfig;
|
|
72
74
|
constructor(userConfig?: SDJWTConfig);
|
|
73
75
|
private createKBJwt;
|
|
74
76
|
private SignJwt;
|
|
75
77
|
private VerifyJwt;
|
|
76
|
-
issue<Payload extends
|
|
78
|
+
issue<Payload extends ExtendedPayload>(payload: Payload, disclosureFrame?: DisclosureFrame<Payload>, options?: {
|
|
77
79
|
header?: object;
|
|
78
80
|
}): Promise<SDJWTCompact>;
|
|
81
|
+
protected abstract validateReservedFields<T extends ExtendedPayload>(disclosureFrame: DisclosureFrame<T>): void;
|
|
79
82
|
present(encodedSDJwt: string, presentationKeys?: string[], options?: {
|
|
80
83
|
kb?: KBOptions;
|
|
81
84
|
}): Promise<SDJWTCompact>;
|
|
@@ -91,6 +94,7 @@ declare class SDJwtInstance {
|
|
|
91
94
|
header: _sd_jwt_types.kbHeader;
|
|
92
95
|
};
|
|
93
96
|
}>;
|
|
97
|
+
private calculateSDHash;
|
|
94
98
|
validate(encodedSDJwt: string): Promise<{
|
|
95
99
|
payload: unknown;
|
|
96
100
|
header: Record<string, unknown>;
|
|
@@ -103,4 +107,4 @@ declare class SDJwtInstance {
|
|
|
103
107
|
getClaims(endcodedSDJwt: SDJWTCompact): Promise<unknown>;
|
|
104
108
|
}
|
|
105
109
|
|
|
106
|
-
export { Jwt, type JwtData, KBJwt, SDJwt, type SDJwtData, SDJwtInstance, createDecoy, listKeys, pack };
|
|
110
|
+
export { Jwt, type JwtData, KBJwt, SDJwt, type SDJwtData, SDJwtInstance, type SdJwtPayload, createDecoy, listKeys, pack };
|
package/dist/index.js
CHANGED
|
@@ -403,6 +403,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(void 0, nul
|
|
|
403
403
|
|
|
404
404
|
// src/index.ts
|
|
405
405
|
var import_types2 = require("@sd-jwt/types");
|
|
406
|
+
var import_decode3 = require("@sd-jwt/decode");
|
|
406
407
|
var _SDJwtInstance = class _SDJwtInstance {
|
|
407
408
|
constructor(userConfig) {
|
|
408
409
|
this.userConfig = {};
|
|
@@ -410,7 +411,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
410
411
|
this.userConfig = userConfig;
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
|
-
createKBJwt(options) {
|
|
414
|
+
createKBJwt(options, sdHash) {
|
|
414
415
|
return __async(this, null, function* () {
|
|
415
416
|
if (!this.userConfig.kbSigner) {
|
|
416
417
|
throw new import_utils5.SDJWTException("Key Binding Signer not found");
|
|
@@ -424,7 +425,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
424
425
|
typ: import_types2.KB_JWT_TYP,
|
|
425
426
|
alg: this.userConfig.kbSignAlg
|
|
426
427
|
},
|
|
427
|
-
payload
|
|
428
|
+
payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
|
|
428
429
|
});
|
|
429
430
|
yield kbJwt.sign(this.userConfig.kbSigner);
|
|
430
431
|
return kbJwt;
|
|
@@ -459,6 +460,9 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
459
460
|
if (!this.userConfig.signAlg) {
|
|
460
461
|
throw new import_utils5.SDJWTException("sign alogrithm not specified");
|
|
461
462
|
}
|
|
463
|
+
if (disclosureFrame) {
|
|
464
|
+
this.validateReservedFields(disclosureFrame);
|
|
465
|
+
}
|
|
462
466
|
const hasher = this.userConfig.hasher;
|
|
463
467
|
const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : _SDJwtInstance.DEFAULT_hashAlg;
|
|
464
468
|
const { packedClaims, disclosures } = yield pack(
|
|
@@ -469,7 +473,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
469
473
|
);
|
|
470
474
|
const alg = this.userConfig.signAlg;
|
|
471
475
|
const OptionHeader = (_b = options == null ? void 0 : options.header) != null ? _b : {};
|
|
472
|
-
const CustomHeader = this.userConfig.omitTyp ? OptionHeader : __spreadValues({ typ:
|
|
476
|
+
const CustomHeader = this.userConfig.omitTyp ? OptionHeader : __spreadValues({ typ: this.type }, OptionHeader);
|
|
473
477
|
const header = __spreadProps(__spreadValues({}, CustomHeader), { alg });
|
|
474
478
|
const jwt = new Jwt({
|
|
475
479
|
header,
|
|
@@ -487,6 +491,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
487
491
|
}
|
|
488
492
|
present(encodedSDJwt, presentationKeys, options) {
|
|
489
493
|
return __async(this, null, function* () {
|
|
494
|
+
var _a;
|
|
490
495
|
if (!presentationKeys)
|
|
491
496
|
return encodedSDJwt;
|
|
492
497
|
if (!this.userConfig.hasher) {
|
|
@@ -494,8 +499,21 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
494
499
|
}
|
|
495
500
|
const hasher = this.userConfig.hasher;
|
|
496
501
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
497
|
-
|
|
498
|
-
|
|
502
|
+
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload))
|
|
503
|
+
throw new import_utils5.SDJWTException("Payload not found");
|
|
504
|
+
const presentSdJwtWithoutKb = yield sdjwt.present(
|
|
505
|
+
presentationKeys.sort(),
|
|
506
|
+
hasher
|
|
507
|
+
);
|
|
508
|
+
if (!(options == null ? void 0 : options.kb)) {
|
|
509
|
+
return presentSdJwtWithoutKb;
|
|
510
|
+
}
|
|
511
|
+
const sdHashStr = yield this.calculateSDHash(
|
|
512
|
+
presentSdJwtWithoutKb,
|
|
513
|
+
sdjwt,
|
|
514
|
+
hasher
|
|
515
|
+
);
|
|
516
|
+
sdjwt.kbJwt = yield this.createKBJwt(options.kb, sdHashStr);
|
|
499
517
|
return sdjwt.present(presentationKeys.sort(), hasher);
|
|
500
518
|
});
|
|
501
519
|
}
|
|
@@ -509,7 +527,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
509
527
|
}
|
|
510
528
|
const hasher = this.userConfig.hasher;
|
|
511
529
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
512
|
-
if (!sdjwt.jwt) {
|
|
530
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
513
531
|
throw new import_utils5.SDJWTException("Invalid SD JWT");
|
|
514
532
|
}
|
|
515
533
|
const { payload, header } = yield this.validate(encodedSDJwt);
|
|
@@ -532,9 +550,34 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
532
550
|
throw new import_utils5.SDJWTException("Key Binding Verifier not found");
|
|
533
551
|
}
|
|
534
552
|
const kb = yield sdjwt.kbJwt.verify(this.userConfig.kbVerifier);
|
|
553
|
+
const sdHashfromKb = kb.payload.sd_hash;
|
|
554
|
+
const sdjwtWithoutKb = new SDJwt({
|
|
555
|
+
jwt: sdjwt.jwt,
|
|
556
|
+
disclosures: sdjwt.disclosures
|
|
557
|
+
});
|
|
558
|
+
const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
|
|
559
|
+
const sdHashStr = yield this.calculateSDHash(
|
|
560
|
+
presentSdJwtWithoutKb,
|
|
561
|
+
sdjwt,
|
|
562
|
+
hasher
|
|
563
|
+
);
|
|
564
|
+
if (sdHashStr !== sdHashfromKb) {
|
|
565
|
+
throw new import_utils5.SDJWTException("Invalid sd_hash in Key Binding JWT");
|
|
566
|
+
}
|
|
535
567
|
return { payload, header, kb };
|
|
536
568
|
});
|
|
537
569
|
}
|
|
570
|
+
calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
|
|
571
|
+
return __async(this, null, function* () {
|
|
572
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
573
|
+
throw new import_utils5.SDJWTException("Invalid SD JWT");
|
|
574
|
+
}
|
|
575
|
+
const { _sd_alg } = (0, import_decode3.getSDAlgAndPayload)(sdjwt.jwt.payload);
|
|
576
|
+
const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
577
|
+
const sdHashStr = (0, import_utils5.Uint8ArrayToBase64Url)(sdHash);
|
|
578
|
+
return sdHashStr;
|
|
579
|
+
});
|
|
580
|
+
}
|
|
538
581
|
// This function is for validating the SD JWT
|
|
539
582
|
// Just checking signature and return its the claims
|
|
540
583
|
validate(encodedSDJwt) {
|
package/dist/index.mjs
CHANGED
|
@@ -42,7 +42,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
// src/index.ts
|
|
45
|
-
import { SDJWTException as SDJWTException4 } from "@sd-jwt/utils";
|
|
45
|
+
import { SDJWTException as SDJWTException4, Uint8ArrayToBase64Url as Uint8ArrayToBase64Url2 } from "@sd-jwt/utils";
|
|
46
46
|
|
|
47
47
|
// src/jwt.ts
|
|
48
48
|
import { Base64urlEncode, SDJWTException } from "@sd-jwt/utils";
|
|
@@ -381,9 +381,9 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(void 0, nul
|
|
|
381
381
|
|
|
382
382
|
// src/index.ts
|
|
383
383
|
import {
|
|
384
|
-
KB_JWT_TYP
|
|
385
|
-
SD_JWT_TYP
|
|
384
|
+
KB_JWT_TYP as KB_JWT_TYP2
|
|
386
385
|
} from "@sd-jwt/types";
|
|
386
|
+
import { getSDAlgAndPayload as getSDAlgAndPayload2 } from "@sd-jwt/decode";
|
|
387
387
|
var _SDJwtInstance = class _SDJwtInstance {
|
|
388
388
|
constructor(userConfig) {
|
|
389
389
|
this.userConfig = {};
|
|
@@ -391,7 +391,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
391
391
|
this.userConfig = userConfig;
|
|
392
392
|
}
|
|
393
393
|
}
|
|
394
|
-
createKBJwt(options) {
|
|
394
|
+
createKBJwt(options, sdHash) {
|
|
395
395
|
return __async(this, null, function* () {
|
|
396
396
|
if (!this.userConfig.kbSigner) {
|
|
397
397
|
throw new SDJWTException4("Key Binding Signer not found");
|
|
@@ -402,10 +402,10 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
402
402
|
const { payload } = options;
|
|
403
403
|
const kbJwt = new KBJwt({
|
|
404
404
|
header: {
|
|
405
|
-
typ:
|
|
405
|
+
typ: KB_JWT_TYP2,
|
|
406
406
|
alg: this.userConfig.kbSignAlg
|
|
407
407
|
},
|
|
408
|
-
payload
|
|
408
|
+
payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
|
|
409
409
|
});
|
|
410
410
|
yield kbJwt.sign(this.userConfig.kbSigner);
|
|
411
411
|
return kbJwt;
|
|
@@ -440,6 +440,9 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
440
440
|
if (!this.userConfig.signAlg) {
|
|
441
441
|
throw new SDJWTException4("sign alogrithm not specified");
|
|
442
442
|
}
|
|
443
|
+
if (disclosureFrame) {
|
|
444
|
+
this.validateReservedFields(disclosureFrame);
|
|
445
|
+
}
|
|
443
446
|
const hasher = this.userConfig.hasher;
|
|
444
447
|
const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : _SDJwtInstance.DEFAULT_hashAlg;
|
|
445
448
|
const { packedClaims, disclosures } = yield pack(
|
|
@@ -450,7 +453,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
450
453
|
);
|
|
451
454
|
const alg = this.userConfig.signAlg;
|
|
452
455
|
const OptionHeader = (_b = options == null ? void 0 : options.header) != null ? _b : {};
|
|
453
|
-
const CustomHeader = this.userConfig.omitTyp ? OptionHeader : __spreadValues({ typ:
|
|
456
|
+
const CustomHeader = this.userConfig.omitTyp ? OptionHeader : __spreadValues({ typ: this.type }, OptionHeader);
|
|
454
457
|
const header = __spreadProps(__spreadValues({}, CustomHeader), { alg });
|
|
455
458
|
const jwt = new Jwt({
|
|
456
459
|
header,
|
|
@@ -468,6 +471,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
468
471
|
}
|
|
469
472
|
present(encodedSDJwt, presentationKeys, options) {
|
|
470
473
|
return __async(this, null, function* () {
|
|
474
|
+
var _a;
|
|
471
475
|
if (!presentationKeys)
|
|
472
476
|
return encodedSDJwt;
|
|
473
477
|
if (!this.userConfig.hasher) {
|
|
@@ -475,8 +479,21 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
475
479
|
}
|
|
476
480
|
const hasher = this.userConfig.hasher;
|
|
477
481
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
478
|
-
|
|
479
|
-
|
|
482
|
+
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload))
|
|
483
|
+
throw new SDJWTException4("Payload not found");
|
|
484
|
+
const presentSdJwtWithoutKb = yield sdjwt.present(
|
|
485
|
+
presentationKeys.sort(),
|
|
486
|
+
hasher
|
|
487
|
+
);
|
|
488
|
+
if (!(options == null ? void 0 : options.kb)) {
|
|
489
|
+
return presentSdJwtWithoutKb;
|
|
490
|
+
}
|
|
491
|
+
const sdHashStr = yield this.calculateSDHash(
|
|
492
|
+
presentSdJwtWithoutKb,
|
|
493
|
+
sdjwt,
|
|
494
|
+
hasher
|
|
495
|
+
);
|
|
496
|
+
sdjwt.kbJwt = yield this.createKBJwt(options.kb, sdHashStr);
|
|
480
497
|
return sdjwt.present(presentationKeys.sort(), hasher);
|
|
481
498
|
});
|
|
482
499
|
}
|
|
@@ -490,7 +507,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
490
507
|
}
|
|
491
508
|
const hasher = this.userConfig.hasher;
|
|
492
509
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
493
|
-
if (!sdjwt.jwt) {
|
|
510
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
494
511
|
throw new SDJWTException4("Invalid SD JWT");
|
|
495
512
|
}
|
|
496
513
|
const { payload, header } = yield this.validate(encodedSDJwt);
|
|
@@ -513,9 +530,34 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
513
530
|
throw new SDJWTException4("Key Binding Verifier not found");
|
|
514
531
|
}
|
|
515
532
|
const kb = yield sdjwt.kbJwt.verify(this.userConfig.kbVerifier);
|
|
533
|
+
const sdHashfromKb = kb.payload.sd_hash;
|
|
534
|
+
const sdjwtWithoutKb = new SDJwt({
|
|
535
|
+
jwt: sdjwt.jwt,
|
|
536
|
+
disclosures: sdjwt.disclosures
|
|
537
|
+
});
|
|
538
|
+
const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
|
|
539
|
+
const sdHashStr = yield this.calculateSDHash(
|
|
540
|
+
presentSdJwtWithoutKb,
|
|
541
|
+
sdjwt,
|
|
542
|
+
hasher
|
|
543
|
+
);
|
|
544
|
+
if (sdHashStr !== sdHashfromKb) {
|
|
545
|
+
throw new SDJWTException4("Invalid sd_hash in Key Binding JWT");
|
|
546
|
+
}
|
|
516
547
|
return { payload, header, kb };
|
|
517
548
|
});
|
|
518
549
|
}
|
|
550
|
+
calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
|
|
551
|
+
return __async(this, null, function* () {
|
|
552
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
553
|
+
throw new SDJWTException4("Invalid SD JWT");
|
|
554
|
+
}
|
|
555
|
+
const { _sd_alg } = getSDAlgAndPayload2(sdjwt.jwt.payload);
|
|
556
|
+
const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
557
|
+
const sdHashStr = Uint8ArrayToBase64Url2(sdHash);
|
|
558
|
+
return sdHashStr;
|
|
559
|
+
});
|
|
560
|
+
}
|
|
519
561
|
// This function is for validating the SD JWT
|
|
520
562
|
// Just checking signature and return its the claims
|
|
521
563
|
validate(encodedSDJwt) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sd-jwt/core",
|
|
3
|
-
"version": "0.3.2-next.
|
|
3
|
+
"version": "0.3.2-next.94+32af6cf",
|
|
4
4
|
"description": "sd-jwt draft 7 implementation in typescript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
},
|
|
40
40
|
"license": "Apache-2.0",
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@sd-jwt/crypto-nodejs": "0.3.2-next.
|
|
42
|
+
"@sd-jwt/crypto-nodejs": "0.3.2-next.94+32af6cf"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@sd-jwt/decode": "0.3.2-next.
|
|
46
|
-
"@sd-jwt/types": "0.3.2-next.
|
|
47
|
-
"@sd-jwt/utils": "0.3.2-next.
|
|
45
|
+
"@sd-jwt/decode": "0.3.2-next.94+32af6cf",
|
|
46
|
+
"@sd-jwt/types": "0.3.2-next.94+32af6cf",
|
|
47
|
+
"@sd-jwt/utils": "0.3.2-next.94+32af6cf"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"esm"
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "32af6cfa150fceb440fc9225bcaf2791a6aeee90"
|
|
66
66
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import { SDJWTException } from '@sd-jwt/utils';
|
|
1
|
+
import { SDJWTException, Uint8ArrayToBase64Url } from '@sd-jwt/utils';
|
|
2
2
|
import { Jwt } from './jwt';
|
|
3
3
|
import { KBJwt } from './kbjwt';
|
|
4
4
|
import { SDJwt, pack } from './sdjwt';
|
|
5
5
|
import {
|
|
6
6
|
DisclosureFrame,
|
|
7
|
+
Hasher,
|
|
7
8
|
KBOptions,
|
|
8
9
|
KB_JWT_TYP,
|
|
9
10
|
SDJWTCompact,
|
|
10
11
|
SDJWTConfig,
|
|
11
|
-
SD_JWT_TYP,
|
|
12
12
|
} from '@sd-jwt/types';
|
|
13
|
+
import { getSDAlgAndPayload } from '@sd-jwt/decode';
|
|
13
14
|
|
|
14
15
|
export * from './sdjwt';
|
|
15
16
|
export * from './kbjwt';
|
|
16
17
|
export * from './jwt';
|
|
17
18
|
export * from './decoy';
|
|
18
19
|
|
|
19
|
-
export
|
|
20
|
+
export type SdJwtPayload = Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
export abstract class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
|
|
23
|
+
//header type
|
|
24
|
+
protected abstract type: string;
|
|
25
|
+
|
|
20
26
|
public static DEFAULT_hashAlg = 'sha-256';
|
|
21
27
|
|
|
22
28
|
private userConfig: SDJWTConfig = {};
|
|
@@ -27,20 +33,24 @@ export class SDJwtInstance {
|
|
|
27
33
|
}
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
private async createKBJwt(
|
|
36
|
+
private async createKBJwt(
|
|
37
|
+
options: KBOptions,
|
|
38
|
+
sdHash: string,
|
|
39
|
+
): Promise<KBJwt> {
|
|
31
40
|
if (!this.userConfig.kbSigner) {
|
|
32
41
|
throw new SDJWTException('Key Binding Signer not found');
|
|
33
42
|
}
|
|
34
43
|
if (!this.userConfig.kbSignAlg) {
|
|
35
44
|
throw new SDJWTException('Key Binding sign algorithm not specified');
|
|
36
45
|
}
|
|
46
|
+
|
|
37
47
|
const { payload } = options;
|
|
38
48
|
const kbJwt = new KBJwt({
|
|
39
49
|
header: {
|
|
40
50
|
typ: KB_JWT_TYP,
|
|
41
51
|
alg: this.userConfig.kbSignAlg,
|
|
42
52
|
},
|
|
43
|
-
payload,
|
|
53
|
+
payload: { ...payload, sd_hash: sdHash },
|
|
44
54
|
});
|
|
45
55
|
|
|
46
56
|
await kbJwt.sign(this.userConfig.kbSigner);
|
|
@@ -62,7 +72,7 @@ export class SDJwtInstance {
|
|
|
62
72
|
return jwt.verify(this.userConfig.verifier);
|
|
63
73
|
}
|
|
64
74
|
|
|
65
|
-
public async issue<Payload extends
|
|
75
|
+
public async issue<Payload extends ExtendedPayload>(
|
|
66
76
|
payload: Payload,
|
|
67
77
|
disclosureFrame?: DisclosureFrame<Payload>,
|
|
68
78
|
options?: {
|
|
@@ -81,6 +91,10 @@ export class SDJwtInstance {
|
|
|
81
91
|
throw new SDJWTException('sign alogrithm not specified');
|
|
82
92
|
}
|
|
83
93
|
|
|
94
|
+
if (disclosureFrame) {
|
|
95
|
+
this.validateReservedFields<Payload>(disclosureFrame);
|
|
96
|
+
}
|
|
97
|
+
|
|
84
98
|
const hasher = this.userConfig.hasher;
|
|
85
99
|
const hashAlg = this.userConfig.hashAlg ?? SDJwtInstance.DEFAULT_hashAlg;
|
|
86
100
|
|
|
@@ -94,7 +108,7 @@ export class SDJwtInstance {
|
|
|
94
108
|
const OptionHeader = options?.header ?? {};
|
|
95
109
|
const CustomHeader = this.userConfig.omitTyp
|
|
96
110
|
? OptionHeader
|
|
97
|
-
: { typ:
|
|
111
|
+
: { typ: this.type, ...OptionHeader };
|
|
98
112
|
const header = { ...CustomHeader, alg };
|
|
99
113
|
const jwt = new Jwt({
|
|
100
114
|
header,
|
|
@@ -113,6 +127,10 @@ export class SDJwtInstance {
|
|
|
113
127
|
return sdJwt.encodeSDJwt();
|
|
114
128
|
}
|
|
115
129
|
|
|
130
|
+
protected abstract validateReservedFields<T extends ExtendedPayload>(
|
|
131
|
+
disclosureFrame: DisclosureFrame<T>,
|
|
132
|
+
): void;
|
|
133
|
+
|
|
116
134
|
public async present(
|
|
117
135
|
encodedSDJwt: string,
|
|
118
136
|
presentationKeys?: string[],
|
|
@@ -127,9 +145,24 @@ export class SDJwtInstance {
|
|
|
127
145
|
const hasher = this.userConfig.hasher;
|
|
128
146
|
|
|
129
147
|
const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
130
|
-
const kbJwt = options?.kb ? await this.createKBJwt(options.kb) : undefined;
|
|
131
|
-
sdjwt.kbJwt = kbJwt;
|
|
132
148
|
|
|
149
|
+
if (!sdjwt.jwt?.payload) throw new SDJWTException('Payload not found');
|
|
150
|
+
const presentSdJwtWithoutKb = await sdjwt.present(
|
|
151
|
+
presentationKeys.sort(),
|
|
152
|
+
hasher,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
if (!options?.kb) {
|
|
156
|
+
return presentSdJwtWithoutKb;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const sdHashStr = await this.calculateSDHash(
|
|
160
|
+
presentSdJwtWithoutKb,
|
|
161
|
+
sdjwt,
|
|
162
|
+
hasher,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
sdjwt.kbJwt = await this.createKBJwt(options.kb, sdHashStr);
|
|
133
166
|
return sdjwt.present(presentationKeys.sort(), hasher);
|
|
134
167
|
}
|
|
135
168
|
|
|
@@ -147,7 +180,7 @@ export class SDJwtInstance {
|
|
|
147
180
|
const hasher = this.userConfig.hasher;
|
|
148
181
|
|
|
149
182
|
const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
150
|
-
if (!sdjwt.jwt) {
|
|
183
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
151
184
|
throw new SDJWTException('Invalid SD JWT');
|
|
152
185
|
}
|
|
153
186
|
const { payload, header } = await this.validate(encodedSDJwt);
|
|
@@ -173,9 +206,40 @@ export class SDJwtInstance {
|
|
|
173
206
|
throw new SDJWTException('Key Binding Verifier not found');
|
|
174
207
|
}
|
|
175
208
|
const kb = await sdjwt.kbJwt.verify(this.userConfig.kbVerifier);
|
|
209
|
+
const sdHashfromKb = kb.payload.sd_hash;
|
|
210
|
+
const sdjwtWithoutKb = new SDJwt({
|
|
211
|
+
jwt: sdjwt.jwt,
|
|
212
|
+
disclosures: sdjwt.disclosures,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
|
|
216
|
+
const sdHashStr = await this.calculateSDHash(
|
|
217
|
+
presentSdJwtWithoutKb,
|
|
218
|
+
sdjwt,
|
|
219
|
+
hasher,
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
if (sdHashStr !== sdHashfromKb) {
|
|
223
|
+
throw new SDJWTException('Invalid sd_hash in Key Binding JWT');
|
|
224
|
+
}
|
|
225
|
+
|
|
176
226
|
return { payload, header, kb };
|
|
177
227
|
}
|
|
178
228
|
|
|
229
|
+
private async calculateSDHash(
|
|
230
|
+
presentSdJwtWithoutKb: string,
|
|
231
|
+
sdjwt: SDJwt,
|
|
232
|
+
hasher: Hasher,
|
|
233
|
+
) {
|
|
234
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
235
|
+
throw new SDJWTException('Invalid SD JWT');
|
|
236
|
+
}
|
|
237
|
+
const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
|
|
238
|
+
const sdHash = await hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
239
|
+
const sdHashStr = Uint8ArrayToBase64Url(sdHash);
|
|
240
|
+
return sdHashStr;
|
|
241
|
+
}
|
|
242
|
+
|
|
179
243
|
// This function is for validating the SD JWT
|
|
180
244
|
// Just checking signature and return its the claims
|
|
181
245
|
public async validate(encodedSDJwt: string) {
|
package/src/sdjwt.ts
CHANGED
package/src/test/index.spec.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { SDJwtInstance } from '../index';
|
|
2
|
-
import { Signer, Verifier } from '@sd-jwt/types';
|
|
1
|
+
import { SDJwtInstance, SdJwtPayload } from '../index';
|
|
2
|
+
import { DisclosureFrame, Signer, Verifier } from '@sd-jwt/types';
|
|
3
3
|
import Crypto from 'node:crypto';
|
|
4
4
|
import { describe, expect, test } from 'vitest';
|
|
5
5
|
import { digest, generateSalt } from '@sd-jwt/crypto-nodejs';
|
|
6
6
|
|
|
7
|
+
export class TestInstance extends SDJwtInstance<SdJwtPayload> {
|
|
8
|
+
protected type = 'sd-jwt';
|
|
9
|
+
|
|
10
|
+
protected validateReservedFields(
|
|
11
|
+
disclosureFrame: DisclosureFrame<SdJwtPayload>,
|
|
12
|
+
): void {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
7
17
|
export const createSignerVerifier = () => {
|
|
8
18
|
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
|
|
9
19
|
const signer: Signer = async (data: string) => {
|
|
@@ -23,13 +33,13 @@ export const createSignerVerifier = () => {
|
|
|
23
33
|
|
|
24
34
|
describe('index', () => {
|
|
25
35
|
test('create', async () => {
|
|
26
|
-
const sdjwt = new
|
|
36
|
+
const sdjwt = new TestInstance();
|
|
27
37
|
expect(sdjwt).toBeDefined();
|
|
28
38
|
});
|
|
29
39
|
|
|
30
40
|
test('kbJwt', async () => {
|
|
31
41
|
const { signer, verifier } = createSignerVerifier();
|
|
32
|
-
const sdjwt = new
|
|
42
|
+
const sdjwt = new TestInstance({
|
|
33
43
|
signer,
|
|
34
44
|
signAlg: 'EdDSA',
|
|
35
45
|
verifier,
|
|
@@ -41,6 +51,9 @@ describe('index', () => {
|
|
|
41
51
|
const credential = await sdjwt.issue(
|
|
42
52
|
{
|
|
43
53
|
foo: 'bar',
|
|
54
|
+
iss: 'Issuer',
|
|
55
|
+
iat: new Date().getTime(),
|
|
56
|
+
vct: '',
|
|
44
57
|
},
|
|
45
58
|
{
|
|
46
59
|
_sd: ['foo'],
|
|
@@ -52,7 +65,6 @@ describe('index', () => {
|
|
|
52
65
|
const presentation = await sdjwt.present(credential, ['foo'], {
|
|
53
66
|
kb: {
|
|
54
67
|
payload: {
|
|
55
|
-
sd_hash: 'sha-256',
|
|
56
68
|
aud: '1',
|
|
57
69
|
iat: 1,
|
|
58
70
|
nonce: '342',
|
|
@@ -65,7 +77,7 @@ describe('index', () => {
|
|
|
65
77
|
|
|
66
78
|
test('issue', async () => {
|
|
67
79
|
const { signer, verifier } = createSignerVerifier();
|
|
68
|
-
const sdjwt = new
|
|
80
|
+
const sdjwt = new TestInstance({
|
|
69
81
|
signer,
|
|
70
82
|
signAlg: 'EdDSA',
|
|
71
83
|
verifier,
|
|
@@ -75,6 +87,9 @@ describe('index', () => {
|
|
|
75
87
|
const credential = await sdjwt.issue(
|
|
76
88
|
{
|
|
77
89
|
foo: 'bar',
|
|
90
|
+
iss: 'Issuer',
|
|
91
|
+
iat: new Date().getTime(),
|
|
92
|
+
vct: '',
|
|
78
93
|
},
|
|
79
94
|
{
|
|
80
95
|
_sd: ['foo'],
|
|
@@ -96,7 +111,7 @@ describe('index', () => {
|
|
|
96
111
|
);
|
|
97
112
|
};
|
|
98
113
|
|
|
99
|
-
const sdjwt = new
|
|
114
|
+
const sdjwt = new TestInstance({
|
|
100
115
|
signer,
|
|
101
116
|
signAlg: 'EdDSA',
|
|
102
117
|
verifier: failedverifier,
|
|
@@ -107,6 +122,9 @@ describe('index', () => {
|
|
|
107
122
|
const credential = await sdjwt.issue(
|
|
108
123
|
{
|
|
109
124
|
foo: 'bar',
|
|
125
|
+
iss: 'Issuer',
|
|
126
|
+
iat: new Date().getTime(),
|
|
127
|
+
vct: '',
|
|
110
128
|
},
|
|
111
129
|
{
|
|
112
130
|
_sd: ['foo'],
|
|
@@ -131,7 +149,7 @@ describe('index', () => {
|
|
|
131
149
|
Buffer.from(sig, 'base64url'),
|
|
132
150
|
);
|
|
133
151
|
};
|
|
134
|
-
const sdjwt = new
|
|
152
|
+
const sdjwt = new TestInstance({
|
|
135
153
|
signer,
|
|
136
154
|
signAlg: 'EdDSA',
|
|
137
155
|
verifier,
|
|
@@ -145,6 +163,9 @@ describe('index', () => {
|
|
|
145
163
|
const credential = await sdjwt.issue(
|
|
146
164
|
{
|
|
147
165
|
foo: 'bar',
|
|
166
|
+
iss: 'Issuer',
|
|
167
|
+
iat: new Date().getTime(),
|
|
168
|
+
vct: '',
|
|
148
169
|
},
|
|
149
170
|
{
|
|
150
171
|
_sd: ['foo'],
|
|
@@ -154,8 +175,7 @@ describe('index', () => {
|
|
|
154
175
|
const presentation = await sdjwt.present(credential, ['foo'], {
|
|
155
176
|
kb: {
|
|
156
177
|
payload: {
|
|
157
|
-
|
|
158
|
-
aud: '1',
|
|
178
|
+
aud: '',
|
|
159
179
|
iat: 1,
|
|
160
180
|
nonce: '342',
|
|
161
181
|
},
|
|
@@ -171,7 +191,7 @@ describe('index', () => {
|
|
|
171
191
|
|
|
172
192
|
test('verify with kbJwt', async () => {
|
|
173
193
|
const { signer, verifier } = createSignerVerifier();
|
|
174
|
-
const sdjwt = new
|
|
194
|
+
const sdjwt = new TestInstance({
|
|
175
195
|
signer,
|
|
176
196
|
signAlg: 'EdDSA',
|
|
177
197
|
verifier,
|
|
@@ -185,6 +205,9 @@ describe('index', () => {
|
|
|
185
205
|
const credential = await sdjwt.issue(
|
|
186
206
|
{
|
|
187
207
|
foo: 'bar',
|
|
208
|
+
iss: 'Issuer',
|
|
209
|
+
iat: new Date().getTime(),
|
|
210
|
+
vct: '',
|
|
188
211
|
},
|
|
189
212
|
{
|
|
190
213
|
_sd: ['foo'],
|
|
@@ -194,7 +217,6 @@ describe('index', () => {
|
|
|
194
217
|
const presentation = await sdjwt.present(credential, ['foo'], {
|
|
195
218
|
kb: {
|
|
196
219
|
payload: {
|
|
197
|
-
sd_hash: 'sha-256',
|
|
198
220
|
aud: '1',
|
|
199
221
|
iat: 1,
|
|
200
222
|
nonce: '342',
|
|
@@ -207,11 +229,14 @@ describe('index', () => {
|
|
|
207
229
|
});
|
|
208
230
|
|
|
209
231
|
test('Hasher not found', async () => {
|
|
210
|
-
const sdjwt = new
|
|
232
|
+
const sdjwt = new TestInstance({});
|
|
211
233
|
try {
|
|
212
234
|
const credential = await sdjwt.issue(
|
|
213
235
|
{
|
|
214
236
|
foo: 'bar',
|
|
237
|
+
iss: 'Issuer',
|
|
238
|
+
iat: new Date().getTime(),
|
|
239
|
+
vct: '',
|
|
215
240
|
},
|
|
216
241
|
{
|
|
217
242
|
_sd: ['foo'],
|
|
@@ -225,13 +250,16 @@ describe('index', () => {
|
|
|
225
250
|
});
|
|
226
251
|
|
|
227
252
|
test('SaltGenerator not found', async () => {
|
|
228
|
-
const sdjwt = new
|
|
253
|
+
const sdjwt = new TestInstance({
|
|
229
254
|
hasher: digest,
|
|
230
255
|
});
|
|
231
256
|
try {
|
|
232
257
|
const credential = await sdjwt.issue(
|
|
233
258
|
{
|
|
234
259
|
foo: 'bar',
|
|
260
|
+
iss: 'Issuer',
|
|
261
|
+
iat: new Date().getTime(),
|
|
262
|
+
vct: '',
|
|
235
263
|
},
|
|
236
264
|
{
|
|
237
265
|
_sd: ['foo'],
|
|
@@ -245,7 +273,7 @@ describe('index', () => {
|
|
|
245
273
|
});
|
|
246
274
|
|
|
247
275
|
test('Signer not found', async () => {
|
|
248
|
-
const sdjwt = new
|
|
276
|
+
const sdjwt = new TestInstance({
|
|
249
277
|
hasher: digest,
|
|
250
278
|
saltGenerator: generateSalt,
|
|
251
279
|
});
|
|
@@ -253,6 +281,9 @@ describe('index', () => {
|
|
|
253
281
|
const credential = await sdjwt.issue(
|
|
254
282
|
{
|
|
255
283
|
foo: 'bar',
|
|
284
|
+
iss: 'Issuer',
|
|
285
|
+
iat: new Date().getTime(),
|
|
286
|
+
vct: '',
|
|
256
287
|
},
|
|
257
288
|
{
|
|
258
289
|
_sd: ['foo'],
|
|
@@ -267,7 +298,7 @@ describe('index', () => {
|
|
|
267
298
|
|
|
268
299
|
test('Verifier not found', async () => {
|
|
269
300
|
const { signer, verifier } = createSignerVerifier();
|
|
270
|
-
const sdjwt = new
|
|
301
|
+
const sdjwt = new TestInstance({
|
|
271
302
|
signer,
|
|
272
303
|
hasher: digest,
|
|
273
304
|
saltGenerator: generateSalt,
|
|
@@ -280,6 +311,9 @@ describe('index', () => {
|
|
|
280
311
|
const credential = await sdjwt.issue(
|
|
281
312
|
{
|
|
282
313
|
foo: 'bar',
|
|
314
|
+
iss: 'Issuer',
|
|
315
|
+
iat: new Date().getTime(),
|
|
316
|
+
vct: '',
|
|
283
317
|
},
|
|
284
318
|
{
|
|
285
319
|
_sd: ['foo'],
|
|
@@ -289,7 +323,6 @@ describe('index', () => {
|
|
|
289
323
|
const presentation = await sdjwt.present(credential, ['foo'], {
|
|
290
324
|
kb: {
|
|
291
325
|
payload: {
|
|
292
|
-
sd_hash: 'sha-256',
|
|
293
326
|
aud: '1',
|
|
294
327
|
iat: 1,
|
|
295
328
|
nonce: '342',
|
|
@@ -305,7 +338,7 @@ describe('index', () => {
|
|
|
305
338
|
|
|
306
339
|
test('kbSigner not found', async () => {
|
|
307
340
|
const { signer, verifier } = createSignerVerifier();
|
|
308
|
-
const sdjwt = new
|
|
341
|
+
const sdjwt = new TestInstance({
|
|
309
342
|
signer,
|
|
310
343
|
verifier,
|
|
311
344
|
hasher: digest,
|
|
@@ -318,6 +351,9 @@ describe('index', () => {
|
|
|
318
351
|
const credential = await sdjwt.issue(
|
|
319
352
|
{
|
|
320
353
|
foo: 'bar',
|
|
354
|
+
iss: 'Issuer',
|
|
355
|
+
iat: new Date().getTime(),
|
|
356
|
+
vct: '',
|
|
321
357
|
},
|
|
322
358
|
{
|
|
323
359
|
_sd: ['foo'],
|
|
@@ -327,7 +363,6 @@ describe('index', () => {
|
|
|
327
363
|
const presentation = await sdjwt.present(credential, ['foo'], {
|
|
328
364
|
kb: {
|
|
329
365
|
payload: {
|
|
330
|
-
sd_hash: 'sha-256',
|
|
331
366
|
aud: '1',
|
|
332
367
|
iat: 1,
|
|
333
368
|
nonce: '342',
|
|
@@ -341,7 +376,7 @@ describe('index', () => {
|
|
|
341
376
|
|
|
342
377
|
test('kbVerifier not found', async () => {
|
|
343
378
|
const { signer, verifier } = createSignerVerifier();
|
|
344
|
-
const sdjwt = new
|
|
379
|
+
const sdjwt = new TestInstance({
|
|
345
380
|
signer,
|
|
346
381
|
verifier,
|
|
347
382
|
hasher: digest,
|
|
@@ -354,6 +389,9 @@ describe('index', () => {
|
|
|
354
389
|
const credential = await sdjwt.issue(
|
|
355
390
|
{
|
|
356
391
|
foo: 'bar',
|
|
392
|
+
iss: 'Issuer',
|
|
393
|
+
iat: new Date().getTime(),
|
|
394
|
+
vct: '',
|
|
357
395
|
},
|
|
358
396
|
{
|
|
359
397
|
_sd: ['foo'],
|
|
@@ -363,7 +401,6 @@ describe('index', () => {
|
|
|
363
401
|
const presentation = await sdjwt.present(credential, ['foo'], {
|
|
364
402
|
kb: {
|
|
365
403
|
payload: {
|
|
366
|
-
sd_hash: 'sha-256',
|
|
367
404
|
aud: '1',
|
|
368
405
|
iat: 1,
|
|
369
406
|
nonce: '342',
|
|
@@ -376,4 +413,47 @@ describe('index', () => {
|
|
|
376
413
|
expect(e).toBeDefined();
|
|
377
414
|
}
|
|
378
415
|
});
|
|
416
|
+
|
|
417
|
+
test('kbSignAlg not found', async () => {
|
|
418
|
+
const { signer, verifier } = createSignerVerifier();
|
|
419
|
+
const sdjwt = new TestInstance({
|
|
420
|
+
signer,
|
|
421
|
+
verifier,
|
|
422
|
+
hasher: digest,
|
|
423
|
+
saltGenerator: generateSalt,
|
|
424
|
+
kbSigner: signer,
|
|
425
|
+
signAlg: 'EdDSA',
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
const credential = await sdjwt.issue(
|
|
429
|
+
{
|
|
430
|
+
foo: 'bar',
|
|
431
|
+
iss: 'Issuer',
|
|
432
|
+
iat: new Date().getTime(),
|
|
433
|
+
vct: '',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
_sd: ['foo'],
|
|
437
|
+
},
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
const presentation = sdjwt.present(credential, ['foo'], {
|
|
441
|
+
kb: {
|
|
442
|
+
payload: {
|
|
443
|
+
sd_hash: 'sha-256',
|
|
444
|
+
aud: '1',
|
|
445
|
+
iat: 1,
|
|
446
|
+
nonce: '342',
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
expect(presentation).rejects.toThrow(
|
|
451
|
+
'Key Binding sign algorithm not specified',
|
|
452
|
+
);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test('hasher is not found', () => {
|
|
456
|
+
const sdjwt = new TestInstance({});
|
|
457
|
+
expect(sdjwt.keys('')).rejects.toThrow('Hasher not found');
|
|
458
|
+
});
|
|
379
459
|
});
|
package/test/app-e2e.spec.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import Crypto from 'node:crypto';
|
|
2
|
-
import {
|
|
3
|
-
import { DisclosureFrame, Signer, Verifier } from '@sd-jwt/types';
|
|
2
|
+
import { SdJwtPayload } from '../src';
|
|
3
|
+
import { DisclosureFrame, SD, Signer, Verifier } from '@sd-jwt/types';
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { describe, expect, test } from 'vitest';
|
|
7
7
|
import { digest, generateSalt } from '@sd-jwt/crypto-nodejs';
|
|
8
|
+
import { TestInstance } from '../src/test/index.spec';
|
|
8
9
|
|
|
9
10
|
export const createSignerVerifier = () => {
|
|
10
11
|
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
|
|
@@ -26,7 +27,7 @@ export const createSignerVerifier = () => {
|
|
|
26
27
|
describe('App', () => {
|
|
27
28
|
test('Example', async () => {
|
|
28
29
|
const { signer, verifier } = createSignerVerifier();
|
|
29
|
-
const sdjwt = new
|
|
30
|
+
const sdjwt = new TestInstance({
|
|
30
31
|
signer,
|
|
31
32
|
signAlg: 'EdDSA',
|
|
32
33
|
verifier,
|
|
@@ -192,7 +193,7 @@ describe('App', () => {
|
|
|
192
193
|
async function JSONtest(filename: string) {
|
|
193
194
|
const test = loadTestJsonFile(filename);
|
|
194
195
|
const { signer, verifier } = createSignerVerifier();
|
|
195
|
-
const sdjwt = new
|
|
196
|
+
const sdjwt = new TestInstance({
|
|
196
197
|
signer,
|
|
197
198
|
signAlg: 'EdDSA',
|
|
198
199
|
verifier,
|
|
@@ -234,8 +235,8 @@ async function JSONtest(filename: string) {
|
|
|
234
235
|
}
|
|
235
236
|
|
|
236
237
|
type TestJson = {
|
|
237
|
-
claims:
|
|
238
|
-
disclosureFrame: DisclosureFrame<
|
|
238
|
+
claims: SdJwtPayload;
|
|
239
|
+
disclosureFrame: DisclosureFrame<SdJwtPayload>;
|
|
239
240
|
presentationKeys: string[];
|
|
240
241
|
presenatedClaims: object;
|
|
241
242
|
requiredClaimKeys: string[];
|