@sd-jwt/core 0.19.1-next.1 → 0.19.1-next.10
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 +359 -16
- package/dist/index.d.ts +359 -16
- package/dist/index.js +795 -138
- package/dist/index.mjs +736 -123
- 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 +227 -14
- package/src/jwt.ts +10 -15
- package/src/kbjwt.ts +5 -6
- 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 +154 -2
- package/src/test/jwt.spec.ts +7 -13
- package/src/test/kbjwt.spec.ts +5 -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,20 +718,17 @@ 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
|
|
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");
|
|
367
732
|
}
|
|
368
733
|
const data = this.getUnsignedToken();
|
|
369
734
|
const verified = yield values.verifier(
|
|
@@ -372,10 +737,10 @@ var KBJwt = class _KBJwt extends Jwt {
|
|
|
372
737
|
values.payload
|
|
373
738
|
);
|
|
374
739
|
if (!verified) {
|
|
375
|
-
throw new
|
|
740
|
+
throw new SDJWTException("Verify Error: Invalid JWT Signature");
|
|
376
741
|
}
|
|
377
742
|
if (this.payload.nonce !== values.nonce) {
|
|
378
|
-
throw new
|
|
743
|
+
throw new SDJWTException("Verify Error: Invalid Nonce");
|
|
379
744
|
}
|
|
380
745
|
return { payload: this.payload, header: this.header };
|
|
381
746
|
});
|
|
@@ -395,21 +760,118 @@ var KBJwt = class _KBJwt extends Jwt {
|
|
|
395
760
|
}
|
|
396
761
|
};
|
|
397
762
|
|
|
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
763
|
// src/decoy.ts
|
|
405
|
-
var import_utils5 = require("@sd-jwt/utils");
|
|
406
764
|
var createDecoy = (hash, saltGenerator) => __async(null, null, function* () {
|
|
407
765
|
const { hasher, alg } = hash;
|
|
408
766
|
const salt = yield saltGenerator(16);
|
|
409
767
|
const decoy = yield hasher(salt, alg);
|
|
410
|
-
return (0,
|
|
768
|
+
return (0, import_identity_common.uint8ArrayToBase64Url)(decoy);
|
|
411
769
|
});
|
|
412
770
|
|
|
771
|
+
// src/present/present.ts
|
|
772
|
+
var presentableKeys = (rawPayload, disclosures, hasher) => __async(null, null, function* () {
|
|
773
|
+
const { disclosureKeymap } = yield unpack(rawPayload, disclosures, hasher);
|
|
774
|
+
return Object.keys(disclosureKeymap).sort();
|
|
775
|
+
});
|
|
776
|
+
var presentableKeysSync = (rawPayload, disclosures, hasher) => {
|
|
777
|
+
const { disclosureKeymap } = unpackSync(rawPayload, disclosures, hasher);
|
|
778
|
+
return Object.keys(disclosureKeymap).sort();
|
|
779
|
+
};
|
|
780
|
+
var present = (sdJwt, presentFrame, hasher) => __async(null, null, function* () {
|
|
781
|
+
const { jwt, kbJwt } = splitSdJwt(sdJwt);
|
|
782
|
+
const {
|
|
783
|
+
jwt: { payload },
|
|
784
|
+
disclosures
|
|
785
|
+
} = yield decodeSdJwt(sdJwt, hasher);
|
|
786
|
+
const { _sd_alg: alg } = getSDAlgAndPayload(payload);
|
|
787
|
+
const hash = { alg, hasher };
|
|
788
|
+
const keys = transformPresentationFrame(presentFrame);
|
|
789
|
+
const hashmap = yield createHashMapping(disclosures, hash);
|
|
790
|
+
const { disclosureKeymap } = yield unpack(payload, disclosures, hasher);
|
|
791
|
+
const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
792
|
+
return [
|
|
793
|
+
jwt,
|
|
794
|
+
...presentedDisclosures.map((d) => d.encode()),
|
|
795
|
+
kbJwt != null ? kbJwt : ""
|
|
796
|
+
].join(SD_SEPARATOR);
|
|
797
|
+
});
|
|
798
|
+
var presentSync = (sdJwt, presentFrame, hasher) => {
|
|
799
|
+
const { jwt, kbJwt } = splitSdJwt(sdJwt);
|
|
800
|
+
const {
|
|
801
|
+
jwt: { payload },
|
|
802
|
+
disclosures
|
|
803
|
+
} = decodeSdJwtSync(sdJwt, hasher);
|
|
804
|
+
const { _sd_alg: alg } = getSDAlgAndPayload(payload);
|
|
805
|
+
const hash = { alg, hasher };
|
|
806
|
+
const keys = transformPresentationFrame(presentFrame);
|
|
807
|
+
const hashmap = createHashMappingSync(disclosures, hash);
|
|
808
|
+
const { disclosureKeymap } = unpackSync(payload, disclosures, hasher);
|
|
809
|
+
const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
810
|
+
return [
|
|
811
|
+
jwt,
|
|
812
|
+
...presentedDisclosures.map((d) => d.encode()),
|
|
813
|
+
kbJwt != null ? kbJwt : ""
|
|
814
|
+
].join(SD_SEPARATOR);
|
|
815
|
+
};
|
|
816
|
+
var transformPresentationFrame = (obj, prefix = "") => {
|
|
817
|
+
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
818
|
+
const newPrefix = prefix ? `${prefix}.${key}` : key;
|
|
819
|
+
if (typeof value === "boolean") {
|
|
820
|
+
if (value) {
|
|
821
|
+
acc.push(newPrefix);
|
|
822
|
+
}
|
|
823
|
+
} else if (typeof value === "object" && value !== null) {
|
|
824
|
+
acc.push(
|
|
825
|
+
newPrefix,
|
|
826
|
+
...transformPresentationFrame(
|
|
827
|
+
value,
|
|
828
|
+
newPrefix
|
|
829
|
+
)
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
return acc;
|
|
833
|
+
}, []);
|
|
834
|
+
};
|
|
835
|
+
var createHashMappingForSerializedDisclosure = (disclosures) => {
|
|
836
|
+
const map = {};
|
|
837
|
+
for (let i = 0; i < disclosures.length; i++) {
|
|
838
|
+
const disclosure = disclosures[i];
|
|
839
|
+
const { digest, encoded, key, salt, value } = disclosure;
|
|
840
|
+
map[digest] = Disclosure.fromArray(
|
|
841
|
+
key ? [salt, key, value] : [salt, value],
|
|
842
|
+
{ digest, encoded }
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
return map;
|
|
846
|
+
};
|
|
847
|
+
var selectDisclosures = (payload, disclosures, presentationFrame) => {
|
|
848
|
+
if (disclosures.length === 0) {
|
|
849
|
+
return [];
|
|
850
|
+
}
|
|
851
|
+
const hashmap = createHashMappingForSerializedDisclosure(disclosures);
|
|
852
|
+
const { disclosureKeymap } = unpackObj(payload, hashmap);
|
|
853
|
+
const keys = transformPresentationFrame(presentationFrame);
|
|
854
|
+
const presentedDisclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
855
|
+
const selectedDisclosures = presentedDisclosures.map(
|
|
856
|
+
(d) => {
|
|
857
|
+
const { salt, key, value, _digest } = d;
|
|
858
|
+
if (!_digest) {
|
|
859
|
+
throw new SDJWTException(
|
|
860
|
+
"Implementation error: _digest is not defined"
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
return {
|
|
864
|
+
digest: _digest,
|
|
865
|
+
encoded: d.encode(),
|
|
866
|
+
salt,
|
|
867
|
+
key,
|
|
868
|
+
value
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
);
|
|
872
|
+
return selectedDisclosures;
|
|
873
|
+
};
|
|
874
|
+
|
|
413
875
|
// src/sdjwt.ts
|
|
414
876
|
var SDJwt = class _SDJwt {
|
|
415
877
|
constructor(data) {
|
|
@@ -419,7 +881,7 @@ var SDJwt = class _SDJwt {
|
|
|
419
881
|
}
|
|
420
882
|
static decodeSDJwt(sdjwt, hasher) {
|
|
421
883
|
return __async(this, null, function* () {
|
|
422
|
-
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(
|
|
884
|
+
const [encodedJwt, ...encodedDisclosures] = sdjwt.split(SD_SEPARATOR);
|
|
423
885
|
const jwt = Jwt.fromEncode(encodedJwt);
|
|
424
886
|
if (!jwt.payload) {
|
|
425
887
|
throw new Error("Payload is undefined on the JWT. Invalid state reached");
|
|
@@ -432,10 +894,10 @@ var SDJwt = class _SDJwt {
|
|
|
432
894
|
}
|
|
433
895
|
const encodedKeyBindingJwt = encodedDisclosures.pop();
|
|
434
896
|
const kbJwt = encodedKeyBindingJwt ? KBJwt.fromKBEncode(encodedKeyBindingJwt) : void 0;
|
|
435
|
-
const { _sd_alg } =
|
|
897
|
+
const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
|
|
436
898
|
const disclosures = yield Promise.all(
|
|
437
899
|
encodedDisclosures.map(
|
|
438
|
-
(ed) =>
|
|
900
|
+
(ed) => Disclosure.fromEncode(ed, { alg: _sd_alg, hasher })
|
|
439
901
|
)
|
|
440
902
|
);
|
|
441
903
|
return {
|
|
@@ -447,7 +909,7 @@ var SDJwt = class _SDJwt {
|
|
|
447
909
|
}
|
|
448
910
|
static extractJwt(encodedSdJwt) {
|
|
449
911
|
return __async(this, null, function* () {
|
|
450
|
-
const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split(
|
|
912
|
+
const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split(SD_SEPARATOR);
|
|
451
913
|
return Jwt.fromEncode(encodedJwt);
|
|
452
914
|
});
|
|
453
915
|
}
|
|
@@ -476,17 +938,17 @@ var SDJwt = class _SDJwt {
|
|
|
476
938
|
return __async(this, null, function* () {
|
|
477
939
|
var _a;
|
|
478
940
|
if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
|
|
479
|
-
throw new
|
|
941
|
+
throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
|
|
480
942
|
}
|
|
481
|
-
const { _sd_alg: alg } =
|
|
943
|
+
const { _sd_alg: alg } = getSDAlgAndPayload(this.jwt.payload);
|
|
482
944
|
const hash = { alg, hasher };
|
|
483
|
-
const hashmap = yield
|
|
484
|
-
const { disclosureKeymap } = yield
|
|
945
|
+
const hashmap = yield createHashMapping(this.disclosures, hash);
|
|
946
|
+
const { disclosureKeymap } = yield unpack(
|
|
485
947
|
this.jwt.payload,
|
|
486
948
|
this.disclosures,
|
|
487
949
|
hasher
|
|
488
950
|
);
|
|
489
|
-
const keys = presentFrame ?
|
|
951
|
+
const keys = presentFrame ? transformPresentationFrame(presentFrame) : yield this.presentableKeys(hasher);
|
|
490
952
|
const disclosures = keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
|
|
491
953
|
return disclosures;
|
|
492
954
|
});
|
|
@@ -494,16 +956,16 @@ var SDJwt = class _SDJwt {
|
|
|
494
956
|
encodeSDJwt() {
|
|
495
957
|
const data = [];
|
|
496
958
|
if (!this.jwt) {
|
|
497
|
-
throw new
|
|
959
|
+
throw new SDJWTException("Invalid sd-jwt: jwt is missing");
|
|
498
960
|
}
|
|
499
961
|
const encodedJwt = this.jwt.encodeJwt();
|
|
500
962
|
data.push(encodedJwt);
|
|
501
963
|
if (this.disclosures && this.disclosures.length > 0) {
|
|
502
|
-
const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join(
|
|
964
|
+
const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join(SD_SEPARATOR);
|
|
503
965
|
data.push(encodeddisclosures);
|
|
504
966
|
}
|
|
505
967
|
data.push(this.kbJwt ? this.kbJwt.encodeJwt() : "");
|
|
506
|
-
return data.join(
|
|
968
|
+
return data.join(SD_SEPARATOR);
|
|
507
969
|
}
|
|
508
970
|
keys(hasher) {
|
|
509
971
|
return __async(this, null, function* () {
|
|
@@ -514,9 +976,9 @@ var SDJwt = class _SDJwt {
|
|
|
514
976
|
return __async(this, null, function* () {
|
|
515
977
|
var _a, _b;
|
|
516
978
|
if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
|
|
517
|
-
throw new
|
|
979
|
+
throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
|
|
518
980
|
}
|
|
519
|
-
const { disclosureKeymap } = yield
|
|
981
|
+
const { disclosureKeymap } = yield unpack(
|
|
520
982
|
(_b = this.jwt) == null ? void 0 : _b.payload,
|
|
521
983
|
this.disclosures,
|
|
522
984
|
hasher
|
|
@@ -528,9 +990,9 @@ var SDJwt = class _SDJwt {
|
|
|
528
990
|
return __async(this, null, function* () {
|
|
529
991
|
var _a;
|
|
530
992
|
if (!((_a = this.jwt) == null ? void 0 : _a.payload) || !this.disclosures) {
|
|
531
|
-
throw new
|
|
993
|
+
throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
|
|
532
994
|
}
|
|
533
|
-
const { unpackedObj } = yield
|
|
995
|
+
const { unpackedObj } = yield unpack(
|
|
534
996
|
this.jwt.payload,
|
|
535
997
|
this.disclosures,
|
|
536
998
|
hasher
|
|
@@ -545,8 +1007,9 @@ var listKeys = (obj, prefix = "") => {
|
|
|
545
1007
|
if (obj[key] === void 0) continue;
|
|
546
1008
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
547
1009
|
keys.push(newKey);
|
|
548
|
-
|
|
549
|
-
|
|
1010
|
+
const value = obj[key];
|
|
1011
|
+
if (value && typeof value === "object") {
|
|
1012
|
+
keys.push(...listKeys(value, newKey));
|
|
550
1013
|
}
|
|
551
1014
|
}
|
|
552
1015
|
return keys;
|
|
@@ -559,14 +1022,14 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
559
1022
|
disclosures: []
|
|
560
1023
|
};
|
|
561
1024
|
}
|
|
562
|
-
const sd = (_a = disclosureFrame[
|
|
563
|
-
const decoyCount = (_b = disclosureFrame[
|
|
1025
|
+
const sd = (_a = disclosureFrame[SD_DIGEST]) != null ? _a : [];
|
|
1026
|
+
const decoyCount = (_b = disclosureFrame[SD_DECOY]) != null ? _b : 0;
|
|
564
1027
|
if (Array.isArray(claims)) {
|
|
565
1028
|
const packedClaims2 = [];
|
|
566
1029
|
const disclosures2 = [];
|
|
567
1030
|
const recursivePackedClaims2 = {};
|
|
568
1031
|
for (const key in disclosureFrame) {
|
|
569
|
-
if (key !==
|
|
1032
|
+
if (key !== SD_DIGEST) {
|
|
570
1033
|
const idx = Number.parseInt(key, 10);
|
|
571
1034
|
const packed = yield pack(
|
|
572
1035
|
claims[idx],
|
|
@@ -582,9 +1045,9 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
582
1045
|
const claim = recursivePackedClaims2[i] ? recursivePackedClaims2[i] : claims[i];
|
|
583
1046
|
if (sd.includes(i)) {
|
|
584
1047
|
const salt = yield saltGenerator(16);
|
|
585
|
-
const disclosure = new
|
|
1048
|
+
const disclosure = new Disclosure([salt, claim]);
|
|
586
1049
|
const digest = yield disclosure.digest(hash);
|
|
587
|
-
packedClaims2.push({ [
|
|
1050
|
+
packedClaims2.push({ [SD_LIST_KEY]: digest });
|
|
588
1051
|
disclosures2.push(disclosure);
|
|
589
1052
|
} else {
|
|
590
1053
|
packedClaims2.push(claim);
|
|
@@ -592,7 +1055,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
592
1055
|
}
|
|
593
1056
|
for (let j = 0; j < decoyCount; j++) {
|
|
594
1057
|
const decoyDigest = yield createDecoy(hash, saltGenerator);
|
|
595
|
-
packedClaims2.push({ [
|
|
1058
|
+
packedClaims2.push({ [SD_LIST_KEY]: decoyDigest });
|
|
596
1059
|
}
|
|
597
1060
|
return { packedClaims: packedClaims2, disclosures: disclosures2 };
|
|
598
1061
|
}
|
|
@@ -600,7 +1063,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
600
1063
|
const disclosures = [];
|
|
601
1064
|
const recursivePackedClaims = {};
|
|
602
1065
|
for (const key in disclosureFrame) {
|
|
603
|
-
if (key !==
|
|
1066
|
+
if (key !== SD_DIGEST) {
|
|
604
1067
|
const packed = yield pack(
|
|
605
1068
|
// @ts-expect-error
|
|
606
1069
|
claims[key],
|
|
@@ -617,7 +1080,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
617
1080
|
const claim = recursivePackedClaims[key] ? recursivePackedClaims[key] : claims[key];
|
|
618
1081
|
if (sd.includes(key)) {
|
|
619
1082
|
const salt = yield saltGenerator(16);
|
|
620
|
-
const disclosure = new
|
|
1083
|
+
const disclosure = new Disclosure([salt, key, claim]);
|
|
621
1084
|
const digest = yield disclosure.digest(hash);
|
|
622
1085
|
_sd.push(digest);
|
|
623
1086
|
disclosures.push(disclosure);
|
|
@@ -630,7 +1093,7 @@ var pack = (claims, disclosureFrame, hash, saltGenerator) => __async(null, null,
|
|
|
630
1093
|
_sd.push(decoyDigest);
|
|
631
1094
|
}
|
|
632
1095
|
if (_sd.length > 0) {
|
|
633
|
-
packedClaims[
|
|
1096
|
+
packedClaims[SD_DIGEST] = _sd.sort();
|
|
634
1097
|
}
|
|
635
1098
|
return { packedClaims, disclosures };
|
|
636
1099
|
});
|
|
@@ -640,8 +1103,8 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
640
1103
|
constructor(userConfig) {
|
|
641
1104
|
this.userConfig = {};
|
|
642
1105
|
if (userConfig) {
|
|
643
|
-
if (userConfig.hashAlg && !
|
|
644
|
-
throw new
|
|
1106
|
+
if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
|
|
1107
|
+
throw new SDJWTException(
|
|
645
1108
|
`Invalid hash algorithm: ${userConfig.hashAlg}`
|
|
646
1109
|
);
|
|
647
1110
|
}
|
|
@@ -651,15 +1114,15 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
651
1114
|
createKBJwt(options, sdHash) {
|
|
652
1115
|
return __async(this, null, function* () {
|
|
653
1116
|
if (!this.userConfig.kbSigner) {
|
|
654
|
-
throw new
|
|
1117
|
+
throw new SDJWTException("Key Binding Signer not found");
|
|
655
1118
|
}
|
|
656
1119
|
if (!this.userConfig.kbSignAlg) {
|
|
657
|
-
throw new
|
|
1120
|
+
throw new SDJWTException("Key Binding sign algorithm not specified");
|
|
658
1121
|
}
|
|
659
1122
|
const { payload } = options;
|
|
660
1123
|
const kbJwt = new KBJwt({
|
|
661
1124
|
header: {
|
|
662
|
-
typ:
|
|
1125
|
+
typ: KB_JWT_TYP,
|
|
663
1126
|
alg: this.userConfig.kbSignAlg
|
|
664
1127
|
},
|
|
665
1128
|
payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
|
|
@@ -671,7 +1134,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
671
1134
|
SignJwt(jwt) {
|
|
672
1135
|
return __async(this, null, function* () {
|
|
673
1136
|
if (!this.userConfig.signer) {
|
|
674
|
-
throw new
|
|
1137
|
+
throw new SDJWTException("Signer not found");
|
|
675
1138
|
}
|
|
676
1139
|
yield jwt.sign(this.userConfig.signer);
|
|
677
1140
|
return jwt;
|
|
@@ -680,7 +1143,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
680
1143
|
VerifyJwt(jwt, options) {
|
|
681
1144
|
return __async(this, null, function* () {
|
|
682
1145
|
if (!this.userConfig.verifier) {
|
|
683
|
-
throw new
|
|
1146
|
+
throw new SDJWTException("Verifier not found");
|
|
684
1147
|
}
|
|
685
1148
|
return jwt.verify(this.userConfig.verifier, options);
|
|
686
1149
|
});
|
|
@@ -689,13 +1152,13 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
689
1152
|
return __async(this, null, function* () {
|
|
690
1153
|
var _a, _b;
|
|
691
1154
|
if (!this.userConfig.hasher) {
|
|
692
|
-
throw new
|
|
1155
|
+
throw new SDJWTException("Hasher not found");
|
|
693
1156
|
}
|
|
694
1157
|
if (!this.userConfig.saltGenerator) {
|
|
695
|
-
throw new
|
|
1158
|
+
throw new SDJWTException("SaltGenerator not found");
|
|
696
1159
|
}
|
|
697
1160
|
if (!this.userConfig.signAlg) {
|
|
698
|
-
throw new
|
|
1161
|
+
throw new SDJWTException("sign alogrithm not specified");
|
|
699
1162
|
}
|
|
700
1163
|
if (disclosureFrame) {
|
|
701
1164
|
this.validateReservedFields(disclosureFrame);
|
|
@@ -738,11 +1201,11 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
738
1201
|
return __async(this, null, function* () {
|
|
739
1202
|
var _a;
|
|
740
1203
|
if (!this.userConfig.hasher) {
|
|
741
|
-
throw new
|
|
1204
|
+
throw new SDJWTException("Hasher not found");
|
|
742
1205
|
}
|
|
743
1206
|
const hasher = this.userConfig.hasher;
|
|
744
1207
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
745
|
-
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new
|
|
1208
|
+
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
|
|
746
1209
|
const presentSdJwtWithoutKb = yield sdjwt.present(
|
|
747
1210
|
presentationFrame,
|
|
748
1211
|
hasher
|
|
@@ -765,12 +1228,12 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
765
1228
|
verify(encodedSDJwt, options) {
|
|
766
1229
|
return __async(this, null, function* () {
|
|
767
1230
|
if (!this.userConfig.hasher) {
|
|
768
|
-
throw new
|
|
1231
|
+
throw new SDJWTException("Hasher not found");
|
|
769
1232
|
}
|
|
770
1233
|
const hasher = this.userConfig.hasher;
|
|
771
1234
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
772
1235
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
773
|
-
throw new
|
|
1236
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
774
1237
|
}
|
|
775
1238
|
const { payload, header } = yield this.validate(encodedSDJwt, options);
|
|
776
1239
|
if (options == null ? void 0 : options.requiredClaimKeys) {
|
|
@@ -779,7 +1242,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
779
1242
|
(k) => !keys.includes(k)
|
|
780
1243
|
);
|
|
781
1244
|
if (missingKeys.length > 0) {
|
|
782
|
-
throw new
|
|
1245
|
+
throw new SDJWTException(
|
|
783
1246
|
`Missing required claim keys: ${missingKeys.join(", ")}`
|
|
784
1247
|
);
|
|
785
1248
|
}
|
|
@@ -788,10 +1251,10 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
788
1251
|
return { payload, header };
|
|
789
1252
|
}
|
|
790
1253
|
if (!sdjwt.kbJwt) {
|
|
791
|
-
throw new
|
|
1254
|
+
throw new SDJWTException("Key Binding JWT not exist");
|
|
792
1255
|
}
|
|
793
1256
|
if (!this.userConfig.kbVerifier) {
|
|
794
|
-
throw new
|
|
1257
|
+
throw new SDJWTException("Key Binding Verifier not found");
|
|
795
1258
|
}
|
|
796
1259
|
const kb = yield sdjwt.kbJwt.verifyKB({
|
|
797
1260
|
verifier: this.userConfig.kbVerifier,
|
|
@@ -813,19 +1276,181 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
813
1276
|
hasher
|
|
814
1277
|
);
|
|
815
1278
|
if (sdHashStr !== sdHashfromKb) {
|
|
816
|
-
throw new
|
|
1279
|
+
throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
|
|
817
1280
|
}
|
|
818
1281
|
return { payload, header, kb };
|
|
819
1282
|
});
|
|
820
1283
|
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Safe verification that collects all errors instead of failing fast.
|
|
1286
|
+
* Returns a result object with either the verified data or an array of all errors.
|
|
1287
|
+
*
|
|
1288
|
+
* @param encodedSDJwt - The encoded SD-JWT to verify
|
|
1289
|
+
* @param options - Verification options
|
|
1290
|
+
* @returns A SafeVerifyResult containing either success data or collected errors
|
|
1291
|
+
*/
|
|
1292
|
+
safeVerify(encodedSDJwt, options) {
|
|
1293
|
+
return __async(this, null, function* () {
|
|
1294
|
+
const errors = [];
|
|
1295
|
+
const addError = (code, message, details) => {
|
|
1296
|
+
errors.push({ code, message, details });
|
|
1297
|
+
};
|
|
1298
|
+
const exceptionToCode = (error) => {
|
|
1299
|
+
const message = error.message.toLowerCase();
|
|
1300
|
+
if (message.includes("hasher not found")) return "HASHER_NOT_FOUND";
|
|
1301
|
+
if (message.includes("verifier not found")) return "VERIFIER_NOT_FOUND";
|
|
1302
|
+
if (message.includes("invalid sd jwt") || message.includes("invalid jwt"))
|
|
1303
|
+
return "INVALID_SD_JWT";
|
|
1304
|
+
if (message.includes("not yet valid")) return "JWT_NOT_YET_VALID";
|
|
1305
|
+
if (message.includes("expired")) return "JWT_EXPIRED";
|
|
1306
|
+
if (message.includes("signature")) return "INVALID_JWT_SIGNATURE";
|
|
1307
|
+
if (message.includes("missing required claim"))
|
|
1308
|
+
return "MISSING_REQUIRED_CLAIMS";
|
|
1309
|
+
if (message.includes("key binding jwt not exist"))
|
|
1310
|
+
return "KEY_BINDING_JWT_MISSING";
|
|
1311
|
+
if (message.includes("key binding verifier not found"))
|
|
1312
|
+
return "KEY_BINDING_VERIFIER_NOT_FOUND";
|
|
1313
|
+
if (message.includes("sd_hash")) return "KEY_BINDING_SD_HASH_INVALID";
|
|
1314
|
+
return "UNKNOWN_ERROR";
|
|
1315
|
+
};
|
|
1316
|
+
if (!this.userConfig.hasher) {
|
|
1317
|
+
addError("HASHER_NOT_FOUND", "Hasher not found");
|
|
1318
|
+
}
|
|
1319
|
+
if (!this.userConfig.verifier) {
|
|
1320
|
+
addError("VERIFIER_NOT_FOUND", "Verifier not found");
|
|
1321
|
+
}
|
|
1322
|
+
if (errors.length > 0) {
|
|
1323
|
+
return { success: false, errors };
|
|
1324
|
+
}
|
|
1325
|
+
if (!this.userConfig.hasher) {
|
|
1326
|
+
throw new SDJWTException("Hasher not found");
|
|
1327
|
+
}
|
|
1328
|
+
const hasher = this.userConfig.hasher;
|
|
1329
|
+
let sdjwt;
|
|
1330
|
+
let payload;
|
|
1331
|
+
let header;
|
|
1332
|
+
try {
|
|
1333
|
+
sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1334
|
+
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
1335
|
+
addError("INVALID_SD_JWT", "Invalid SD JWT: missing JWT or payload");
|
|
1336
|
+
}
|
|
1337
|
+
} catch (e) {
|
|
1338
|
+
const error = ensureError(e);
|
|
1339
|
+
addError(
|
|
1340
|
+
"INVALID_SD_JWT",
|
|
1341
|
+
`Failed to decode SD-JWT: ${error.message}`,
|
|
1342
|
+
error
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
if (sdjwt == null ? void 0 : sdjwt.jwt) {
|
|
1346
|
+
try {
|
|
1347
|
+
const result = yield this.VerifyJwt(sdjwt.jwt, options);
|
|
1348
|
+
header = result.header;
|
|
1349
|
+
const claims = yield sdjwt.getClaims(hasher);
|
|
1350
|
+
payload = claims;
|
|
1351
|
+
} catch (e) {
|
|
1352
|
+
const error = ensureError(e);
|
|
1353
|
+
const code = exceptionToCode(error);
|
|
1354
|
+
addError(code, error.message, error);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if (sdjwt && (options == null ? void 0 : options.requiredClaimKeys)) {
|
|
1358
|
+
try {
|
|
1359
|
+
const keys = yield sdjwt.keys(hasher);
|
|
1360
|
+
const missingKeys = options.requiredClaimKeys.filter(
|
|
1361
|
+
(k) => !keys.includes(k)
|
|
1362
|
+
);
|
|
1363
|
+
if (missingKeys.length > 0) {
|
|
1364
|
+
addError(
|
|
1365
|
+
"MISSING_REQUIRED_CLAIMS",
|
|
1366
|
+
`Missing required claim keys: ${missingKeys.join(", ")}`,
|
|
1367
|
+
{ missingKeys }
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
} catch (e) {
|
|
1371
|
+
const error = ensureError(e);
|
|
1372
|
+
addError(
|
|
1373
|
+
"UNKNOWN_ERROR",
|
|
1374
|
+
`Failed to check required claims: ${error.message}`,
|
|
1375
|
+
error
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
let kb;
|
|
1380
|
+
if ((options == null ? void 0 : options.keyBindingNonce) && sdjwt) {
|
|
1381
|
+
if (!sdjwt.kbJwt) {
|
|
1382
|
+
addError("KEY_BINDING_JWT_MISSING", "Key Binding JWT not exist");
|
|
1383
|
+
} else if (!this.userConfig.kbVerifier) {
|
|
1384
|
+
addError(
|
|
1385
|
+
"KEY_BINDING_VERIFIER_NOT_FOUND",
|
|
1386
|
+
"Key Binding Verifier not found"
|
|
1387
|
+
);
|
|
1388
|
+
} else if (payload) {
|
|
1389
|
+
try {
|
|
1390
|
+
const kbResult = yield sdjwt.kbJwt.verifyKB({
|
|
1391
|
+
verifier: this.userConfig.kbVerifier,
|
|
1392
|
+
payload,
|
|
1393
|
+
nonce: options.keyBindingNonce
|
|
1394
|
+
});
|
|
1395
|
+
if (!kbResult) {
|
|
1396
|
+
addError(
|
|
1397
|
+
"KEY_BINDING_SIGNATURE_INVALID",
|
|
1398
|
+
"Key binding signature is not valid"
|
|
1399
|
+
);
|
|
1400
|
+
} else {
|
|
1401
|
+
kb = kbResult;
|
|
1402
|
+
const sdjwtWithoutKb = new SDJwt({
|
|
1403
|
+
jwt: sdjwt.jwt,
|
|
1404
|
+
disclosures: sdjwt.disclosures
|
|
1405
|
+
});
|
|
1406
|
+
const presentSdJwtWithoutKb = sdjwtWithoutKb.encodeSDJwt();
|
|
1407
|
+
const sdHashStr = yield this.calculateSDHash(
|
|
1408
|
+
presentSdJwtWithoutKb,
|
|
1409
|
+
sdjwt,
|
|
1410
|
+
hasher
|
|
1411
|
+
);
|
|
1412
|
+
if (sdHashStr !== kbResult.payload.sd_hash) {
|
|
1413
|
+
addError(
|
|
1414
|
+
"KEY_BINDING_SD_HASH_INVALID",
|
|
1415
|
+
"Invalid sd_hash in Key Binding JWT",
|
|
1416
|
+
{
|
|
1417
|
+
expected: sdHashStr,
|
|
1418
|
+
received: kbResult.payload.sd_hash
|
|
1419
|
+
}
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
} catch (e) {
|
|
1424
|
+
const error = ensureError(e);
|
|
1425
|
+
addError(
|
|
1426
|
+
"KEY_BINDING_SIGNATURE_INVALID",
|
|
1427
|
+
`Key binding verification failed: ${error.message}`,
|
|
1428
|
+
error
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
if (errors.length > 0) {
|
|
1434
|
+
return { success: false, errors };
|
|
1435
|
+
}
|
|
1436
|
+
return {
|
|
1437
|
+
success: true,
|
|
1438
|
+
data: {
|
|
1439
|
+
payload,
|
|
1440
|
+
header,
|
|
1441
|
+
kb
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
821
1446
|
calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
|
|
822
1447
|
return __async(this, null, function* () {
|
|
823
1448
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
824
|
-
throw new
|
|
1449
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
825
1450
|
}
|
|
826
|
-
const { _sd_alg } =
|
|
1451
|
+
const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
|
|
827
1452
|
const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
828
|
-
const sdHashStr = (0,
|
|
1453
|
+
const sdHashStr = (0, import_identity_common.uint8ArrayToBase64Url)(sdHash);
|
|
829
1454
|
return sdHashStr;
|
|
830
1455
|
});
|
|
831
1456
|
}
|
|
@@ -839,12 +1464,12 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
839
1464
|
validate(encodedSDJwt, options) {
|
|
840
1465
|
return __async(this, null, function* () {
|
|
841
1466
|
if (!this.userConfig.hasher) {
|
|
842
|
-
throw new
|
|
1467
|
+
throw new SDJWTException("Hasher not found");
|
|
843
1468
|
}
|
|
844
1469
|
const hasher = this.userConfig.hasher;
|
|
845
1470
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
846
1471
|
if (!sdjwt.jwt) {
|
|
847
|
-
throw new
|
|
1472
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
848
1473
|
}
|
|
849
1474
|
const verifiedPayloads = yield this.VerifyJwt(sdjwt.jwt, options);
|
|
850
1475
|
const claims = yield sdjwt.getClaims(hasher);
|
|
@@ -859,14 +1484,14 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
859
1484
|
}
|
|
860
1485
|
decode(endcodedSDJwt) {
|
|
861
1486
|
if (!this.userConfig.hasher) {
|
|
862
|
-
throw new
|
|
1487
|
+
throw new SDJWTException("Hasher not found");
|
|
863
1488
|
}
|
|
864
1489
|
return SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
865
1490
|
}
|
|
866
1491
|
keys(endcodedSDJwt) {
|
|
867
1492
|
return __async(this, null, function* () {
|
|
868
1493
|
if (!this.userConfig.hasher) {
|
|
869
|
-
throw new
|
|
1494
|
+
throw new SDJWTException("Hasher not found");
|
|
870
1495
|
}
|
|
871
1496
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
872
1497
|
return sdjwt.keys(this.userConfig.hasher);
|
|
@@ -875,7 +1500,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
875
1500
|
presentableKeys(endcodedSDJwt) {
|
|
876
1501
|
return __async(this, null, function* () {
|
|
877
1502
|
if (!this.userConfig.hasher) {
|
|
878
|
-
throw new
|
|
1503
|
+
throw new SDJWTException("Hasher not found");
|
|
879
1504
|
}
|
|
880
1505
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
881
1506
|
return sdjwt.presentableKeys(this.userConfig.hasher);
|
|
@@ -884,7 +1509,7 @@ var _SDJwtInstance = class _SDJwtInstance {
|
|
|
884
1509
|
getClaims(endcodedSDJwt) {
|
|
885
1510
|
return __async(this, null, function* () {
|
|
886
1511
|
if (!this.userConfig.hasher) {
|
|
887
|
-
throw new
|
|
1512
|
+
throw new SDJWTException("Hasher not found");
|
|
888
1513
|
}
|
|
889
1514
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
890
1515
|
return sdjwt.getClaims(this.userConfig.hasher);
|
|
@@ -903,8 +1528,8 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
903
1528
|
constructor(userConfig) {
|
|
904
1529
|
this.userConfig = {};
|
|
905
1530
|
if (userConfig) {
|
|
906
|
-
if (userConfig.hashAlg && !
|
|
907
|
-
throw new
|
|
1531
|
+
if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) {
|
|
1532
|
+
throw new SDJWTException(
|
|
908
1533
|
`Invalid hash algorithm: ${userConfig.hashAlg}`
|
|
909
1534
|
);
|
|
910
1535
|
}
|
|
@@ -914,15 +1539,15 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
914
1539
|
createKBJwt(options, sdHash) {
|
|
915
1540
|
return __async(this, null, function* () {
|
|
916
1541
|
if (!this.userConfig.kbSigner) {
|
|
917
|
-
throw new
|
|
1542
|
+
throw new SDJWTException("Key Binding Signer not found");
|
|
918
1543
|
}
|
|
919
1544
|
if (!this.userConfig.kbSignAlg) {
|
|
920
|
-
throw new
|
|
1545
|
+
throw new SDJWTException("Key Binding sign algorithm not specified");
|
|
921
1546
|
}
|
|
922
1547
|
const { payload } = options;
|
|
923
1548
|
const kbJwt = new KBJwt({
|
|
924
1549
|
header: {
|
|
925
|
-
typ:
|
|
1550
|
+
typ: KB_JWT_TYP,
|
|
926
1551
|
alg: this.userConfig.kbSignAlg
|
|
927
1552
|
},
|
|
928
1553
|
payload: __spreadProps(__spreadValues({}, payload), { sd_hash: sdHash })
|
|
@@ -932,16 +1557,16 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
932
1557
|
});
|
|
933
1558
|
}
|
|
934
1559
|
encodeObj(obj) {
|
|
935
|
-
return (0,
|
|
1560
|
+
return (0, import_identity_common.base64urlEncode)(JSON.stringify(obj));
|
|
936
1561
|
}
|
|
937
1562
|
issue(payload, disclosureFrame, options) {
|
|
938
1563
|
return __async(this, null, function* () {
|
|
939
1564
|
var _a;
|
|
940
1565
|
if (!this.userConfig.hasher) {
|
|
941
|
-
throw new
|
|
1566
|
+
throw new SDJWTException("Hasher not found");
|
|
942
1567
|
}
|
|
943
1568
|
if (!this.userConfig.saltGenerator) {
|
|
944
|
-
throw new
|
|
1569
|
+
throw new SDJWTException("SaltGenerator not found");
|
|
945
1570
|
}
|
|
946
1571
|
if (disclosureFrame) {
|
|
947
1572
|
this.validateReservedFields(disclosureFrame);
|
|
@@ -993,12 +1618,12 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
993
1618
|
return __async(this, null, function* () {
|
|
994
1619
|
var _a;
|
|
995
1620
|
if (!this.userConfig.hasher) {
|
|
996
|
-
throw new
|
|
1621
|
+
throw new SDJWTException("Hasher not found");
|
|
997
1622
|
}
|
|
998
1623
|
const hasher = this.userConfig.hasher;
|
|
999
1624
|
const encodedSDJwt = generalJSON.toEncoded(0);
|
|
1000
1625
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1001
|
-
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new
|
|
1626
|
+
if (!((_a = sdjwt.jwt) == null ? void 0 : _a.payload)) throw new SDJWTException("Payload not found");
|
|
1002
1627
|
const disclosures = yield sdjwt.getPresentDisclosures(
|
|
1003
1628
|
presentationFrame,
|
|
1004
1629
|
hasher
|
|
@@ -1033,14 +1658,14 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1033
1658
|
verify(generalJSON, options) {
|
|
1034
1659
|
return __async(this, null, function* () {
|
|
1035
1660
|
if (!this.userConfig.hasher) {
|
|
1036
|
-
throw new
|
|
1661
|
+
throw new SDJWTException("Hasher not found");
|
|
1037
1662
|
}
|
|
1038
1663
|
const hasher = this.userConfig.hasher;
|
|
1039
1664
|
const { payload, headers } = yield this.validate(generalJSON);
|
|
1040
1665
|
const encodedSDJwt = generalJSON.toEncoded(0);
|
|
1041
1666
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1042
1667
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
1043
|
-
throw new
|
|
1668
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
1044
1669
|
}
|
|
1045
1670
|
if (options == null ? void 0 : options.requiredClaimKeys) {
|
|
1046
1671
|
const keys = yield sdjwt.keys(hasher);
|
|
@@ -1048,7 +1673,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1048
1673
|
(k) => !keys.includes(k)
|
|
1049
1674
|
);
|
|
1050
1675
|
if (missingKeys.length > 0) {
|
|
1051
|
-
throw new
|
|
1676
|
+
throw new SDJWTException(
|
|
1052
1677
|
`Missing required claim keys: ${missingKeys.join(", ")}`
|
|
1053
1678
|
);
|
|
1054
1679
|
}
|
|
@@ -1057,10 +1682,10 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1057
1682
|
return { payload, headers };
|
|
1058
1683
|
}
|
|
1059
1684
|
if (!sdjwt.kbJwt) {
|
|
1060
|
-
throw new
|
|
1685
|
+
throw new SDJWTException("Key Binding JWT not exist");
|
|
1061
1686
|
}
|
|
1062
1687
|
if (!this.userConfig.kbVerifier) {
|
|
1063
|
-
throw new
|
|
1688
|
+
throw new SDJWTException("Key Binding Verifier not found");
|
|
1064
1689
|
}
|
|
1065
1690
|
const kb = yield sdjwt.kbJwt.verifyKB({
|
|
1066
1691
|
verifier: this.userConfig.kbVerifier,
|
|
@@ -1082,7 +1707,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1082
1707
|
hasher
|
|
1083
1708
|
);
|
|
1084
1709
|
if (sdHashStr !== sdHashfromKb) {
|
|
1085
|
-
throw new
|
|
1710
|
+
throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
|
|
1086
1711
|
}
|
|
1087
1712
|
return { payload, headers, kb };
|
|
1088
1713
|
});
|
|
@@ -1090,11 +1715,11 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1090
1715
|
calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
|
|
1091
1716
|
return __async(this, null, function* () {
|
|
1092
1717
|
if (!sdjwt.jwt || !sdjwt.jwt.payload) {
|
|
1093
|
-
throw new
|
|
1718
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
1094
1719
|
}
|
|
1095
|
-
const { _sd_alg } =
|
|
1720
|
+
const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
|
|
1096
1721
|
const sdHash = yield hasher(presentSdJwtWithoutKb, _sd_alg);
|
|
1097
|
-
const sdHashStr = (0,
|
|
1722
|
+
const sdHashStr = (0, import_identity_common.uint8ArrayToBase64Url)(sdHash);
|
|
1098
1723
|
return sdHashStr;
|
|
1099
1724
|
});
|
|
1100
1725
|
}
|
|
@@ -1103,10 +1728,10 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1103
1728
|
validate(generalJSON) {
|
|
1104
1729
|
return __async(this, null, function* () {
|
|
1105
1730
|
if (!this.userConfig.hasher) {
|
|
1106
|
-
throw new
|
|
1731
|
+
throw new SDJWTException("Hasher not found");
|
|
1107
1732
|
}
|
|
1108
1733
|
if (!this.userConfig.verifier) {
|
|
1109
|
-
throw new
|
|
1734
|
+
throw new SDJWTException("Verifier not found");
|
|
1110
1735
|
}
|
|
1111
1736
|
const hasher = this.userConfig.hasher;
|
|
1112
1737
|
const verifier = this.userConfig.verifier;
|
|
@@ -1118,18 +1743,18 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1118
1743
|
`${encodedHeader}.${payload}`,
|
|
1119
1744
|
signature
|
|
1120
1745
|
);
|
|
1121
|
-
const header = JSON.parse((0,
|
|
1746
|
+
const header = JSON.parse((0, import_identity_common.base64urlDecode)(encodedHeader));
|
|
1122
1747
|
return { verified: verified2, header };
|
|
1123
1748
|
}))
|
|
1124
1749
|
);
|
|
1125
1750
|
const verified = results.every((r) => r.verified);
|
|
1126
1751
|
if (!verified) {
|
|
1127
|
-
throw new
|
|
1752
|
+
throw new SDJWTException("Signature is not valid");
|
|
1128
1753
|
}
|
|
1129
1754
|
const encodedSDJwt = generalJSON.toEncoded(0);
|
|
1130
1755
|
const sdjwt = yield SDJwt.fromEncode(encodedSDJwt, hasher);
|
|
1131
1756
|
if (!sdjwt.jwt) {
|
|
1132
|
-
throw new
|
|
1757
|
+
throw new SDJWTException("Invalid SD JWT");
|
|
1133
1758
|
}
|
|
1134
1759
|
const claims = yield sdjwt.getClaims(hasher);
|
|
1135
1760
|
return { payload: claims, headers: results.map((r) => r.header) };
|
|
@@ -1147,7 +1772,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1147
1772
|
keys(generalSdjwt) {
|
|
1148
1773
|
return __async(this, null, function* () {
|
|
1149
1774
|
if (!this.userConfig.hasher) {
|
|
1150
|
-
throw new
|
|
1775
|
+
throw new SDJWTException("Hasher not found");
|
|
1151
1776
|
}
|
|
1152
1777
|
const endcodedSDJwt = generalSdjwt.toEncoded(0);
|
|
1153
1778
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
@@ -1157,7 +1782,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1157
1782
|
presentableKeys(generalSdjwt) {
|
|
1158
1783
|
return __async(this, null, function* () {
|
|
1159
1784
|
if (!this.userConfig.hasher) {
|
|
1160
|
-
throw new
|
|
1785
|
+
throw new SDJWTException("Hasher not found");
|
|
1161
1786
|
}
|
|
1162
1787
|
const endcodedSDJwt = generalSdjwt.toEncoded(0);
|
|
1163
1788
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
@@ -1167,7 +1792,7 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1167
1792
|
getClaims(generalSdjwt) {
|
|
1168
1793
|
return __async(this, null, function* () {
|
|
1169
1794
|
if (!this.userConfig.hasher) {
|
|
1170
|
-
throw new
|
|
1795
|
+
throw new SDJWTException("Hasher not found");
|
|
1171
1796
|
}
|
|
1172
1797
|
const endcodedSDJwt = generalSdjwt.toEncoded(0);
|
|
1173
1798
|
const sdjwt = yield SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
|
|
@@ -1178,14 +1803,46 @@ var SDJwtGeneralJSONInstance = class {
|
|
|
1178
1803
|
SDJwtGeneralJSONInstance.DEFAULT_hashAlg = "sha-256";
|
|
1179
1804
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1180
1805
|
0 && (module.exports = {
|
|
1806
|
+
Disclosure,
|
|
1181
1807
|
FlattenJSON,
|
|
1182
1808
|
GeneralJSON,
|
|
1809
|
+
IANA_HASH_ALGORITHMS,
|
|
1183
1810
|
Jwt,
|
|
1184
1811
|
KBJwt,
|
|
1812
|
+
KB_JWT_TYP,
|
|
1813
|
+
SDJWTException,
|
|
1185
1814
|
SDJwt,
|
|
1186
1815
|
SDJwtGeneralJSONInstance,
|
|
1187
1816
|
SDJwtInstance,
|
|
1817
|
+
SD_DECOY,
|
|
1818
|
+
SD_DIGEST,
|
|
1819
|
+
SD_LIST_KEY,
|
|
1820
|
+
SD_SEPARATOR,
|
|
1821
|
+
base64UrlToUint8Array,
|
|
1822
|
+
base64urlDecode,
|
|
1823
|
+
base64urlEncode,
|
|
1188
1824
|
createDecoy,
|
|
1825
|
+
createHashMapping,
|
|
1826
|
+
createHashMappingForSerializedDisclosure,
|
|
1827
|
+
createHashMappingSync,
|
|
1828
|
+
decodeJwt,
|
|
1829
|
+
decodeSdJwt,
|
|
1830
|
+
decodeSdJwtSync,
|
|
1831
|
+
ensureError,
|
|
1832
|
+
getClaims,
|
|
1833
|
+
getClaimsSync,
|
|
1834
|
+
getSDAlgAndPayload,
|
|
1189
1835
|
listKeys,
|
|
1190
|
-
pack
|
|
1836
|
+
pack,
|
|
1837
|
+
present,
|
|
1838
|
+
presentSync,
|
|
1839
|
+
presentableKeys,
|
|
1840
|
+
presentableKeysSync,
|
|
1841
|
+
selectDisclosures,
|
|
1842
|
+
splitSdJwt,
|
|
1843
|
+
transformPresentationFrame,
|
|
1844
|
+
uint8ArrayToBase64Url,
|
|
1845
|
+
unpack,
|
|
1846
|
+
unpackObj,
|
|
1847
|
+
unpackSync
|
|
1191
1848
|
});
|