unjwt 0.8.1 → 0.8.2

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.
@@ -1,16 +1,22 @@
1
1
  import { safeJsonParse, sanitizeObjectCopy, secureRandomBytes, textEncoder } from "./libs/unsecure.mjs";
2
- import { JWTError, assertClaimValidationOptions, assertCritShape, assertCryptoKey, assertPlainObject, assertStringList, base64Parse, base64Stringify, base64UrlParse, base64UrlStringify, concatUint8Arrays, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet, isPlainObject, parsePayloadBytes, parsePayloadSegment, uint32be, validateJwtClaims } from "./_jwt-internal.mjs";
3
- import { ECDSA_CURVES, PBES2_ALGORITHMS, aesBitsOf, checkKeyUsage, cryptoKeyCurve, hashBitsOf, inferJWEAllowedAlgorithms, inferJWSAllowedAlgorithms, innerKeyWrapAlg, isAlgorithm, isContentEncryptionAlgorithm, isEd25519Signature, jwsHashOf, lengthOf, modulusLengthOf, namedCurveOf, rsaOaepHashOf, unusableKey } from "./algorithms.mjs";
2
+ import { JWTError, assertClaimValidationOptions, assertCritShape, assertCryptoKey, assertPlainObject, assertStringList, base64Parse, base64Stringify, base64UrlParse, base64UrlStringify, concatUint8Arrays, isAsymmetricJWK, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet, isPlainObject, isPublicJWK, parsePayloadBytes, parsePayloadSegment, uint32be, validateJwtClaims } from "./_jwt-internal.mjs";
3
+ import { ECDSA_CURVES, PBES2_ALGORITHMS, aesBitsOf, checkKeyUsage, cryptoKeyCurve, digestUrl, hashBitsOf, inferJWEAllowedAlgorithms, inferJWSAllowedAlgorithms, innerKeyWrapAlg, isAlgorithm, isContentEncryptionAlgorithm, isECDHESAlgorithm, isEd25519Signature, isJWSAlgorithm, isKeyManagementAlgorithm, isPBES2Algorithm, jwsHashOf, lengthOf, modulusLengthOf, namedCurveOf, pbes2HashOf, rsaOaepHashOf, shaBitsOf, unusableKey } from "./digest.mjs";
4
4
  const MAX_QUOTED_VALUE = 64;
5
5
  function quoteTokenValue(value) {
6
6
  const text = String(value);
7
7
  return JSON.stringify(text.length > MAX_QUOTED_VALUE ? `${text.slice(0, MAX_QUOTED_VALUE)}…` : text);
8
8
  }
9
- const HASHED_SIGNATURE_ALGORITHMS = {
10
- HS: "HMAC",
11
- RS: "RSASSA-PKCS1-v1_5",
12
- PS: "RSA-PSS"
13
- };
9
+ const HASHED_SIGNATURE_ALGORITHMS = /* @__PURE__ */ Object.freeze({
10
+ HS256: "HMAC",
11
+ HS384: "HMAC",
12
+ HS512: "HMAC",
13
+ RS256: "RSASSA-PKCS1-v1_5",
14
+ RS384: "RSASSA-PKCS1-v1_5",
15
+ RS512: "RSASSA-PKCS1-v1_5",
16
+ PS256: "RSA-PSS",
17
+ PS384: "RSA-PSS",
18
+ PS512: "RSA-PSS"
19
+ });
14
20
  async function sign(alg, key, data) {
15
21
  checkSigCryptoKey(key, alg, "sign");
16
22
  const signature = await crypto.subtle.sign(subtleAlgorithm(alg, key.algorithm), key, data);
@@ -35,9 +41,9 @@ function checkSigCryptoKey(key, alg, usage) {
35
41
  case "PS256":
36
42
  case "PS384":
37
43
  case "PS512": {
38
- const name = HASHED_SIGNATURE_ALGORITHMS[alg.slice(0, 2)];
44
+ const name = HASHED_SIGNATURE_ALGORITHMS[alg];
39
45
  if (!isAlgorithm(key.algorithm, name)) throw unusableKey(name);
40
- const expected = Number.parseInt(alg.slice(2), 10);
46
+ const expected = shaBitsOf(jwsHashOf(alg));
41
47
  if (hashBitsOf(key.algorithm.hash) !== expected) throw unusableKey(`SHA-${expected}`, "algorithm.hash");
42
48
  break;
43
49
  }
@@ -53,45 +59,49 @@ function checkSigCryptoKey(key, alg, usage) {
53
59
  if (key.algorithm.namedCurve !== expected) throw unusableKey(expected, "algorithm.namedCurve");
54
60
  break;
55
61
  }
56
- default: throw new JWTError("CryptoKey does not support this operation", "ERR_JWK_INVALID");
57
62
  }
58
63
  checkKeyUsage(key, usage);
59
64
  }
60
65
  function subtleAlgorithm(alg, algorithm) {
61
- const hash = jwsHashOf(alg);
62
66
  switch (alg) {
63
67
  case "HS256":
64
68
  case "HS384":
65
69
  case "HS512": return {
66
- hash,
70
+ hash: jwsHashOf(alg),
67
71
  name: "HMAC"
68
72
  };
69
73
  case "PS256":
70
74
  case "PS384":
71
- case "PS512": return {
72
- hash,
73
- name: "RSA-PSS",
74
- saltLength: Number.parseInt(alg.slice(-3), 10) >> 3
75
- };
75
+ case "PS512": {
76
+ const hash = jwsHashOf(alg);
77
+ return {
78
+ hash,
79
+ name: "RSA-PSS",
80
+ saltLength: shaBitsOf(hash) >> 3
81
+ };
82
+ }
76
83
  case "RS256":
77
84
  case "RS384":
78
85
  case "RS512": return {
79
- hash,
86
+ hash: jwsHashOf(alg),
80
87
  name: "RSASSA-PKCS1-v1_5"
81
88
  };
82
89
  case "ES256":
83
90
  case "ES384":
84
91
  case "ES512": return {
85
- hash,
92
+ hash: jwsHashOf(alg),
86
93
  name: "ECDSA",
87
94
  namedCurve: namedCurveOf(algorithm)
88
95
  };
89
96
  case "Ed25519":
90
97
  case "EdDSA": return { name: "Ed25519" };
91
- default: throw new JWTError(`alg ${alg} is not supported either by JOSE or your javascript runtime`, "ERR_JWS_ALG_NOT_ALLOWED");
98
+ default: return unsupportedSignatureAlgorithm(alg);
92
99
  }
93
100
  }
94
- const IV_BIT_LENGTHS = {
101
+ function unsupportedSignatureAlgorithm(alg) {
102
+ throw new JWTError(`alg ${String(alg)} is not supported either by JOSE or your javascript runtime`, "ERR_JWS_ALG_NOT_ALLOWED");
103
+ }
104
+ const IV_BIT_LENGTHS = /* @__PURE__ */ Object.freeze({
95
105
  "A128GCM": 96,
96
106
  "A128GCMKW": 96,
97
107
  "A192GCM": 96,
@@ -101,19 +111,17 @@ const IV_BIT_LENGTHS = {
101
111
  "A128CBC-HS256": 128,
102
112
  "A192CBC-HS384": 128,
103
113
  "A256CBC-HS512": 128
104
- };
105
- const CEK_BIT_LENGTHS = {
114
+ });
115
+ const CEK_BIT_LENGTHS = /* @__PURE__ */ Object.freeze({
106
116
  "A128GCM": 128,
107
117
  "A192GCM": 192,
108
118
  "A256GCM": 256,
109
119
  "A128CBC-HS256": 256,
110
120
  "A192CBC-HS384": 384,
111
121
  "A256CBC-HS512": 512
112
- };
122
+ });
113
123
  function bitLengthIV(alg) {
114
- const length = IV_BIT_LENGTHS[alg];
115
- if (length === void 0) throw new JWTError(`Unsupported JWE Algorithm: ${quoteTokenValue(alg)}`, "ERR_JWE_INVALID");
116
- return length;
124
+ return IV_BIT_LENGTHS[alg];
117
125
  }
118
126
  function generateIV(alg) {
119
127
  return crypto.getRandomValues(new Uint8Array(bitLengthIV(alg) >> 3));
@@ -121,7 +129,7 @@ function generateIV(alg) {
121
129
  function checkIvLength(enc, iv) {
122
130
  if (iv.length << 3 !== bitLengthIV(enc)) throw new JWTError("Invalid Initialization Vector length", "ERR_JWE_INVALID");
123
131
  }
124
- const TAG_BIT_LENGTHS = {
132
+ const TAG_BIT_LENGTHS = /* @__PURE__ */ Object.freeze({
125
133
  "A128GCM": 128,
126
134
  "A128GCMKW": 128,
127
135
  "A192GCM": 128,
@@ -131,19 +139,15 @@ const TAG_BIT_LENGTHS = {
131
139
  "A128CBC-HS256": 128,
132
140
  "A192CBC-HS384": 192,
133
141
  "A256CBC-HS512": 256
134
- };
142
+ });
135
143
  function bitLengthTag(alg) {
136
- const length = TAG_BIT_LENGTHS[alg];
137
- if (length === void 0) throw new JWTError(`Unsupported JWE Algorithm: ${quoteTokenValue(alg)}`, "ERR_JWE_INVALID");
138
- return length;
144
+ return TAG_BIT_LENGTHS[alg];
139
145
  }
140
146
  function checkTagLength(enc, tag) {
141
147
  if (tag.length << 3 !== bitLengthTag(enc)) throw new JWTError("Invalid Authentication Tag length", "ERR_JWE_INVALID");
142
148
  }
143
- function bitLengthCEK(alg) {
144
- const length = CEK_BIT_LENGTHS[alg];
145
- if (length === void 0) throw new JWTError(`Unsupported JWE Algorithm: ${quoteTokenValue(alg)}`, "ERR_JWE_INVALID");
146
- return length;
149
+ function bitLengthCEK(enc) {
150
+ return CEK_BIT_LENGTHS[enc];
147
151
  }
148
152
  function generateCEK(alg) {
149
153
  return crypto.getRandomValues(new Uint8Array(bitLengthCEK(alg) >> 3));
@@ -155,29 +159,18 @@ function checkCEKLength(cek, expected) {
155
159
  function assertOctKeyLength(bytes, alg) {
156
160
  if (!alg) return;
157
161
  if (alg === "HS256" || alg === "HS384" || alg === "HS512") {
158
- const minBytes = Number.parseInt(alg.slice(2), 10) >> 3;
162
+ const minBytes = shaBitsOf(jwsHashOf(alg)) >> 3;
159
163
  if (bytes.length < minBytes) throw new JWTError(`${alg} requires a key of at least ${minBytes} bytes (got ${bytes.length})`, "ERR_JWK_INVALID");
160
164
  return;
161
165
  }
162
- const exactBits = /^A(128|192|256)(GCM)?KW$/.test(alg) ? aesBitsOf(alg) : CEK_BIT_LENGTHS[alg];
166
+ const exactBits = isKeyWrapAlgorithm(alg) ? aesBitsOf(alg) : isContentEncryption(alg) ? CEK_BIT_LENGTHS[alg] : void 0;
163
167
  if (exactBits !== void 0 && bytes.length << 3 !== exactBits) throw new JWTError(`${alg} requires a key of exactly ${exactBits >> 3} bytes (got ${bytes.length})`, "ERR_JWK_INVALID");
164
168
  }
165
169
  function checkAESCryptoKey(key, alg, usage) {
166
- switch (alg) {
167
- case "A128GCM":
168
- case "A192GCM":
169
- case "A256GCM":
170
- case "A128KW":
171
- case "A192KW":
172
- case "A256KW": {
173
- const name = alg.endsWith("KW") ? "AES-KW" : "AES-GCM";
174
- if (!isAlgorithm(key.algorithm, name)) throw unusableKey(name);
175
- const expected = aesBitsOf(alg);
176
- if (key.algorithm.length !== expected) throw unusableKey(expected, "algorithm.length");
177
- break;
178
- }
179
- default: throw new JWTError("CryptoKey does not support this operation", "ERR_JWK_INVALID");
180
- }
170
+ const name = alg.endsWith("KW") ? "AES-KW" : "AES-GCM";
171
+ if (!isAlgorithm(key.algorithm, name)) throw unusableKey(name);
172
+ const expected = aesBitsOf(alg);
173
+ if (key.algorithm.length !== expected) throw unusableKey(expected, "algorithm.length");
181
174
  checkKeyUsage(key, usage);
182
175
  }
183
176
  async function aesKwWrap(alg, key, cek) {
@@ -199,7 +192,7 @@ async function aesKwUnwrap(alg, key, encryptedKey) {
199
192
  return new Uint8Array(await crypto.subtle.exportKey("raw", cryptoKeyCek));
200
193
  }
201
194
  async function gcmkwEncrypt(alg, key, plaintext, iv) {
202
- const wrapped = await encrypt(alg.slice(0, 7), plaintext, key, iv, /* @__PURE__ */ new Uint8Array(0));
195
+ const wrapped = await encrypt(gcmOf(alg), plaintext, key, iv, /* @__PURE__ */ new Uint8Array(0));
203
196
  return {
204
197
  encryptedKey: wrapped.ciphertext,
205
198
  iv: base64UrlStringify(wrapped.iv),
@@ -207,7 +200,7 @@ async function gcmkwEncrypt(alg, key, plaintext, iv) {
207
200
  };
208
201
  }
209
202
  async function gcmkwDecrypt(alg, key, ciphertext, iv, tag) {
210
- return decrypt(alg.slice(0, 7), key, ciphertext, iv, tag, /* @__PURE__ */ new Uint8Array(0));
203
+ return decrypt(gcmOf(alg), key, ciphertext, iv, tag, /* @__PURE__ */ new Uint8Array(0));
211
204
  }
212
205
  async function encrypt(enc, plaintext, cek, iv, aad) {
213
206
  if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) throw new JWTError("Key must be one of type: CryptoKey or Uint8Array", "ERR_JWK_INVALID");
@@ -217,14 +210,14 @@ async function encrypt(enc, plaintext, cek, iv, aad) {
217
210
  case "A128CBC-HS256":
218
211
  case "A192CBC-HS384":
219
212
  case "A256CBC-HS512":
220
- if (cek instanceof Uint8Array) checkCEKLength(cek, Number.parseInt(enc.slice(-3), 10));
213
+ if (cek instanceof Uint8Array) checkCEKLength(cek, bitLengthCEK(enc));
221
214
  return cbcEncrypt(enc, plaintext, cek, iv, aad);
222
215
  case "A128GCM":
223
216
  case "A192GCM":
224
217
  case "A256GCM":
225
- if (cek instanceof Uint8Array) checkCEKLength(cek, aesBitsOf(enc));
218
+ if (cek instanceof Uint8Array) checkCEKLength(cek, bitLengthCEK(enc));
226
219
  return gcmEncrypt(enc, plaintext, cek, iv, aad);
227
- default: throw new JWTError("Unsupported JWE Content Encryption Algorithm", "ERR_JWE_INVALID");
220
+ default: return unsupportedContentEncryption(enc);
228
221
  }
229
222
  }
230
223
  async function decrypt(enc, cek, ciphertext, iv, tag, aad) {
@@ -237,14 +230,14 @@ async function decrypt(enc, cek, ciphertext, iv, tag, aad) {
237
230
  case "A128CBC-HS256":
238
231
  case "A192CBC-HS384":
239
232
  case "A256CBC-HS512":
240
- if (cek instanceof Uint8Array) checkCEKLength(cek, Number.parseInt(enc.slice(-3), 10));
233
+ if (cek instanceof Uint8Array) checkCEKLength(cek, bitLengthCEK(enc));
241
234
  return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad);
242
235
  case "A128GCM":
243
236
  case "A192GCM":
244
237
  case "A256GCM":
245
- if (cek instanceof Uint8Array) checkCEKLength(cek, aesBitsOf(enc));
238
+ if (cek instanceof Uint8Array) checkCEKLength(cek, bitLengthCEK(enc));
246
239
  return gcmDecrypt(enc, cek, ciphertext, iv, tag, aad);
247
- default: throw new JWTError("Unsupported JWE Content Encryption Algorithm", "ERR_JWE_INVALID");
240
+ default: return unsupportedContentEncryption(enc);
248
241
  }
249
242
  }
250
243
  async function getAESKWCryptoKey(key, alg, options = {}) {
@@ -369,16 +362,33 @@ async function timingSafeEqual(a, b) {
369
362
  function uint64be(value) {
370
363
  return concatUint8Arrays(uint32be(Math.floor(value / 2 ** 32)), uint32be(value % 2 ** 32));
371
364
  }
365
+ function gcmOf(alg) {
366
+ return alg.slice(0, 7);
367
+ }
368
+ function isKeyWrapAlgorithm(alg) {
369
+ return alg.startsWith("A") && alg.endsWith("KW");
370
+ }
371
+ function isContentEncryption(alg) {
372
+ return Object.hasOwn(CEK_BIT_LENGTHS, alg);
373
+ }
374
+ function unsupportedContentEncryption(enc) {
375
+ throw new JWTError(`Unsupported JWE Content Encryption Algorithm: ${quoteTokenValue(String(enc))}`, "ERR_JWE_INVALID");
376
+ }
372
377
  async function jwkTokey(jwk, options = {}) {
373
- if (!jwk.alg) throw new JWTError("\"alg\" argument is required when \"jwk.alg\" is not present", "ERR_JWK_INVALID");
374
- const { algorithm, keyUsages } = subtleMapping(jwk);
378
+ const alg = jwk.alg ?? options.alg;
379
+ if (!alg) throw new JWTError("\"alg\" argument is required when \"jwk.alg\" is not present", "ERR_JWK_INVALID");
380
+ const { algorithm, keyUsages } = subtleMapping(jwk, alg);
381
+ const material = {
382
+ ...jwk,
383
+ alg
384
+ };
375
385
  const isPrivate = "d" in jwk && jwk.d !== void 0;
376
386
  const extractable = jwk.ext === false ? false : options.extractable ?? !isPrivate;
377
387
  try {
378
- return await crypto.subtle.importKey("jwk", jwk, algorithm, extractable, permittedUsages(jwk, keyUsages));
388
+ return await crypto.subtle.importKey("jwk", material, algorithm, extractable, permittedUsages(jwk, keyUsages));
379
389
  } catch (error) {
380
390
  if (error instanceof JWTError) throw error;
381
- throw new JWTError(`Key is not usable for ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID", error);
391
+ throw new JWTError(`Key is not usable for ${quoteTokenValue(alg)}.`, "ERR_JWK_INVALID", error);
382
392
  }
383
393
  }
384
394
  async function keyToJWK(key) {
@@ -390,7 +400,8 @@ async function keyToJWK(key) {
390
400
  else {
391
401
  if (!isCryptoKey(key)) throw new JWTError("Key must be one of type: CryptoKey or Uint8Array", "ERR_JWK_INVALID");
392
402
  if (!key.extractable) throw new JWTError("non-extractable CryptoKey cannot be exported as a JWK", "ERR_JWK_INVALID");
393
- jwk = await crypto.subtle.exportKey("jwk", key);
403
+ const { ext: _ext, key_ops: _keyOps, ...exported } = await crypto.subtle.exportKey("jwk", key);
404
+ jwk = exported;
394
405
  }
395
406
  return jwk;
396
407
  }
@@ -401,18 +412,18 @@ function permittedUsages(jwk, keyUsages) {
401
412
  if (permitted.length === 0) throw new JWTError(`JWK "key_ops" does not permit ${keyUsages.join(", ")}.`, "ERR_JWK_INVALID");
402
413
  return permitted;
403
414
  }
404
- function subtleMapping(jwk) {
415
+ function subtleMapping(jwk, alg) {
405
416
  let algorithm;
406
417
  let keyUsages;
407
418
  switch (jwk.kty) {
408
419
  case "RSA":
409
- switch (jwk.alg) {
420
+ switch (alg) {
410
421
  case "PS256":
411
422
  case "PS384":
412
423
  case "PS512":
413
424
  algorithm = {
414
425
  name: "RSA-PSS",
415
- hash: jwsHashOf(jwk.alg)
426
+ hash: jwsHashOf(alg)
416
427
  };
417
428
  keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
418
429
  break;
@@ -421,7 +432,7 @@ function subtleMapping(jwk) {
421
432
  case "RS512":
422
433
  algorithm = {
423
434
  name: "RSASSA-PKCS1-v1_5",
424
- hash: jwsHashOf(jwk.alg)
435
+ hash: jwsHashOf(alg)
425
436
  };
426
437
  keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
427
438
  break;
@@ -431,21 +442,21 @@ function subtleMapping(jwk) {
431
442
  case "RSA-OAEP-512":
432
443
  algorithm = {
433
444
  name: "RSA-OAEP",
434
- hash: rsaOaepHashOf(jwk.alg)
445
+ hash: rsaOaepHashOf(alg)
435
446
  };
436
447
  keyUsages = hasPrivateMember(jwk) ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
437
448
  break;
438
- default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID");
449
+ default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(alg)}.`, "ERR_JWK_INVALID");
439
450
  }
440
451
  break;
441
452
  case "EC":
442
- switch (jwk.alg) {
453
+ switch (alg) {
443
454
  case "ES256":
444
455
  case "ES384":
445
456
  case "ES512":
446
457
  algorithm = {
447
458
  name: "ECDSA",
448
- namedCurve: ECDSA_CURVES[jwk.alg]
459
+ namedCurve: ECDSA_CURVES[alg]
449
460
  };
450
461
  keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
451
462
  break;
@@ -463,11 +474,11 @@ function subtleMapping(jwk) {
463
474
  };
464
475
  keyUsages = hasPrivateMember(jwk) ? ["deriveBits"] : [];
465
476
  break;
466
- default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID");
477
+ default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(alg)}.`, "ERR_JWK_INVALID");
467
478
  }
468
479
  break;
469
480
  case "OKP":
470
- switch (jwk.alg) {
481
+ switch (alg) {
471
482
  case "Ed25519":
472
483
  case "EdDSA":
473
484
  algorithm = { name: requireCurve(jwk, ["Ed25519"]) };
@@ -480,7 +491,7 @@ function subtleMapping(jwk) {
480
491
  algorithm = { name: requireCurve(jwk, ["X25519"]) };
481
492
  keyUsages = hasPrivateMember(jwk) ? ["deriveBits"] : [];
482
493
  break;
483
- default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID");
494
+ default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(alg)}.`, "ERR_JWK_INVALID");
484
495
  }
485
496
  break;
486
497
  default: throw new JWTError(`Invalid or unsupported JWK "kty" (Key Type) Parameter value: ${quoteTokenValue(jwk.kty)}.`, "ERR_JWK_INVALID");
@@ -510,19 +521,17 @@ async function decryptRSAES(alg, key, encryptedKey) {
510
521
  }
511
522
  function checkRSACryptoKey(key, alg, usage) {
512
523
  if (!isAlgorithm(key.algorithm, "RSA-OAEP")) throw unusableKey("RSA-OAEP");
513
- const expected = Number.parseInt(alg.slice(9), 10) || 1;
524
+ const expected = shaBitsOf(rsaOaepHashOf(alg));
514
525
  if (hashBitsOf(key.algorithm.hash) !== expected) throw unusableKey(`SHA-${expected}`, "algorithm.hash");
515
526
  checkKeyUsage(key, usage);
516
527
  }
517
528
  function checkRSAModulusLength(alg, key) {
518
- if (alg.startsWith("RS") || alg.startsWith("PS") || alg.startsWith("RSA")) {
519
- const modulusLength = modulusLengthOf(key.algorithm);
520
- if (typeof modulusLength !== "number" || modulusLength < 2048) throw new JWTError(`${alg} requires key modulusLength to be 2048 bits or larger`, "ERR_JWK_INVALID");
521
- }
529
+ const modulusLength = modulusLengthOf(key.algorithm);
530
+ if (typeof modulusLength !== "number" || modulusLength < 2048) throw new JWTError(`${alg} requires key modulusLength to be 2048 bits or larger`, "ERR_JWK_INVALID");
522
531
  }
523
532
  async function deriveECDHESKey(publicKey, privateKey, algorithm, keyLength, apu = /* @__PURE__ */ new Uint8Array(0), apv = /* @__PURE__ */ new Uint8Array(0)) {
524
- checkECDHCryptoKey(publicKey, "ECDH");
525
- checkECDHCryptoKey(privateKey, "ECDH", "deriveBits");
533
+ checkECDHCryptoKey(publicKey);
534
+ checkECDHCryptoKey(privateKey, "deriveBits");
526
535
  const value = concatUint8Arrays(lengthAndInput(textEncoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
527
536
  const length = publicKey.algorithm.name === "X25519" ? 256 : Math.ceil(Number.parseInt((namedCurveOf(publicKey.algorithm) ?? "").slice(-3), 10) / 8) << 3;
528
537
  return concatKdf(new Uint8Array(await crypto.subtle.deriveBits({
@@ -531,7 +540,9 @@ async function deriveECDHESKey(publicKey, privateKey, algorithm, keyLength, apu
531
540
  }, privateKey, length)), keyLength, value);
532
541
  }
533
542
  function ecdhDerivedBits(alg, enc) {
534
- return alg === "ECDH-ES" ? bitLengthCEK(enc) : Number.parseInt(alg.slice(-5, -2), 10);
543
+ if (alg !== "ECDH-ES") return aesBitsOf(innerKeyWrapAlg(alg));
544
+ if (enc) return bitLengthCEK(enc);
545
+ throw new JWTError("ECDH-ES requires \"enc\", the content encryption algorithm the key is agreed for.", "ERR_JWE_INVALID");
535
546
  }
536
547
  function generateEphemeralKeyPair(recipientKey) {
537
548
  return crypto.subtle.generateKey(recipientKey.algorithm, true, ["deriveBits"]);
@@ -545,7 +556,7 @@ function assertECDHKeyAllowed(key) {
545
556
  default: throw new JWTError("ECDH with the provided key is not allowed or not supported", "ERR_JWK_INVALID");
546
557
  }
547
558
  }
548
- function checkECDHCryptoKey(key, alg, usage) {
559
+ function checkECDHCryptoKey(key, usage) {
549
560
  switch (key.algorithm.name) {
550
561
  case "ECDH":
551
562
  case "X25519": break;
@@ -614,9 +625,9 @@ async function deriveKey(p2s, alg, p2c, key) {
614
625
  assertPBES2Salt(p2s, "\"p2s\"");
615
626
  if (p2c === void 0 || p2c < 1) throw new JWTError("PBES2 Iteration Count Parameter must be a positive integer", "ERR_INVALID_OPTION");
616
627
  const salt = concatUint8Arrays(textEncoder.encode(alg), new Uint8Array([0]), p2s);
617
- const keylen = Number.parseInt(alg.slice(13, 16), 10);
628
+ const keylen = aesBitsOf(innerKeyWrapAlg(alg));
618
629
  const subtleAlg = {
619
- hash: `SHA-${alg.slice(8, 11)}`,
630
+ hash: pbes2HashOf(alg),
620
631
  iterations: p2c,
621
632
  name: "PBKDF2",
622
633
  salt
@@ -710,7 +721,7 @@ async function ecdhesWrap(alg, options) {
710
721
  epk = await exportPublicJwkFrom(generated.publicKey);
711
722
  }
712
723
  const kdfAlg = alg === "ECDH-ES" ? contentAlgorithm(enc) : alg;
713
- const sharedSecret = await deriveECDHESKey(recipientKey, ephemeralPrivateKey, kdfAlg, ecdhDerivedBits(alg, kdfAlg), apu, apv);
724
+ const sharedSecret = await deriveECDHESKey(recipientKey, ephemeralPrivateKey, kdfAlg, ecdhDerivedBits(alg, enc), apu, apv);
714
725
  const parameters = { epk };
715
726
  if (apu) parameters.apu = base64UrlStringify(apu);
716
727
  if (apv) parameters.apv = base64UrlStringify(apv);
@@ -726,6 +737,7 @@ async function ecdhesWrap(alg, options) {
726
737
  };
727
738
  }
728
739
  async function normalizeEpk(epk, options) {
740
+ const { alg } = options;
729
741
  const recipientCurve = cryptoKeyCurve(options.recipientKey);
730
742
  if (isCryptoKey(epk)) {
731
743
  if (epk.type !== "public") throw invalidEpk("must not contain private key material.");
@@ -746,12 +758,12 @@ async function normalizeEpk(epk, options) {
746
758
  crv,
747
759
  x,
748
760
  y,
749
- alg: options.alg
761
+ alg
750
762
  } : {
751
763
  kty: "OKP",
752
764
  crv,
753
765
  x,
754
- alg: options.alg
766
+ alg
755
767
  });
756
768
  }
757
769
  const EC_ECDH_CURVES = /* @__PURE__ */ new Set([
@@ -800,10 +812,7 @@ function toPublicEpkJwk(jwk) {
800
812
  };
801
813
  }
802
814
  async function ensurePrivateKey(alg, value) {
803
- const normalized = isCryptoKey(value) ? value : await jwkTokey(value.alg ? value : {
804
- ...value,
805
- alg
806
- });
815
+ const normalized = isCryptoKey(value) ? value : await jwkTokey(value, { alg });
807
816
  if (normalized.type !== "private") throw new JWTError("ECDH-ES ephemeral private key must have type \"private\".", "ERR_JWK_INVALID");
808
817
  return normalized;
809
818
  }
@@ -1121,8 +1130,7 @@ async function thumbprint(jwk, options = {}) {
1121
1130
  if (typeof value !== "string" || value.length === 0) throw new JWTError(`JWK thumbprint requires the member "${name}" on an ${jwk.kty} key.`, "ERR_JWK_INVALID");
1122
1131
  return `${JSON.stringify(name)}:${JSON.stringify(value)}`;
1123
1132
  });
1124
- const digest = await crypto.subtle.digest(hash, textEncoder.encode(`{${canonical.join(",")}}`));
1125
- return base64UrlStringify(new Uint8Array(digest));
1133
+ return digestUrl(`{${canonical.join(",")}}`, hash);
1126
1134
  }
1127
1135
  const MAX_PARTY_INFO_BYTES = 1024;
1128
1136
  const DEFAULT_JOSE_LIMITS = /* @__PURE__ */ Object.freeze({
@@ -1194,6 +1202,18 @@ function assertProtectedOnlyOption(header, options) {
1194
1202
  throw new JWTError(`${family} "${param}" must be integrity protected; move it from the ${tier} header to the protected header.`, "ERR_INVALID_OPTION");
1195
1203
  }
1196
1204
  }
1205
+ function assertProducerKeyHeaders(header, options) {
1206
+ if (!header) return;
1207
+ const { tier, family } = options;
1208
+ if (Object.hasOwn(header, "jwk") && !isPublicJWK(Reflect.get(header, "jwk"))) throw new JWTError(`${family} "jwk" in the ${tier} header must be a public JWK; pass the pair's publicKey half.`, "ERR_INVALID_OPTION");
1209
+ if (Object.hasOwn(header, "epk")) throw new JWTError(`${family} "epk" is written by the ECDH-ES key agreement; pass an ephemeral key through "ecdh.ephemeralKey" instead of the ${tier} header.`, "ERR_INVALID_OPTION");
1210
+ }
1211
+ function assertProducerConfirmation(payload) {
1212
+ if (typeof payload !== "object" || payload === null) return;
1213
+ const cnf = Reflect.get(payload, "cnf");
1214
+ if (typeof cnf !== "object" || cnf === null || !Object.hasOwn(cnf, "jwk")) return;
1215
+ if (!isPublicJWK(Reflect.get(cnf, "jwk"))) throw new JWTError("Invalid JWT \"cnf\" (Confirmation) Claim: \"jwk\" must be a public JWK (RFC 7800 §3.2).", "ERR_JWT_CLAIM_INVALID");
1216
+ }
1197
1217
  function assertOptionEntry(entry, options) {
1198
1218
  const { label, objects } = options;
1199
1219
  assertPlainObject(entry, label);
@@ -1300,14 +1320,14 @@ function buildECDHAgreementParams(ecdh) {
1300
1320
  }
1301
1321
  async function resolveSigningKey(alg, key, usage) {
1302
1322
  if (key instanceof Uint8Array) {
1303
- if (!alg.startsWith("HS")) throw new JWTError(`Raw key bytes are HMAC secrets; ${alg} needs an asymmetric key. Pass a JWK or a CryptoKey.`, "ERR_JWK_INVALID");
1323
+ if (alg !== "HS256" && alg !== "HS384" && alg !== "HS512") throw new JWTError(`Raw key bytes are HMAC secrets; ${alg} needs an asymmetric key. Pass a JWK or a CryptoKey.`, "ERR_JWK_INVALID");
1304
1324
  assertOctKeyLength(key, alg);
1305
1325
  return crypto.subtle.importKey("raw", key, {
1306
1326
  name: "HMAC",
1307
1327
  hash: jwsHashOf(alg)
1308
1328
  }, false, [usage]);
1309
1329
  }
1310
- if (alg.startsWith("RS") || alg.startsWith("PS")) {
1330
+ if (RSA_SIGNATURE_ALGORITHMS.has(alg)) {
1311
1331
  const modulusLength = modulusLengthOf(key.algorithm);
1312
1332
  if (typeof modulusLength !== "number" || modulusLength < 2048) throw new JWTError(`${alg} requires a key modulusLength of at least 2048 bits`, "ERR_JWK_INVALID");
1313
1333
  }
@@ -1341,7 +1361,7 @@ function assertNotStringKey(key) {
1341
1361
  }
1342
1362
  function resolvePasswordKey(alg, key) {
1343
1363
  if (typeof key !== "string") return key;
1344
- if (!alg.startsWith("PBES2")) throw stringKeyError();
1364
+ if (!isPBES2Algorithm(alg)) throw stringKeyError();
1345
1365
  return textEncoder.encode(key);
1346
1366
  }
1347
1367
  const JWS_ALG_CTX = /* @__PURE__ */ Object.freeze({
@@ -1382,25 +1402,13 @@ function keyMatchesHeader(header, keyMaterial, options) {
1382
1402
  if (isCryptoKey(keyMaterial)) return keyServesHeaderAlg(header, keyMaterial, ctx);
1383
1403
  return true;
1384
1404
  }
1385
- const JWS_ALGORITHM_SET = /* @__PURE__ */ new Set(Object.keys({
1386
- HS256: true,
1387
- HS384: true,
1388
- HS512: true,
1389
- RS256: true,
1390
- RS384: true,
1391
- RS512: true,
1392
- PS256: true,
1393
- PS384: true,
1394
- PS512: true,
1395
- ES256: true,
1396
- ES384: true,
1397
- ES512: true,
1398
- Ed25519: true,
1399
- EdDSA: true
1400
- }));
1405
+ function assertJWSAlgSupported(alg) {
1406
+ const error = checkJWSAlgSupported(alg);
1407
+ if (error) throw error;
1408
+ }
1401
1409
  function checkJWSAlgSupported(alg) {
1402
1410
  return checkAlgSupported(alg, {
1403
- supported: JWS_ALGORITHM_SET,
1411
+ supported: isJWSAlgorithm,
1404
1412
  code: "ERR_JWS_ALG_NOT_ALLOWED",
1405
1413
  label: "Algorithm",
1406
1414
  role: "signing algorithm"
@@ -1474,26 +1482,6 @@ function asKeyUsageError(error, alg) {
1474
1482
  message: `Key is not usable for ${alg}.`
1475
1483
  });
1476
1484
  }
1477
- const JWE_ALGORITHM_SET = /* @__PURE__ */ new Set(Object.keys({
1478
- "dir": true,
1479
- "A128KW": true,
1480
- "A192KW": true,
1481
- "A256KW": true,
1482
- "A128GCMKW": true,
1483
- "A192GCMKW": true,
1484
- "A256GCMKW": true,
1485
- "PBES2-HS256+A128KW": true,
1486
- "PBES2-HS384+A192KW": true,
1487
- "PBES2-HS512+A256KW": true,
1488
- "RSA-OAEP": true,
1489
- "RSA-OAEP-256": true,
1490
- "RSA-OAEP-384": true,
1491
- "RSA-OAEP-512": true,
1492
- "ECDH-ES": true,
1493
- "ECDH-ES+A128KW": true,
1494
- "ECDH-ES+A192KW": true,
1495
- "ECDH-ES+A256KW": true
1496
- }));
1497
1485
  const JWE_ENC_CEK_FORMAT = /* @__PURE__ */ Object.freeze({
1498
1486
  "A128GCM": "cryptokey",
1499
1487
  "A192GCM": "cryptokey",
@@ -1510,7 +1498,7 @@ function assertDirectKeyRole(key, enc) {
1510
1498
  const JWE_DIRECT_ALGS = /* @__PURE__ */ new Set(["dir", "ECDH-ES"]);
1511
1499
  function checkJWEAlgSupported(alg) {
1512
1500
  return checkAlgSupported(alg, {
1513
- supported: JWE_ALGORITHM_SET,
1501
+ supported: isKeyManagementAlgorithm,
1514
1502
  code: "ERR_JWE_ALG_NOT_ALLOWED",
1515
1503
  label: "Key management algorithm",
1516
1504
  role: "key management algorithm"
@@ -1521,7 +1509,7 @@ function checkJWEEncSupported(enc) {
1521
1509
  return new JWTError(`Invalid JWE: unsupported "enc" ${quoteTokenValue(enc)}`, "ERR_JWE_INVALID");
1522
1510
  }
1523
1511
  function isJWEAlgSupported(alg) {
1524
- return JWE_ALGORITHM_SET.has(alg);
1512
+ return isKeyManagementAlgorithm(alg);
1525
1513
  }
1526
1514
  function assertJWEAlgSupported(alg) {
1527
1515
  const error = checkJWEAlgSupported(alg);
@@ -1646,18 +1634,26 @@ function decodeJWEPayload(plaintext, mode) {
1646
1634
  function checkAlgSupported(alg, options) {
1647
1635
  const { supported, code, label, role } = options;
1648
1636
  if (alg === "none") return new JWTError(`"none" is not a valid ${role}`, code);
1649
- if (!supported.has(alg)) return new JWTError(`${label} not supported: ${quoteTokenValue(alg)}`, code);
1637
+ if (!supported(alg)) return new JWTError(`${label} not supported: ${quoteTokenValue(alg)}`, code);
1650
1638
  }
1651
1639
  function keyServesHeaderAlg(header, key, ctx) {
1652
1640
  const { alg } = header;
1653
1641
  if (!alg) return false;
1654
1642
  const inferred = ctx.infer(key);
1655
1643
  if (inferred && !inferred.includes(alg)) return false;
1656
- if (!alg.startsWith("ECDH-ES")) return true;
1644
+ if (!isECDHESAlgorithm(alg)) return true;
1657
1645
  const epkCurve = header.epk?.crv;
1658
1646
  const keyCurve = isCryptoKey(key) ? cryptoKeyCurve(key) : "crv" in key ? key.crv : void 0;
1659
1647
  return !epkCurve || !keyCurve || epkCurve === keyCurve;
1660
1648
  }
1649
+ const RSA_SIGNATURE_ALGORITHMS = /* @__PURE__ */ new Set([
1650
+ "RS256",
1651
+ "RS384",
1652
+ "RS512",
1653
+ "PS256",
1654
+ "PS384",
1655
+ "PS512"
1656
+ ]);
1661
1657
  async function generateKey(alg, options = {}) {
1662
1658
  const exportToJWK = options.toJWK !== void 0 && options.toJWK;
1663
1659
  const defaultExtractable = exportToJWK || options.extractable !== false;
@@ -1665,41 +1661,37 @@ async function generateKey(alg, options = {}) {
1665
1661
  if (alg === "A128CBC-HS256" || alg === "A192CBC-HS384" || alg === "A256CBC-HS512") {
1666
1662
  const keyLength = bitLengthCEK(alg);
1667
1663
  const keyBytes = secureRandomBytes(keyLength >> 3);
1668
- if (exportToJWK) return withGeneratedKid(kid, {
1669
- ...await keyToJWK(keyBytes),
1670
- alg,
1671
- ext: true,
1672
- key_ops: resolveKeyUsage(options.keyUsage, {
1664
+ if (exportToJWK) {
1665
+ const jwk = await keyToJWK(keyBytes);
1666
+ const keyOps = options.keyUsage === void 0 ? void 0 : resolveKeyUsage(options.keyUsage, {
1673
1667
  allowed: CONTENT_ENCRYPTION_USAGES,
1674
1668
  fallback: ["encrypt", "decrypt"],
1675
1669
  alg
1676
- })
1677
- });
1670
+ });
1671
+ return withGeneratedKid(kid, withKeyOps({
1672
+ ...jwk,
1673
+ alg
1674
+ }, keyOps));
1675
+ }
1678
1676
  return keyBytes;
1679
1677
  }
1680
1678
  const { algorithm, keyUsages } = getGenerateKeyParams(alg, options);
1681
1679
  const key = await crypto.subtle.generateKey(algorithm, defaultExtractable, keyUsages);
1682
1680
  if (exportToJWK) {
1683
- if (key instanceof CryptoKey) return withGeneratedKid(kid, {
1684
- ...await exportKey(key),
1685
- alg
1686
- });
1687
- else {
1688
- const [pub, priv] = await Promise.all([exportKey(key.publicKey), exportKey(key.privateKey)]);
1689
- const publicKey = await withGeneratedKid(kid, {
1690
- ...pub,
1691
- alg
1692
- });
1681
+ if (isCryptoKeyPair(key)) {
1682
+ const pairAlg = generatedPairAlgorithm(alg);
1683
+ const [pub, priv] = await Promise.all([exportJWK(key.publicKey), exportJWK(key.privateKey)]);
1684
+ const publicKey = await withGeneratedKid(kid, withKeyOps(withAlg(pub, pairAlg), requestedKeyOps(options, key.publicKey)));
1693
1685
  const named = publicKey.kid === void 0 ? void 0 : { kid: publicKey.kid };
1694
1686
  return {
1695
1687
  privateKey: {
1696
- ...priv,
1697
- alg,
1688
+ ...withKeyOps(withAlg(priv, pairAlg), requestedKeyOps(options, key.privateKey)),
1698
1689
  ...named
1699
1690
  },
1700
1691
  publicKey
1701
1692
  };
1702
1693
  }
1694
+ return withGeneratedKid(kid, withKeyOps(withAlg(await exportJWK(key), generatedSecretAlgorithm(alg)), requestedKeyOps(options, key)));
1703
1695
  }
1704
1696
  return key;
1705
1697
  }
@@ -1743,11 +1735,11 @@ async function deriveKeyFromPassword(password, options) {
1743
1735
  const finalUsages = keyUsage ?? ["wrapKey", "unwrapKey"];
1744
1736
  const finalExtractable = exportToJWK ? true : extractable === true;
1745
1737
  const derivedKey = await crypto.subtle.importKey("raw", derivedBytes, { name: "AES-KW" }, finalExtractable, finalUsages);
1746
- if (exportToJWK) return {
1738
+ if (exportToJWK) return withKeyOps({
1747
1739
  ...await keyToJWK(derivedKey),
1748
1740
  alg: wrappingAlg,
1749
1741
  kty: "oct"
1750
- };
1742
+ }, requestedKeyOps(options, derivedKey));
1751
1743
  return derivedKey;
1752
1744
  }
1753
1745
  async function deriveJWKFromPassword(password, options) {
@@ -1824,10 +1816,10 @@ async function importKey(key, algOrOptions) {
1824
1816
  const cached = await cache.get(key, effectiveAlg);
1825
1817
  if (cached) return cached;
1826
1818
  }
1827
- const cryptoKey = await jwkTokey(key.alg ? key : {
1828
- ...key,
1819
+ const cryptoKey = await jwkTokey(key, {
1820
+ extractable,
1829
1821
  alg
1830
- }, { extractable });
1822
+ });
1831
1823
  if (cache) await cache.set(key, effectiveAlg, cryptoKey);
1832
1824
  return cryptoKey;
1833
1825
  }
@@ -1843,7 +1835,7 @@ function assertJWKAlgAuthority(jwk, alg) {
1843
1835
  function assertIntentOnJWK(jwk, expect) {
1844
1836
  if (expect === void 0 || jwk.kty === "oct") return;
1845
1837
  const hasPrivateScalar = "d" in jwk && typeof jwk.d === "string";
1846
- if (expect === "public" && hasPrivateScalar) throw new JWTError("Private JWK passed where a public key is expected. Strip `d` (and CRT fields on RSA) before import.", "ERR_JWK_INVALID");
1838
+ if (expect === "public" && hasPrivateScalar) throw new JWTError("Private JWK passed where a public key is expected.", "ERR_JWK_INVALID");
1847
1839
  if (expect === "private" && !hasPrivateScalar) throw new JWTError("Public JWK passed where a private key is expected.", "ERR_JWK_INVALID");
1848
1840
  }
1849
1841
  function assertIntentOnCryptoKey(key, expect) {
@@ -1851,8 +1843,8 @@ function assertIntentOnCryptoKey(key, expect) {
1851
1843
  if (expect === "public" && key.type === "private") throw new JWTError("Private CryptoKey passed where a public key is expected.", "ERR_JWK_INVALID");
1852
1844
  if (expect === "private" && key.type === "public") throw new JWTError("Public CryptoKey passed where a private key is expected.", "ERR_JWK_INVALID");
1853
1845
  }
1854
- async function exportKey(key, jwkParams) {
1855
- if (!isCryptoKey(key)) throw new JWTError(`exportKey expects a CryptoKey, got ${key === null ? "null" : typeof key}.`, "ERR_INVALID_OPTION");
1846
+ async function exportJWK(key, jwkParams) {
1847
+ if (!isCryptoKey(key)) throw new JWTError(`exportJWK expects a CryptoKey, got ${key === null ? "null" : typeof key}.`, "ERR_INVALID_OPTION");
1856
1848
  if (!key.extractable) throw new JWTError("A non-extractable CryptoKey cannot be exported as a JWK.", "ERR_JWK_INVALID");
1857
1849
  const exportedJwk = await keyToJWK(key);
1858
1850
  if (jwkParams) {
@@ -1865,6 +1857,19 @@ async function exportKey(key, jwkParams) {
1865
1857
  }
1866
1858
  return exportedJwk;
1867
1859
  }
1860
+ async function exportKey(key, jwkParams) {
1861
+ return exportJWK(key, jwkParams);
1862
+ }
1863
+ function toPublicJWK(jwk) {
1864
+ if (!isAsymmetricJWK(jwk)) throw new JWTError(isJWK(jwk) ? "An oct JWK has no public half." : "toPublicJWK expects an asymmetric JWK.", "ERR_JWK_INVALID");
1865
+ const { d: _d, p: _p, q: _q, dp: _dp, dq: _dq, qi: _qi, oth: _oth, key_ops, ...publicMembers } = sanitizeObjectCopy({ ...jwk });
1866
+ const publicKey = key_ops === void 0 ? publicMembers : {
1867
+ ...publicMembers,
1868
+ key_ops: publicKeyOps(key_ops)
1869
+ };
1870
+ if (!isPublicJWK(publicKey)) throw new JWTError(`${jwk.kty} JWK lacks the public members of its key type.`, "ERR_JWK_INVALID");
1871
+ return publicKey;
1872
+ }
1868
1873
  async function wrapKey(keyToWrap, wrappingKey, options) {
1869
1874
  assertPlainObject(options, "options");
1870
1875
  assertKeyBytesArg(keyToWrap, "keyToWrap");
@@ -1913,6 +1918,7 @@ async function wrapKey(keyToWrap, wrappingKey, options) {
1913
1918
  case "ECDH-ES+A256KW": {
1914
1919
  assertCryptoKeyFor(alg, importedWrappingKey, "wrapping");
1915
1920
  const enc = options.ecdh?.enc;
1921
+ if (enc !== void 0) assertJWEEncSupported(enc);
1916
1922
  if (alg === "ECDH-ES" && !enc) throw new JWTError("ECDH-ES direct key agreement requires options.ecdh.enc (the target content encryption algorithm)", "ERR_JWK_INVALID");
1917
1923
  const { encryptedKey, parameters } = await ecdhesWrap(alg, {
1918
1924
  enc,
@@ -2004,9 +2010,10 @@ async function unwrapKey(wrappedKey, unwrappingKey, options) {
2004
2010
  const apvBytes = segmentBytes(options.apv ?? /* @__PURE__ */ new Uint8Array(0), "apv");
2005
2011
  assertPartyInfoLength("apu", apuBytes);
2006
2012
  assertPartyInfoLength("apv", apvBytes);
2013
+ if (options.enc !== void 0) assertJWEEncSupported(options.enc);
2007
2014
  const infoAlg = alg === "ECDH-ES" ? options.enc : alg;
2008
2015
  if (!infoAlg) throw new JWTError("ECDH-ES requires content encryption algorithm ('enc') to derive the shared secret", "ERR_JWE_INVALID");
2009
- const sharedSecret = await unwrapping(deriveECDHESKey(epkCandidate, importedUnwrappingKey, infoAlg, ecdhDerivedBits(alg, infoAlg), apuBytes, apvBytes));
2016
+ const sharedSecret = await unwrapping(deriveECDHESKey(epkCandidate, importedUnwrappingKey, infoAlg, ecdhDerivedBits(alg, options.enc), apuBytes, apvBytes));
2010
2017
  if (alg === "ECDH-ES") unwrappedCekBytes = sharedSecret;
2011
2018
  else {
2012
2019
  const kwAlg = innerKeyWrapAlg(alg);
@@ -2040,7 +2047,7 @@ async function importPEM(pem, alg, options) {
2040
2047
  default: throw new JWTError(`Unsupported PEM type: ${String(pemType)}`, "ERR_JWK_UNSUPPORTED");
2041
2048
  }
2042
2049
  return {
2043
- ...await exportKey(cryptoKey, options?.jwkParams),
2050
+ ...await exportJWK(cryptoKey, options?.jwkParams),
2044
2051
  alg
2045
2052
  };
2046
2053
  }
@@ -2080,8 +2087,9 @@ function inferPEMType(pem) {
2080
2087
  async function deriveSharedSecret(publicKey, privateKey, options) {
2081
2088
  assertPlainObject(options, "options");
2082
2089
  const { enc: alg, keyLength: requestedKeyLength, partyUInfo, partyVInfo } = options;
2090
+ if (!isECDHESAlgorithm(alg)) assertJWEEncSupported(alg);
2083
2091
  if (requestedKeyLength !== void 0) assertDerivedKeyLength(requestedKeyLength);
2084
- const importAlg = alg.startsWith("ECDH-ES") ? alg : "ECDH-ES";
2092
+ const importAlg = isECDHESAlgorithm(alg) ? alg : "ECDH-ES";
2085
2093
  const pubCryptoKey = isCryptoKey(publicKey) ? publicKey : await importKey(publicKey, {
2086
2094
  alg: importAlg,
2087
2095
  expect: "public"
@@ -2093,7 +2101,7 @@ async function deriveSharedSecret(publicKey, privateKey, options) {
2093
2101
  let keyLength;
2094
2102
  if (requestedKeyLength !== void 0) keyLength = requestedKeyLength;
2095
2103
  else if (alg === "ECDH-ES") throw new JWTError("deriveSharedSecret with enc \"ECDH-ES\" requires an explicit keyLength in options", "ERR_JWK_INVALID");
2096
- else if (alg.startsWith("ECDH-ES+")) keyLength = Number.parseInt(alg.slice(-5, -2), 10);
2104
+ else if (isECDHESAlgorithm(alg)) keyLength = aesBitsOf(innerKeyWrapAlg(alg));
2097
2105
  else keyLength = bitLengthCEK(alg);
2098
2106
  return deriveECDHESKey(pubCryptoKey, privCryptoKey, alg, keyLength, partyUInfo ?? /* @__PURE__ */ new Uint8Array(0), partyVInfo ?? /* @__PURE__ */ new Uint8Array(0));
2099
2107
  }
@@ -2402,4 +2410,42 @@ function segmentBytes(value, name) {
2402
2410
  what: `"${name}"`
2403
2411
  }) : value;
2404
2412
  }
2405
- export { DEFAULT_JOSE_LIMITS, DEFAULT_PBES2_ITERATIONS, JWE_ALG_CTX, JWE_DIRECT_ALGS, JWS_ALG_CTX, WeakMapJWKCache, applyB64Header, asDecryptionError, asJWTError, asKeyLookupError, asKeyUsageError, assertB64Option, assertCompactToken, assertConsumerOptions, assertDirectKeyRole, assertEntryLimit, assertJWEAlgSupported, assertJWEEncSupported, assertJWKSetCandidates, assertNoZipOption, assertNotStringKey, assertOptionEntry, assertPBES2Params, assertProducerCEK, assertProducerCrit, assertProducerIV, assertProtectedOnlyOption, assertSerializationObject, buildECDHAgreementParams, buildJWKSetFilter, buildUnwrapKeyOptions, checkAlgAllowed, checkJWEAlgSupported, checkJWEContentSegments, checkJWEDirectEncryptedKey, checkJWEEncAllowed, checkJWEEncSupported, checkJWEUnprotectedCrit, checkJWEZip, checkJWSAlgSupported, checkJWSB64, checkProtectedTyp, checkSerializationEntry, clearJWKCache, configureJWKCache, createPBES2Budget, decodeJWEPayload, decodeJWSPayload, decodeProtectedHeader, decodeSegment, decrypt, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, encrypt, encryptKey, exportKey, exportPEM, exportReturnedCek, generateCEK, generateIV, generateJWK, generateKey, getJWKsFromSet, importKey, importPEM, isJWEAlgSupported, keyMatchesHeader, quoteTokenValue, resolveKeyInput, resolveLimit, resolvePasswordKey, resolvePayloadMode, resolveSigningKey, serializeProtectedHeader, sign, stringKeyError, thumbprint, unwrapKey, validateClaimsIfJson, verify, wrapKey };
2413
+ function withAlg(jwk, alg) {
2414
+ return {
2415
+ ...jwk,
2416
+ alg
2417
+ };
2418
+ }
2419
+ function generatedPairAlgorithm(alg) {
2420
+ return alg;
2421
+ }
2422
+ function generatedSecretAlgorithm(alg) {
2423
+ return alg;
2424
+ }
2425
+ const PUBLIC_KEY_OPS = /* @__PURE__ */ new Map([
2426
+ ["sign", "verify"],
2427
+ ["verify", "verify"],
2428
+ ["decrypt", "encrypt"],
2429
+ ["encrypt", "encrypt"],
2430
+ ["unwrapKey", "wrapKey"],
2431
+ ["wrapKey", "wrapKey"]
2432
+ ]);
2433
+ function publicKeyOps(keyOps) {
2434
+ if (!Array.isArray(keyOps)) return [];
2435
+ const ops = [];
2436
+ for (const op of keyOps) {
2437
+ const publicOp = typeof op === "string" ? PUBLIC_KEY_OPS.get(op) : void 0;
2438
+ if (publicOp !== void 0 && !ops.includes(publicOp)) ops.push(publicOp);
2439
+ }
2440
+ return ops;
2441
+ }
2442
+ function requestedKeyOps(options, key) {
2443
+ return options.keyUsage === void 0 ? void 0 : [...key.usages];
2444
+ }
2445
+ function withKeyOps(jwk, keyOps) {
2446
+ return keyOps === void 0 ? jwk : {
2447
+ ...jwk,
2448
+ key_ops: keyOps
2449
+ };
2450
+ }
2451
+ export { DEFAULT_JOSE_LIMITS, DEFAULT_PBES2_ITERATIONS, JWE_ALG_CTX, JWE_DIRECT_ALGS, JWS_ALG_CTX, WeakMapJWKCache, applyB64Header, asDecryptionError, asJWTError, asKeyLookupError, asKeyUsageError, assertB64Option, assertCompactToken, assertConsumerOptions, assertDirectKeyRole, assertEntryLimit, assertJWEAlgSupported, assertJWEEncSupported, assertJWKSetCandidates, assertJWSAlgSupported, assertNoZipOption, assertNotStringKey, assertOptionEntry, assertPBES2Params, assertProducerCEK, assertProducerConfirmation, assertProducerCrit, assertProducerIV, assertProducerKeyHeaders, assertProtectedOnlyOption, assertSerializationObject, buildECDHAgreementParams, buildJWKSetFilter, buildUnwrapKeyOptions, checkAlgAllowed, checkJWEAlgSupported, checkJWEContentSegments, checkJWEDirectEncryptedKey, checkJWEEncAllowed, checkJWEEncSupported, checkJWEUnprotectedCrit, checkJWEZip, checkJWSAlgSupported, checkJWSB64, checkProtectedTyp, checkSerializationEntry, clearJWKCache, configureJWKCache, createPBES2Budget, decodeJWEPayload, decodeJWSPayload, decodeProtectedHeader, decodeSegment, decrypt, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, encrypt, encryptKey, exportJWK, exportKey, exportPEM, exportReturnedCek, generateCEK, generateIV, generateJWK, generateKey, getJWKsFromSet, importKey, importPEM, isJWEAlgSupported, keyMatchesHeader, quoteTokenValue, resolveKeyInput, resolveLimit, resolvePasswordKey, resolvePayloadMode, resolveSigningKey, serializeProtectedHeader, sign, stringKeyError, thumbprint, toPublicJWK, unwrapKey, validateClaimsIfJson, verify, wrapKey };