@sd-jwt/core 0.19.1-next.1 → 0.19.1-next.11
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 +68 -5
- package/dist/index.d.mts +364 -16
- package/dist/index.d.ts +364 -16
- package/dist/index.js +803 -148
- package/dist/index.mjs +744 -133
- package/package.json +4 -7
- package/src/decode/decode.ts +366 -0
- package/src/decode/index.ts +1 -0
- package/src/decoy.ts +2 -2
- package/src/flattenJSON.ts +3 -3
- package/src/generalJSON.ts +3 -3
- package/src/index.ts +230 -14
- package/src/jwt.ts +10 -15
- package/src/kbjwt.ts +19 -15
- package/src/present/index.ts +1 -0
- package/src/present/present.ts +210 -0
- package/src/sdjwt.ts +11 -10
- package/src/test/decode/decode.spec.ts +202 -0
- package/src/test/decoy.spec.ts +2 -2
- package/src/test/generalJSON.spec.ts +1 -1
- package/src/test/index.spec.ts +288 -2
- package/src/test/jwt.spec.ts +7 -13
- package/src/test/kbjwt.spec.ts +216 -5
- package/src/test/present/present.spec.ts +305 -0
- package/src/test/sdjwt.spec.ts +4 -4
- package/src/test/types/type.spec.ts +88 -0
- package/src/test/utils/base64url.spec.ts +33 -0
- package/src/test/utils/disclosure.spec.ts +170 -0
- package/src/test/utils/error.spec.ts +15 -0
- package/src/types/index.ts +2 -0
- package/src/types/type.ts +249 -0
- package/src/types/verification-error.ts +55 -0
- package/src/utils/base64url.ts +6 -0
- package/src/utils/disclosure.ts +98 -0
- package/src/utils/error.ts +25 -0
- package/src/utils/index.ts +3 -0
- package/test/app-e2e.spec.ts +8 -8
- package/test/rfc9901-validation.spec.ts +150 -0
- package/CHANGELOG.md +0 -240
package/dist/index.js
CHANGED
|
@@ -20,6 +20,18 @@ var __spreadValues = (a, b) => {
|
|
|
20
20
|
return a;
|
|
21
21
|
};
|
|
22
22
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
23
|
+
var __objRest = (source, exclude) => {
|
|
24
|
+
var target = {};
|
|
25
|
+
for (var prop in source)
|
|
26
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
27
|
+
target[prop] = source[prop];
|
|
28
|
+
if (source != null && __getOwnPropSymbols)
|
|
29
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
30
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
31
|
+
target[prop] = source[prop];
|
|
32
|
+
}
|
|
33
|
+
return target;
|
|
34
|
+
};
|
|
23
35
|
var __export = (target, all) => {
|
|
24
36
|
for (var name in all)
|
|
25
37
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -57,26 +69,384 @@ var __async = (__this, __arguments, generator) => {
|
|
|
57
69
|
// src/index.ts
|
|
58
70
|
var index_exports = {};
|
|
59
71
|
__export(index_exports, {
|
|
72
|
+
Disclosure: () => Disclosure,
|
|
60
73
|
FlattenJSON: () => FlattenJSON,
|
|
61
74
|
GeneralJSON: () => GeneralJSON,
|
|
75
|
+
IANA_HASH_ALGORITHMS: () => IANA_HASH_ALGORITHMS,
|
|
62
76
|
Jwt: () => Jwt,
|
|
63
77
|
KBJwt: () => KBJwt,
|
|
78
|
+
KB_JWT_TYP: () => KB_JWT_TYP,
|
|
79
|
+
SDJWTException: () => SDJWTException,
|
|
64
80
|
SDJwt: () => SDJwt,
|
|
65
81
|
SDJwtGeneralJSONInstance: () => SDJwtGeneralJSONInstance,
|
|
66
82
|
SDJwtInstance: () => SDJwtInstance,
|
|
83
|
+
SD_DECOY: () => SD_DECOY,
|
|
84
|
+
SD_DIGEST: () => SD_DIGEST,
|
|
85
|
+
SD_LIST_KEY: () => SD_LIST_KEY,
|
|
86
|
+
SD_SEPARATOR: () => SD_SEPARATOR,
|
|
87
|
+
base64UrlToUint8Array: () => import_identity_common.base64UrlToUint8Array,
|
|
88
|
+
base64urlDecode: () => import_identity_common.base64urlDecode,
|
|
89
|
+
base64urlEncode: () => import_identity_common.base64urlEncode,
|
|
67
90
|
createDecoy: () => createDecoy,
|
|
91
|
+
createHashMapping: () => createHashMapping,
|
|
92
|
+
createHashMappingForSerializedDisclosure: () => createHashMappingForSerializedDisclosure,
|
|
93
|
+
createHashMappingSync: () => createHashMappingSync,
|
|
94
|
+
decodeJwt: () => decodeJwt,
|
|
95
|
+
decodeSdJwt: () => decodeSdJwt,
|
|
96
|
+
decodeSdJwtSync: () => decodeSdJwtSync,
|
|
97
|
+
ensureError: () => ensureError,
|
|
98
|
+
getClaims: () => getClaims,
|
|
99
|
+
getClaimsSync: () => getClaimsSync,
|
|
100
|
+
getSDAlgAndPayload: () => getSDAlgAndPayload,
|
|
68
101
|
listKeys: () => listKeys,
|
|
69
|
-
pack: () => pack
|
|
102
|
+
pack: () => pack,
|
|
103
|
+
present: () => present,
|
|
104
|
+
presentSync: () => presentSync,
|
|
105
|
+
presentableKeys: () => presentableKeys,
|
|
106
|
+
presentableKeysSync: () => presentableKeysSync,
|
|
107
|
+
selectDisclosures: () => selectDisclosures,
|
|
108
|
+
splitSdJwt: () => splitSdJwt,
|
|
109
|
+
transformPresentationFrame: () => transformPresentationFrame,
|
|
110
|
+
uint8ArrayToBase64Url: () => import_identity_common.uint8ArrayToBase64Url,
|
|
111
|
+
unpack: () => unpack,
|
|
112
|
+
unpackObj: () => unpackObj,
|
|
113
|
+
unpackSync: () => unpackSync
|
|
70
114
|
});
|
|
71
115
|
module.exports = __toCommonJS(index_exports);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
var
|
|
116
|
+
|
|
117
|
+
// src/types/type.ts
|
|
118
|
+
var SD_SEPARATOR = "~";
|
|
119
|
+
var SD_LIST_KEY = "...";
|
|
120
|
+
var SD_DIGEST = "_sd";
|
|
121
|
+
var SD_DECOY = "_sd_decoy";
|
|
122
|
+
var KB_JWT_TYP = "kb+jwt";
|
|
123
|
+
var IANA_HASH_ALGORITHMS = [
|
|
124
|
+
"sha-256",
|
|
125
|
+
"sha-256-128",
|
|
126
|
+
"sha-256-120",
|
|
127
|
+
"sha-256-96",
|
|
128
|
+
"sha-256-64",
|
|
129
|
+
"sha-256-32",
|
|
130
|
+
"sha-384",
|
|
131
|
+
"sha-512",
|
|
132
|
+
"sha3-224",
|
|
133
|
+
"sha3-256",
|
|
134
|
+
"sha3-384",
|
|
135
|
+
"sha3-512",
|
|
136
|
+
"blake2s-256",
|
|
137
|
+
"blake2b-256",
|
|
138
|
+
"blake2b-512",
|
|
139
|
+
"k12-256",
|
|
140
|
+
"k12-512"
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
// src/utils/base64url.ts
|
|
144
|
+
var import_identity_common = require("@owf/identity-common");
|
|
145
|
+
|
|
146
|
+
// src/utils/error.ts
|
|
147
|
+
var SDJWTException = class _SDJWTException extends Error {
|
|
148
|
+
constructor(message, details) {
|
|
149
|
+
super(message);
|
|
150
|
+
Object.setPrototypeOf(this, _SDJWTException.prototype);
|
|
151
|
+
this.name = "SDJWTException";
|
|
152
|
+
this.details = details;
|
|
153
|
+
}
|
|
154
|
+
getFullMessage() {
|
|
155
|
+
return `${this.name}: ${this.message} ${this.details ? `- ${JSON.stringify(this.details)}` : ""}`;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
function ensureError(value) {
|
|
159
|
+
if (value instanceof Error) return value;
|
|
160
|
+
if (typeof value === "string") return new Error(value);
|
|
161
|
+
return new Error(String(value));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/utils/disclosure.ts
|
|
165
|
+
var Disclosure = class _Disclosure {
|
|
166
|
+
constructor(data, _meta) {
|
|
167
|
+
this._digest = _meta == null ? void 0 : _meta.digest;
|
|
168
|
+
this._encoded = _meta == null ? void 0 : _meta.encoded;
|
|
169
|
+
if (data.length === 2) {
|
|
170
|
+
this.salt = data[0];
|
|
171
|
+
this.value = data[1];
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (data.length === 3) {
|
|
175
|
+
this.salt = data[0];
|
|
176
|
+
this.key = data[1];
|
|
177
|
+
this.value = data[2];
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
throw new SDJWTException("Invalid disclosure data");
|
|
181
|
+
}
|
|
182
|
+
// We need to digest of the original encoded data.
|
|
183
|
+
// After decode process, we use JSON.stringify to encode the data.
|
|
184
|
+
// This can be different from the original encoded data.
|
|
185
|
+
static fromEncode(s, hash) {
|
|
186
|
+
return __async(this, null, function* () {
|
|
187
|
+
const { hasher, alg } = hash;
|
|
188
|
+
const digest = yield hasher(s, alg);
|
|
189
|
+
const digestStr = (0, import_identity_common.uint8ArrayToBase64Url)(digest);
|
|
190
|
+
const item = JSON.parse((0, import_identity_common.base64urlDecode)(s));
|
|
191
|
+
return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
static fromEncodeSync(s, hash) {
|
|
195
|
+
const { hasher, alg } = hash;
|
|
196
|
+
const digest = hasher(s, alg);
|
|
197
|
+
const digestStr = (0, import_identity_common.uint8ArrayToBase64Url)(digest);
|
|
198
|
+
const item = JSON.parse((0, import_identity_common.base64urlDecode)(s));
|
|
199
|
+
return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
|
|
200
|
+
}
|
|
201
|
+
static fromArray(item, _meta) {
|
|
202
|
+
return new _Disclosure(item, _meta);
|
|
203
|
+
}
|
|
204
|
+
encode() {
|
|
205
|
+
if (!this._encoded) {
|
|
206
|
+
this._encoded = (0, import_identity_common.base64urlEncode)(JSON.stringify(this.decode()));
|
|
207
|
+
}
|
|
208
|
+
return this._encoded;
|
|
209
|
+
}
|
|
210
|
+
decode() {
|
|
211
|
+
return this.key ? [this.salt, this.key, this.value] : [this.salt, this.value];
|
|
212
|
+
}
|
|
213
|
+
digest(hash) {
|
|
214
|
+
return __async(this, null, function* () {
|
|
215
|
+
const { hasher, alg } = hash;
|
|
216
|
+
if (!this._digest) {
|
|
217
|
+
const hash2 = yield hasher(this.encode(), alg);
|
|
218
|
+
this._digest = (0, import_identity_common.uint8ArrayToBase64Url)(hash2);
|
|
219
|
+
}
|
|
220
|
+
return this._digest;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
digestSync(hash) {
|
|
224
|
+
const { hasher, alg } = hash;
|
|
225
|
+
if (!this._digest) {
|
|
226
|
+
const hash2 = hasher(this.encode(), alg);
|
|
227
|
+
this._digest = (0, import_identity_common.uint8ArrayToBase64Url)(hash2);
|
|
228
|
+
}
|
|
229
|
+
return this._digest;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// src/decode/decode.ts
|
|
234
|
+
var decodeJwt = (jwt) => {
|
|
235
|
+
const { 0: header, 1: payload, 2: signature, length } = jwt.split(".");
|
|
236
|
+
if (length !== 3) {
|
|
237
|
+
throw new SDJWTException("Invalid JWT as input");
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
header: JSON.parse((0, import_identity_common.base64urlDecode)(header)),
|
|
241
|
+
payload: JSON.parse((0, import_identity_common.base64urlDecode)(payload)),
|
|
242
|
+
signature
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
var splitSdJwt = (sdjwt) => {
|
|
246
|
+
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
|
|
247
|
+
if (encodedDisclosures.length === 0) {
|
|
248
|
+
return {
|
|
249
|
+
jwt: encodedJwt,
|
|
250
|
+
disclosures: []
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const encodedKeyBindingJwt = encodedDisclosures.pop();
|
|
254
|
+
return {
|
|
255
|
+
jwt: encodedJwt,
|
|
256
|
+
disclosures: encodedDisclosures,
|
|
257
|
+
kbJwt: encodedKeyBindingJwt || void 0
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
var decodeSdJwt = (sdjwt, hasher) => __async(null, null, function* () {
|
|
261
|
+
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
|
|
262
|
+
const jwt = decodeJwt(encodedJwt);
|
|
263
|
+
if (encodedDisclosures.length === 0) {
|
|
264
|
+
return {
|
|
265
|
+
jwt,
|
|
266
|
+
disclosures: []
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const encodedKeyBindingJwt = encodedDisclosures.pop();
|
|
270
|
+
const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
|
|
271
|
+
const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
|
|
272
|
+
const disclosures = yield Promise.all(
|
|
273
|
+
encodedDisclosures.map(
|
|
274
|
+
(ed) => Disclosure.fromEncode(ed, { alg: _sd_alg, hasher })
|
|
275
|
+
)
|
|
276
|
+
);
|
|
277
|
+
return {
|
|
278
|
+
jwt,
|
|
279
|
+
disclosures,
|
|
280
|
+
kbJwt
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
var decodeSdJwtSync = (sdjwt, hasher) => {
|
|
284
|
+
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
|
|
285
|
+
const jwt = decodeJwt(encodedJwt);
|
|
286
|
+
if (encodedDisclosures.length === 0) {
|
|
287
|
+
return {
|
|
288
|
+
jwt,
|
|
289
|
+
disclosures: []
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const encodedKeyBindingJwt = encodedDisclosures.pop();
|
|
293
|
+
const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
|
|
294
|
+
const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
|
|
295
|
+
const disclosures = encodedDisclosures.map(
|
|
296
|
+
(ed) => Disclosure.fromEncodeSync(ed, { alg: _sd_alg, hasher })
|
|
297
|
+
);
|
|
298
|
+
return {
|
|
299
|
+
jwt,
|
|
300
|
+
disclosures,
|
|
301
|
+
kbJwt
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
var getClaims = (rawPayload, disclosures, hasher) => __async(null, null, function* () {
|
|
305
|
+
const { unpackedObj } = yield unpack(rawPayload, disclosures, hasher);
|
|
306
|
+
return unpackedObj;
|
|
307
|
+
});
|
|
308
|
+
var getClaimsSync = (rawPayload, disclosures, hasher) => {
|
|
309
|
+
const { unpackedObj } = unpackSync(rawPayload, disclosures, hasher);
|
|
310
|
+
return unpackedObj;
|
|
311
|
+
};
|
|
312
|
+
var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
313
|
+
var unpackArray = (arr, map, prefix = "", seenDigests) => {
|
|
314
|
+
const keys = {};
|
|
315
|
+
const unpackedArray = [];
|
|
316
|
+
arr.forEach((item, idx) => {
|
|
317
|
+
if (isRecord(item)) {
|
|
318
|
+
const hash = item[SD_LIST_KEY];
|
|
319
|
+
if (typeof hash === "string") {
|
|
320
|
+
if (seenDigests) {
|
|
321
|
+
if (seenDigests.has(hash)) {
|
|
322
|
+
throw new SDJWTException(
|
|
323
|
+
"Duplicate digest found in SD-JWT payload"
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
seenDigests.add(hash);
|
|
327
|
+
}
|
|
328
|
+
const disclosed = map[hash];
|
|
329
|
+
if (disclosed) {
|
|
330
|
+
const presentKey = prefix ? `${prefix}.${idx}` : `${idx}`;
|
|
331
|
+
keys[presentKey] = hash;
|
|
332
|
+
const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
|
|
333
|
+
unpackedArray.push(unpackedObj);
|
|
334
|
+
Object.assign(keys, disclosureKeys);
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
|
|
338
|
+
const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
|
|
339
|
+
unpackedArray.push(unpackedObj);
|
|
340
|
+
Object.assign(keys, disclosureKeys);
|
|
341
|
+
}
|
|
342
|
+
} else if (Array.isArray(item)) {
|
|
343
|
+
const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
|
|
344
|
+
const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
|
|
345
|
+
unpackedArray.push(unpackedObj);
|
|
346
|
+
Object.assign(keys, disclosureKeys);
|
|
347
|
+
} else {
|
|
348
|
+
unpackedArray.push(item);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
return { unpackedObj: unpackedArray, disclosureKeymap: keys };
|
|
352
|
+
};
|
|
353
|
+
var unpackObj = (obj, map) => {
|
|
354
|
+
const copiedObj = JSON.parse(JSON.stringify(obj));
|
|
355
|
+
const seenDigests = /* @__PURE__ */ new Set();
|
|
356
|
+
const result = unpackObjInternal(copiedObj, map, "", seenDigests);
|
|
357
|
+
const mapDigests = Object.keys(map);
|
|
358
|
+
const unusedDigests = mapDigests.filter((d) => !seenDigests.has(d));
|
|
359
|
+
if (unusedDigests.length > 0) {
|
|
360
|
+
throw new SDJWTException("Unreferenced disclosure(s) detected in SD-JWT");
|
|
361
|
+
}
|
|
362
|
+
return result;
|
|
363
|
+
};
|
|
364
|
+
var unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
|
|
365
|
+
const keys = {};
|
|
366
|
+
if (typeof obj === "object" && obj !== null) {
|
|
367
|
+
if (Array.isArray(obj)) {
|
|
368
|
+
return unpackArray(obj, map, prefix, seenDigests);
|
|
369
|
+
}
|
|
370
|
+
const record = obj;
|
|
371
|
+
for (const key in record) {
|
|
372
|
+
if (key !== SD_DIGEST && key !== SD_LIST_KEY && typeof record[key] === "object") {
|
|
373
|
+
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
374
|
+
const { unpackedObj: unpackedObj2, disclosureKeymap: disclosureKeys } = unpackObjInternal(record[key], map, newKey, seenDigests);
|
|
375
|
+
record[key] = unpackedObj2;
|
|
376
|
+
Object.assign(keys, disclosureKeys);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const _a = record, { _sd } = _a, payload = __objRest(_a, ["_sd"]);
|
|
380
|
+
const claims = {};
|
|
381
|
+
if (_sd) {
|
|
382
|
+
for (const hash of _sd) {
|
|
383
|
+
if (seenDigests) {
|
|
384
|
+
if (seenDigests.has(hash)) {
|
|
385
|
+
throw new SDJWTException(
|
|
386
|
+
"Duplicate digest found in SD-JWT payload"
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
seenDigests.add(hash);
|
|
390
|
+
}
|
|
391
|
+
const disclosed = map[hash];
|
|
392
|
+
if (disclosed == null ? void 0 : disclosed.key) {
|
|
393
|
+
if (disclosed.key in payload) {
|
|
394
|
+
throw new SDJWTException(
|
|
395
|
+
`Disclosed claim name "${disclosed.key}" conflicts with existing payload key`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
const presentKey = prefix ? `${prefix}.${disclosed.key}` : disclosed.key;
|
|
399
|
+
keys[presentKey] = hash;
|
|
400
|
+
const { unpackedObj: unpackedObj2, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
|
|
401
|
+
claims[disclosed.key] = unpackedObj2;
|
|
402
|
+
Object.assign(keys, disclosureKeys);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const unpackedObj = Object.assign(payload, claims);
|
|
407
|
+
return { unpackedObj, disclosureKeymap: keys };
|
|
408
|
+
}
|
|
409
|
+
return { unpackedObj: obj, disclosureKeymap: keys };
|
|
410
|
+
};
|
|
411
|
+
var createHashMapping = (disclosures, hash) => __async(null, null, function* () {
|
|
412
|
+
const map = {};
|
|
413
|
+
for (let i = 0; i < disclosures.length; i++) {
|
|
414
|
+
const disclosure = disclosures[i];
|
|
415
|
+
const digest = yield disclosure.digest(hash);
|
|
416
|
+
map[digest] = disclosure;
|
|
417
|
+
}
|
|
418
|
+
return map;
|
|
419
|
+
});
|
|
420
|
+
var createHashMappingSync = (disclosures, hash) => {
|
|
421
|
+
const map = {};
|
|
422
|
+
for (let i = 0; i < disclosures.length; i++) {
|
|
423
|
+
const disclosure = disclosures[i];
|
|
424
|
+
const digest = disclosure.digestSync(hash);
|
|
425
|
+
map[digest] = disclosure;
|
|
426
|
+
}
|
|
427
|
+
return map;
|
|
428
|
+
};
|
|
429
|
+
var getSDAlgAndPayload = (SdJwtPayload) => {
|
|
430
|
+
const _a = SdJwtPayload, { _sd_alg } = _a, payload = __objRest(_a, ["_sd_alg"]);
|
|
431
|
+
if (typeof _sd_alg !== "string") {
|
|
432
|
+
return { _sd_alg: "sha-256", payload };
|
|
433
|
+
}
|
|
434
|
+
return { _sd_alg, payload };
|
|
435
|
+
};
|
|
436
|
+
var unpack = (SdJwtPayload, disclosures, hasher) => __async(null, null, function* () {
|
|
437
|
+
const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
|
|
438
|
+
const hash = { hasher, alg: _sd_alg };
|
|
439
|
+
const map = yield createHashMapping(disclosures, hash);
|
|
440
|
+
return unpackObj(payload, map);
|
|
441
|
+
});
|
|
442
|
+
var unpackSync = (SdJwtPayload, disclosures, hasher) => {
|
|
443
|
+
const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
|
|
444
|
+
const hash = { hasher, alg: _sd_alg };
|
|
445
|
+
const map = createHashMappingSync(disclosures, hash);
|
|
446
|
+
return unpackObj(payload, map);
|
|
447
|
+
};
|
|
75
448
|
|
|
76
449
|
// src/flattenJSON.ts
|
|
77
|
-
var import_decode = require("@sd-jwt/decode");
|
|
78
|
-
var import_types = require("@sd-jwt/types");
|
|
79
|
-
var import_utils = require("@sd-jwt/utils");
|
|
80
450
|
var FlattenJSON = class _FlattenJSON {
|
|
81
451
|
constructor(data) {
|
|
82
452
|
this.disclosures = data.disclosures;
|
|
@@ -86,10 +456,10 @@ var FlattenJSON = class _FlattenJSON {
|
|
|
86
456
|
this.protected = data.jwtData.protected;
|
|
87
457
|
}
|
|
88
458
|
static fromEncode(encodedSdJwt) {
|
|
89
|
-
const { jwt, disclosures, kbJwt } =
|
|
459
|
+
const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
|
|
90
460
|
const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
|
|
91
461
|
if (!protectedHeader || !payload || !signature) {
|
|
92
|
-
throw new
|
|
462
|
+
throw new SDJWTException("Invalid JWT");
|
|
93
463
|
}
|
|
94
464
|
return new _FlattenJSON({
|
|
95
465
|
jwtData: {
|
|
@@ -129,19 +499,16 @@ var FlattenJSON = class _FlattenJSON {
|
|
|
129
499
|
const jwt = `${this.protected}.${this.payload}.${this.signature}`;
|
|
130
500
|
data.push(jwt);
|
|
131
501
|
if (this.disclosures && this.disclosures.length > 0) {
|
|
132
|
-
const disclosures = this.disclosures.join(
|
|
502
|
+
const disclosures = this.disclosures.join(SD_SEPARATOR);
|
|
133
503
|
data.push(disclosures);
|
|
134
504
|
}
|
|
135
505
|
const kb_jwt = (_a = this.kb_jwt) != null ? _a : "";
|
|
136
506
|
data.push(kb_jwt);
|
|
137
|
-
return data.join(
|
|
507
|
+
return data.join(SD_SEPARATOR);
|
|
138
508
|
}
|
|
139
509
|
};
|
|
140
510
|
|
|
141
511
|
// src/generalJSON.ts
|
|
142
|
-
var import_decode2 = require("@sd-jwt/decode");
|
|
143
|
-
var import_types2 = require("@sd-jwt/types");
|
|
144
|
-
var import_utils2 = require("@sd-jwt/utils");
|
|
145
512
|
var GeneralJSON = class _GeneralJSON {
|
|
146
513
|
constructor(data) {
|
|
147
514
|
this.payload = data.payload;
|
|
@@ -150,10 +517,10 @@ var GeneralJSON = class _GeneralJSON {
|
|
|
150
517
|
this.signatures = data.signatures;
|
|
151
518
|
}
|
|
152
519
|
static fromEncode(encodedSdJwt) {
|
|
153
|
-
const { jwt, disclosures, kbJwt } =
|
|
520
|
+
const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
|
|
154
521
|
const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
|
|
155
522
|
if (!protectedHeader || !payload || !signature) {
|
|
156
|
-
throw new
|
|
523
|
+
throw new SDJWTException("Invalid JWT");
|
|
157
524
|
}
|
|
158
525
|
return new _GeneralJSON({
|
|
159
526
|
payload,
|
|
@@ -170,7 +537,7 @@ var GeneralJSON = class _GeneralJSON {
|
|
|
170
537
|
static fromSerialized(json) {
|
|
171
538
|
var _a, _b, _c;
|
|
172
539
|
if (!json.signatures[0]) {
|
|
173
|
-
throw new
|
|
540
|
+
throw new SDJWTException("Invalid JSON");
|
|
174
541
|
}
|
|
175
542
|
const disclosures = (_b = (_a = json.signatures[0].header) == null ? void 0 : _a.disclosures) != null ? _b : [];
|
|
176
543
|
const kb_jwt = (_c = json.signatures[0].header) == null ? void 0 : _c.kb_jwt;
|
|
@@ -216,23 +583,23 @@ var GeneralJSON = class _GeneralJSON {
|
|
|
216
583
|
toEncoded(index) {
|
|
217
584
|
var _a;
|
|
218
585
|
if (index < 0 || index >= this.signatures.length) {
|
|
219
|
-
throw new
|
|
586
|
+
throw new SDJWTException("Index out of bounds");
|
|
220
587
|
}
|
|
221
588
|
const data = [];
|
|
222
589
|
const { protected: protectedHeader, signature } = this.signatures[index];
|
|
223
590
|
const jwt = `${protectedHeader}.${this.payload}.${signature}`;
|
|
224
591
|
data.push(jwt);
|
|
225
592
|
if (this.disclosures && this.disclosures.length > 0) {
|
|
226
|
-
const disclosures = this.disclosures.join(
|
|
593
|
+
const disclosures = this.disclosures.join(SD_SEPARATOR);
|
|
227
594
|
data.push(disclosures);
|
|
228
595
|
}
|
|
229
596
|
const kb = (_a = this.kb_jwt) != null ? _a : "";
|
|
230
597
|
data.push(kb);
|
|
231
|
-
return data.join(
|
|
598
|
+
return data.join(SD_SEPARATOR);
|
|
232
599
|
}
|
|
233
600
|
addSignature(protectedHeader, signer, kid) {
|
|
234
601
|
return __async(this, null, function* () {
|
|
235
|
-
const header = (0,
|
|
602
|
+
const header = (0, import_identity_common.base64urlEncode)(JSON.stringify(protectedHeader));
|
|
236
603
|
const signature = yield signer(`${header}.${this.payload}`);
|
|
237
604
|
this.signatures.push({
|
|
238
605
|
protected: header,
|
|
@@ -244,8 +611,6 @@ var GeneralJSON = class _GeneralJSON {
|
|
|
244
611
|
};
|
|
245
612
|
|
|
246
613
|
// src/jwt.ts
|
|
247
|
-
var import_decode3 = require("@sd-jwt/decode");
|
|
248
|
-
var import_utils3 = require("@sd-jwt/utils");
|
|
249
614
|
var Jwt = class _Jwt {
|
|
250
615
|
constructor(data) {
|
|
251
616
|
this.header = data == null ? void 0 : data.header;
|
|
@@ -254,7 +619,7 @@ var Jwt = class _Jwt {
|
|
|
254
619
|
this.encoded = data == null ? void 0 : data.encoded;
|
|
255
620
|
}
|
|
256
621
|
static decodeJWT(jwt) {
|
|
257
|
-
return
|
|
622
|
+
return decodeJwt(jwt);
|
|
258
623
|
}
|
|
259
624
|
static fromEncode(encodedJwt) {
|
|
260
625
|
const { header, payload, signature } = _Jwt.decodeJWT(
|
|
@@ -280,18 +645,18 @@ var Jwt = class _Jwt {
|
|
|
280
645
|
}
|
|
281
646
|
getUnsignedToken() {
|
|
282
647
|
if (!this.header || !this.payload) {
|
|
283
|
-
throw new
|
|
648
|
+
throw new SDJWTException("Serialize Error: Invalid JWT");
|
|
284
649
|
}
|
|
285
650
|
if (this.encoded) {
|
|
286
651
|
const parts = this.encoded.split(".");
|
|
287
652
|
if (parts.length !== 3) {
|
|
288
|
-
throw new
|
|
653
|
+
throw new SDJWTException(`Invalid JWT format: ${this.encoded}`);
|
|
289
654
|
}
|
|
290
655
|
const unsignedToken = parts.slice(0, 2).join(".");
|
|
291
656
|
return unsignedToken;
|
|
292
657
|
}
|
|
293
|
-
const header = (0,
|
|
294
|
-
const payload = (0,
|
|
658
|
+
const header = (0, import_identity_common.base64urlEncode)(JSON.stringify(this.header));
|
|
659
|
+
const payload = (0, import_identity_common.base64urlEncode)(JSON.stringify(this.payload));
|
|
295
660
|
return `${header}.${payload}`;
|
|
296
661
|
}
|
|
297
662
|
sign(signer) {
|
|
@@ -306,10 +671,10 @@ var Jwt = class _Jwt {
|
|
|
306
671
|
return this.encoded;
|
|
307
672
|
}
|
|
308
673
|
if (!this.header || !this.payload || !this.signature) {
|
|
309
|
-
throw new
|
|
674
|
+
throw new SDJWTException("Serialize Error: Invalid JWT");
|
|
310
675
|
}
|
|
311
|
-
const header = (0,
|
|
312
|
-
const payload = (0,
|
|
676
|
+
const header = (0, import_identity_common.base64urlEncode)(JSON.stringify(this.header));
|
|
677
|
+
const payload = (0, import_identity_common.base64urlEncode)(JSON.stringify(this.payload));
|
|
313
678
|
const signature = this.signature;
|
|
314
679
|
const compact = `${header}.${payload}.${signature}`;
|
|
315
680
|
this.encoded = compact;
|
|
@@ -327,22 +692,25 @@ var Jwt = class _Jwt {
|
|
|
327
692
|
var _a, _b, _c, _d;
|
|
328
693
|
const skew = (options == null ? void 0 : options.skewSeconds) ? options.skewSeconds : 0;
|
|
329
694
|
const currentDate = (_a = options == null ? void 0 : options.currentDate) != null ? _a : Math.floor(Date.now() / 1e3);
|
|
330
|
-
|
|
331
|
-
|
|
695
|
+
const iat = (_b = this.payload) == null ? void 0 : _b.iat;
|
|
696
|
+
const nbf = (_c = this.payload) == null ? void 0 : _c.nbf;
|
|
697
|
+
const exp = (_d = this.payload) == null ? void 0 : _d.exp;
|
|
698
|
+
if (typeof iat === "number" && iat - skew > currentDate) {
|
|
699
|
+
throw new SDJWTException("Verify Error: JWT is not yet valid");
|
|
332
700
|
}
|
|
333
|
-
if (
|
|
334
|
-
throw new
|
|
701
|
+
if (typeof nbf === "number" && nbf - skew > currentDate) {
|
|
702
|
+
throw new SDJWTException("Verify Error: JWT is not yet valid");
|
|
335
703
|
}
|
|
336
|
-
if (
|
|
337
|
-
throw new
|
|
704
|
+
if (typeof exp === "number" && exp + skew < currentDate) {
|
|
705
|
+
throw new SDJWTException("Verify Error: JWT is expired");
|
|
338
706
|
}
|
|
339
707
|
if (!this.signature) {
|
|
340
|
-
throw new
|
|
708
|
+
throw new SDJWTException("Verify Error: no signature in JWT");
|
|
341
709
|
}
|
|
342
710
|
const data = this.getUnsignedToken();
|
|
343
711
|
const verified = yield verifier(data, this.signature, options);
|
|
344
712
|
if (!verified) {
|
|
345
|
-
throw new
|
|
713
|
+
throw new SDJWTException("Verify Error: Invalid JWT Signature");
|
|
346
714
|
}
|
|
347
715
|
return { payload: this.payload, header: this.header };
|
|
348
716
|
});
|
|
@@ -350,33 +718,25 @@ var Jwt = class _Jwt {
|
|
|
350
718
|
};
|
|
351
719
|
|
|
352
720
|
// src/kbjwt.ts
|
|
353
|
-
var import_types3 = require("@sd-jwt/types");
|
|
354
|
-
var import_utils4 = require("@sd-jwt/utils");
|
|
355
721
|
var KBJwt = class _KBJwt extends Jwt {
|
|
356
722
|
// Checking the validity of the key binding jwt
|
|
357
723
|
// 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
|
|
358
724
|
verifyKB(values) {
|
|
359
725
|
return __async(this, null, function* () {
|
|
360
|
-
var _a;
|
|
361
726
|
if (!this.header || !this.payload || !this.signature) {
|
|
362
|
-
throw new
|
|
727
|
+
throw new SDJWTException("Verify Error: Invalid JWT");
|
|
363
728
|
}
|
|
364
|
-
if (!this.header.alg || this.header.alg === "none" || !this.header.typ || this.header.typ !==
|
|
365
|
-
!(this.payload.sd_hash ||
|
|
366
|
-
throw new
|
|
367
|
-
}
|
|
368
|
-
const data = this.getUnsignedToken();
|
|
369
|
-
const verified = yield values.verifier(
|
|
370
|
-
data,
|
|
371
|
-
this.signature,
|
|
372
|
-
values.payload
|
|
373
|
-
);
|
|
374
|
-
if (!verified) {
|
|
375
|
-
throw new import_utils4.SDJWTException("Verify Error: Invalid JWT Signature");
|
|
729
|
+
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
|
|
730
|
+
!(this.payload.sd_hash || "_sd_hash" in this.payload && this.payload._sd_hash)) {
|
|
731
|
+
throw new SDJWTException("Invalid Key Binding Jwt");
|
|
376
732
|
}
|
|
377
733
|
if (this.payload.nonce !== values.nonce) {
|
|
378
|
-
throw new
|
|
734
|
+
throw new SDJWTException("Verify Error: Invalid Nonce");
|
|
379
735
|
}
|
|
736
|
+
yield this.verify(
|
|
737
|
+
(data, sig) => values.verifier(data, sig, values.payload),
|
|
738
|
+
values.options
|
|
739
|
+
);
|
|
380
740
|
return { payload: this.payload, header: this.header };
|
|
381
741
|
});
|
|
382
742
|
}
|
|
@@ -395,20 +755,117 @@ var KBJwt = class _KBJwt extends Jwt {
|
|
|
395
755
|
}
|
|
396
756
|
};
|
|
397
757
|
|
|
398
|
-
// src/sdjwt.ts
|
|
399
|
-
var import_decode4 = require("@sd-jwt/decode");
|
|
400
|
-
var import_present = require("@sd-jwt/present");
|
|
401
|
-
var import_types4 = require("@sd-jwt/types");
|
|
402
|
-
var import_utils6 = require("@sd-jwt/utils");
|
|
403
|
-
|
|
404
758
|
// src/decoy.ts
|
|
405
|
-
var import_utils5 = require("@sd-jwt/utils");
|
|
406
759
|
var createDecoy = (hash, saltGenerator) => __async(null, null, function* () {
|
|
407
760
|
const { hasher, alg } = hash;
|
|
408
761
|
const salt = yield saltGenerator(16);
|
|
409
762
|
const decoy = yield hasher(salt, alg);
|
|
410
|
-
return (0,
|
|
763
|
+
return (0, import_identity_common.uint8ArrayToBase64Url)(decoy);
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
// src/present/present.ts
|
|
767
|
+
var presentableKeys = (rawPayload, disclosures, hasher) => __async(null, null, function* () {
|
|
768
|
+
const { disclosureKeymap } = yield unpack(rawPayload, disclosures, hasher);
|
|
769
|
+
return Object.keys(disclosureKeymap).sort();
|
|
770
|
+
});
|
|
771
|
+
var presentableKeysSync = (rawPayload, disclosures, hasher) => {
|
|
772
|
+
const { disclosureKeymap } = unpackSync(rawPayload, disclosures, hasher);
|
|
773
|
+
return Object.keys(disclosureKeymap).sort();
|
|
774
|
+
};
|
|
775
|
+
var present = (sdJwt, presentFrame, hasher) => __async(null, null, function* () {
|
|
776
|
+
const { jwt, kbJwt } = splitSdJwt(sdJwt);
|
|
777
|
+
const {
|
|
778
|
+
jwt: { payload },
|
|
779
|
+
disclosures
|
|
780
|
+
} = yield decodeSdJwt(sdJwt, hasher);
|
|
781
|
+
const { _sd_alg: alg } = getSDAlgAndPayload(payload);
|
|
782
|
+
const hash = { alg, hasher };
|
|
783
|
+
const keys = transformPresentationFrame(presentFrame);
|
|
784
|
+
const hashmap = yield createHashMapping(disclosures, hash);
|
|
785
|
+
const { disclosureKeymap } = yield unpack(payload, disclosures, hasher);
|
|
786
|
+
const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
787
|
+
return [
|
|
788
|
+
jwt,
|
|
789
|
+
...presentedDisclosures.map((d) => d.encode()),
|
|
790
|
+
kbJwt != null ? kbJwt : ""
|
|
791
|
+
].join(SD_SEPARATOR);
|
|
411
792
|
});
|
|
793
|
+
var presentSync = (sdJwt, presentFrame, hasher) => {
|
|
794
|
+
const { jwt, kbJwt } = splitSdJwt(sdJwt);
|
|
795
|
+
const {
|
|
796
|
+
jwt: { payload },
|
|
797
|
+
disclosures
|
|
798
|
+
} = decodeSdJwtSync(sdJwt, hasher);
|
|
799
|
+
const { _sd_alg: alg } = getSDAlgAndPayload(payload);
|
|
800
|
+
const hash = { alg, hasher };
|
|
801
|
+
const keys = transformPresentationFrame(presentFrame);
|
|
802
|
+
const hashmap = createHashMappingSync(disclosures, hash);
|
|
803
|
+
const { disclosureKeymap } = unpackSync(payload, disclosures, hasher);
|
|
804
|
+
const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
805
|
+
return [
|
|
806
|
+
jwt,
|
|
807
|
+
...presentedDisclosures.map((d) => d.encode()),
|
|
808
|
+
kbJwt != null ? kbJwt : ""
|
|
809
|
+
].join(SD_SEPARATOR);
|
|
810
|
+
};
|
|
811
|
+
var transformPresentationFrame = (obj, prefix = "") => {
|
|
812
|
+
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
813
|
+
const newPrefix = prefix ? `${prefix}.${key}` : key;
|
|
814
|
+
if (typeof value === "boolean") {
|
|
815
|
+
if (value) {
|
|
816
|
+
acc.push(newPrefix);
|
|
817
|
+
}
|
|
818
|
+
} else if (typeof value === "object" && value !== null) {
|
|
819
|
+
acc.push(
|
|
820
|
+
newPrefix,
|
|
821
|
+
...transformPresentationFrame(
|
|
822
|
+
value,
|
|
823
|
+
newPrefix
|
|
824
|
+
)
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
return acc;
|
|
828
|
+
}, []);
|
|
829
|
+
};
|
|
830
|
+
var createHashMappingForSerializedDisclosure = (disclosures) => {
|
|
831
|
+
const map = {};
|
|
832
|
+
for (let i = 0; i < disclosures.length; i++) {
|
|
833
|
+
const disclosure = disclosures[i];
|
|
834
|
+
const { digest, encoded, key, salt, value } = disclosure;
|
|
835
|
+
map[digest] = Disclosure.fromArray(
|
|
836
|
+
key ? [salt, key, value] : [salt, value],
|
|
837
|
+
{ digest, encoded }
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
return map;
|
|
841
|
+
};
|
|
842
|
+
var selectDisclosures = (payload, disclosures, presentationFrame) => {
|
|
843
|
+
if (disclosures.length === 0) {
|
|
844
|
+
return [];
|
|
845
|
+
}
|
|
846
|
+
const hashmap = createHashMappingForSerializedDisclosure(disclosures);
|
|
847
|
+
const { disclosureKeymap } = unpackObj(payload, hashmap);
|
|
848
|
+
const keys = transformPresentationFrame(presentationFrame);
|
|
849
|
+
const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
850
|
+
const selectedDisclosures = presentedDisclosures.map(
|
|
851
|
+
(d) => {
|
|
852
|
+
const { salt, key, value, _digest } = d;
|
|
853
|
+
if (!_digest) {
|
|
854
|
+
throw new SDJWTException(
|
|
855
|
+
"Implementation error: _digest is not defined"
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
return {
|
|
859
|
+
digest: _digest,
|
|
860
|
+
encoded: d.encode(),
|
|
861
|
+
salt,
|
|
862
|
+
key,
|
|
863
|
+
value
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
);
|
|
867
|
+
return selectedDisclosures;
|
|
868
|
+
};
|
|
412
869
|
|
|
413
870
|
// src/sdjwt.ts
|
|
414
871
|
var SDJwt = class _SDJwt {
|
|
@@ -419,7 +876,7 @@ var SDJwt = class _SDJwt {
|
|
|
419
876
|
}
|
|
420
877
|
static decodeSDJwt(sdjwt, hasher) {
|
|
421
878
|
return __async(this, null, function* () {
|
|
422
|
-
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(
|
|
879
|
+
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
|
|
423
880
|
const jwt = Jwt.fromEncode(encodedJwt);
|
|
424
881
|
if (!jwt.payload) {
|
|
425
882
|
throw new Error("Payload is undefined on the JWT. Invalid state reached");
|
|
@@ -432,10 +889,10 @@ var SDJwt = class _SDJwt {
|
|
|
432
889
|
}
|
|
433
890
|
const encodedKeyBindingJwt = encodedDisclosures.pop();
|
|
434
891
|
const kbJwt = encodedKeyBindingJwt ? KBJwt.fromKBEncode(encodedKeyBindingJwt) : void 0;
|
|
435
|
-
const { _sd_alg } =
|
|
892
|
+
const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
|
|
436
893
|
const disclosures = yield Promise.all(
|
|
437
894
|
encodedDisclosures.map(
|
|
438
|
-
(ed) =>
|
|
895
|
+
(ed) => Disclosure.fromEncode(ed, { alg: _sd_alg, hasher })
|
|
439
896
|
)
|
|
440
897
|
);
|
|
441
898
|
return {
|
|
@@ -447,7 +904,7 @@ var SDJwt = class _SDJwt {
|
|
|
447
904
|
}
|
|
448
905
|
static extractJwt(encodedSdJwt) {
|
|
449
906
|
return __async(this, null, function* () {
|
|
450
|
-
const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split(
|
|
907
|
+
const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split(SD_SEPARATOR);
|
|
451
908
|
return Jwt.fromEncode(encodedJwt);
|
|
452
909
|
});
|
|
453
910
|
}
|
|
@@ -476,17 +933,17 @@ var SDJwt = class _SDJwt {
|
|
|
476
933
|
return __async(this, null, function* () {
|
|
477
934
|
var _a;
|
|
478
935
|
if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
|
|
479
|
-
throw new
|
|
936
|
+
throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
|
|
480
937
|
}
|
|
481
|
-
const { _sd_alg: alg } =
|
|
938
|
+
const { _sd_alg: alg } = getSDAlgAndPayload(this.jwt.payload);
|
|
482
939
|
const hash = { alg, hasher };
|
|
483
|
-
const hashmap = yield
|
|
484
|
-
const { disclosureKeymap } = yield
|
|
940
|
+
const hashmap = yield createHashMapping(this.disclosures, hash);
|
|
941
|
+
const { disclosureKeymap } = yield unpack(
|
|
485
942
|
this.jwt.payload,
|
|
486
943
|
this.disclosures,
|
|
487
944
|
hasher
|
|
488
945
|
);
|
|
489
|
-
const keys = presentFrame ?
|
|
946
|
+
const keys = presentFrame ? transformPresentationFrame(presentFrame) : yield this.presentableKeys(hasher);
|
|
490
947
|
const disclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
491
948
|
return disclosures;
|
|
492
949
|
});
|
|
@@ -494,16 +951,16 @@ var SDJwt = class _SDJwt {
|
|
|
494
951
|
encodeSDJwt() {
|
|
495
952
|
const data = [];
|
|
496
953
|
if (!this.jwt) {
|
|
497
|
-
throw new
|
|
954
|
+
throw new SDJWTException("Invalid sd-jwt: jwt is missing");
|
|
498
955
|
}
|
|
499
956
|
const encodedJwt = this.jwt.encodeJwt();
|
|
500
957
|
data.push(encodedJwt);
|
|
501
958
|
if (this.disclosures && this.disclosures.length > 0) {
|
|
502
|
-
const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join(
|
|
959
|
+
const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join(SD_SEPARATOR);
|
|
503
960
|
data.push(encodeddisclosures);
|
|
504
961
|
}
|
|
505
962
|
data.push(this.kbJwt ? this.kbJwt.encodeJwt() : "");
|
|
506
|
-
return data.join(
|
|
963
|
+
return data.join(SD_SEPARATOR);
|
|
507
964
|
}
|
|
508
965
|
keys(hasher) {
|
|
509
966
|
return __async(this, null, function* () {
|
|
@@ -514,9 +971,9 @@ var SDJwt = class _SDJwt {
|
|
|
514
971
|
return __async(this, null, function* () {
|
|
515
972
|
var _a, _b;
|
|
516
973
|
if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
|
|
517
|
-
throw new
|
|
974
|
+
throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
|
|
518
975
|
}
|
|
519
|
-
const { disclosureKeymap } = yield
|
|
976
|
+
const { disclosureKeymap } = yield unpack(
|
|
520
977
|
(_b = this.jwt) == null ? void 0 : _b.payload,
|
|
521
978
|
this.disclosures,
|
|
522
979
|
hasher
|
|
@@ -528,9 +985,9 @@ var SDJwt = class _SDJwt {
|
|
|
528
985
|
return __async(this, null, function* () {
|
|
529
986
|
var _a;
|
|
530
987
|
if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
|
|
531
|
-
throw new
|
|
988
|
+
throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
|
|
532
989
|
}
|
|
533
|
-
const { unpackedObj } = yield
|
|
990
|
+
const { unpackedObj } = yield unpack(
|
|
534
991
|
this.jwt.payload,
|
|
535
992
|
this.disclosures,
|
|
536
993
|
hasher
|
|
@@ -545,8 +1002,9 @@ var listKeys = (obj, prefix = "") => {
|
|
|
545
1002
|
if (obj[key] === void 0) continue;
|
|
546
1003
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
547
1004
|
keys.push(newKey);
|
|
548
|
-
|
|
549
|
-
|
|
1005
|
+
const value = obj[key];
|
|
1006
|
+
if (value && typeof value === "object") {
|
|
1007
|
+
keys.push(...listKeys(value, newKey));
|
|
550
1008
|
}
|
|
551
1009
|
}
|
|
552
1010
|
return keys;
|
|
@@ -559,14 +1017,14 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
559
1017
|
disclosures: []
|
|
560
1018
|
};
|
|
561
1019
|
}
|
|
562
|
-
const sd = (_a = disclosureFrame[
|
|
563
|
-
const decoyCount = (_b = disclosureFrame[
|
|
1020
|
+
const sd = (_a = disclosureFrame[SD_DIGEST]) != null ? _a : [];
|
|
1021
|
+
const decoyCount = (_b = disclosureFrame[SD_DECOY]) != null ? _b : 0;
|
|
564
1022
|
if (Array.isArray(claims)) {
|
|
565
1023
|
const packedClaims2 = [];
|
|
566
1024
|
const disclosures2 = [];
|
|
567
1025
|
const recursivePackedClaims2 = {};
|
|
568
1026
|
for (const key in disclosureFrame) {
|
|
569
|
-
if (key !==
|
|
1027
|
+
if (key !== SD_DIGEST) {
|
|
570
1028
|
const idx = Number.parseInt(key, 10);
|
|
571
1029
|
const packed = yield pack(
|
|
572
1030
|
claims[idx],
|
|
@@ -582,9 +1040,9 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
582
1040
|
const claim = recursivePackedClaims2[i] ? recursivePackedClaims2[i] : claims[i];
|
|
583
1041
|
if (sd.includes(i)) {
|
|
584
1042
|
const salt = yield saltGenerator(16);
|
|
585
|
-
const disclosure = new
|
|
1043
|
+
const disclosure = new Disclosure([salt, claim]);
|
|
586
1044
|
const digest = yield disclosure.digest(hash);
|
|
587
|
-
packedClaims2.push({ [
|
|
1045
|
+
packedClaims2.push({ [SD_LIST_KEY]: digest });
|
|
588
1046
|
disclosures2.push(disclosure);
|
|
589
1047
|
} else {
|
|
590
1048
|
packedClaims2.push(claim);
|
|
@@ -592,7 +1050,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
592
1050
|
}
|
|
593
1051
|
for (let j = 0; j < decoyCount; j++) {
|
|
594
1052
|
const decoyDigest = yield createDecoy(hash, saltGenerator);
|
|
595
|
-
packedClaims2.push({ [
|
|
1053
|
+
packedClaims2.push({ [SD_LIST_KEY]: decoyDigest });
|
|
596
1054
|
}
|
|
597
1055
|
return { packedClaims: packedClaims2, disclosures: disclosures2 };
|
|
598
1056
|
}
|
|
@@ -600,7 +1058,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
600
1058
|
const disclosures = [];
|
|
601
1059
|
const recursivePackedClaims = {};
|
|
602
1060
|
for (const key in disclosureFrame) {
|
|
603
|
-
if (key !==
|
|
1061
|
+
if (key !== SD_DIGEST) {
|
|
604
1062
|
const packed = yield pack(
|
|
605
1063
|
// @ts-expect-error
|
|
606
1064
|
claims[key],
|
|
@@ -617,7 +1075,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
617
1075
|
const claim = recursivePackedClaims[key] ? recursivePackedClaims[key] : claims[key];
|
|
618
1076
|
if (sd.includes(key)) {
|
|
619
1077
|
const salt = yield saltGenerator(16);
|
|
620
|
-
const disclosure = new
|
|
1078
|
+
const disclosure = new Disclosure([salt, key, claim]);
|
|
621
1079
|
const digest = yield disclosure.digest(hash);
|
|
622
1080
|
_sd.push(digest);
|
|
623
1081
|
disclosures.push(disclosure);
|
|
@@ -630,7 +1088,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
630
1088
|
_sd.push(decoyDigest);
|
|
631
1089
|
}
|
|
632
1090
|
if (_sd.length > 0) {
|
|
633
|
-
packedClaims[
|
|
1091
|
+
packedClaims[SD_DIGEST] = _sd.sort();
|
|
634
1092
|
}
|
|
635
1093
|
return { packedClaims, disclosures };
|
|
636
1094
|
});
|
|
@@ -640,8 +1098,8 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
640
1098
|
constructor(userConfig) {
|
|
641
1099
|
this.userConfig = {};
|
|
642
1100
|
if (userConfig) {
|
|
643
|
-
if (userConfig.hashAlg && !
|
|
644
|
-
throw new
|
|
1101
|
+
if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
|
|
1102
|
+
throw new SDJWTException(
|
|
645
1103
|
`Invalid hash algorithm: ${userConfig.hashAlg}`
|
|
646
1104
|
);
|
|
647
1105
|
}
|
|
@@ -651,15 +1109,15 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
651
1109
|
createKBJwt(options, sdHash) {
|
|
652
1110
|
return __async(this, null, function* () {
|
|
653
1111
|
if (!this.userConfig.kbSigner) {
|
|
654
|
-
throw new
|
|
1112
|
+
throw new SDJWTException("Key Binding Signer not found");
|
|
655
1113
|
}
|
|
656
1114
|
if (!this.userConfig.kbSignAlg) {
|
|
657
|
-
throw new
|
|
1115
|
+
throw new SDJWTException("Key Binding sign algorithm not specified");
|
|
658
1116
|
}
|
|
659
1117
|
const { payload } = options;
|
|
660
1118
|
const kbJwt = new KBJwt({
|
|
661
1119
|
header: {
|
|
662
|
-
typ:
|
|
1120
|
+
typ: KB_JWT_TYP,
|
|
663
1121
|
alg: this.userConfig.kbSignAlg
|
|
664
1122
|
},
|
|
665
1123
|
payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
|
|
@@ -671,7 +1129,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
671
1129
|
SignJwt(jwt) {
|
|
672
1130
|
return __async(this, null, function* () {
|
|
673
1131
|
if (!this.userConfig.signer) {
|
|
674
|
-
throw new
|
|
1132
|
+
throw new SDJWTException("Signer not found");
|
|
675
1133
|
}
|
|
676
1134
|
yield jwt.sign(this.userConfig.signer);
|
|
677
1135
|
return jwt;
|
|
@@ -680,7 +1138,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
680
1138
|
VerifyJwt(jwt, options) {
|
|
681
1139
|
return __async(this, null, function* () {
|
|
682
1140
|
if (!this.userConfig.verifier) {
|
|
683
|
-
throw new
|
|
1141
|
+
throw new SDJWTException("Verifier not found");
|
|
684
1142
|
}
|
|
685
1143
|
return jwt.verify(this.userConfig.verifier, options);
|
|
686
1144
|
});
|
|
@@ -689,13 +1147,13 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
689
1147
|
return __async(this, null, function* () {
|
|
690
1148
|
var _a, _b;
|
|
691
1149
|
if (!this.userConfig.hasher) {
|
|
692
|
-
throw new
|
|
1150
|
+
throw new SDJWTException("Hasher not found");
|
|
693
1151
|
}
|
|
694
1152
|
if (!this.userConfig.saltGenerator) {
|
|
695
|
-
throw new
|
|
1153
|
+
throw new SDJWTException("SaltGenerator not found");
|
|
696
1154
|
}
|
|
697
1155
|
if (!this.userConfig.signAlg) {
|
|
698
|
-
throw new
|
|
1156
|
+
throw new SDJWTException("sign alogrithm not specified");
|
|
699
1157
|
}
|
|
700
1158
|
if (disclosureFrame) {
|
|
701
1159
|
this.validateReservedFields(disclosureFrame);
|
|
@@ -738,11 +1196,11 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
738
1196
|
return __async(this, null, function* () {
|
|
739
1197
|
var _a;
|
|
740
1198
|
if (!this.userConfig.hasher) {
|
|
741
|
-
throw new
|
|
1199
|
+
throw new SDJWTException("Hasher not found");
|
|
742
1200
|
}
|
|
743
1201
|
const hasher = this.userConfig.hasher;
|
|
744
1202
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
745
|
-
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new
|
|
1203
|
+
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
|
|
746
1204
|
const presentSdJwtWithoutKb = yield sdjwt.present(
|
|
747
1205
|
presentationFrame,
|
|
748
1206
|
hasher
|
|
@@ -765,12 +1223,12 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
765
1223
|
verify(encodedSDJwt, options) {
|
|
766
1224
|
return __async(this, null, function* () {
|
|
767
1225
|
if (!this.userConfig.hasher) {
|
|
768
|
-
throw new
|
|
1226
|
+
throw new SDJWTException("Hasher not found");
|
|
769
1227
|
}
|
|
770
1228
|
const hasher = this.userConfig.hasher;
|
|
771
1229
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
772
1230
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
773
|
-
throw new
|
|
1231
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
774
1232
|
}
|
|
775
1233
|
const { payload, header } = yield this.validate(encodedSDJwt, options);
|
|
776
1234
|
if (options == null ? void 0 : options.requiredClaimKeys) {
|
|
@@ -779,7 +1237,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
779
1237
|
(k) => !keys.includes(k)
|
|
780
1238
|
);
|
|
781
1239
|
if (missingKeys.length > 0) {
|
|
782
|
-
throw new
|
|
1240
|
+
throw new SDJWTException(
|
|
783
1241
|
`Missing required claim keys: ${missingKeys.join(", ")}`
|
|
784
1242
|
);
|
|
785
1243
|
}
|
|
@@ -788,15 +1246,16 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
788
1246
|
return { payload, header };
|
|
789
1247
|
}
|
|
790
1248
|
if (!sdjwt.kbJwt) {
|
|
791
|
-
throw new
|
|
1249
|
+
throw new SDJWTException("Key Binding JWT not exist");
|
|
792
1250
|
}
|
|
793
1251
|
if (!this.userConfig.kbVerifier) {
|
|
794
|
-
throw new
|
|
1252
|
+
throw new SDJWTException("Key Binding Verifier not found");
|
|
795
1253
|
}
|
|
796
1254
|
const kb = yield sdjwt.kbJwt.verifyKB({
|
|
797
1255
|
verifier: this.userConfig.kbVerifier,
|
|
798
1256
|
payload,
|
|
799
|
-
nonce: options.keyBindingNonce
|
|
1257
|
+
nonce: options.keyBindingNonce,
|
|
1258
|
+
options
|
|
800
1259
|
});
|
|
801
1260
|
if (!kb) {
|
|
802
1261
|
throw new Error("signature is not valid");
|
|
@@ -813,19 +1272,182 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
813
1272
|
hasher
|
|
814
1273
|
);
|
|
815
1274
|
if (sdHashStr !== sdHashfromKb) {
|
|
816
|
-
throw new
|
|
1275
|
+
throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
|
|
817
1276
|
}
|
|
818
1277
|
return { payload, header, kb };
|
|
819
1278
|
});
|
|
820
1279
|
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Safe verification that collects all errors instead of failing fast.
|
|
1282
|
+
* Returns a result object with either the verified data or an array of all errors.
|
|
1283
|
+
*
|
|
1284
|
+
* @param encodedSDJwt - The encoded SD-JWT to verify
|
|
1285
|
+
* @param options - Verification options
|
|
1286
|
+
* @returns A SafeVerifyResult containing either success data or collected errors
|
|
1287
|
+
*/
|
|
1288
|
+
safeVerify(encodedSDJwt, options) {
|
|
1289
|
+
return __async(this, null, function* () {
|
|
1290
|
+
const errors = [];
|
|
1291
|
+
const addError = (code, message, details) => {
|
|
1292
|
+
errors.push({ code, message, details });
|
|
1293
|
+
};
|
|
1294
|
+
const exceptionToCode = (error) => {
|
|
1295
|
+
const message = error.message.toLowerCase();
|
|
1296
|
+
if (message.includes("hasher not found")) return "HASHER_NOT_FOUND";
|
|
1297
|
+
if (message.includes("verifier not found")) return "VERIFIER_NOT_FOUND";
|
|
1298
|
+
if (message.includes("invalid sd jwt") || message.includes("invalid jwt"))
|
|
1299
|
+
return "INVALID_SD_JWT";
|
|
1300
|
+
if (message.includes("not yet valid")) return "JWT_NOT_YET_VALID";
|
|
1301
|
+
if (message.includes("expired")) return "JWT_EXPIRED";
|
|
1302
|
+
if (message.includes("signature")) return "INVALID_JWT_SIGNATURE";
|
|
1303
|
+
if (message.includes("missing required claim"))
|
|
1304
|
+
return "MISSING_REQUIRED_CLAIMS";
|
|
1305
|
+
if (message.includes("key binding jwt not exist"))
|
|
1306
|
+
return "KEY_BINDING_JWT_MISSING";
|
|
1307
|
+
if (message.includes("key binding verifier not found"))
|
|
1308
|
+
return "KEY_BINDING_VERIFIER_NOT_FOUND";
|
|
1309
|
+
if (message.includes("sd_hash")) return "KEY_BINDING_SD_HASH_INVALID";
|
|
1310
|
+
return "UNKNOWN_ERROR";
|
|
1311
|
+
};
|
|
1312
|
+
if (!this.userConfig.hasher) {
|
|
1313
|
+
addError("HASHER_NOT_FOUND", "Hasher not found");
|
|
1314
|
+
}
|
|
1315
|
+
if (!this.userConfig.verifier) {
|
|
1316
|
+
addError("VERIFIER_NOT_FOUND", "Verifier not found");
|
|
1317
|
+
}
|
|
1318
|
+
if (errors.length > 0) {
|
|
1319
|
+
return { success: false, errors };
|
|
1320
|
+
}
|
|
1321
|
+
if (!this.userConfig.hasher) {
|
|
1322
|
+
throw new SDJWTException("Hasher not found");
|
|
1323
|
+
}
|
|
1324
|
+
const hasher = this.userConfig.hasher;
|
|
1325
|
+
let sdjwt;
|
|
1326
|
+
let payload;
|
|
1327
|
+
let header;
|
|
1328
|
+
try {
|
|
1329
|
+
sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1330
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
1331
|
+
addError("INVALID_SD_JWT", "Invalid SD JWT: missing JWT or payload");
|
|
1332
|
+
}
|
|
1333
|
+
} catch (e) {
|
|
1334
|
+
const error = ensureError(e);
|
|
1335
|
+
addError(
|
|
1336
|
+
"INVALID_SD_JWT",
|
|
1337
|
+
`Failed to decode SD-JWT: ${error.message}`,
|
|
1338
|
+
error
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
if (sdjwt == null ? void 0 : sdjwt.jwt) {
|
|
1342
|
+
try {
|
|
1343
|
+
const result = yield this.VerifyJwt(sdjwt.jwt, options);
|
|
1344
|
+
header = result.header;
|
|
1345
|
+
const claims = yield sdjwt.getClaims(hasher);
|
|
1346
|
+
payload = claims;
|
|
1347
|
+
} catch (e) {
|
|
1348
|
+
const error = ensureError(e);
|
|
1349
|
+
const code = exceptionToCode(error);
|
|
1350
|
+
addError(code, error.message, error);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
if (sdjwt && (options == null ? void 0 : options.requiredClaimKeys)) {
|
|
1354
|
+
try {
|
|
1355
|
+
const keys = yield sdjwt.keys(hasher);
|
|
1356
|
+
const missingKeys = options.requiredClaimKeys.filter(
|
|
1357
|
+
(k) => !keys.includes(k)
|
|
1358
|
+
);
|
|
1359
|
+
if (missingKeys.length > 0) {
|
|
1360
|
+
addError(
|
|
1361
|
+
"MISSING_REQUIRED_CLAIMS",
|
|
1362
|
+
`Missing required claim keys: ${missingKeys.join(", ")}`,
|
|
1363
|
+
{ missingKeys }
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
} catch (e) {
|
|
1367
|
+
const error = ensureError(e);
|
|
1368
|
+
addError(
|
|
1369
|
+
"UNKNOWN_ERROR",
|
|
1370
|
+
`Failed to check required claims: ${error.message}`,
|
|
1371
|
+
error
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
let kb;
|
|
1376
|
+
if ((options == null ? void 0 : options.keyBindingNonce) && sdjwt) {
|
|
1377
|
+
if (!sdjwt.kbJwt) {
|
|
1378
|
+
addError("KEY_BINDING_JWT_MISSING", "Key Binding JWT not exist");
|
|
1379
|
+
} else if (!this.userConfig.kbVerifier) {
|
|
1380
|
+
addError(
|
|
1381
|
+
"KEY_BINDING_VERIFIER_NOT_FOUND",
|
|
1382
|
+
"Key Binding Verifier not found"
|
|
1383
|
+
);
|
|
1384
|
+
} else if (payload) {
|
|
1385
|
+
try {
|
|
1386
|
+
const kbResult = yield sdjwt.kbJwt.verifyKB({
|
|
1387
|
+
verifier: this.userConfig.kbVerifier,
|
|
1388
|
+
payload,
|
|
1389
|
+
nonce: options.keyBindingNonce,
|
|
1390
|
+
options
|
|
1391
|
+
});
|
|
1392
|
+
if (!kbResult) {
|
|
1393
|
+
addError(
|
|
1394
|
+
"KEY_BINDING_SIGNATURE_INVALID",
|
|
1395
|
+
"Key binding signature is not valid"
|
|
1396
|
+
);
|
|
1397
|
+
} else {
|
|
1398
|
+
kb = kbResult;
|
|
1399
|
+
const sdjwtWithoutKb = new SDJwt({
|
|
1400
|
+
jwt: sdjwt.jwt,
|
|
1401
|
+
disclosures: sdjwt.disclosures
|
|
1402
|
+
});
|
|
1403
|
+
const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
|
|
1404
|
+
const sdHashStr = yield this.calculateSDHash(
|
|
1405
|
+
presentSdJwtWithoutKb,
|
|
1406
|
+
sdjwt,
|
|
1407
|
+
hasher
|
|
1408
|
+
);
|
|
1409
|
+
if (sdHashStr !== kbResult.payload.sd_hash) {
|
|
1410
|
+
addError(
|
|
1411
|
+
"KEY_BINDING_SD_HASH_INVALID",
|
|
1412
|
+
"Invalid sd_hash in Key Binding JWT",
|
|
1413
|
+
{
|
|
1414
|
+
expected: sdHashStr,
|
|
1415
|
+
received: kbResult.payload.sd_hash
|
|
1416
|
+
}
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
} catch (e) {
|
|
1421
|
+
const error = ensureError(e);
|
|
1422
|
+
addError(
|
|
1423
|
+
"KEY_BINDING_SIGNATURE_INVALID",
|
|
1424
|
+
`Key binding verification failed: ${error.message}`,
|
|
1425
|
+
error
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
if (errors.length > 0) {
|
|
1431
|
+
return { success: false, errors };
|
|
1432
|
+
}
|
|
1433
|
+
return {
|
|
1434
|
+
success: true,
|
|
1435
|
+
data: {
|
|
1436
|
+
payload,
|
|
1437
|
+
header,
|
|
1438
|
+
kb
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
821
1443
|
calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
|
|
822
1444
|
return __async(this, null, function* () {
|
|
823
1445
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
824
|
-
throw new
|
|
1446
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
825
1447
|
}
|
|
826
|
-
const { _sd_alg } =
|
|
1448
|
+
const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
|
|
827
1449
|
const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
828
|
-
const sdHashStr = (0,
|
|
1450
|
+
const sdHashStr = (0, import_identity_common.uint8ArrayToBase64Url)(sdHash);
|
|
829
1451
|
return sdHashStr;
|
|
830
1452
|
});
|
|
831
1453
|
}
|
|
@@ -839,12 +1461,12 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
839
1461
|
validate(encodedSDJwt, options) {
|
|
840
1462
|
return __async(this, null, function* () {
|
|
841
1463
|
if (!this.userConfig.hasher) {
|
|
842
|
-
throw new
|
|
1464
|
+
throw new SDJWTException("Hasher not found");
|
|
843
1465
|
}
|
|
844
1466
|
const hasher = this.userConfig.hasher;
|
|
845
1467
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
846
1468
|
if (!sdjwt.jwt) {
|
|
847
|
-
throw new
|
|
1469
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
848
1470
|
}
|
|
849
1471
|
const verifiedPayloads = yield this.VerifyJwt(sdjwt.jwt, options);
|
|
850
1472
|
const claims = yield sdjwt.getClaims(hasher);
|
|
@@ -859,14 +1481,14 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
859
1481
|
}
|
|
860
1482
|
decode(endcodedSDJwt) {
|
|
861
1483
|
if (!this.userConfig.hasher) {
|
|
862
|
-
throw new
|
|
1484
|
+
throw new SDJWTException("Hasher not found");
|
|
863
1485
|
}
|
|
864
1486
|
return SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
865
1487
|
}
|
|
866
1488
|
keys(endcodedSDJwt) {
|
|
867
1489
|
return __async(this, null, function* () {
|
|
868
1490
|
if (!this.userConfig.hasher) {
|
|
869
|
-
throw new
|
|
1491
|
+
throw new SDJWTException("Hasher not found");
|
|
870
1492
|
}
|
|
871
1493
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
872
1494
|
return sdjwt.keys(this.userConfig.hasher);
|
|
@@ -875,7 +1497,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
875
1497
|
presentableKeys(endcodedSDJwt) {
|
|
876
1498
|
return __async(this, null, function* () {
|
|
877
1499
|
if (!this.userConfig.hasher) {
|
|
878
|
-
throw new
|
|
1500
|
+
throw new SDJWTException("Hasher not found");
|
|
879
1501
|
}
|
|
880
1502
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
881
1503
|
return sdjwt.presentableKeys(this.userConfig.hasher);
|
|
@@ -884,7 +1506,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
884
1506
|
getClaims(endcodedSDJwt) {
|
|
885
1507
|
return __async(this, null, function* () {
|
|
886
1508
|
if (!this.userConfig.hasher) {
|
|
887
|
-
throw new
|
|
1509
|
+
throw new SDJWTException("Hasher not found");
|
|
888
1510
|
}
|
|
889
1511
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
890
1512
|
return sdjwt.getClaims(this.userConfig.hasher);
|
|
@@ -903,8 +1525,8 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
903
1525
|
constructor(userConfig) {
|
|
904
1526
|
this.userConfig = {};
|
|
905
1527
|
if (userConfig) {
|
|
906
|
-
if (userConfig.hashAlg && !
|
|
907
|
-
throw new
|
|
1528
|
+
if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
|
|
1529
|
+
throw new SDJWTException(
|
|
908
1530
|
`Invalid hash algorithm: ${userConfig.hashAlg}`
|
|
909
1531
|
);
|
|
910
1532
|
}
|
|
@@ -914,15 +1536,15 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
914
1536
|
createKBJwt(options, sdHash) {
|
|
915
1537
|
return __async(this, null, function* () {
|
|
916
1538
|
if (!this.userConfig.kbSigner) {
|
|
917
|
-
throw new
|
|
1539
|
+
throw new SDJWTException("Key Binding Signer not found");
|
|
918
1540
|
}
|
|
919
1541
|
if (!this.userConfig.kbSignAlg) {
|
|
920
|
-
throw new
|
|
1542
|
+
throw new SDJWTException("Key Binding sign algorithm not specified");
|
|
921
1543
|
}
|
|
922
1544
|
const { payload } = options;
|
|
923
1545
|
const kbJwt = new KBJwt({
|
|
924
1546
|
header: {
|
|
925
|
-
typ:
|
|
1547
|
+
typ: KB_JWT_TYP,
|
|
926
1548
|
alg: this.userConfig.kbSignAlg
|
|
927
1549
|
},
|
|
928
1550
|
payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
|
|
@@ -932,16 +1554,16 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
932
1554
|
});
|
|
933
1555
|
}
|
|
934
1556
|
encodeObj(obj) {
|
|
935
|
-
return (0,
|
|
1557
|
+
return (0, import_identity_common.base64urlEncode)(JSON.stringify(obj));
|
|
936
1558
|
}
|
|
937
1559
|
issue(payload, disclosureFrame, options) {
|
|
938
1560
|
return __async(this, null, function* () {
|
|
939
1561
|
var _a;
|
|
940
1562
|
if (!this.userConfig.hasher) {
|
|
941
|
-
throw new
|
|
1563
|
+
throw new SDJWTException("Hasher not found");
|
|
942
1564
|
}
|
|
943
1565
|
if (!this.userConfig.saltGenerator) {
|
|
944
|
-
throw new
|
|
1566
|
+
throw new SDJWTException("SaltGenerator not found");
|
|
945
1567
|
}
|
|
946
1568
|
if (disclosureFrame) {
|
|
947
1569
|
this.validateReservedFields(disclosureFrame);
|
|
@@ -993,12 +1615,12 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
993
1615
|
return __async(this, null, function* () {
|
|
994
1616
|
var _a;
|
|
995
1617
|
if (!this.userConfig.hasher) {
|
|
996
|
-
throw new
|
|
1618
|
+
throw new SDJWTException("Hasher not found");
|
|
997
1619
|
}
|
|
998
1620
|
const hasher = this.userConfig.hasher;
|
|
999
1621
|
const encodedSDJwt = generalJSON.toEncoded(0);
|
|
1000
1622
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1001
|
-
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new
|
|
1623
|
+
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
|
|
1002
1624
|
const disclosures = yield sdjwt.getPresentDisclosures(
|
|
1003
1625
|
presentationFrame,
|
|
1004
1626
|
hasher
|
|
@@ -1033,14 +1655,14 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1033
1655
|
verify(generalJSON, options) {
|
|
1034
1656
|
return __async(this, null, function* () {
|
|
1035
1657
|
if (!this.userConfig.hasher) {
|
|
1036
|
-
throw new
|
|
1658
|
+
throw new SDJWTException("Hasher not found");
|
|
1037
1659
|
}
|
|
1038
1660
|
const hasher = this.userConfig.hasher;
|
|
1039
1661
|
const { payload, headers } = yield this.validate(generalJSON);
|
|
1040
1662
|
const encodedSDJwt = generalJSON.toEncoded(0);
|
|
1041
1663
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1042
1664
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
1043
|
-
throw new
|
|
1665
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
1044
1666
|
}
|
|
1045
1667
|
if (options == null ? void 0 : options.requiredClaimKeys) {
|
|
1046
1668
|
const keys = yield sdjwt.keys(hasher);
|
|
@@ -1048,7 +1670,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1048
1670
|
(k) => !keys.includes(k)
|
|
1049
1671
|
);
|
|
1050
1672
|
if (missingKeys.length > 0) {
|
|
1051
|
-
throw new
|
|
1673
|
+
throw new SDJWTException(
|
|
1052
1674
|
`Missing required claim keys: ${missingKeys.join(", ")}`
|
|
1053
1675
|
);
|
|
1054
1676
|
}
|
|
@@ -1057,15 +1679,16 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1057
1679
|
return { payload, headers };
|
|
1058
1680
|
}
|
|
1059
1681
|
if (!sdjwt.kbJwt) {
|
|
1060
|
-
throw new
|
|
1682
|
+
throw new SDJWTException("Key Binding JWT not exist");
|
|
1061
1683
|
}
|
|
1062
1684
|
if (!this.userConfig.kbVerifier) {
|
|
1063
|
-
throw new
|
|
1685
|
+
throw new SDJWTException("Key Binding Verifier not found");
|
|
1064
1686
|
}
|
|
1065
1687
|
const kb = yield sdjwt.kbJwt.verifyKB({
|
|
1066
1688
|
verifier: this.userConfig.kbVerifier,
|
|
1067
1689
|
payload,
|
|
1068
|
-
nonce: options.keyBindingNonce
|
|
1690
|
+
nonce: options.keyBindingNonce,
|
|
1691
|
+
options
|
|
1069
1692
|
});
|
|
1070
1693
|
if (!kb) {
|
|
1071
1694
|
throw new Error("signature is not valid");
|
|
@@ -1082,7 +1705,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1082
1705
|
hasher
|
|
1083
1706
|
);
|
|
1084
1707
|
if (sdHashStr !== sdHashfromKb) {
|
|
1085
|
-
throw new
|
|
1708
|
+
throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
|
|
1086
1709
|
}
|
|
1087
1710
|
return { payload, headers, kb };
|
|
1088
1711
|
});
|
|
@@ -1090,11 +1713,11 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1090
1713
|
calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
|
|
1091
1714
|
return __async(this, null, function* () {
|
|
1092
1715
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
1093
|
-
throw new
|
|
1716
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
1094
1717
|
}
|
|
1095
|
-
const { _sd_alg } =
|
|
1718
|
+
const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
|
|
1096
1719
|
const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
1097
|
-
const sdHashStr = (0,
|
|
1720
|
+
const sdHashStr = (0, import_identity_common.uint8ArrayToBase64Url)(sdHash);
|
|
1098
1721
|
return sdHashStr;
|
|
1099
1722
|
});
|
|
1100
1723
|
}
|
|
@@ -1103,10 +1726,10 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1103
1726
|
validate(generalJSON) {
|
|
1104
1727
|
return __async(this, null, function* () {
|
|
1105
1728
|
if (!this.userConfig.hasher) {
|
|
1106
|
-
throw new
|
|
1729
|
+
throw new SDJWTException("Hasher not found");
|
|
1107
1730
|
}
|
|
1108
1731
|
if (!this.userConfig.verifier) {
|
|
1109
|
-
throw new
|
|
1732
|
+
throw new SDJWTException("Verifier not found");
|
|
1110
1733
|
}
|
|
1111
1734
|
const hasher = this.userConfig.hasher;
|
|
1112
1735
|
const verifier = this.userConfig.verifier;
|
|
@@ -1118,18 +1741,18 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1118
1741
|
`${encodedHeader}.${payload}`,
|
|
1119
1742
|
signature
|
|
1120
1743
|
);
|
|
1121
|
-
const header = JSON.parse((0,
|
|
1744
|
+
const header = JSON.parse((0, import_identity_common.base64urlDecode)(encodedHeader));
|
|
1122
1745
|
return { verified: verified2, header };
|
|
1123
1746
|
}))
|
|
1124
1747
|
);
|
|
1125
1748
|
const verified = results.every((r) => r.verified);
|
|
1126
1749
|
if (!verified) {
|
|
1127
|
-
throw new
|
|
1750
|
+
throw new SDJWTException("Signature is not valid");
|
|
1128
1751
|
}
|
|
1129
1752
|
const encodedSDJwt = generalJSON.toEncoded(0);
|
|
1130
1753
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1131
1754
|
if (!sdjwt.jwt) {
|
|
1132
|
-
throw new
|
|
1755
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
1133
1756
|
}
|
|
1134
1757
|
const claims = yield sdjwt.getClaims(hasher);
|
|
1135
1758
|
return { payload: claims, headers: results.map((r) => r.header) };
|
|
@@ -1147,7 +1770,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1147
1770
|
keys(generalSdjwt) {
|
|
1148
1771
|
return __async(this, null, function* () {
|
|
1149
1772
|
if (!this.userConfig.hasher) {
|
|
1150
|
-
throw new
|
|
1773
|
+
throw new SDJWTException("Hasher not found");
|
|
1151
1774
|
}
|
|
1152
1775
|
const endcodedSDJwt = generalSdjwt.toEncoded(0);
|
|
1153
1776
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
@@ -1157,7 +1780,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1157
1780
|
presentableKeys(generalSdjwt) {
|
|
1158
1781
|
return __async(this, null, function* () {
|
|
1159
1782
|
if (!this.userConfig.hasher) {
|
|
1160
|
-
throw new
|
|
1783
|
+
throw new SDJWTException("Hasher not found");
|
|
1161
1784
|
}
|
|
1162
1785
|
const endcodedSDJwt = generalSdjwt.toEncoded(0);
|
|
1163
1786
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
@@ -1167,7 +1790,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1167
1790
|
getClaims(generalSdjwt) {
|
|
1168
1791
|
return __async(this, null, function* () {
|
|
1169
1792
|
if (!this.userConfig.hasher) {
|
|
1170
|
-
throw new
|
|
1793
|
+
throw new SDJWTException("Hasher not found");
|
|
1171
1794
|
}
|
|
1172
1795
|
const endcodedSDJwt = generalSdjwt.toEncoded(0);
|
|
1173
1796
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
@@ -1178,14 +1801,46 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1178
1801
|
SDJwtGeneralJSONInstance.DEFAULT_hashAlg = "sha-256";
|
|
1179
1802
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1180
1803
|
0 && (module.exports = {
|
|
1804
|
+
Disclosure,
|
|
1181
1805
|
FlattenJSON,
|
|
1182
1806
|
GeneralJSON,
|
|
1807
|
+
IANA_HASH_ALGORITHMS,
|
|
1183
1808
|
Jwt,
|
|
1184
1809
|
KBJwt,
|
|
1810
|
+
KB_JWT_TYP,
|
|
1811
|
+
SDJWTException,
|
|
1185
1812
|
SDJwt,
|
|
1186
1813
|
SDJwtGeneralJSONInstance,
|
|
1187
1814
|
SDJwtInstance,
|
|
1815
|
+
SD_DECOY,
|
|
1816
|
+
SD_DIGEST,
|
|
1817
|
+
SD_LIST_KEY,
|
|
1818
|
+
SD_SEPARATOR,
|
|
1819
|
+
base64UrlToUint8Array,
|
|
1820
|
+
base64urlDecode,
|
|
1821
|
+
base64urlEncode,
|
|
1188
1822
|
createDecoy,
|
|
1823
|
+
createHashMapping,
|
|
1824
|
+
createHashMappingForSerializedDisclosure,
|
|
1825
|
+
createHashMappingSync,
|
|
1826
|
+
decodeJwt,
|
|
1827
|
+
decodeSdJwt,
|
|
1828
|
+
decodeSdJwtSync,
|
|
1829
|
+
ensureError,
|
|
1830
|
+
getClaims,
|
|
1831
|
+
getClaimsSync,
|
|
1832
|
+
getSDAlgAndPayload,
|
|
1189
1833
|
listKeys,
|
|
1190
|
-
pack
|
|
1834
|
+
pack,
|
|
1835
|
+
present,
|
|
1836
|
+
presentSync,
|
|
1837
|
+
presentableKeys,
|
|
1838
|
+
presentableKeysSync,
|
|
1839
|
+
selectDisclosures,
|
|
1840
|
+
splitSdJwt,
|
|
1841
|
+
transformPresentationFrame,
|
|
1842
|
+
uint8ArrayToBase64Url,
|
|
1843
|
+
unpack,
|
|
1844
|
+
unpackObj,
|
|
1845
|
+
unpackSync
|
|
1191
1846
|
});
|