unjwt 0.8.3 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/_codec-jws.mjs +17 -17
- package/dist/_chunks/{jwk.mjs → _import-key.mjs} +36 -741
- package/dist/_chunks/_jwt-internal.mjs +19 -19
- package/dist/_chunks/jwe.d.mts +1 -0
- package/dist/_chunks/jwe.mjs +8 -7
- package/dist/_chunks/jwk.d.mts +205 -0
- package/dist/_chunks/jws.d.mts +4 -1
- package/dist/_chunks/jws.mjs +10 -10
- package/dist/_chunks/libs/unsecure.mjs +143 -130
- package/dist/adapters/elysia/index.d.mts +1 -1
- package/dist/adapters/elysia/index.mjs +3 -2
- package/dist/adapters/h3/index.d.mts +1 -1
- package/dist/adapters/h3/index.mjs +2 -1
- package/dist/adapters/h3v1/index.d.mts +1 -1
- package/dist/adapters/h3v1/index.mjs +2 -1
- package/dist/core/jwe.mjs +1 -1
- package/dist/core/jwk.d.mts +2 -204
- package/dist/core/jwk.mjs +712 -3
- package/dist/core/jws.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -1
- package/dist/session/index.d.mts +1 -1
- package/dist/session/index.mjs +2 -1
- package/package.json +3 -2
package/dist/core/jwk.mjs
CHANGED
|
@@ -1,4 +1,713 @@
|
|
|
1
|
-
import { UnsecureError } from "../_chunks/libs/unsecure.mjs";
|
|
2
|
-
import { JWTError, isJWTError, isUnsecureError } from "../_chunks/_jwt-internal.mjs";
|
|
3
|
-
import {
|
|
1
|
+
import { UnsecureError, sanitizeObjectCopy, secureRandomBytes, textEncoder } from "../_chunks/libs/unsecure.mjs";
|
|
2
|
+
import { JWTError, assertPlainObject, isAsymmetricJWK, isCryptoKey, isCryptoKeyPair, isJWK, isJWTError, isPublicJWK, isUnsecureError } from "../_chunks/_jwt-internal.mjs";
|
|
3
|
+
import { ECDSA_CURVES, PBES2_ALGORITHMS, aesBitsOf, innerKeyWrapAlg, isECDHESAlgorithm, jwsHashOf, rsaOaepHashOf } from "../_chunks/digest.mjs";
|
|
4
|
+
import { MAX_PARTY_INFO_BYTES, WeakMapJWKCache, aesKwUnwrap, aesKwWrap, asDecryptionError, assertDirectKeyRole, assertECDHKeyAllowed, assertJWEEncSupported, assertOctKeyLength, assertPBES2Count, assertPBES2Params, assertPBES2Salt, bitLengthCEK, bitLengthIV, bitLengthTag, buildECDHAgreementParams, clearJWKCache, configureJWKCache, decodeSegment, decryptRSAES, deriveECDHESKey, deriveKey, ecdhDerivedBits, ecdhesWrap, encryptRSAES, fromPKCS8, fromSPKI, fromX509, gcmkwDecrypt, gcmkwEncrypt, getJWKsFromSet, importKey, keyToJWK, normalizeEpk, pbes2Unwrap, pbes2Wrap, resolvePasswordKey, thumbprint, toPKCS8, toSPKI } from "../_chunks/_import-key.mjs";
|
|
5
|
+
async function generateKey(alg, options = {}) {
|
|
6
|
+
const exportToJWK = options.toJWK !== void 0 && options.toJWK;
|
|
7
|
+
const defaultExtractable = exportToJWK || options.extractable !== false;
|
|
8
|
+
const kid = exportToJWK ? assertKidOption(options.kid) : void 0;
|
|
9
|
+
if (alg === "A128CBC-HS256" || alg === "A192CBC-HS384" || alg === "A256CBC-HS512") {
|
|
10
|
+
const keyLength = bitLengthCEK(alg);
|
|
11
|
+
const keyBytes = secureRandomBytes(keyLength >> 3);
|
|
12
|
+
if (exportToJWK) {
|
|
13
|
+
const jwk = await keyToJWK(keyBytes);
|
|
14
|
+
const keyOps = options.keyUsage === void 0 ? void 0 : resolveKeyUsage(options.keyUsage, {
|
|
15
|
+
allowed: CONTENT_ENCRYPTION_USAGES,
|
|
16
|
+
fallback: ["encrypt", "decrypt"],
|
|
17
|
+
alg
|
|
18
|
+
});
|
|
19
|
+
return withGeneratedKid(kid, withKeyOps({
|
|
20
|
+
...jwk,
|
|
21
|
+
alg
|
|
22
|
+
}, keyOps));
|
|
23
|
+
}
|
|
24
|
+
return keyBytes;
|
|
25
|
+
}
|
|
26
|
+
const { algorithm, keyUsages } = getGenerateKeyParams(alg, options);
|
|
27
|
+
const key = await crypto.subtle.generateKey(algorithm, defaultExtractable, keyUsages);
|
|
28
|
+
if (exportToJWK) {
|
|
29
|
+
if (isCryptoKeyPair(key)) {
|
|
30
|
+
const pairAlg = generatedPairAlgorithm(alg);
|
|
31
|
+
const [pub, priv] = await Promise.all([exportJWK(key.publicKey), exportJWK(key.privateKey)]);
|
|
32
|
+
const publicKey = await withGeneratedKid(kid, withKeyOps(withAlg(pub, pairAlg), requestedKeyOps(options, key.publicKey)));
|
|
33
|
+
const named = publicKey.kid === void 0 ? void 0 : { kid: publicKey.kid };
|
|
34
|
+
return {
|
|
35
|
+
privateKey: {
|
|
36
|
+
...withKeyOps(withAlg(priv, pairAlg), requestedKeyOps(options, key.privateKey)),
|
|
37
|
+
...named
|
|
38
|
+
},
|
|
39
|
+
publicKey
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return withGeneratedKid(kid, withKeyOps(withAlg(await exportJWK(key), generatedSecretAlgorithm(alg)), requestedKeyOps(options, key)));
|
|
43
|
+
}
|
|
44
|
+
return key;
|
|
45
|
+
}
|
|
46
|
+
async function generateJWK(alg, options) {
|
|
47
|
+
const { keyUsage, modulusLength, publicExponent, namedCurve, kid, extractable: _extractable, toJWK: _toJWK, ...jwkParams } = options ?? {};
|
|
48
|
+
assertNoReservedJWKParams(jwkParams);
|
|
49
|
+
const result = await generateKey(alg, {
|
|
50
|
+
keyUsage,
|
|
51
|
+
modulusLength,
|
|
52
|
+
publicExponent,
|
|
53
|
+
namedCurve,
|
|
54
|
+
kid,
|
|
55
|
+
toJWK: true
|
|
56
|
+
});
|
|
57
|
+
if (result && typeof result === "object" && "privateKey" in result && "publicKey" in result) return {
|
|
58
|
+
privateKey: {
|
|
59
|
+
...jwkParams,
|
|
60
|
+
...result.privateKey
|
|
61
|
+
},
|
|
62
|
+
publicKey: {
|
|
63
|
+
...jwkParams,
|
|
64
|
+
...result.publicKey
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
...jwkParams,
|
|
69
|
+
...result
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function deriveKeyFromPassword(password, options) {
|
|
73
|
+
assertPlainObject(options, "options");
|
|
74
|
+
if (typeof password !== "string" && !(password instanceof Uint8Array)) throw new JWTError("\"password\" must be a string or a Uint8Array.", "ERR_INVALID_OPTION");
|
|
75
|
+
const { alg, salt, iterations, extractable, keyUsage } = options;
|
|
76
|
+
assertPBES2Algorithm(alg);
|
|
77
|
+
const exportToJWK = options.toJWK !== void 0 && options.toJWK;
|
|
78
|
+
const saltBytes = typeof salt === "string" ? textEncoder.encode(salt) : salt;
|
|
79
|
+
assertPBES2Salt(saltBytes, "\"salt\"");
|
|
80
|
+
assertPBES2Count(iterations, "\"iterations\"");
|
|
81
|
+
const passwordBytes = typeof password === "string" ? textEncoder.encode(password) : password;
|
|
82
|
+
const derivedBytes = await deriveKey(saltBytes, alg, iterations, passwordBytes);
|
|
83
|
+
const wrappingAlg = innerKeyWrapAlg(alg);
|
|
84
|
+
const finalUsages = keyUsage ?? ["wrapKey", "unwrapKey"];
|
|
85
|
+
const finalExtractable = exportToJWK ? true : extractable === true;
|
|
86
|
+
const derivedKey = await crypto.subtle.importKey("raw", derivedBytes, { name: "AES-KW" }, finalExtractable, finalUsages);
|
|
87
|
+
if (exportToJWK) return withKeyOps({
|
|
88
|
+
...await keyToJWK(derivedKey),
|
|
89
|
+
alg: wrappingAlg,
|
|
90
|
+
kty: "oct"
|
|
91
|
+
}, requestedKeyOps(options, derivedKey));
|
|
92
|
+
return derivedKey;
|
|
93
|
+
}
|
|
94
|
+
async function deriveJWKFromPassword(password, options) {
|
|
95
|
+
assertPlainObject(options, "options");
|
|
96
|
+
const { alg, salt, iterations, keyUsage, kid: kidOption, extractable: _extractable, toJWK: _toJWK, ...jwkParams } = options;
|
|
97
|
+
assertNoReservedJWKParams(jwkParams);
|
|
98
|
+
const kid = assertKidOption(kidOption);
|
|
99
|
+
const result = await deriveKeyFromPassword(password, {
|
|
100
|
+
alg,
|
|
101
|
+
salt,
|
|
102
|
+
iterations,
|
|
103
|
+
keyUsage,
|
|
104
|
+
toJWK: true
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
...jwkParams,
|
|
108
|
+
...await withGeneratedKid(kid, result)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function exportJWK(key, jwkParams) {
|
|
112
|
+
if (!isCryptoKey(key)) throw new JWTError("exportJWK expects a CryptoKey.", "ERR_INVALID_OPTION");
|
|
113
|
+
if (!key.extractable) throw new JWTError("A non-extractable CryptoKey cannot be exported as a JWK.", "ERR_JWK_INVALID");
|
|
114
|
+
const exportedJwk = await keyToJWK(key);
|
|
115
|
+
if (jwkParams) {
|
|
116
|
+
const extraParams = sanitizeObjectCopy(jwkParams);
|
|
117
|
+
assertNoReservedJWKParams(extraParams);
|
|
118
|
+
return {
|
|
119
|
+
...exportedJwk,
|
|
120
|
+
...extraParams
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return exportedJwk;
|
|
124
|
+
}
|
|
125
|
+
async function exportKey(key, jwkParams) {
|
|
126
|
+
return exportJWK(key, jwkParams);
|
|
127
|
+
}
|
|
128
|
+
function toPublicJWK(jwk) {
|
|
129
|
+
if (!isAsymmetricJWK(jwk)) throw new JWTError(isJWK(jwk) ? "An oct JWK has no public half." : "toPublicJWK expects an asymmetric JWK.", "ERR_JWK_INVALID");
|
|
130
|
+
const { d: _d, p: _p, q: _q, dp: _dp, dq: _dq, qi: _qi, oth: _oth, key_ops, ...publicMembers } = sanitizeObjectCopy({ ...jwk });
|
|
131
|
+
const publicKey = key_ops === void 0 ? publicMembers : {
|
|
132
|
+
...publicMembers,
|
|
133
|
+
key_ops: publicKeyOps(key_ops)
|
|
134
|
+
};
|
|
135
|
+
if (!isPublicJWK(publicKey)) throw new JWTError(`${jwk.kty} JWK lacks the public members of its key type.`, "ERR_JWK_INVALID");
|
|
136
|
+
return publicKey;
|
|
137
|
+
}
|
|
138
|
+
async function wrapKey(keyToWrap, wrappingKey, options) {
|
|
139
|
+
assertPlainObject(options, "options");
|
|
140
|
+
assertKeyBytesArg(keyToWrap, "keyToWrap");
|
|
141
|
+
const { alg } = options;
|
|
142
|
+
const cekBytes = keyToWrap instanceof Uint8Array ? keyToWrap : new Uint8Array(await crypto.subtle.exportKey("raw", keyToWrap));
|
|
143
|
+
if (alg.endsWith("KW")) assertWrappableCEK(cekBytes, alg);
|
|
144
|
+
if (alg.startsWith("PBES2")) assertPBES2Params({
|
|
145
|
+
p2s: options.p2s,
|
|
146
|
+
p2c: options.p2c
|
|
147
|
+
});
|
|
148
|
+
const importedWrappingKey = await importKey(resolvePasswordKey(alg, wrappingKey), {
|
|
149
|
+
alg,
|
|
150
|
+
expect: "public"
|
|
151
|
+
});
|
|
152
|
+
switch (alg) {
|
|
153
|
+
case "dir": return { encryptedKey: /* @__PURE__ */ new Uint8Array(0) };
|
|
154
|
+
case "A128KW":
|
|
155
|
+
case "A192KW":
|
|
156
|
+
case "A256KW": return { encryptedKey: await aesKwWrap(alg, importedWrappingKey, cekBytes) };
|
|
157
|
+
case "PBES2-HS256+A128KW":
|
|
158
|
+
case "PBES2-HS384+A192KW":
|
|
159
|
+
case "PBES2-HS512+A256KW": {
|
|
160
|
+
const { p2s, p2c } = options;
|
|
161
|
+
if (!p2s || typeof p2c !== "number") throw new JWTError("PBES2 requires 'p2s' (salt) and 'p2c' (count) options", "ERR_JWE_INVALID");
|
|
162
|
+
return pbes2Wrap(alg, importedWrappingKey, cekBytes, p2c, p2s);
|
|
163
|
+
}
|
|
164
|
+
case "A128GCMKW":
|
|
165
|
+
case "A192GCMKW":
|
|
166
|
+
case "A256GCMKW": {
|
|
167
|
+
const { encryptedKey, iv, tag } = await gcmkwEncrypt(alg, importedWrappingKey, cekBytes, options.iv);
|
|
168
|
+
return {
|
|
169
|
+
encryptedKey,
|
|
170
|
+
iv,
|
|
171
|
+
tag
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
case "RSA-OAEP":
|
|
175
|
+
case "RSA-OAEP-256":
|
|
176
|
+
case "RSA-OAEP-384":
|
|
177
|
+
case "RSA-OAEP-512":
|
|
178
|
+
assertCryptoKeyFor(alg, importedWrappingKey, "wrapping");
|
|
179
|
+
return { encryptedKey: await encryptRSAES(alg, importedWrappingKey, cekBytes) };
|
|
180
|
+
case "ECDH-ES":
|
|
181
|
+
case "ECDH-ES+A128KW":
|
|
182
|
+
case "ECDH-ES+A192KW":
|
|
183
|
+
case "ECDH-ES+A256KW": {
|
|
184
|
+
assertCryptoKeyFor(alg, importedWrappingKey, "wrapping");
|
|
185
|
+
const enc = options.ecdh?.enc;
|
|
186
|
+
if (enc !== void 0) assertJWEEncSupported(enc);
|
|
187
|
+
if (alg === "ECDH-ES" && !enc) throw new JWTError("ECDH-ES direct key agreement requires options.ecdh.enc", "ERR_JWK_INVALID");
|
|
188
|
+
const { encryptedKey, parameters } = await ecdhesWrap(alg, {
|
|
189
|
+
enc,
|
|
190
|
+
recipientKey: importedWrappingKey,
|
|
191
|
+
cek: cekBytes,
|
|
192
|
+
parameters: buildECDHAgreementParams(options.ecdh)
|
|
193
|
+
});
|
|
194
|
+
const wrapResult = {
|
|
195
|
+
encryptedKey: encryptedKey ?? /* @__PURE__ */ new Uint8Array(0),
|
|
196
|
+
epk: parameters.epk
|
|
197
|
+
};
|
|
198
|
+
if (parameters.apu) wrapResult.apu = parameters.apu;
|
|
199
|
+
if (parameters.apv) wrapResult.apv = parameters.apv;
|
|
200
|
+
return wrapResult;
|
|
201
|
+
}
|
|
202
|
+
default: throw new JWTError(`Unsupported key wrapping algorithm: ${alg}`, "ERR_JWK_UNSUPPORTED");
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async function unwrapKey(wrappedKey, unwrappingKey, options) {
|
|
206
|
+
assertPlainObject(options, "options");
|
|
207
|
+
if (!(wrappedKey instanceof Uint8Array)) throw new JWTError("\"wrappedKey\" must be a Uint8Array.", "ERR_INVALID_OPTION");
|
|
208
|
+
const { alg } = options;
|
|
209
|
+
const returnRaw = options.format === "raw";
|
|
210
|
+
const defaultExtractable = options.extractable !== false;
|
|
211
|
+
const importedUnwrappingKey = await importKey(resolvePasswordKey(alg, unwrappingKey), {
|
|
212
|
+
alg,
|
|
213
|
+
expect: "private"
|
|
214
|
+
});
|
|
215
|
+
let unwrappedCekBytes;
|
|
216
|
+
switch (alg) {
|
|
217
|
+
case "dir":
|
|
218
|
+
assertDirectKeyRole(unwrappingKey, options.enc);
|
|
219
|
+
if (importedUnwrappingKey instanceof Uint8Array) {
|
|
220
|
+
assertOctKeyLength(importedUnwrappingKey, options.enc);
|
|
221
|
+
unwrappedCekBytes = importedUnwrappingKey;
|
|
222
|
+
} else {
|
|
223
|
+
if (!returnRaw) return importedUnwrappingKey;
|
|
224
|
+
unwrappedCekBytes = new Uint8Array(await crypto.subtle.exportKey("raw", importedUnwrappingKey));
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
case "A128KW":
|
|
228
|
+
case "A192KW":
|
|
229
|
+
case "A256KW":
|
|
230
|
+
unwrappedCekBytes = await unwrapping(aesKwUnwrap(alg, importedUnwrappingKey, wrappedKey));
|
|
231
|
+
break;
|
|
232
|
+
case "PBES2-HS256+A128KW":
|
|
233
|
+
case "PBES2-HS384+A192KW":
|
|
234
|
+
case "PBES2-HS512+A256KW": {
|
|
235
|
+
const { p2s, p2c, minIterations, maxIterations } = options;
|
|
236
|
+
if (!p2s || typeof p2c !== "number") throw new JWTError("PBES2 requires 'p2s' (salt) and 'p2c' (count) options", "ERR_JWE_INVALID");
|
|
237
|
+
const p2sBytes = segmentBytes(p2s, "p2s");
|
|
238
|
+
unwrappedCekBytes = await unwrapping(pbes2Unwrap(alg, importedUnwrappingKey, wrappedKey, p2c, p2sBytes, minIterations, maxIterations));
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case "A128GCMKW":
|
|
242
|
+
case "A192GCMKW":
|
|
243
|
+
case "A256GCMKW": {
|
|
244
|
+
if (!options.iv || !options.tag) throw new JWTError("AES-GCMKW requires 'iv' and 'tag' options for unwrapping", "ERR_JWE_INVALID");
|
|
245
|
+
const ivBytes = segmentBytes(options.iv, "iv");
|
|
246
|
+
const tagBytes = segmentBytes(options.tag, "tag");
|
|
247
|
+
assertKeyWrapSegmentLength("iv", ivBytes, bitLengthIV(alg) >> 3, alg);
|
|
248
|
+
assertKeyWrapSegmentLength("tag", tagBytes, bitLengthTag(alg) >> 3, alg);
|
|
249
|
+
unwrappedCekBytes = await unwrapping(gcmkwDecrypt(alg, importedUnwrappingKey, wrappedKey, ivBytes, tagBytes));
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "RSA-OAEP":
|
|
253
|
+
case "RSA-OAEP-256":
|
|
254
|
+
case "RSA-OAEP-384":
|
|
255
|
+
case "RSA-OAEP-512": {
|
|
256
|
+
assertCryptoKeyFor(alg, importedUnwrappingKey, "unwrapping");
|
|
257
|
+
unwrappedCekBytes = await unwrapping(decryptRSAES(alg, importedUnwrappingKey, wrappedKey));
|
|
258
|
+
if (returnRaw) break;
|
|
259
|
+
const inferredAlgorithm = options.unwrappedKeyAlgorithm || inferAesImportAlgorithm(options.enc, unwrappedCekBytes.length);
|
|
260
|
+
if (!inferredAlgorithm) throw new JWTError("Cannot infer the RSA-OAEP unwrapped key algorithm, pass \"unwrappedKeyAlgorithm\".", "ERR_JWE_INVALID");
|
|
261
|
+
const keyUsages = options.keyUsage || ["encrypt", "decrypt"];
|
|
262
|
+
return await crypto.subtle.importKey("raw", unwrappedCekBytes, inferredAlgorithm, defaultExtractable, keyUsages);
|
|
263
|
+
}
|
|
264
|
+
case "ECDH-ES":
|
|
265
|
+
case "ECDH-ES+A128KW":
|
|
266
|
+
case "ECDH-ES+A192KW":
|
|
267
|
+
case "ECDH-ES+A256KW": {
|
|
268
|
+
if (!options.epk) throw new JWTError("ECDH-ES requires 'epk' option", "ERR_JWE_INVALID");
|
|
269
|
+
assertCryptoKeyFor(alg, importedUnwrappingKey, "unwrapping");
|
|
270
|
+
assertECDHKeyAllowed(importedUnwrappingKey);
|
|
271
|
+
const epkCandidate = await normalizeEpk(options.epk, {
|
|
272
|
+
alg,
|
|
273
|
+
recipientKey: importedUnwrappingKey
|
|
274
|
+
});
|
|
275
|
+
const apuBytes = segmentBytes(options.apu ?? /* @__PURE__ */ new Uint8Array(0), "apu");
|
|
276
|
+
const apvBytes = segmentBytes(options.apv ?? /* @__PURE__ */ new Uint8Array(0), "apv");
|
|
277
|
+
assertPartyInfoLength("apu", apuBytes);
|
|
278
|
+
assertPartyInfoLength("apv", apvBytes);
|
|
279
|
+
if (options.enc !== void 0) assertJWEEncSupported(options.enc);
|
|
280
|
+
const infoAlg = alg === "ECDH-ES" ? options.enc : alg;
|
|
281
|
+
if (!infoAlg) throw new JWTError("ECDH-ES requires 'enc' to derive the shared secret", "ERR_JWE_INVALID");
|
|
282
|
+
const keyLength = ecdhDerivedBits(alg, options.enc);
|
|
283
|
+
const sharedSecret = await unwrapping(deriveECDHESKey(epkCandidate, importedUnwrappingKey, infoAlg, keyLength, apuBytes, apvBytes));
|
|
284
|
+
if (alg === "ECDH-ES") unwrappedCekBytes = sharedSecret;
|
|
285
|
+
else {
|
|
286
|
+
const kwAlg = innerKeyWrapAlg(alg);
|
|
287
|
+
if (!(wrappedKey instanceof Uint8Array) || wrappedKey.length === 0) throw new JWTError("ECDH-ES key agreement with key wrapping requires an encrypted key", "ERR_JWE_INVALID");
|
|
288
|
+
unwrappedCekBytes = await unwrapping(aesKwUnwrap(kwAlg, sharedSecret, wrappedKey));
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
default: throw new JWTError(`Unsupported key unwrapping algorithm: ${alg}`, "ERR_JWK_UNSUPPORTED");
|
|
293
|
+
}
|
|
294
|
+
if (returnRaw) return unwrappedCekBytes;
|
|
295
|
+
return await crypto.subtle.importKey("raw", unwrappedCekBytes, options.unwrappedKeyAlgorithm || { name: "AES-GCM" }, defaultExtractable, options.keyUsage || ["encrypt", "decrypt"]);
|
|
296
|
+
}
|
|
297
|
+
async function importPEM(pem, alg, options) {
|
|
298
|
+
if (typeof pem !== "string") throw new JWTError("\"pem\" must be a PEM-encoded string.", "ERR_INVALID_OPTION");
|
|
299
|
+
if (options !== void 0) assertPlainObject(options, "options");
|
|
300
|
+
const extractable = true;
|
|
301
|
+
const pemType = options?.pemType ?? inferPEMType(pem);
|
|
302
|
+
if (!pemType) throw new JWTError("Cannot infer PEM type from the input, pass \"pemType\".", "ERR_JWK_INVALID");
|
|
303
|
+
let cryptoKey;
|
|
304
|
+
switch (pemType) {
|
|
305
|
+
case "pkcs8":
|
|
306
|
+
cryptoKey = await fromPKCS8(pem, alg, { extractable });
|
|
307
|
+
break;
|
|
308
|
+
case "spki":
|
|
309
|
+
cryptoKey = await fromSPKI(pem, alg, { extractable });
|
|
310
|
+
break;
|
|
311
|
+
case "x509":
|
|
312
|
+
cryptoKey = await fromX509(pem, alg, { extractable });
|
|
313
|
+
break;
|
|
314
|
+
default: throw new JWTError(`Unsupported PEM type: ${String(pemType)}`, "ERR_JWK_UNSUPPORTED");
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
...await exportJWK(cryptoKey, options?.jwkParams),
|
|
318
|
+
alg
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
async function exportPEM(jwk, options) {
|
|
322
|
+
assertPlainObject(jwk, "jwk");
|
|
323
|
+
if (options !== void 0) assertPlainObject(options, "options");
|
|
324
|
+
if (jwk.kty === "oct") throw new JWTError("An oct JWK cannot be exported to PKCS8 or SPKI PEM.", "ERR_JWK_UNSUPPORTED");
|
|
325
|
+
const effectiveAlg = jwk.alg || options?.alg;
|
|
326
|
+
if (!effectiveAlg && (jwk.kty === "RSA" || jwk.kty === "EC" || jwk.kty === "OKP")) throw new JWTError("\"alg\" is required, set it on the JWK or pass it in options.", "ERR_JWK_INVALID");
|
|
327
|
+
if (effectiveAlg !== void 0 && !PEM_ALGORITHMS.has(effectiveAlg)) throw new JWTError(`Unsupported PEM algorithm: ${effectiveAlg}`, "ERR_JWK_UNSUPPORTED");
|
|
328
|
+
const pemFormat = options?.pemFormat ?? ("d" in jwk ? "pkcs8" : "spki");
|
|
329
|
+
const cryptoKeyCandidate = await importKey({
|
|
330
|
+
...jwk,
|
|
331
|
+
ext: true
|
|
332
|
+
}, {
|
|
333
|
+
alg: effectiveAlg,
|
|
334
|
+
expect: pemFormat === "pkcs8" ? "private" : "public",
|
|
335
|
+
extractable: true
|
|
336
|
+
});
|
|
337
|
+
if (!isCryptoKey(cryptoKeyCandidate)) throw new JWTError("Failed to convert JWK to a CryptoKey instance suitable for PEM export.", "ERR_JWK_INVALID");
|
|
338
|
+
const cryptoKey = cryptoKeyCandidate;
|
|
339
|
+
switch (pemFormat) {
|
|
340
|
+
case "pkcs8":
|
|
341
|
+
if (cryptoKey.type !== "private") throw new JWTError(`Only a private CryptoKey can be exported to PKCS8 PEM (got ${cryptoKey.type}).`, "ERR_JWK_INVALID");
|
|
342
|
+
return toPKCS8(cryptoKey);
|
|
343
|
+
case "spki":
|
|
344
|
+
if (cryptoKey.type !== "public") throw new JWTError(`Only a public CryptoKey can be exported to SPKI PEM (got ${cryptoKey.type}).`, "ERR_JWK_INVALID");
|
|
345
|
+
return toSPKI(cryptoKey);
|
|
346
|
+
default: throw new JWTError(`Unsupported PEM format: ${String(pemFormat)}`, "ERR_JWK_UNSUPPORTED");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function inferPEMType(pem) {
|
|
350
|
+
if (pem.includes("-----BEGIN PRIVATE KEY-----")) return "pkcs8";
|
|
351
|
+
if (pem.includes("-----BEGIN PUBLIC KEY-----")) return "spki";
|
|
352
|
+
if (pem.includes("-----BEGIN CERTIFICATE-----")) return "x509";
|
|
353
|
+
}
|
|
354
|
+
async function deriveSharedSecret(publicKey, privateKey, options) {
|
|
355
|
+
assertPlainObject(options, "options");
|
|
356
|
+
const { enc: alg, keyLength: requestedKeyLength, partyUInfo, partyVInfo } = options;
|
|
357
|
+
if (!isECDHESAlgorithm(alg)) assertJWEEncSupported(alg);
|
|
358
|
+
if (requestedKeyLength !== void 0) assertDerivedKeyLength(requestedKeyLength);
|
|
359
|
+
const importAlg = isECDHESAlgorithm(alg) ? alg : "ECDH-ES";
|
|
360
|
+
const pubCryptoKey = isCryptoKey(publicKey) ? publicKey : await importKey(publicKey, {
|
|
361
|
+
alg: importAlg,
|
|
362
|
+
expect: "public"
|
|
363
|
+
});
|
|
364
|
+
const privCryptoKey = isCryptoKey(privateKey) ? privateKey : await importKey(privateKey, {
|
|
365
|
+
alg: importAlg,
|
|
366
|
+
expect: "private"
|
|
367
|
+
});
|
|
368
|
+
let keyLength;
|
|
369
|
+
if (requestedKeyLength !== void 0) keyLength = requestedKeyLength;
|
|
370
|
+
else if (alg === "ECDH-ES") throw new JWTError("deriveSharedSecret with enc \"ECDH-ES\" requires an explicit keyLength in options", "ERR_JWK_INVALID");
|
|
371
|
+
else if (isECDHESAlgorithm(alg)) keyLength = aesBitsOf(innerKeyWrapAlg(alg));
|
|
372
|
+
else keyLength = bitLengthCEK(alg);
|
|
373
|
+
return deriveECDHESKey(pubCryptoKey, privCryptoKey, alg, keyLength, partyUInfo ?? /* @__PURE__ */ new Uint8Array(0), partyVInfo ?? /* @__PURE__ */ new Uint8Array(0));
|
|
374
|
+
}
|
|
375
|
+
function getGenerateKeyParams(alg, options) {
|
|
376
|
+
let algorithm;
|
|
377
|
+
let keyUsages;
|
|
378
|
+
const requested = options?.keyUsage;
|
|
379
|
+
const usage = (allowed, fallback) => resolveKeyUsage(requested, {
|
|
380
|
+
allowed,
|
|
381
|
+
fallback,
|
|
382
|
+
alg
|
|
383
|
+
});
|
|
384
|
+
const pairUsage = (allowed, fallback) => assertPairUsages(usage(allowed, fallback), {
|
|
385
|
+
fallback,
|
|
386
|
+
alg
|
|
387
|
+
});
|
|
388
|
+
switch (alg) {
|
|
389
|
+
case "HS256":
|
|
390
|
+
case "HS384":
|
|
391
|
+
case "HS512":
|
|
392
|
+
algorithm = {
|
|
393
|
+
name: "HMAC",
|
|
394
|
+
hash: jwsHashOf(alg)
|
|
395
|
+
};
|
|
396
|
+
keyUsages = usage(SIGNATURE_USAGES, ["sign", "verify"]);
|
|
397
|
+
break;
|
|
398
|
+
case "RS256":
|
|
399
|
+
case "RS384":
|
|
400
|
+
case "RS512":
|
|
401
|
+
algorithm = {
|
|
402
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
403
|
+
modulusLength: assertModulusLength(options?.modulusLength),
|
|
404
|
+
publicExponent: assertPublicExponent(options?.publicExponent),
|
|
405
|
+
hash: jwsHashOf(alg)
|
|
406
|
+
};
|
|
407
|
+
keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
|
|
408
|
+
break;
|
|
409
|
+
case "PS256":
|
|
410
|
+
case "PS384":
|
|
411
|
+
case "PS512":
|
|
412
|
+
algorithm = {
|
|
413
|
+
name: "RSA-PSS",
|
|
414
|
+
modulusLength: assertModulusLength(options?.modulusLength),
|
|
415
|
+
publicExponent: assertPublicExponent(options?.publicExponent),
|
|
416
|
+
hash: jwsHashOf(alg)
|
|
417
|
+
};
|
|
418
|
+
keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
|
|
419
|
+
break;
|
|
420
|
+
case "RSA-OAEP":
|
|
421
|
+
case "RSA-OAEP-256":
|
|
422
|
+
case "RSA-OAEP-384":
|
|
423
|
+
case "RSA-OAEP-512":
|
|
424
|
+
algorithm = {
|
|
425
|
+
name: "RSA-OAEP",
|
|
426
|
+
modulusLength: assertModulusLength(options?.modulusLength),
|
|
427
|
+
publicExponent: assertPublicExponent(options?.publicExponent),
|
|
428
|
+
hash: rsaOaepHashOf(alg)
|
|
429
|
+
};
|
|
430
|
+
keyUsages = pairUsage(KEY_ENCRYPTION_USAGES, [
|
|
431
|
+
"encrypt",
|
|
432
|
+
"decrypt",
|
|
433
|
+
"wrapKey",
|
|
434
|
+
"unwrapKey"
|
|
435
|
+
]);
|
|
436
|
+
break;
|
|
437
|
+
case "A128KW":
|
|
438
|
+
case "A192KW":
|
|
439
|
+
case "A256KW":
|
|
440
|
+
algorithm = {
|
|
441
|
+
name: "AES-KW",
|
|
442
|
+
length: aesBitsOf(alg)
|
|
443
|
+
};
|
|
444
|
+
keyUsages = usage(KEY_WRAPPING_USAGES, ["wrapKey", "unwrapKey"]);
|
|
445
|
+
break;
|
|
446
|
+
case "A128GCM":
|
|
447
|
+
case "A192GCM":
|
|
448
|
+
case "A256GCM":
|
|
449
|
+
case "A128GCMKW":
|
|
450
|
+
case "A192GCMKW":
|
|
451
|
+
case "A256GCMKW":
|
|
452
|
+
algorithm = {
|
|
453
|
+
name: "AES-GCM",
|
|
454
|
+
length: aesBitsOf(alg)
|
|
455
|
+
};
|
|
456
|
+
keyUsages = usage(KEY_ENCRYPTION_USAGES, ["encrypt", "decrypt"]);
|
|
457
|
+
break;
|
|
458
|
+
case "ES256":
|
|
459
|
+
case "ES384":
|
|
460
|
+
case "ES512": {
|
|
461
|
+
const namedCurve = ECDSA_CURVES[alg];
|
|
462
|
+
assertNamedCurve(options?.namedCurve, namedCurve, alg);
|
|
463
|
+
algorithm = {
|
|
464
|
+
name: "ECDSA",
|
|
465
|
+
namedCurve
|
|
466
|
+
};
|
|
467
|
+
keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
case "Ed25519":
|
|
471
|
+
assertNamedCurve(options?.namedCurve, "Ed25519", alg);
|
|
472
|
+
keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
|
|
473
|
+
algorithm = { name: "Ed25519" };
|
|
474
|
+
break;
|
|
475
|
+
case "EdDSA": {
|
|
476
|
+
keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
|
|
477
|
+
const namedCurve = options?.namedCurve ?? "Ed25519";
|
|
478
|
+
if (namedCurve !== "Ed25519") throw new JWTError("Unsupported namedCurve, expected Ed25519", "ERR_JWK_UNSUPPORTED");
|
|
479
|
+
algorithm = { name: namedCurve };
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
case "ECDH-ES":
|
|
483
|
+
case "ECDH-ES+A128KW":
|
|
484
|
+
case "ECDH-ES+A192KW":
|
|
485
|
+
case "ECDH-ES+A256KW": {
|
|
486
|
+
keyUsages = pairUsage(DERIVATION_USAGES, ["deriveBits"]);
|
|
487
|
+
const namedCurve = options?.namedCurve ?? "P-256";
|
|
488
|
+
switch (namedCurve) {
|
|
489
|
+
case "P-256":
|
|
490
|
+
case "P-384":
|
|
491
|
+
case "P-521":
|
|
492
|
+
algorithm = {
|
|
493
|
+
name: "ECDH",
|
|
494
|
+
namedCurve
|
|
495
|
+
};
|
|
496
|
+
break;
|
|
497
|
+
case "X25519":
|
|
498
|
+
algorithm = { name: "X25519" };
|
|
499
|
+
break;
|
|
500
|
+
default: throw new JWTError("Unsupported namedCurve, expected P-256, P-384, P-521 or X25519", "ERR_JWK_UNSUPPORTED");
|
|
501
|
+
}
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
default: throw new JWTError(`Unsupported or invalid algorithm for key generation: ${alg}`, "ERR_JWK_UNSUPPORTED");
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
algorithm,
|
|
508
|
+
keyUsages
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function inferAesImportAlgorithm(enc, cekLengthBytes) {
|
|
512
|
+
const bitLength = cekLengthBytes << 3;
|
|
513
|
+
if (enc) {
|
|
514
|
+
if (enc.includes("GCM")) return {
|
|
515
|
+
name: "AES-GCM",
|
|
516
|
+
length: aesBitsOf(enc)
|
|
517
|
+
};
|
|
518
|
+
if (enc.includes("CBC-HS")) return;
|
|
519
|
+
}
|
|
520
|
+
if (bitLength === 128 || bitLength === 192 || bitLength === 256) return {
|
|
521
|
+
name: "AES-GCM",
|
|
522
|
+
length: bitLength
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
const RESERVED_JWK_PARAMS = /* @__PURE__ */ new Set([
|
|
526
|
+
"kty",
|
|
527
|
+
"alg",
|
|
528
|
+
"key_ops",
|
|
529
|
+
"ext",
|
|
530
|
+
"k",
|
|
531
|
+
"d",
|
|
532
|
+
"n",
|
|
533
|
+
"e",
|
|
534
|
+
"p",
|
|
535
|
+
"q",
|
|
536
|
+
"dp",
|
|
537
|
+
"dq",
|
|
538
|
+
"qi",
|
|
539
|
+
"oth",
|
|
540
|
+
"x",
|
|
541
|
+
"y",
|
|
542
|
+
"crv"
|
|
543
|
+
]);
|
|
544
|
+
function assertNoReservedJWKParams(jwkParams) {
|
|
545
|
+
const reserved = Object.keys(jwkParams).filter((name) => RESERVED_JWK_PARAMS.has(name));
|
|
546
|
+
if (reserved.length > 0) throw new JWTError(`jwkParams must not set reserved JWK members: ${reserved.join(", ")}`, "ERR_INVALID_OPTION");
|
|
547
|
+
}
|
|
548
|
+
function assertNamedCurve(requested, expected, alg) {
|
|
549
|
+
if (requested === void 0 || requested === expected) return;
|
|
550
|
+
throw new JWTError(`"namedCurve" ${requested} contradicts ${alg}, which is defined over ${expected}.`, "ERR_INVALID_OPTION");
|
|
551
|
+
}
|
|
552
|
+
function assertPublicExponent(publicExponent) {
|
|
553
|
+
if (publicExponent === void 0) return new Uint8Array([
|
|
554
|
+
1,
|
|
555
|
+
0,
|
|
556
|
+
1
|
|
557
|
+
]);
|
|
558
|
+
if (!(publicExponent instanceof Uint8Array) || publicExponent.length === 0) throw new JWTError("\"publicExponent\" must be the exponent's big-endian bytes as a Uint8Array.", "ERR_INVALID_OPTION");
|
|
559
|
+
return publicExponent;
|
|
560
|
+
}
|
|
561
|
+
const SIGNATURE_USAGES = ["sign", "verify"];
|
|
562
|
+
const KEY_WRAPPING_USAGES = ["wrapKey", "unwrapKey"];
|
|
563
|
+
const KEY_ENCRYPTION_USAGES = [
|
|
564
|
+
"encrypt",
|
|
565
|
+
"decrypt",
|
|
566
|
+
"wrapKey",
|
|
567
|
+
"unwrapKey"
|
|
568
|
+
];
|
|
569
|
+
const DERIVATION_USAGES = ["deriveBits", "deriveKey"];
|
|
570
|
+
const CONTENT_ENCRYPTION_USAGES = ["encrypt", "decrypt"];
|
|
571
|
+
function resolveKeyUsage(requested, options) {
|
|
572
|
+
const { allowed, fallback, alg } = options;
|
|
573
|
+
if (requested === void 0) return fallback;
|
|
574
|
+
if (!Array.isArray(requested) || requested.length === 0) throw new JWTError("\"keyUsage\" must be a non-empty array.", "ERR_INVALID_OPTION");
|
|
575
|
+
const rejected = requested.filter((entry) => !allowed.includes(entry));
|
|
576
|
+
if (rejected.length > 0) throw new JWTError(`"keyUsage" ${rejected.join(", ")} cannot be served by ${alg}, use ${allowed.join(", ")}.`, "ERR_INVALID_OPTION");
|
|
577
|
+
return requested;
|
|
578
|
+
}
|
|
579
|
+
const PRIVATE_KEY_USAGES = [
|
|
580
|
+
"sign",
|
|
581
|
+
"decrypt",
|
|
582
|
+
"unwrapKey",
|
|
583
|
+
"deriveBits",
|
|
584
|
+
"deriveKey"
|
|
585
|
+
];
|
|
586
|
+
const PUBLIC_KEY_USAGES = [
|
|
587
|
+
"verify",
|
|
588
|
+
"encrypt",
|
|
589
|
+
"wrapKey"
|
|
590
|
+
];
|
|
591
|
+
function assertPairUsages(usages, options) {
|
|
592
|
+
const { fallback, alg } = options;
|
|
593
|
+
for (const [half, side] of [[PRIVATE_KEY_USAGES, "private"], [PUBLIC_KEY_USAGES, "public"]]) {
|
|
594
|
+
const wanted = fallback.filter((entry) => half.includes(entry));
|
|
595
|
+
if (wanted.length === 0 || usages.some((entry) => half.includes(entry))) continue;
|
|
596
|
+
throw new JWTError(`"keyUsage" leaves the ${side} half of a ${alg} key pair unusable, add ${wanted.join(" or ")}.`, "ERR_INVALID_OPTION");
|
|
597
|
+
}
|
|
598
|
+
return usages;
|
|
599
|
+
}
|
|
600
|
+
function assertKidOption(kid) {
|
|
601
|
+
if (kid === void 0 || kid === false || typeof kid === "string") return kid;
|
|
602
|
+
throw new JWTError("\"kid\" must be a string or false.", "ERR_INVALID_OPTION");
|
|
603
|
+
}
|
|
604
|
+
async function withGeneratedKid(kid, jwk) {
|
|
605
|
+
if (kid === false) return jwk;
|
|
606
|
+
return {
|
|
607
|
+
...jwk,
|
|
608
|
+
kid: kid ?? await thumbprint(jwk)
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
const PEM_ALGORITHMS = /* @__PURE__ */ new Set(Object.keys({
|
|
612
|
+
"PS256": true,
|
|
613
|
+
"PS384": true,
|
|
614
|
+
"PS512": true,
|
|
615
|
+
"RS256": true,
|
|
616
|
+
"RS384": true,
|
|
617
|
+
"RS512": true,
|
|
618
|
+
"RSA-OAEP": true,
|
|
619
|
+
"RSA-OAEP-256": true,
|
|
620
|
+
"RSA-OAEP-384": true,
|
|
621
|
+
"RSA-OAEP-512": true,
|
|
622
|
+
"ES256": true,
|
|
623
|
+
"ES384": true,
|
|
624
|
+
"ES512": true,
|
|
625
|
+
"ECDH-ES": true,
|
|
626
|
+
"ECDH-ES+A128KW": true,
|
|
627
|
+
"ECDH-ES+A192KW": true,
|
|
628
|
+
"ECDH-ES+A256KW": true,
|
|
629
|
+
"Ed25519": true,
|
|
630
|
+
"EdDSA": true
|
|
631
|
+
}));
|
|
632
|
+
function assertWrappableCEK(cek, alg) {
|
|
633
|
+
if (cek.length >= 16 && cek.length % 8 === 0) return;
|
|
634
|
+
throw new JWTError(`${alg} wraps a key of 16 or more bytes in whole 8-byte blocks (got ${cek.length}).`, "ERR_INVALID_OPTION");
|
|
635
|
+
}
|
|
636
|
+
async function unwrapping(operation) {
|
|
637
|
+
try {
|
|
638
|
+
return await operation;
|
|
639
|
+
} catch (error) {
|
|
640
|
+
throw asDecryptionError(error);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function assertPBES2Algorithm(alg) {
|
|
644
|
+
if (typeof alg === "string" && PBES2_ALGORITHMS.includes(alg)) return;
|
|
645
|
+
throw new JWTError(`Password derivation is defined for ${PBES2_ALGORITHMS.join(", ")}, not ${String(alg)}.`, "ERR_JWK_UNSUPPORTED");
|
|
646
|
+
}
|
|
647
|
+
function assertKeyBytesArg(value, name) {
|
|
648
|
+
if (value instanceof Uint8Array || isCryptoKey(value)) return;
|
|
649
|
+
throw new JWTError(`"${name}" must be a Uint8Array or a CryptoKey.`, "ERR_INVALID_OPTION");
|
|
650
|
+
}
|
|
651
|
+
function assertModulusLength(modulusLength) {
|
|
652
|
+
const length = modulusLength ?? 2048;
|
|
653
|
+
if (!Number.isInteger(length) || length < 2048) throw new JWTError("modulusLength must be at least 2048 bits", "ERR_INVALID_OPTION");
|
|
654
|
+
return length;
|
|
655
|
+
}
|
|
656
|
+
function assertPartyInfoLength(name, bytes) {
|
|
657
|
+
if (bytes.length > 1024) throw new JWTError(`Invalid JWE: "${name}" must not exceed ${MAX_PARTY_INFO_BYTES} bytes (got ${bytes.length}).`, "ERR_JWE_INVALID");
|
|
658
|
+
}
|
|
659
|
+
function assertKeyWrapSegmentLength(name, bytes, expected, alg) {
|
|
660
|
+
if (bytes.length !== expected) throw new JWTError(`Invalid JWE: "${name}" must be ${expected} bytes for ${alg} (got ${bytes.length}).`, "ERR_JWE_INVALID");
|
|
661
|
+
}
|
|
662
|
+
function assertDerivedKeyLength(keyLength) {
|
|
663
|
+
if (!Number.isInteger(keyLength) || keyLength <= 0 || keyLength % 8 !== 0 || keyLength > 8192) throw new JWTError(`keyLength must be a positive multiple of 8 no greater than 8192 bits, got ${keyLength}`, "ERR_INVALID_OPTION");
|
|
664
|
+
}
|
|
665
|
+
function assertCryptoKeyFor(alg, key, role) {
|
|
666
|
+
if (isCryptoKey(key)) return;
|
|
667
|
+
throw new JWTError(`${alg} requires the ${role} key to be a CryptoKey`, "ERR_JWK_INVALID");
|
|
668
|
+
}
|
|
669
|
+
function segmentBytes(value, name) {
|
|
670
|
+
return typeof value === "string" ? decodeSegment(value, {
|
|
671
|
+
family: "JWE",
|
|
672
|
+
what: `"${name}"`
|
|
673
|
+
}) : value;
|
|
674
|
+
}
|
|
675
|
+
function withAlg(jwk, alg) {
|
|
676
|
+
return {
|
|
677
|
+
...jwk,
|
|
678
|
+
alg
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function generatedPairAlgorithm(alg) {
|
|
682
|
+
return alg;
|
|
683
|
+
}
|
|
684
|
+
function generatedSecretAlgorithm(alg) {
|
|
685
|
+
return alg;
|
|
686
|
+
}
|
|
687
|
+
const PUBLIC_KEY_OPS = /* @__PURE__ */ new Map([
|
|
688
|
+
["sign", "verify"],
|
|
689
|
+
["verify", "verify"],
|
|
690
|
+
["decrypt", "encrypt"],
|
|
691
|
+
["encrypt", "encrypt"],
|
|
692
|
+
["unwrapKey", "wrapKey"],
|
|
693
|
+
["wrapKey", "wrapKey"]
|
|
694
|
+
]);
|
|
695
|
+
function publicKeyOps(keyOps) {
|
|
696
|
+
if (!Array.isArray(keyOps)) return [];
|
|
697
|
+
const ops = [];
|
|
698
|
+
for (const op of keyOps) {
|
|
699
|
+
const publicOp = typeof op === "string" ? PUBLIC_KEY_OPS.get(op) : void 0;
|
|
700
|
+
if (publicOp !== void 0 && !ops.includes(publicOp)) ops.push(publicOp);
|
|
701
|
+
}
|
|
702
|
+
return ops;
|
|
703
|
+
}
|
|
704
|
+
function requestedKeyOps(options, key) {
|
|
705
|
+
return options.keyUsage === void 0 ? void 0 : [...key.usages];
|
|
706
|
+
}
|
|
707
|
+
function withKeyOps(jwk, keyOps) {
|
|
708
|
+
return keyOps === void 0 ? jwk : {
|
|
709
|
+
...jwk,
|
|
710
|
+
key_ops: keyOps
|
|
711
|
+
};
|
|
712
|
+
}
|
|
4
713
|
export { JWTError, UnsecureError, WeakMapJWKCache, clearJWKCache, configureJWKCache, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, exportJWK, exportKey, exportPEM, generateJWK, generateKey, getJWKsFromSet, importKey, importPEM, isJWTError, isUnsecureError, thumbprint, toPublicJWK, unwrapKey, wrapKey };
|