@owf/eudi-jades 0.1.0
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 +199 -0
- package/dist/index.d.mts +1001 -0
- package/dist/index.mjs +924 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,924 @@
|
|
|
1
|
+
import { base64urlDecode, base64urlEncode } from "@owf/identity-common";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { parseCertificateChain } from "@owf/crypto";
|
|
4
|
+
//#region src/constants.ts
|
|
5
|
+
/**
|
|
6
|
+
* JAdES Constants
|
|
7
|
+
*
|
|
8
|
+
* Algorithm definitions and OIDs as per ETSI TS 119 182-1.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Supported signature algorithms with their hash algorithms.
|
|
12
|
+
*/
|
|
13
|
+
const ALGORITHMS = {
|
|
14
|
+
RS256: {
|
|
15
|
+
hash: "SHA-256",
|
|
16
|
+
family: "RSA"
|
|
17
|
+
},
|
|
18
|
+
RS384: {
|
|
19
|
+
hash: "SHA-384",
|
|
20
|
+
family: "RSA"
|
|
21
|
+
},
|
|
22
|
+
RS512: {
|
|
23
|
+
hash: "SHA-512",
|
|
24
|
+
family: "RSA"
|
|
25
|
+
},
|
|
26
|
+
PS256: {
|
|
27
|
+
hash: "SHA-256",
|
|
28
|
+
family: "RSA-PSS"
|
|
29
|
+
},
|
|
30
|
+
PS384: {
|
|
31
|
+
hash: "SHA-384",
|
|
32
|
+
family: "RSA-PSS"
|
|
33
|
+
},
|
|
34
|
+
PS512: {
|
|
35
|
+
hash: "SHA-512",
|
|
36
|
+
family: "RSA-PSS"
|
|
37
|
+
},
|
|
38
|
+
ES256: {
|
|
39
|
+
hash: "SHA-256",
|
|
40
|
+
family: "ECDSA",
|
|
41
|
+
namedCurve: "P-256"
|
|
42
|
+
},
|
|
43
|
+
ES384: {
|
|
44
|
+
hash: "SHA-384",
|
|
45
|
+
family: "ECDSA",
|
|
46
|
+
namedCurve: "P-384"
|
|
47
|
+
},
|
|
48
|
+
ES512: {
|
|
49
|
+
hash: "SHA-512",
|
|
50
|
+
family: "ECDSA",
|
|
51
|
+
namedCurve: "P-521"
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Commitment type OIDs as per RFC 5035.
|
|
56
|
+
*/
|
|
57
|
+
let CommitmentOIDs = /* @__PURE__ */ function(CommitmentOIDs) {
|
|
58
|
+
/** Proof of origin */
|
|
59
|
+
CommitmentOIDs["proofOfOrigin"] = "1.2.840.113549.1.9.16.6.1";
|
|
60
|
+
/** Proof of receipt */
|
|
61
|
+
CommitmentOIDs["proofOfReceipt"] = "1.2.840.113549.1.9.16.6.2";
|
|
62
|
+
/** Proof of delivery */
|
|
63
|
+
CommitmentOIDs["proofOfDelivery"] = "1.2.840.113549.1.9.16.6.3";
|
|
64
|
+
/** Proof of sender */
|
|
65
|
+
CommitmentOIDs["proofOfSender"] = "1.2.840.113549.1.9.16.6.4";
|
|
66
|
+
/** Proof of approval */
|
|
67
|
+
CommitmentOIDs["proofOfApproval"] = "1.2.840.113549.1.9.16.6.5";
|
|
68
|
+
/** Proof of creation */
|
|
69
|
+
CommitmentOIDs["proofOfCreation"] = "1.2.840.113549.1.9.16.6.6";
|
|
70
|
+
return CommitmentOIDs;
|
|
71
|
+
}({});
|
|
72
|
+
/**
|
|
73
|
+
* JAdES baseline profiles as per ETSI TS 119 182-1.
|
|
74
|
+
*/
|
|
75
|
+
let JAdESProfile = /* @__PURE__ */ function(JAdESProfile) {
|
|
76
|
+
/** Basic - Baseline: basic signature format */
|
|
77
|
+
JAdESProfile["B_B"] = "B-B";
|
|
78
|
+
/** Basic with Time: signatures with timestamp */
|
|
79
|
+
JAdESProfile["B_T"] = "B-T";
|
|
80
|
+
/** Basic Long-Term: signatures with validation data for long-term preservation */
|
|
81
|
+
JAdESProfile["B_LT"] = "B-LT";
|
|
82
|
+
/** Basic Long-Term with Archive timestamps */
|
|
83
|
+
JAdESProfile["B_LTA"] = "B-LTA";
|
|
84
|
+
return JAdESProfile;
|
|
85
|
+
}({});
|
|
86
|
+
/**
|
|
87
|
+
* Detached signature mechanism identifiers as per ETSI TS 119 182-1 Section 5.2.8.
|
|
88
|
+
*/
|
|
89
|
+
const DETACHED_MECHANISM_IDS = {
|
|
90
|
+
httpHeaders: "http://uri.etsi.org/19182/HttpHeaders",
|
|
91
|
+
objectDigest: "http://uri.etsi.org/19182/ObjectIdByURIHash"
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Critical header parameters that must be understood.
|
|
95
|
+
* ETSI TS 119 182-1 specifies these parameters as critical.
|
|
96
|
+
*/
|
|
97
|
+
const CRITICAL_PARAMETERS = [
|
|
98
|
+
"x5t#o",
|
|
99
|
+
"sigX5ts",
|
|
100
|
+
"sigT",
|
|
101
|
+
"sigD",
|
|
102
|
+
"sigPl",
|
|
103
|
+
"sigPId",
|
|
104
|
+
"srCms",
|
|
105
|
+
"srAts",
|
|
106
|
+
"adoTst",
|
|
107
|
+
"b64"
|
|
108
|
+
];
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/jades-exception.ts
|
|
111
|
+
/**
|
|
112
|
+
* JAdES Exception
|
|
113
|
+
*
|
|
114
|
+
* Custom exception for JAdES-related errors.
|
|
115
|
+
*/
|
|
116
|
+
var JAdESException = class JAdESException extends Error {
|
|
117
|
+
constructor(message) {
|
|
118
|
+
super(message);
|
|
119
|
+
this.name = "JAdESException";
|
|
120
|
+
Object.setPrototypeOf(this, JAdESException.prototype);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/schemas.ts
|
|
125
|
+
/**
|
|
126
|
+
* JAdES Zod Schemas
|
|
127
|
+
*
|
|
128
|
+
* Zod schemas for JAdES (JSON Advanced Electronic Signatures) as per ETSI TS 119 182-1.
|
|
129
|
+
* Types are derived from these schemas via z.infer<>.
|
|
130
|
+
*
|
|
131
|
+
* @see https://www.etsi.org/deliver/etsi_ts/119100_119199/11918201/01.02.01_60/ts_11918201v010201p.pdf
|
|
132
|
+
*/
|
|
133
|
+
/**
|
|
134
|
+
* Supported signature algorithms.
|
|
135
|
+
*/
|
|
136
|
+
const SignAlgSchema = z.enum([
|
|
137
|
+
"ES256",
|
|
138
|
+
"ES384",
|
|
139
|
+
"ES512",
|
|
140
|
+
"RS256",
|
|
141
|
+
"RS384",
|
|
142
|
+
"RS512",
|
|
143
|
+
"PS256",
|
|
144
|
+
"PS384",
|
|
145
|
+
"PS512"
|
|
146
|
+
]);
|
|
147
|
+
/**
|
|
148
|
+
* X.509 Certificate Thumbprint with algorithm specification.
|
|
149
|
+
* ETSI TS 119 182-1 Section 5.2.2.2
|
|
150
|
+
*/
|
|
151
|
+
const X5tOSchema = z.object({
|
|
152
|
+
digAlg: z.string().min(1),
|
|
153
|
+
digVal: z.string().min(1)
|
|
154
|
+
});
|
|
155
|
+
/**
|
|
156
|
+
* Commitment reference as per ETSI TS 119 182-1 Section 5.2.5.
|
|
157
|
+
*/
|
|
158
|
+
const CommitmentReferenceSchema = z.object({
|
|
159
|
+
commId: z.string().min(1),
|
|
160
|
+
commQuals: z.array(z.object({}).passthrough()).optional()
|
|
161
|
+
});
|
|
162
|
+
/**
|
|
163
|
+
* Signature policy hash.
|
|
164
|
+
*/
|
|
165
|
+
const SignaturePolicyHashSchema = z.object({
|
|
166
|
+
hashAlgo: z.string().min(1),
|
|
167
|
+
hashVal: z.string().min(1)
|
|
168
|
+
});
|
|
169
|
+
/**
|
|
170
|
+
* Signature policy descriptor.
|
|
171
|
+
* ETSI TS 119 182-1 Section 5.2.4
|
|
172
|
+
*/
|
|
173
|
+
const SignaturePolicySchema = z.object({
|
|
174
|
+
sigPolicyId: z.string().optional(),
|
|
175
|
+
sigPolicyHash: SignaturePolicyHashSchema.optional(),
|
|
176
|
+
sigPolicyQualifiers: z.array(z.object({}).passthrough()).optional()
|
|
177
|
+
});
|
|
178
|
+
/**
|
|
179
|
+
* Issuer and serial number for signer identification.
|
|
180
|
+
*/
|
|
181
|
+
const IssuerSerialSchema = z.object({
|
|
182
|
+
issuer: z.string().min(1),
|
|
183
|
+
serialNumber: z.string().min(1)
|
|
184
|
+
});
|
|
185
|
+
/**
|
|
186
|
+
* Signer identifier.
|
|
187
|
+
* ETSI TS 119 182-1 Section 5.2.3
|
|
188
|
+
*/
|
|
189
|
+
const SignerIdentifierSchema = z.object({
|
|
190
|
+
issuerSerial: IssuerSerialSchema.optional(),
|
|
191
|
+
subjectKeyIdentifier: z.string().optional()
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* Detached signature descriptor.
|
|
195
|
+
* ETSI TS 119 182-1 Section 5.2.8
|
|
196
|
+
*/
|
|
197
|
+
const SigDSchema = z.object({
|
|
198
|
+
mId: z.string().min(1),
|
|
199
|
+
pars: z.tuple([z.string(), z.string()]),
|
|
200
|
+
hashM: z.string().optional(),
|
|
201
|
+
ctM: z.string().optional()
|
|
202
|
+
});
|
|
203
|
+
/**
|
|
204
|
+
* Timestamp token value.
|
|
205
|
+
*/
|
|
206
|
+
const TstTokenValueSchema = z.object({ val: z.string().min(1) });
|
|
207
|
+
/**
|
|
208
|
+
* Timestamp tokens container.
|
|
209
|
+
*/
|
|
210
|
+
const TstTokensSchema = z.object({ tstTokens: z.array(TstTokenValueSchema).min(1) });
|
|
211
|
+
/**
|
|
212
|
+
* Signature timestamp container (for B-T profile).
|
|
213
|
+
*/
|
|
214
|
+
const SigTstSchema = z.object({ sigTst: TstTokensSchema });
|
|
215
|
+
/**
|
|
216
|
+
* X.509 certificate values (for B-LT profile).
|
|
217
|
+
*/
|
|
218
|
+
const XValsSchema = z.object({ xVals: z.array(z.object({ x509Cert: z.string().min(1) })) });
|
|
219
|
+
/**
|
|
220
|
+
* Revocation values (for B-LT profile).
|
|
221
|
+
*/
|
|
222
|
+
const RValsSchema = z.object({ rVals: z.object({
|
|
223
|
+
crlVals: z.array(z.string()),
|
|
224
|
+
ocspVals: z.array(z.string())
|
|
225
|
+
}) });
|
|
226
|
+
/**
|
|
227
|
+
* Archive timestamp (for B-LTA profile).
|
|
228
|
+
*/
|
|
229
|
+
const ArcTstSchema = z.object({ arcTst: TstTokensSchema.extend({ canonAlg: z.string().optional() }) });
|
|
230
|
+
/**
|
|
231
|
+
* ETSI Unsigned properties for different JAdES profiles.
|
|
232
|
+
*/
|
|
233
|
+
const EtsiUSchema = z.union([
|
|
234
|
+
z.array(SigTstSchema),
|
|
235
|
+
z.tuple([
|
|
236
|
+
SigTstSchema,
|
|
237
|
+
XValsSchema,
|
|
238
|
+
RValsSchema
|
|
239
|
+
]),
|
|
240
|
+
z.tuple([
|
|
241
|
+
SigTstSchema,
|
|
242
|
+
XValsSchema,
|
|
243
|
+
RValsSchema,
|
|
244
|
+
ArcTstSchema
|
|
245
|
+
])
|
|
246
|
+
]);
|
|
247
|
+
/**
|
|
248
|
+
* JAdES Protected Header parameters as per ETSI TS 119 182-1.
|
|
249
|
+
*/
|
|
250
|
+
const ProtectedHeaderSchema = z.object({
|
|
251
|
+
alg: SignAlgSchema.optional(),
|
|
252
|
+
cty: z.string().optional(),
|
|
253
|
+
kid: z.string().optional(),
|
|
254
|
+
x5u: z.string().url().optional(),
|
|
255
|
+
x5c: z.array(z.string().min(1)).min(1).optional(),
|
|
256
|
+
"x5t#S256": z.string().min(1).optional(),
|
|
257
|
+
"x5t#o": X5tOSchema.optional(),
|
|
258
|
+
sigX5ts: z.array(X5tOSchema).min(2).optional(),
|
|
259
|
+
srCms: z.array(CommitmentReferenceSchema).optional(),
|
|
260
|
+
srAts: z.array(z.object({}).passthrough()).optional(),
|
|
261
|
+
sigPl: SignaturePolicySchema.optional(),
|
|
262
|
+
sigPId: SignerIdentifierSchema.optional(),
|
|
263
|
+
sigT: z.string().optional(),
|
|
264
|
+
sigD: SigDSchema.optional(),
|
|
265
|
+
b64: z.literal(false).optional(),
|
|
266
|
+
crit: z.array(z.string()).optional(),
|
|
267
|
+
iat: z.number().int().positive().optional(),
|
|
268
|
+
signedAt: z.number().int().positive().optional(),
|
|
269
|
+
jti: z.string().optional(),
|
|
270
|
+
typ: z.string().optional(),
|
|
271
|
+
adoTst: z.array(z.object({}).passthrough()).optional()
|
|
272
|
+
}).passthrough();
|
|
273
|
+
/**
|
|
274
|
+
* Protected header schema for signing (alg required).
|
|
275
|
+
*/
|
|
276
|
+
const ProtectedHeaderForSigningSchema = ProtectedHeaderSchema.extend({ alg: SignAlgSchema }).refine((header) => {
|
|
277
|
+
return !!(header["x5t#S256"] || header.x5c || header["x5t#o"] || header.sigX5ts);
|
|
278
|
+
}, { message: "JAdES signature requires at least one certificate header: x5t#S256, x5c, x5t#o, or sigX5ts" });
|
|
279
|
+
/**
|
|
280
|
+
* JAdES Unprotected Header parameters.
|
|
281
|
+
*/
|
|
282
|
+
const UnprotectedHeaderSchema = z.object({
|
|
283
|
+
etsiU: EtsiUSchema.optional(),
|
|
284
|
+
disclosures: z.array(z.string()).optional(),
|
|
285
|
+
kid: z.string().optional(),
|
|
286
|
+
kb_jwt: z.string().optional()
|
|
287
|
+
}).passthrough();
|
|
288
|
+
/**
|
|
289
|
+
* Signature entry in General JWS.
|
|
290
|
+
*/
|
|
291
|
+
const JWSSignatureSchema = z.object({
|
|
292
|
+
protected: z.string().min(1),
|
|
293
|
+
signature: z.string().min(1),
|
|
294
|
+
header: UnprotectedHeaderSchema.optional()
|
|
295
|
+
});
|
|
296
|
+
/**
|
|
297
|
+
* General JWS structure with multiple signatures.
|
|
298
|
+
*/
|
|
299
|
+
const GeneralJWSSchema = z.object({
|
|
300
|
+
payload: z.string(),
|
|
301
|
+
signatures: z.array(JWSSignatureSchema).min(1)
|
|
302
|
+
});
|
|
303
|
+
/**
|
|
304
|
+
* Flattened JWS structure (single signature).
|
|
305
|
+
*/
|
|
306
|
+
const FlattenedJWSSchema = z.object({
|
|
307
|
+
protected: z.string().min(1),
|
|
308
|
+
payload: z.string(),
|
|
309
|
+
signature: z.string().min(1),
|
|
310
|
+
header: UnprotectedHeaderSchema.optional()
|
|
311
|
+
});
|
|
312
|
+
/**
|
|
313
|
+
* Compact JWS representation.
|
|
314
|
+
*/
|
|
315
|
+
const CompactJWSSchema = z.object({
|
|
316
|
+
protected: z.string().min(1),
|
|
317
|
+
payload: z.string(),
|
|
318
|
+
signature: z.string().min(1)
|
|
319
|
+
});
|
|
320
|
+
/**
|
|
321
|
+
* Sign options for JAdES signing.
|
|
322
|
+
*/
|
|
323
|
+
const SignOptionsSchema = z.object({
|
|
324
|
+
alg: SignAlgSchema,
|
|
325
|
+
kid: z.string().optional(),
|
|
326
|
+
certificates: z.array(z.string()).optional()
|
|
327
|
+
});
|
|
328
|
+
z.object({ skipSignatureValidation: z.boolean().optional() });
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/utils.ts
|
|
331
|
+
/**
|
|
332
|
+
* JAdES Utility Functions
|
|
333
|
+
*
|
|
334
|
+
* Helper functions for certificate handling and header generation.
|
|
335
|
+
*/
|
|
336
|
+
/**
|
|
337
|
+
* Parse PEM-encoded certificate chain and return base64 DER strings.
|
|
338
|
+
*
|
|
339
|
+
* @param pem - One or more PEM-encoded certificates
|
|
340
|
+
* @returns Array of base64-encoded DER certificate strings
|
|
341
|
+
*/
|
|
342
|
+
function parseCerts(pem) {
|
|
343
|
+
return parseCertificateChain(pem);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Generate x5c header value from PEM certificates.
|
|
347
|
+
* The certificates are converted to base64-encoded DER format.
|
|
348
|
+
*
|
|
349
|
+
* ETSI TS 119 182-1 Section 5.1.8
|
|
350
|
+
*
|
|
351
|
+
* @param certs - PEM-encoded certificate(s) or array of base64 DER certs
|
|
352
|
+
* @returns Array of base64-encoded DER certificate strings
|
|
353
|
+
*/
|
|
354
|
+
function generateX5c(certs) {
|
|
355
|
+
if (typeof certs === "string") return parseCertificateChain(certs);
|
|
356
|
+
return certs;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Generate x5t#S256 header value (SHA-256 thumbprint of certificate).
|
|
360
|
+
*
|
|
361
|
+
* ETSI TS 119 182-1 Section 5.1.7
|
|
362
|
+
*
|
|
363
|
+
* @param certDer - Base64-encoded DER certificate
|
|
364
|
+
* @returns Base64url-encoded SHA-256 thumbprint
|
|
365
|
+
*/
|
|
366
|
+
async function generateX5tS256(certDer) {
|
|
367
|
+
const certBytes = base64ToUint8Array(certDer);
|
|
368
|
+
const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", certBytes);
|
|
369
|
+
return uint8ArrayToBase64Url(new Uint8Array(hashBuffer));
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Generate x5t#o header value (certificate thumbprint with specified algorithm).
|
|
373
|
+
*
|
|
374
|
+
* ETSI TS 119 182-1 Section 5.2.2.2
|
|
375
|
+
*
|
|
376
|
+
* @param certDer - Base64-encoded DER certificate
|
|
377
|
+
* @param algorithm - Hash algorithm ('SHA-384' or 'SHA-512')
|
|
378
|
+
* @returns X5tO object with algorithm identifier and digest value
|
|
379
|
+
*/
|
|
380
|
+
async function generateX5tO(certDer, algorithm = "SHA-512") {
|
|
381
|
+
const algMap = {
|
|
382
|
+
"SHA-384": "S384",
|
|
383
|
+
"SHA-512": "S512"
|
|
384
|
+
};
|
|
385
|
+
const certBytes = base64ToUint8Array(certDer);
|
|
386
|
+
const hashBuffer = await globalThis.crypto.subtle.digest(algorithm, certBytes);
|
|
387
|
+
return {
|
|
388
|
+
digAlg: algMap[algorithm],
|
|
389
|
+
digVal: uint8ArrayToBase64Url(new Uint8Array(hashBuffer))
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Generate sigX5ts header value (certificate chain thumbprints).
|
|
394
|
+
*
|
|
395
|
+
* ETSI TS 119 182-1 Section 5.2.2.3
|
|
396
|
+
*
|
|
397
|
+
* @param certsDer - Array of base64-encoded DER certificates
|
|
398
|
+
* @param algorithm - Hash algorithm ('SHA-384' or 'SHA-512')
|
|
399
|
+
* @returns Array of X5tO objects
|
|
400
|
+
*/
|
|
401
|
+
async function generateSigX5ts(certsDer, algorithm = "SHA-512") {
|
|
402
|
+
if (certsDer.length < 2) throw new JAdESException("sigX5ts requires at least 2 certificates");
|
|
403
|
+
return Promise.all(certsDer.map((cert) => generateX5tO(cert, algorithm)));
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Generate a JAdES-compliant kid from X.509 certificate.
|
|
407
|
+
*
|
|
408
|
+
* According to ETSI TS 119 182-1 Section 5.1.4, the kid should be
|
|
409
|
+
* the base64 encoding of DER-encoded IssuerSerial sequence.
|
|
410
|
+
*
|
|
411
|
+
* This implementation generates a SHA-256 thumbprint of the certificate
|
|
412
|
+
* as a simpler approach that uniquely identifies the certificate.
|
|
413
|
+
*
|
|
414
|
+
* @param certDer - Base64-encoded DER certificate
|
|
415
|
+
* @returns Base64url-encoded key identifier
|
|
416
|
+
*/
|
|
417
|
+
async function generateKid(certDer) {
|
|
418
|
+
return generateX5tS256(certDer);
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Encode an object as a base64url JSON string.
|
|
422
|
+
*
|
|
423
|
+
* @param obj - Object to encode
|
|
424
|
+
* @returns Base64url-encoded JSON string
|
|
425
|
+
*/
|
|
426
|
+
function encodeJSON(obj) {
|
|
427
|
+
return base64urlEncode(JSON.stringify(obj));
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Decode a base64url JSON string to an object.
|
|
431
|
+
*
|
|
432
|
+
* @param encoded - Base64url-encoded JSON string
|
|
433
|
+
* @returns Decoded object
|
|
434
|
+
*/
|
|
435
|
+
function decodeJSON(encoded) {
|
|
436
|
+
return JSON.parse(base64urlDecode(encoded));
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get current ISO 8601 timestamp for sigT header.
|
|
440
|
+
*
|
|
441
|
+
* @returns ISO 8601 timestamp string
|
|
442
|
+
*/
|
|
443
|
+
function getSigningTime() {
|
|
444
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Validate that the protected header has at least one certificate header.
|
|
448
|
+
* As per ETSI TS 119 182-1 Section 5.1.7, a JAdES signature shall have
|
|
449
|
+
* at least one of: x5t#S256, x5c, x5t#o, sigX5ts.
|
|
450
|
+
*
|
|
451
|
+
* @param header - Protected header object
|
|
452
|
+
* @returns true if valid
|
|
453
|
+
* @throws JAdESException if no certificate header is present
|
|
454
|
+
*/
|
|
455
|
+
function validateCertificateHeaders(header) {
|
|
456
|
+
if (!!!(header["x5t#S256"] || header.x5c || header["x5t#o"] || header.sigX5ts)) throw new JAdESException("JAdES signature requires at least one certificate header: x5t#S256, x5c, x5t#o, or sigX5ts");
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
function base64ToUint8Array(base64) {
|
|
460
|
+
const normalized = base64.replace(/-/g, "+").replace(/_/g, "/");
|
|
461
|
+
const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
|
|
462
|
+
const binaryString = atob(padded);
|
|
463
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
464
|
+
for (let i = 0; i < binaryString.length; i++) bytes[i] = binaryString.charCodeAt(i);
|
|
465
|
+
return bytes;
|
|
466
|
+
}
|
|
467
|
+
function uint8ArrayToBase64Url(bytes) {
|
|
468
|
+
let binary = "";
|
|
469
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
470
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
471
|
+
}
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/token.ts
|
|
474
|
+
/**
|
|
475
|
+
* JAdES Token
|
|
476
|
+
*
|
|
477
|
+
* Main class for creating JAdES-compliant signatures.
|
|
478
|
+
* Implements ETSI TS 119 182-1 standard for JSON Advanced Electronic Signatures.
|
|
479
|
+
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```typescript
|
|
482
|
+
* import { Token, parseCerts, generateX5c } from '@owf/eudi-jades'
|
|
483
|
+
* import { ES256 } from '@owf/crypto'
|
|
484
|
+
*
|
|
485
|
+
* const payload = { hello: 'world' }
|
|
486
|
+
* const token = new Token(payload)
|
|
487
|
+
*
|
|
488
|
+
* const certs = parseCerts(pemCertificate)
|
|
489
|
+
* token.setProtectedHeader({
|
|
490
|
+
* alg: 'ES256',
|
|
491
|
+
* x5c: generateX5c(certs),
|
|
492
|
+
* })
|
|
493
|
+
*
|
|
494
|
+
* const signer = await ES256.getSigner(privateKey)
|
|
495
|
+
* await token.sign(signer)
|
|
496
|
+
*
|
|
497
|
+
* const compactJws = token.toString()
|
|
498
|
+
* const generalJws = token.toJSON()
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
/**
|
|
502
|
+
* JAdES Token class for creating conformant JAdES signatures.
|
|
503
|
+
*/
|
|
504
|
+
var Token = class {
|
|
505
|
+
/**
|
|
506
|
+
* Create a new JAdES Token.
|
|
507
|
+
*
|
|
508
|
+
* @param payload - The payload to sign. If undefined, creates a detached signature.
|
|
509
|
+
*/
|
|
510
|
+
constructor(payload) {
|
|
511
|
+
this.protectedHeader = {};
|
|
512
|
+
this.unprotectedHeader = {};
|
|
513
|
+
this.payload = payload;
|
|
514
|
+
this.encodedPayload = payload === void 0 ? "" : base64urlEncode(JSON.stringify(payload));
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Set the protected header parameters.
|
|
518
|
+
*
|
|
519
|
+
* @param header - Protected header parameters
|
|
520
|
+
* @returns this for method chaining
|
|
521
|
+
*/
|
|
522
|
+
setProtectedHeader(header) {
|
|
523
|
+
if (header.alg) {
|
|
524
|
+
if (!SignAlgSchema.safeParse(header.alg).success) throw new JAdESException(`Invalid algorithm: ${header.alg}`);
|
|
525
|
+
}
|
|
526
|
+
const result = ProtectedHeaderSchema.safeParse(header);
|
|
527
|
+
if (!result.success) throw new JAdESException(`Invalid protected header: ${result.error.issues.map((e) => e.message).join(", ")}`);
|
|
528
|
+
this.protectedHeader = {
|
|
529
|
+
...this.protectedHeader,
|
|
530
|
+
...header
|
|
531
|
+
};
|
|
532
|
+
return this;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Set the unprotected header parameters.
|
|
536
|
+
*
|
|
537
|
+
* @param header - Unprotected header parameters
|
|
538
|
+
* @returns this for method chaining
|
|
539
|
+
*/
|
|
540
|
+
setUnprotectedHeader(header) {
|
|
541
|
+
this.unprotectedHeader = {
|
|
542
|
+
...this.unprotectedHeader,
|
|
543
|
+
...header
|
|
544
|
+
};
|
|
545
|
+
return this;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Set X.509 certificate chain (x5c header).
|
|
549
|
+
*
|
|
550
|
+
* ETSI TS 119 182-1 Section 5.1.8
|
|
551
|
+
*
|
|
552
|
+
* @param certs - Array of base64-encoded DER certificates
|
|
553
|
+
* @returns this for method chaining
|
|
554
|
+
*/
|
|
555
|
+
setX5c(certs) {
|
|
556
|
+
this.protectedHeader.x5c = certs;
|
|
557
|
+
return this;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Set X.509 certificate URL (x5u header).
|
|
561
|
+
*
|
|
562
|
+
* ETSI TS 119 182-1 Section 5.1.5
|
|
563
|
+
*
|
|
564
|
+
* @param uri - URI to certificate resource
|
|
565
|
+
* @returns this for method chaining
|
|
566
|
+
*/
|
|
567
|
+
setX5u(uri) {
|
|
568
|
+
this.protectedHeader.x5u = uri;
|
|
569
|
+
return this;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Set X.509 certificate SHA-256 thumbprint (x5t#S256 header).
|
|
573
|
+
*
|
|
574
|
+
* ETSI TS 119 182-1 Section 5.1.7
|
|
575
|
+
*
|
|
576
|
+
* @param thumbprint - Base64url-encoded SHA-256 thumbprint
|
|
577
|
+
* @returns this for method chaining
|
|
578
|
+
*/
|
|
579
|
+
setX5tS256(thumbprint) {
|
|
580
|
+
this.protectedHeader["x5t#S256"] = thumbprint;
|
|
581
|
+
return this;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Set X.509 certificate thumbprint with other algorithm (x5t#o header).
|
|
585
|
+
*
|
|
586
|
+
* ETSI TS 119 182-1 Section 5.2.2.2
|
|
587
|
+
*
|
|
588
|
+
* @param x5tO - X5tO object with algorithm and digest value
|
|
589
|
+
* @returns this for method chaining
|
|
590
|
+
*/
|
|
591
|
+
setX5tO(x5tO) {
|
|
592
|
+
this.protectedHeader["x5t#o"] = x5tO;
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Set signing time (sigT header).
|
|
597
|
+
*
|
|
598
|
+
* ETSI TS 119 182-1 Section 5.2.1
|
|
599
|
+
*
|
|
600
|
+
* @param time - ISO 8601 timestamp (defaults to current time)
|
|
601
|
+
* @returns this for method chaining
|
|
602
|
+
*/
|
|
603
|
+
setSigningTime(time) {
|
|
604
|
+
this.protectedHeader.sigT = time ?? (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Set signedAt timestamp in protected header.
|
|
609
|
+
*
|
|
610
|
+
* @param sec - Unix timestamp in seconds (defaults to current time)
|
|
611
|
+
* @returns this for method chaining
|
|
612
|
+
*/
|
|
613
|
+
setSignedAt(sec) {
|
|
614
|
+
this.protectedHeader.signedAt = sec ?? Math.floor(Date.now() / 1e3);
|
|
615
|
+
return this;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Set issued at timestamp (iat) in protected header.
|
|
619
|
+
*
|
|
620
|
+
* @param sec - Unix timestamp in seconds (defaults to current time)
|
|
621
|
+
* @returns this for method chaining
|
|
622
|
+
*/
|
|
623
|
+
setIssuedAt(sec) {
|
|
624
|
+
this.protectedHeader.iat = sec ?? Math.floor(Date.now() / 1e3);
|
|
625
|
+
return this;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Set key ID (kid header).
|
|
629
|
+
*
|
|
630
|
+
* @param kid - Key identifier
|
|
631
|
+
* @returns this for method chaining
|
|
632
|
+
*/
|
|
633
|
+
setKid(kid) {
|
|
634
|
+
this.protectedHeader.kid = kid;
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Set content type (cty header).
|
|
639
|
+
*
|
|
640
|
+
* @param cty - Content type
|
|
641
|
+
* @returns this for method chaining
|
|
642
|
+
*/
|
|
643
|
+
setContentType(cty) {
|
|
644
|
+
this.protectedHeader.cty = cty;
|
|
645
|
+
return this;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Set token type (typ header).
|
|
649
|
+
*
|
|
650
|
+
* @param typ - Token type
|
|
651
|
+
* @returns this for method chaining
|
|
652
|
+
*/
|
|
653
|
+
setType(typ) {
|
|
654
|
+
this.protectedHeader.typ = typ;
|
|
655
|
+
return this;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Set b64 header parameter.
|
|
659
|
+
*
|
|
660
|
+
* ETSI TS 119 182-1 Section 5.1.10
|
|
661
|
+
* RFC 7797 Section 3
|
|
662
|
+
*
|
|
663
|
+
* @param b64 - If true (default), payload is base64url encoded. If false, payload is unencoded.
|
|
664
|
+
* @returns this for method chaining
|
|
665
|
+
*/
|
|
666
|
+
setB64(b64) {
|
|
667
|
+
if (b64) delete this.protectedHeader.b64;
|
|
668
|
+
else this.protectedHeader.b64 = false;
|
|
669
|
+
return this;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Configure detached signature mode.
|
|
673
|
+
*
|
|
674
|
+
* ETSI TS 119 182-1 Section 5.2.8
|
|
675
|
+
*
|
|
676
|
+
* @param sigD - Detached signature descriptor
|
|
677
|
+
* @returns this for method chaining
|
|
678
|
+
*/
|
|
679
|
+
setDetached(sigD) {
|
|
680
|
+
this.protectedHeader.sigD = sigD;
|
|
681
|
+
this.encodedPayload = "";
|
|
682
|
+
if (sigD.mId === DETACHED_MECHANISM_IDS.httpHeaders) this.setB64(false);
|
|
683
|
+
return this;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Get the signing input (data to be signed).
|
|
687
|
+
*
|
|
688
|
+
* @returns The signing input string (header.payload)
|
|
689
|
+
*/
|
|
690
|
+
getSigningInput() {
|
|
691
|
+
return `${this.getEncodedProtectedHeader()}.${this.encodedPayload}`;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Get the hash of the signing input for external signing.
|
|
695
|
+
*
|
|
696
|
+
* @param algorithm - Hash algorithm (defaults to algorithm from header)
|
|
697
|
+
* @returns Promise resolving to hash bytes
|
|
698
|
+
*/
|
|
699
|
+
async getHash(algorithm) {
|
|
700
|
+
const alg = algorithm ?? this.getHashAlgorithm();
|
|
701
|
+
const signingInput = this.getSigningInput();
|
|
702
|
+
const encoder = new TextEncoder();
|
|
703
|
+
const hashBuffer = await globalThis.crypto.subtle.digest(alg, encoder.encode(signingInput));
|
|
704
|
+
return new Uint8Array(hashBuffer);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Set the signature (for external signing).
|
|
708
|
+
*
|
|
709
|
+
* @param signature - Base64url-encoded signature
|
|
710
|
+
* @returns this for method chaining
|
|
711
|
+
*/
|
|
712
|
+
setSignature(signature) {
|
|
713
|
+
this.signature = signature;
|
|
714
|
+
return this;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Sign the token using the provided signer function.
|
|
718
|
+
*
|
|
719
|
+
* @param signer - Async function that signs data and returns base64url signature
|
|
720
|
+
* @returns Promise resolving to this for method chaining
|
|
721
|
+
*/
|
|
722
|
+
async sign(signer) {
|
|
723
|
+
this.validateBeforeSign();
|
|
724
|
+
this.signature = await signer(this.getSigningInput());
|
|
725
|
+
return this;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Export to compact JWS serialization.
|
|
729
|
+
*
|
|
730
|
+
* @returns Compact JWS string (header.payload.signature)
|
|
731
|
+
*/
|
|
732
|
+
toString() {
|
|
733
|
+
if (!this.signature) throw new JAdESException("Token not signed yet");
|
|
734
|
+
return `${this.getEncodedProtectedHeader()}.${this.encodedPayload}.${this.signature}`;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Export to General JWS JSON serialization.
|
|
738
|
+
*
|
|
739
|
+
* @returns GeneralJWS object
|
|
740
|
+
*/
|
|
741
|
+
toJSON() {
|
|
742
|
+
if (!this.signature) throw new JAdESException("Token not signed yet");
|
|
743
|
+
const result = {
|
|
744
|
+
payload: this.encodedPayload,
|
|
745
|
+
signatures: [{
|
|
746
|
+
protected: this.getEncodedProtectedHeader(),
|
|
747
|
+
signature: this.signature
|
|
748
|
+
}]
|
|
749
|
+
};
|
|
750
|
+
if (Object.keys(this.unprotectedHeader).length > 0) result.signatures[0].header = this.unprotectedHeader;
|
|
751
|
+
return result;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Export to flattened JWS JSON serialization.
|
|
755
|
+
*
|
|
756
|
+
* @returns Flattened JWS object
|
|
757
|
+
*/
|
|
758
|
+
toFlattenedJSON() {
|
|
759
|
+
if (!this.signature) throw new JAdESException("Token not signed yet");
|
|
760
|
+
const result = {
|
|
761
|
+
protected: this.getEncodedProtectedHeader(),
|
|
762
|
+
payload: this.encodedPayload,
|
|
763
|
+
signature: this.signature
|
|
764
|
+
};
|
|
765
|
+
if (Object.keys(this.unprotectedHeader).length > 0) result.header = this.unprotectedHeader;
|
|
766
|
+
return result;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Get the protected header object.
|
|
770
|
+
*/
|
|
771
|
+
getProtectedHeader() {
|
|
772
|
+
return { ...this.protectedHeader };
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Get the unprotected header object.
|
|
776
|
+
*/
|
|
777
|
+
getUnprotectedHeader() {
|
|
778
|
+
return { ...this.unprotectedHeader };
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Get the payload.
|
|
782
|
+
*/
|
|
783
|
+
getPayload() {
|
|
784
|
+
return this.payload;
|
|
785
|
+
}
|
|
786
|
+
getEncodedProtectedHeader() {
|
|
787
|
+
return encodeJSON(this.buildFinalHeader());
|
|
788
|
+
}
|
|
789
|
+
buildFinalHeader() {
|
|
790
|
+
const header = { ...this.protectedHeader };
|
|
791
|
+
const critParams = CRITICAL_PARAMETERS.filter((param) => param in header);
|
|
792
|
+
if (critParams.length > 0) header.crit = critParams;
|
|
793
|
+
return header;
|
|
794
|
+
}
|
|
795
|
+
validateBeforeSign() {
|
|
796
|
+
const result = ProtectedHeaderForSigningSchema.safeParse(this.protectedHeader);
|
|
797
|
+
if (!result.success) throw new JAdESException(`Invalid protected header for signing: ${result.error.issues.map((e) => e.message).join(", ")}`);
|
|
798
|
+
}
|
|
799
|
+
getHashAlgorithm() {
|
|
800
|
+
const algMap = {
|
|
801
|
+
RS256: "SHA-256",
|
|
802
|
+
RS384: "SHA-384",
|
|
803
|
+
RS512: "SHA-512",
|
|
804
|
+
PS256: "SHA-256",
|
|
805
|
+
PS384: "SHA-384",
|
|
806
|
+
PS512: "SHA-512",
|
|
807
|
+
ES256: "SHA-256",
|
|
808
|
+
ES384: "SHA-384",
|
|
809
|
+
ES512: "SHA-512"
|
|
810
|
+
};
|
|
811
|
+
const alg = this.protectedHeader.alg;
|
|
812
|
+
if (!alg || !algMap[alg]) throw new JAdESException(`Unsupported algorithm: ${alg}`);
|
|
813
|
+
return algMap[alg];
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
//#endregion
|
|
817
|
+
//#region src/verifier.ts
|
|
818
|
+
/**
|
|
819
|
+
* JAdES Verifier
|
|
820
|
+
*
|
|
821
|
+
* Functions for verifying JAdES signatures.
|
|
822
|
+
*/
|
|
823
|
+
/**
|
|
824
|
+
* Verify a JAdES signature in compact serialization.
|
|
825
|
+
*
|
|
826
|
+
* @param jws - Compact JWS string
|
|
827
|
+
* @param verifier - Async function that verifies signature
|
|
828
|
+
* @returns Promise resolving to verification result
|
|
829
|
+
*/
|
|
830
|
+
async function verifyCompact(jws, verifier) {
|
|
831
|
+
const parts = jws.split(".");
|
|
832
|
+
if (parts.length !== 3) throw new JAdESException("Invalid JWS format: expected 3 parts");
|
|
833
|
+
const [encodedHeader, encodedPayload, signature] = parts;
|
|
834
|
+
const valid = await verifier(`${encodedHeader}.${encodedPayload}`, signature);
|
|
835
|
+
if (!valid) throw new JAdESException("Invalid signature");
|
|
836
|
+
const rawHeader = JSON.parse(base64urlDecode(encodedHeader));
|
|
837
|
+
const headerResult = ProtectedHeaderSchema.safeParse(rawHeader);
|
|
838
|
+
if (!headerResult.success) throw new JAdESException(`Invalid protected header: ${headerResult.error.issues.map((e) => e.message).join(", ")}`);
|
|
839
|
+
return {
|
|
840
|
+
header: headerResult.data,
|
|
841
|
+
payload: encodedPayload ? JSON.parse(base64urlDecode(encodedPayload)) : {},
|
|
842
|
+
valid
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Verify a JAdES signature in General JWS JSON serialization.
|
|
847
|
+
*
|
|
848
|
+
* @param generalJws - General JWS object
|
|
849
|
+
* @param verifier - Async function that verifies signature
|
|
850
|
+
* @param signatureIndex - Index of signature to verify (default: 0)
|
|
851
|
+
* @returns Promise resolving to verification result
|
|
852
|
+
*/
|
|
853
|
+
async function verifyGeneral(generalJws, verifier, signatureIndex = 0) {
|
|
854
|
+
const jwsResult = GeneralJWSSchema.safeParse(generalJws);
|
|
855
|
+
if (!jwsResult.success) throw new JAdESException(`Invalid General JWS structure: ${jwsResult.error.issues.map((e) => e.message).join(", ")}`);
|
|
856
|
+
const sig = generalJws.signatures[signatureIndex];
|
|
857
|
+
if (!sig) throw new JAdESException(`Signature at index ${signatureIndex} not found`);
|
|
858
|
+
const valid = await verifier(`${sig.protected}.${generalJws.payload}`, sig.signature);
|
|
859
|
+
if (!valid) throw new JAdESException("Invalid signature");
|
|
860
|
+
const rawHeader = JSON.parse(base64urlDecode(sig.protected));
|
|
861
|
+
const headerResult = ProtectedHeaderSchema.safeParse(rawHeader);
|
|
862
|
+
if (!headerResult.success) throw new JAdESException(`Invalid protected header: ${headerResult.error.issues.map((e) => e.message).join(", ")}`);
|
|
863
|
+
return {
|
|
864
|
+
header: headerResult.data,
|
|
865
|
+
payload: generalJws.payload ? JSON.parse(base64urlDecode(generalJws.payload)) : {},
|
|
866
|
+
unprotectedHeader: sig.header,
|
|
867
|
+
valid
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Verify a JAdES signature (auto-detects format).
|
|
872
|
+
*
|
|
873
|
+
* @param jws - JWS string or GeneralJWS object
|
|
874
|
+
* @param verifier - Async function that verifies signature
|
|
875
|
+
* @returns Promise resolving to verification result
|
|
876
|
+
*/
|
|
877
|
+
async function verify(jws, verifier) {
|
|
878
|
+
if (typeof jws === "string") {
|
|
879
|
+
try {
|
|
880
|
+
const parsed = JSON.parse(jws);
|
|
881
|
+
if (parsed.signatures && Array.isArray(parsed.signatures)) return verifyGeneral(parsed, verifier);
|
|
882
|
+
} catch {}
|
|
883
|
+
return verifyCompact(jws, verifier);
|
|
884
|
+
}
|
|
885
|
+
return verifyGeneral(jws, verifier);
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Decode a JWS without verifying the signature.
|
|
889
|
+
* Use this only for inspection - always verify before trusting the content.
|
|
890
|
+
*
|
|
891
|
+
* @param jws - JWS string or GeneralJWS object
|
|
892
|
+
* @returns Decoded header and payload
|
|
893
|
+
*/
|
|
894
|
+
function decode(jws) {
|
|
895
|
+
if (typeof jws === "string") {
|
|
896
|
+
try {
|
|
897
|
+
const parsed = JSON.parse(jws);
|
|
898
|
+
if (parsed.signatures && Array.isArray(parsed.signatures)) {
|
|
899
|
+
const sig = parsed.signatures[0];
|
|
900
|
+
return {
|
|
901
|
+
header: JSON.parse(base64urlDecode(sig.protected)),
|
|
902
|
+
payload: parsed.payload ? JSON.parse(base64urlDecode(parsed.payload)) : {},
|
|
903
|
+
unprotectedHeader: sig.header
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
} catch {}
|
|
907
|
+
const parts = jws.split(".");
|
|
908
|
+
if (parts.length !== 3) throw new JAdESException("Invalid JWS format");
|
|
909
|
+
return {
|
|
910
|
+
header: JSON.parse(base64urlDecode(parts[0])),
|
|
911
|
+
payload: parts[1] ? JSON.parse(base64urlDecode(parts[1])) : {}
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
const sig = jws.signatures[0];
|
|
915
|
+
return {
|
|
916
|
+
header: JSON.parse(base64urlDecode(sig.protected)),
|
|
917
|
+
payload: jws.payload ? JSON.parse(base64urlDecode(jws.payload)) : {},
|
|
918
|
+
unprotectedHeader: sig.header
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
//#endregion
|
|
922
|
+
export { ALGORITHMS, ArcTstSchema, CRITICAL_PARAMETERS, CommitmentOIDs, CompactJWSSchema, DETACHED_MECHANISM_IDS, EtsiUSchema, FlattenedJWSSchema, GeneralJWSSchema, JAdESException, JAdESProfile, ProtectedHeaderForSigningSchema, ProtectedHeaderSchema, RValsSchema, SigDSchema, SigTstSchema, SignAlgSchema, SignOptionsSchema, SignaturePolicySchema, SignerIdentifierSchema, Token, TstTokensSchema, UnprotectedHeaderSchema, X5tOSchema, XValsSchema, decode, decodeJSON, encodeJSON, generateKid, generateSigX5ts, generateX5c, generateX5tO, generateX5tS256, getSigningTime, parseCerts, validateCertificateHeaders, verify, verifyCompact, verifyGeneral };
|
|
923
|
+
|
|
924
|
+
//# sourceMappingURL=index.mjs.map
|