jose 6.2.11 → 6.2.13

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.
Files changed (85) hide show
  1. package/README.md +2 -2
  2. package/dist/types/index.d.ts +1 -2
  3. package/dist/types/jwe/compact/decrypt.d.ts +9 -12
  4. package/dist/types/jwe/compact/encrypt.d.ts +14 -17
  5. package/dist/types/jwe/flattened/decrypt.d.ts +9 -12
  6. package/dist/types/jwe/flattened/encrypt.d.ts +17 -20
  7. package/dist/types/jwe/general/decrypt.d.ts +12 -17
  8. package/dist/types/jwe/general/encrypt.d.ts +19 -22
  9. package/dist/types/jwk/embedded.d.ts +3 -1
  10. package/dist/types/jwk/thumbprint.d.ts +4 -6
  11. package/dist/types/jwks/local.d.ts +5 -4
  12. package/dist/types/jwks/remote.d.ts +20 -21
  13. package/dist/types/jws/compact/sign.d.ts +7 -6
  14. package/dist/types/jws/compact/verify.d.ts +9 -12
  15. package/dist/types/jws/flattened/sign.d.ts +8 -7
  16. package/dist/types/jws/flattened/verify.d.ts +10 -12
  17. package/dist/types/jws/general/sign.d.ts +16 -17
  18. package/dist/types/jws/general/verify.d.ts +14 -18
  19. package/dist/types/jwt/decrypt.d.ts +15 -11
  20. package/dist/types/jwt/encrypt.d.ts +25 -23
  21. package/dist/types/jwt/sign.d.ts +4 -8
  22. package/dist/types/jwt/unsecured.d.ts +3 -7
  23. package/dist/types/jwt/verify.d.ts +12 -7
  24. package/dist/types/key/export.d.ts +6 -6
  25. package/dist/types/key/generate_key_pair.d.ts +9 -14
  26. package/dist/types/key/generate_secret.d.ts +10 -10
  27. package/dist/types/key/import.d.ts +21 -20
  28. package/dist/types/types.d.ts +217 -254
  29. package/dist/types/util/base64url.d.ts +7 -7
  30. package/dist/types/util/decode_jwt.d.ts +6 -1
  31. package/dist/types/util/decode_protected_header.d.ts +4 -3
  32. package/dist/types/util/errors.d.ts +30 -41
  33. package/dist/webapi/jwe/compact/decrypt.js +1 -2
  34. package/dist/webapi/jwe/compact/encrypt.js +9 -26
  35. package/dist/webapi/jwe/flattened/decrypt.js +3 -3
  36. package/dist/webapi/jwe/flattened/encrypt.js +11 -30
  37. package/dist/webapi/jwe/general/decrypt.js +6 -6
  38. package/dist/webapi/jwe/general/encrypt.js +36 -60
  39. package/dist/webapi/jwk/embedded.js +3 -4
  40. package/dist/webapi/jwk/thumbprint.js +11 -14
  41. package/dist/webapi/jwks/local.js +18 -11
  42. package/dist/webapi/jwks/remote.js +5 -5
  43. package/dist/webapi/jws/compact/sign.js +2 -4
  44. package/dist/webapi/jws/compact/verify.js +2 -2
  45. package/dist/webapi/jws/flattened/sign.js +8 -15
  46. package/dist/webapi/jws/flattened/verify.js +4 -14
  47. package/dist/webapi/jws/general/sign.js +6 -13
  48. package/dist/webapi/jws/general/verify.js +8 -10
  49. package/dist/webapi/jwt/decrypt.js +2 -3
  50. package/dist/webapi/jwt/encrypt.js +13 -27
  51. package/dist/webapi/jwt/sign.js +3 -3
  52. package/dist/webapi/jwt/unsecured.js +4 -5
  53. package/dist/webapi/jwt/verify.js +4 -4
  54. package/dist/webapi/key/export.js +12 -16
  55. package/dist/webapi/key/generate_key_pair.js +4 -13
  56. package/dist/webapi/key/generate_secret.js +5 -5
  57. package/dist/webapi/key/import.js +5 -9
  58. package/dist/webapi/lib/asn1.js +4 -6
  59. package/dist/webapi/lib/buffer_utils.js +39 -4
  60. package/dist/webapi/lib/content_encryption.js +29 -37
  61. package/dist/webapi/lib/deflate.js +9 -19
  62. package/dist/webapi/lib/jwe_algorithms.js +0 -4
  63. package/dist/webapi/lib/jwe_decrypt.js +30 -63
  64. package/dist/webapi/lib/jwe_encrypt.js +27 -60
  65. package/dist/webapi/lib/jws_algorithms.js +2 -2
  66. package/dist/webapi/lib/jws_sign.js +31 -45
  67. package/dist/webapi/lib/jws_verify.js +43 -48
  68. package/dist/webapi/lib/jwt_claims_set.js +45 -44
  69. package/dist/webapi/lib/key.js +122 -62
  70. package/dist/webapi/lib/key_management.js +57 -92
  71. package/dist/webapi/lib/{options.js → validate.js} +64 -3
  72. package/dist/webapi/util/base64url.js +5 -19
  73. package/dist/webapi/util/decode_jwt.js +13 -13
  74. package/dist/webapi/util/decode_protected_header.js +6 -6
  75. package/package.json +1 -1
  76. package/dist/webapi/lib/base64.js +0 -20
  77. package/dist/webapi/lib/crypto_key.js +0 -27
  78. package/dist/webapi/lib/helpers.js +0 -45
  79. package/dist/webapi/lib/invalid_key_input.js +0 -12
  80. package/dist/webapi/lib/is_key_like.js +0 -19
  81. package/dist/webapi/lib/jwk_metadata.js +0 -19
  82. package/dist/webapi/lib/jwk_to_key.js +0 -10
  83. package/dist/webapi/lib/key_options.js +0 -8
  84. package/dist/webapi/lib/signing.js +0 -22
  85. package/dist/webapi/lib/type_checks.js +0 -30
@@ -1,72 +1,57 @@
1
1
  import { encode as b64u } from "../util/base64url.js";
2
- import { prepareKey } from "./key.js";
3
- import { jwkToKey } from "./jwk_to_key.js";
4
- import { jweAlgorithm, jweEncryption } from "./jwe_algorithms.js";
2
+ import { prepareKey, rawKey, jwkToKey, checkCryptoKey, checkModulusLength, checkUsage, assertCryptoKey } from "./key.js";
3
+ import { jweAlgorithm, jweEncryption, isJWECEKTransport } from "./jwe_algorithms.js";
5
4
  import { JOSENotSupported, JWEInvalid } from "../util/errors.js";
6
- import { decodeBase64url, digest } from "./helpers.js";
7
- import { generateCek, encrypt, decrypt } from "./content_encryption.js";
8
- import { assertUint8Array, isObject } from "./type_checks.js";
9
- import { checkCryptoKey, checkModulusLength, checkUsage } from "./crypto_key.js";
10
- import { concat, encode, uint32be } from "./buffer_utils.js";
11
- import { assertCryptoKey } from "./is_key_like.js";
5
+ import { decodeBase64url, assertUint8Array, isObject } from "./validate.js";
6
+ import { digest, concat, encode, uint32be } from "./buffer_utils.js";
7
+ import { checkCekLength, generateCek, encrypt, decrypt } from "./content_encryption.js";
12
8
  function checkEcdhCryptoKey(key, usage) {
13
9
  if (key.algorithm.name !== "ECDH" && key.algorithm.name !== "X25519")
14
10
  throw new TypeError("CryptoKey does not support this operation, its algorithm.name must be ECDH or X25519");
15
11
  checkUsage(key, usage);
16
12
  }
17
- async function aeskwCryptoKey(key, alg, usage) {
18
- const expected = jweAlgorithm(alg).subtle, cryptoKey = key instanceof Uint8Array ? await crypto.subtle.importKey("raw", key, "AES-KW", !0, [
19
- usage
20
- ]) : key;
21
- return checkCryptoKey(cryptoKey, expected, usage), cryptoKey;
22
- }
23
13
  async function aeskwWrap(alg, key, cek) {
24
- const cryptoKey = await aeskwCryptoKey(key, alg, "wrapKey"), cryptoKeyCek = await crypto.subtle.importKey("raw", cek, { hash: "SHA-256", name: "HMAC" }, !0, ["sign"]);
14
+ const cryptoKey = await rawKey(key, jweAlgorithm(alg).subtle, "wrapKey", !0), cryptoKeyCek = await crypto.subtle.importKey("raw", cek, { hash: "SHA-256", name: "HMAC" }, !0, ["sign"]);
25
15
  return new Uint8Array(await crypto.subtle.wrapKey("raw", cryptoKeyCek, cryptoKey, "AES-KW"));
26
16
  }
27
17
  async function aeskwUnwrap(alg, key, encryptedKey) {
28
- const cryptoKey = await aeskwCryptoKey(key, alg, "unwrapKey"), cryptoKeyCek = await crypto.subtle.unwrapKey("raw", encryptedKey, cryptoKey, "AES-KW", { hash: "SHA-256", name: "HMAC" }, !0, ["sign"]);
18
+ const cryptoKey = await rawKey(key, jweAlgorithm(alg).subtle, "unwrapKey", !0), cryptoKeyCek = await crypto.subtle.unwrapKey("raw", encryptedKey, cryptoKey, "AES-KW", { hash: "SHA-256", name: "HMAC" }, !0, ["sign"]);
29
19
  return new Uint8Array(await crypto.subtle.exportKey("raw", cryptoKeyCek));
30
20
  }
31
21
  function checkRsaKey(alg, key, usage) {
32
22
  checkCryptoKey(key, jweAlgorithm(alg).subtle, usage), checkModulusLength(alg, key);
33
23
  }
34
- function pbes2CryptoKey(key, alg) {
35
- return key instanceof Uint8Array ? crypto.subtle.importKey("raw", key, "PBKDF2", !1, [
36
- "deriveBits"
37
- ]) : (checkCryptoKey(key, jweAlgorithm(alg).subtle, "deriveBits"), key);
38
- }
39
24
  async function deriveKey(p2s, alg, p2c, key) {
40
25
  if (!(p2s instanceof Uint8Array) || p2s.length < 8)
41
26
  throw new JWEInvalid("PBES2 Salt Input must be 8 or more octets");
42
27
  if (!Number.isSafeInteger(p2c) || Math.sign(p2c) !== 1)
43
28
  throw new JWEInvalid("PBES2 Count Input must be a positive integer");
44
- const salt = concat(encode(alg), Uint8Array.of(0), p2s), keylen = parseInt(alg.slice(13, 16), 10), subtleAlg = {
29
+ const salt = concat(encode(alg), Uint8Array.of(0), p2s), keyLengthBits = parseInt(alg.slice(13, 16), 10), subtleAlg = {
45
30
  hash: `SHA-${alg.slice(8, 11)}`,
46
31
  iterations: p2c,
47
32
  name: "PBKDF2",
48
33
  salt
49
- }, cryptoKey = await pbes2CryptoKey(key, alg);
50
- return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
34
+ }, cryptoKey = await rawKey(key, jweAlgorithm(alg).subtle, "deriveBits");
35
+ return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keyLengthBits));
51
36
  }
52
37
  function lengthAndInput(input) {
53
38
  return concat(uint32be(input.length), input);
54
39
  }
55
- async function concatKdf(Z, L, OtherInfo) {
56
- const dkLen = L >> 3, hashLen = 32, reps = Math.ceil(dkLen / hashLen), dk = new Uint8Array(reps * hashLen);
40
+ async function concatKdf(Z, keyDataLength, OtherInfo) {
41
+ const dkLen = keyDataLength >> 3, hashLen = 32, reps = Math.ceil(dkLen / hashLen), dk = new Uint8Array(reps * hashLen);
57
42
  for (let i = 1; i <= reps; i++) {
58
43
  const hashResult = await digest("sha256", concat(uint32be(i), Z, OtherInfo));
59
44
  dk.set(hashResult, (i - 1) * hashLen);
60
45
  }
61
46
  return dk.slice(0, dkLen);
62
47
  }
63
- async function ecdhesDeriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) {
48
+ async function ecdhesDeriveKey(publicKey, privateKey, algorithmId, keyDataLength, apu = new Uint8Array(), apv = new Uint8Array()) {
64
49
  checkEcdhCryptoKey(publicKey), checkEcdhCryptoKey(privateKey, "deriveBits");
65
- const otherInfo = concat(lengthAndInput(encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength)), Z = new Uint8Array(await crypto.subtle.deriveBits({
50
+ const otherInfo = concat(lengthAndInput(encode(algorithmId)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyDataLength)), Z = new Uint8Array(await crypto.subtle.deriveBits({
66
51
  name: publicKey.algorithm.name,
67
52
  public: publicKey
68
53
  }, privateKey, publicKey.algorithm.name === "X25519" ? 256 : Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3));
69
- return concatKdf(Z, keyLength, otherInfo);
54
+ return concatKdf(Z, keyDataLength, otherInfo);
70
55
  }
71
56
  function assertEcdhKey(key) {
72
57
  assertCryptoKey(key);
@@ -104,32 +89,27 @@ function validateMaxPBES2Count(value) {
104
89
  }
105
90
  async function decryptKeyManagement(entry, enc, key, encryptedKey, joseHeader, maxPBES2Count) {
106
91
  const { alg } = entry, mode = entry.mode;
107
- switch (mode) {
108
- case "direct-encryption":
109
- return assertNoEncryptedKey(encryptedKey), key;
110
- case "direct-key-agreement":
111
- case "key-wrapping":
112
- case "key-encryption":
113
- case "key-agreement-with-key-wrapping":
114
- break;
115
- }
116
- switch (entry.subtle.name) {
92
+ if (mode === "direct-encryption")
93
+ return assertNoEncryptedKey(encryptedKey), key;
94
+ const direct = mode === "direct-key-agreement";
95
+ switch (direct ? assertNoEncryptedKey(encryptedKey) : assertEncryptedKey(encryptedKey), entry.subtle.name) {
117
96
  case "ECDH": {
118
- const direct = mode === "direct-key-agreement";
119
- direct && assertNoEncryptedKey(encryptedKey);
120
97
  const { epk } = joseHeader;
121
98
  if (!isObject(epk) || ["d", "k", "p", "q", "dp", "dq", "qi", "oth", "priv"].some((parameter) => Object.hasOwn(epk, parameter)))
122
99
  throw new JWEInvalid('JOSE Header "epk" (Ephemeral Public Key) missing or invalid');
123
100
  assertEcdhKey(key);
124
101
  const ephemeralPublicKey = await jwkToKey(entry, epk), partyUInfo = partyInfo(joseHeader, "apu"), partyVInfo = partyInfo(joseHeader, "apv");
125
102
  checkPartyInfo(partyUInfo, partyVInfo);
126
- const sharedSecret = await ecdhesDeriveKey(ephemeralPublicKey, key, direct ? enc.alg : alg, direct ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
127
- return direct ? sharedSecret : (assertEncryptedKey(encryptedKey), aeskwUnwrap(alg.slice(-6), sharedSecret, encryptedKey));
103
+ const derivedKey = await ecdhesDeriveKey(ephemeralPublicKey, key, direct ? enc.alg : alg, direct ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
104
+ if (direct)
105
+ return derivedKey;
106
+ key = derivedKey;
107
+ break;
128
108
  }
129
109
  case "RSA-OAEP":
130
- return assertEncryptedKey(encryptedKey), assertCryptoKey(key), checkRsaKey(alg, key, "decrypt"), new Uint8Array(await crypto.subtle.decrypt("RSA-OAEP", key, encryptedKey));
110
+ return assertCryptoKey(key), checkRsaKey(alg, key, "decrypt"), new Uint8Array(await crypto.subtle.decrypt("RSA-OAEP", key, encryptedKey));
131
111
  case "PBKDF2": {
132
- if (assertEncryptedKey(encryptedKey), typeof joseHeader.p2c != "number")
112
+ if (typeof joseHeader.p2c != "number")
133
113
  throw new JWEInvalid('JOSE Header "p2c" (PBES2 Count) missing or invalid');
134
114
  validateMaxPBES2Count(maxPBES2Count);
135
115
  const p2cLimit = maxPBES2Count ?? 1e4;
@@ -137,39 +117,35 @@ async function decryptKeyManagement(entry, enc, key, encryptedKey, joseHeader, m
137
117
  throw new JWEInvalid('JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds');
138
118
  if (typeof joseHeader.p2s != "string")
139
119
  throw new JWEInvalid('JOSE Header "p2s" (PBES2 Salt) missing or invalid');
140
- const p2s = decodeBase64url(joseHeader.p2s, "p2s", JWEInvalid), derived = await deriveKey(p2s, alg, joseHeader.p2c, key);
141
- return aeskwUnwrap(alg.slice(-6), derived, encryptedKey);
120
+ const p2s = decodeBase64url(joseHeader.p2s, "p2s", JWEInvalid);
121
+ key = await deriveKey(p2s, alg, joseHeader.p2c, key);
122
+ break;
142
123
  }
143
- case "AES-KW":
144
- return assertEncryptedKey(encryptedKey), aeskwUnwrap(alg, key, encryptedKey);
145
124
  case "AES-GCM": {
146
- if (assertEncryptedKey(encryptedKey), typeof joseHeader.iv != "string")
125
+ if (typeof joseHeader.iv != "string")
147
126
  throw new JWEInvalid('JOSE Header "iv" (Initialization Vector) missing or invalid');
148
127
  if (typeof joseHeader.tag != "string")
149
128
  throw new JWEInvalid('JOSE Header "tag" (Authentication Tag) missing or invalid');
150
- let iv;
151
- iv = decodeBase64url(joseHeader.iv, "iv", JWEInvalid);
152
- let tag;
153
- if (tag = decodeBase64url(joseHeader.tag, "tag", JWEInvalid), iv.byteLength !== 12)
129
+ const iv = decodeBase64url(joseHeader.iv, "iv", JWEInvalid), tag = decodeBase64url(joseHeader.tag, "tag", JWEInvalid);
130
+ if (iv.byteLength !== 12)
154
131
  throw new JWEInvalid("Invalid Initialization Vector length");
155
132
  if (tag.byteLength !== 16)
156
133
  throw new JWEInvalid("Invalid Authentication Tag length");
157
134
  return decrypt(jweEncryption(alg.slice(0, -2)), key, encryptedKey, iv, tag, new Uint8Array());
158
135
  }
159
136
  }
160
- }
161
- async function encryptKeyManagement(entry, enc, key, joseHeader, providedCek, providedParameters = {}) {
162
- let encryptedKey, parameters, cek;
163
- const { alg } = entry, mode = entry.mode;
164
- switch (mode) {
165
- case "direct-encryption":
166
- return [key, void 0, void 0];
167
- case "direct-key-agreement":
168
- case "key-wrapping":
169
- case "key-encryption":
170
- case "key-agreement-with-key-wrapping":
171
- break;
172
- }
137
+ return aeskwUnwrap(alg.slice(-6), key, encryptedKey);
138
+ }
139
+ async function encryptKeyManagement(entry, enc, inputKey, joseHeader, providedCek, providedParameters = {}) {
140
+ const { alg, mode } = entry, transport = isJWECEKTransport(entry);
141
+ if (providedCek !== void 0 && !transport)
142
+ throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
143
+ let key = await prepareKey(mode === "direct-encryption" ? enc : entry, inputKey, "encrypt");
144
+ if (mode === "direct-encryption")
145
+ return [key, void 0, void 0];
146
+ const cek = transport ? providedCek ?? generateCek(enc) : void 0;
147
+ cek && checkCekLength(cek, enc.cekBits);
148
+ let encryptedKey, parameters;
173
149
  switch (entry.subtle.name) {
174
150
  case "ECDH": {
175
151
  assertEcdhKey(key);
@@ -177,51 +153,40 @@ async function encryptKeyManagement(entry, enc, key, joseHeader, providedCek, pr
177
153
  providedApu !== void 0 && assertUint8Array(providedApu, '"apu"'), providedApv !== void 0 && assertUint8Array(providedApv, '"apv"');
178
154
  const apu = providedApu ?? partyInfo(joseHeader, "apu"), apv = providedApv ?? partyInfo(joseHeader, "apv");
179
155
  checkPartyInfo(apu, apv);
180
- let ephemeralKey;
181
- providedParameters.epk !== void 0 ? ephemeralKey = await prepareKey(entry, providedParameters.epk, "decrypt") : ephemeralKey = (await crypto.subtle.generateKey(key.algorithm, !0, ["deriveBits"])).privateKey;
156
+ let ephemeralPrivateKey;
157
+ providedParameters.epk !== void 0 ? ephemeralPrivateKey = await prepareKey(entry, providedParameters.epk, "decrypt") : ephemeralPrivateKey = (await crypto.subtle.generateKey(key.algorithm, !0, ["deriveBits"])).privateKey;
182
158
  const subtle = crypto.subtle;
183
- let exportableEpk = ephemeralKey;
159
+ let exportableEpk = ephemeralPrivateKey;
184
160
  if (!exportableEpk.extractable) {
185
161
  if (typeof subtle.getPublicKey != "function")
186
162
  throw new TypeError('CryptoKey for "epk" must be extractable');
187
- exportableEpk = await subtle.getPublicKey(ephemeralKey, []);
188
- }
189
- const { x, y, crv, kty } = await subtle.exportKey("jwk", exportableEpk), direct = mode === "direct-key-agreement", sharedSecret = await ecdhesDeriveKey(key, ephemeralKey, direct ? enc.alg : alg, direct ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), apu, apv);
190
- if (parameters = { epk: { x, crv, kty } }, kty === "EC" && (parameters.epk.y = y), providedApu !== void 0 && (parameters.apu = b64u(providedApu)), providedApv !== void 0 && (parameters.apv = b64u(providedApv)), direct) {
191
- cek = sharedSecret;
192
- break;
163
+ exportableEpk = await subtle.getPublicKey(ephemeralPrivateKey, []);
193
164
  }
194
- cek = providedCek ?? generateCek(enc);
195
- const kwAlg = alg.slice(-6);
196
- encryptedKey = await aeskwWrap(kwAlg, sharedSecret, cek);
165
+ const { x, y, crv, kty } = await subtle.exportKey("jwk", exportableEpk), direct = mode === "direct-key-agreement", derivedKey = await ecdhesDeriveKey(key, ephemeralPrivateKey, direct ? enc.alg : alg, direct ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), apu, apv), epk = { x, crv, kty };
166
+ if (kty === "EC" && (epk.y = y), parameters = { epk }, providedApu !== void 0 && (parameters.apu = b64u(providedApu)), providedApv !== void 0 && (parameters.apv = b64u(providedApv)), direct)
167
+ return [derivedKey, void 0, parameters];
168
+ key = derivedKey;
197
169
  break;
198
170
  }
199
171
  case "RSA-OAEP": {
200
- cek = providedCek ?? generateCek(enc), assertCryptoKey(key), checkRsaKey(alg, key, "encrypt"), encryptedKey = new Uint8Array(await crypto.subtle.encrypt("RSA-OAEP", key, cek));
172
+ assertCryptoKey(key), checkRsaKey(alg, key, "encrypt"), encryptedKey = new Uint8Array(await crypto.subtle.encrypt("RSA-OAEP", key, cek));
201
173
  break;
202
174
  }
203
175
  case "PBKDF2": {
204
- cek = providedCek ?? generateCek(enc);
205
- const { p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16)) } = providedParameters, derived = await deriveKey(p2s, alg, p2c, key);
206
- encryptedKey = await aeskwWrap(alg.slice(-6), derived, cek), parameters = { p2c, p2s: b64u(p2s) };
207
- break;
208
- }
209
- case "AES-KW": {
210
- cek = providedCek ?? generateCek(enc), encryptedKey = await aeskwWrap(alg, key, cek);
176
+ const { p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16)) } = providedParameters;
177
+ key = await deriveKey(p2s, alg, p2c, key), parameters = { p2c, p2s: b64u(p2s) };
211
178
  break;
212
179
  }
213
180
  case "AES-GCM": {
214
- cek = providedCek ?? generateCek(enc);
215
181
  const iv = providedParameters.iv === void 0 ? crypto.getRandomValues(new Uint8Array(12)) : providedParameters.iv;
216
182
  if (!(iv instanceof Uint8Array))
217
183
  throw new TypeError('"iv" must be an instance of Uint8Array');
218
184
  const wrapped = await encrypt(jweEncryption(alg.slice(0, -2)), cek, key, iv, new Uint8Array());
219
185
  encryptedKey = wrapped.ciphertext, parameters = { iv: b64u(wrapped.iv), tag: b64u(wrapped.tag) };
220
- break;
221
186
  }
222
187
  }
223
- if (cek === void 0)
224
- throw new TypeError("Invalid JWE key management algorithm");
188
+ if (encryptedKey ??= await aeskwWrap(alg.slice(-6), key, cek), !(encryptedKey instanceof Uint8Array) || !encryptedKey.byteLength)
189
+ throw new TypeError("JWE key management algorithm did not produce an Encrypted Key");
225
190
  return [cek, encryptedKey, parameters];
226
191
  }
227
192
  export {
@@ -1,11 +1,64 @@
1
1
  import { JOSENotSupported, JWSInvalid } from "../util/errors.js";
2
- import { isObject } from "./type_checks.js";
2
+ import { decode } from "../util/base64url.js";
3
+ import { encode, strictDecoder } from "./buffer_utils.js";
4
+ function assertUint8Array(input, label) {
5
+ if (!(input instanceof Uint8Array))
6
+ throw new TypeError(`${label} must be an instance of Uint8Array`);
7
+ }
8
+ function isObject(input) {
9
+ if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]")
10
+ return !1;
11
+ const prototype = Object.getPrototypeOf(input);
12
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
13
+ }
14
+ function isJwkSet(input) {
15
+ return isObject(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject);
16
+ }
17
+ function isDisjoint(...headers) {
18
+ const parameters = /* @__PURE__ */ new Set();
19
+ for (const header of headers)
20
+ if (header)
21
+ for (const parameter of Object.keys(header)) {
22
+ if (parameters.has(parameter))
23
+ return !1;
24
+ parameters.add(parameter);
25
+ }
26
+ return !0;
27
+ }
28
+ function assertNotSet(value, name) {
29
+ if (value !== void 0)
30
+ throw new TypeError(`${name} can only be called once`);
31
+ }
32
+ function decodeBase64url(value, label, ErrorClass) {
33
+ try {
34
+ return decode(value);
35
+ } catch (cause) {
36
+ throw new ErrorClass(`Failed to base64url decode the ${label}`, { cause });
37
+ }
38
+ }
39
+ function encodeAsciiMember(value, label, ErrorClass) {
40
+ try {
41
+ return encode(value);
42
+ } catch (cause) {
43
+ throw new ErrorClass(`The ${label} is not a valid base64url string`, { cause });
44
+ }
45
+ }
46
+ function parseJoseHeader(encodedProtectedHeader, ErrorClass, message) {
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(strictDecoder.decode(decode(encodedProtectedHeader)));
50
+ } catch (cause) {
51
+ throw new ErrorClass(message, { cause });
52
+ }
53
+ if (!isObject(parsed))
54
+ throw new ErrorClass(message);
55
+ return parsed;
56
+ }
3
57
  const JWS_RECOGNIZED = { __proto__: null, b64: !0 }, JWE_RECOGNIZED = { __proto__: null };
4
58
  function validateAlgorithms(option, algorithms) {
5
59
  if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != "string")))
6
60
  throw new TypeError(`"${option}" option must be an array of strings`);
7
- if (algorithms)
8
- return new Set(algorithms);
61
+ return algorithms === void 0 ? void 0 : new Set(algorithms);
9
62
  }
10
63
  function validateCritDuplicates(Err, protectedHeader) {
11
64
  const { crit } = protectedHeader ?? {};
@@ -53,6 +106,14 @@ function serializeJoseHeader(Err, header) {
53
106
  export {
54
107
  JWE_RECOGNIZED,
55
108
  JWS_RECOGNIZED,
109
+ assertNotSet,
110
+ assertUint8Array,
111
+ decodeBase64url,
112
+ encodeAsciiMember,
113
+ isDisjoint,
114
+ isJwkSet,
115
+ isObject,
116
+ parseJoseHeader,
56
117
  serializeJoseHeader,
57
118
  validateAlgorithms,
58
119
  validateB64,
@@ -1,28 +1,14 @@
1
- import { encoder, decoder } from "../lib/buffer_utils.js";
2
- import { encodeBase64, decodeBase64 } from "../lib/base64.js";
1
+ import { encoder, decoder, encodeBase64, decodeBase64 } from "../lib/buffer_utils.js";
3
2
  const invalid = "The input to be decoded is not correctly encoded.";
4
3
  function decode(input) {
5
- if (Uint8Array.fromBase64)
6
- try {
7
- return Uint8Array.fromBase64(typeof input == "string" ? input : decoder.decode(input), {
8
- alphabet: "base64url"
9
- });
10
- } catch (cause) {
11
- throw new TypeError(invalid, { cause });
12
- }
13
- let encoded = input;
14
- if (encoded instanceof Uint8Array && (encoded = decoder.decode(encoded)), encoded.includes("+") || encoded.includes("/"))
15
- throw new TypeError(invalid);
16
- encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
17
4
  try {
18
- return decodeBase64(encoded);
19
- } catch {
20
- throw new TypeError(invalid);
5
+ return decodeBase64(typeof input == "string" ? input : decoder.decode(input), !0);
6
+ } catch (cause) {
7
+ throw new TypeError(invalid, { cause });
21
8
  }
22
9
  }
23
10
  function encode(input) {
24
- let unencoded = input;
25
- return typeof unencoded == "string" && (unencoded = encoder.encode(unencoded)), Uint8Array.prototype.toBase64 ? unencoded.toBase64({ alphabet: "base64url", omitPadding: !0 }) : encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
11
+ return encodeBase64(typeof input == "string" ? encoder.encode(input) : input, !0);
26
12
  }
27
13
  export {
28
14
  decode,
@@ -1,32 +1,32 @@
1
1
  import { decode as b64u } from "./base64url.js";
2
2
  import { strictDecoder } from "../lib/buffer_utils.js";
3
- import { isObject } from "../lib/type_checks.js";
3
+ import { isObject } from "../lib/validate.js";
4
4
  import { JWTInvalid } from "./errors.js";
5
5
  function decodeJwt(jwt) {
6
6
  if (typeof jwt != "string")
7
7
  throw new JWTInvalid("JWTs must use Compact JWS serialization, JWT must be a string");
8
- const { 1: payload, length } = jwt.split(".");
8
+ const { 1: encodedPayload, length } = jwt.split(".");
9
9
  if (length === 5)
10
10
  throw new JWTInvalid("Only JWTs using Compact JWS serialization can be decoded");
11
11
  if (length !== 3)
12
12
  throw new JWTInvalid("Invalid JWT");
13
- if (!payload)
13
+ if (!encodedPayload)
14
14
  throw new JWTInvalid("JWTs must contain a payload");
15
- let decoded;
15
+ let claimsSetBytes;
16
16
  try {
17
- decoded = b64u(payload);
18
- } catch {
19
- throw new JWTInvalid("Failed to base64url decode the payload");
17
+ claimsSetBytes = b64u(encodedPayload);
18
+ } catch (cause) {
19
+ throw new JWTInvalid("Failed to base64url decode the payload", { cause });
20
20
  }
21
- let result;
21
+ let claimsSet;
22
22
  try {
23
- result = JSON.parse(strictDecoder.decode(decoded));
24
- } catch {
25
- throw new JWTInvalid("Failed to parse the decoded payload as JSON");
23
+ claimsSet = JSON.parse(strictDecoder.decode(claimsSetBytes));
24
+ } catch (cause) {
25
+ throw new JWTInvalid("Failed to parse the decoded payload as JSON", { cause });
26
26
  }
27
- if (!isObject(result))
27
+ if (!isObject(claimsSet))
28
28
  throw new JWTInvalid("Invalid JWT Claims Set");
29
- return result;
29
+ return claimsSet;
30
30
  }
31
31
  export {
32
32
  decodeJwt
@@ -1,18 +1,18 @@
1
- import { parseJoseHeader } from "../lib/helpers.js";
1
+ import { parseJoseHeader } from "../lib/validate.js";
2
2
  function decodeProtectedHeader(token) {
3
- let protectedB64u;
3
+ let encodedProtectedHeader;
4
4
  if (typeof token == "string") {
5
5
  const parts = token.split(".");
6
- (parts.length === 3 || parts.length === 5) && ([protectedB64u] = parts);
6
+ (parts.length === 3 || parts.length === 5) && ([encodedProtectedHeader] = parts);
7
7
  } else if (typeof token == "object" && token)
8
8
  if ("protected" in token)
9
- protectedB64u = token.protected;
9
+ encodedProtectedHeader = token.protected;
10
10
  else
11
11
  throw new TypeError("Token does not contain a Protected Header");
12
12
  const invalid = "Invalid Token or Protected Header formatting";
13
- if (typeof protectedB64u != "string" || !protectedB64u)
13
+ if (typeof encodedProtectedHeader != "string" || !encodedProtectedHeader)
14
14
  throw new TypeError(invalid);
15
- return parseJoseHeader(protectedB64u, TypeError, invalid);
15
+ return parseJoseHeader(encodedProtectedHeader, TypeError, invalid);
16
16
  }
17
17
  export {
18
18
  decodeProtectedHeader
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jose",
3
- "version": "6.2.11",
3
+ "version": "6.2.13",
4
4
  "description": "JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes",
5
5
  "keywords": [
6
6
  "akp",
@@ -1,20 +0,0 @@
1
- function encodeBase64(input) {
2
- if (Uint8Array.prototype.toBase64)
3
- return input.toBase64();
4
- const CHUNK_SIZE = 32768, arr = [];
5
- for (let i = 0; i < input.length; i += CHUNK_SIZE)
6
- arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
7
- return btoa(arr.join(""));
8
- }
9
- function decodeBase64(encoded) {
10
- if (Uint8Array.fromBase64)
11
- return Uint8Array.fromBase64(encoded);
12
- const binary = atob(encoded), bytes = new Uint8Array(binary.length);
13
- for (let i = 0; i < binary.length; i++)
14
- bytes[i] = binary.charCodeAt(i);
15
- return bytes;
16
- }
17
- export {
18
- decodeBase64,
19
- encodeBase64
20
- };
@@ -1,27 +0,0 @@
1
- const unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
2
- function checkUsage(key, usage) {
3
- if (usage && !key.usages.includes(usage))
4
- throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
5
- }
6
- function checkModulusLength(alg, key) {
7
- const { modulusLength } = key.algorithm;
8
- if (typeof modulusLength != "number" || modulusLength < 2048)
9
- throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
10
- }
11
- function checkCryptoKey(key, expected, usage) {
12
- const algorithm = key.algorithm;
13
- if (algorithm.name !== expected.name)
14
- throw unusable(expected.name);
15
- if (expected.hash && algorithm.hash?.name !== expected.hash)
16
- throw unusable(expected.hash, "algorithm.hash");
17
- if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)
18
- throw unusable(expected.namedCurve, "algorithm.namedCurve");
19
- if (expected.length !== void 0 && algorithm.length !== expected.length)
20
- throw unusable(expected.length, "algorithm.length");
21
- checkUsage(key, usage);
22
- }
23
- export {
24
- checkCryptoKey,
25
- checkModulusLength,
26
- checkUsage
27
- };
@@ -1,45 +0,0 @@
1
- import { decode } from "../util/base64url.js";
2
- import { encode, strictDecoder } from "./buffer_utils.js";
3
- import { isObject } from "./type_checks.js";
4
- const unprotected = /* @__PURE__ */ Symbol();
5
- function assertNotSet(value, name) {
6
- if (value !== void 0)
7
- throw new TypeError(`${name} can only be called once`);
8
- }
9
- function decodeBase64url(value, label, ErrorClass) {
10
- try {
11
- return decode(value);
12
- } catch {
13
- throw new ErrorClass(`Failed to base64url decode the ${label}`);
14
- }
15
- }
16
- function encodeBase64url(value, label, ErrorClass) {
17
- try {
18
- return encode(value);
19
- } catch {
20
- throw new ErrorClass(`The ${label} is not a valid base64url string`);
21
- }
22
- }
23
- async function digest(algorithm, data) {
24
- const subtleDigest = `SHA-${algorithm.slice(-3)}`;
25
- return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));
26
- }
27
- function parseJoseHeader(b64, ErrorClass, message) {
28
- let parsed;
29
- try {
30
- parsed = JSON.parse(strictDecoder.decode(decode(b64)));
31
- } catch {
32
- throw new ErrorClass(message);
33
- }
34
- if (!isObject(parsed))
35
- throw new ErrorClass(message);
36
- return parsed;
37
- }
38
- export {
39
- assertNotSet,
40
- decodeBase64url,
41
- digest,
42
- encodeBase64url,
43
- parseJoseHeader,
44
- unprotected
45
- };
@@ -1,12 +0,0 @@
1
- function message(msg, actual, ...types) {
2
- if (types.length > 2) {
3
- const last = types.pop();
4
- msg += `one of type ${types.join(", ")}, or ${last}.`;
5
- } else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
6
- return actual == null ? msg += ` Received ${actual}` : typeof actual == "function" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == "object" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;
7
- }
8
- const invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types), withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
9
- export {
10
- invalidKeyInput,
11
- withAlg
12
- };
@@ -1,19 +0,0 @@
1
- function assertCryptoKey(key) {
2
- if (!isCryptoKey(key))
3
- throw new Error("CryptoKey instance expected");
4
- }
5
- const isCryptoKey = (key) => {
6
- if (key?.[Symbol.toStringTag] === "CryptoKey")
7
- return !0;
8
- try {
9
- return key instanceof CryptoKey;
10
- } catch {
11
- return !1;
12
- }
13
- }, isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject", isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
14
- export {
15
- assertCryptoKey,
16
- isCryptoKey,
17
- isKeyLike,
18
- isKeyObject
19
- };
@@ -1,19 +0,0 @@
1
- function snapshotJwk(jwk) {
2
- return { __proto__: null, ...jwk };
3
- }
4
- function normalizeJwk(jwk) {
5
- const normalized = snapshotJwk(jwk);
6
- if (normalized.ext !== void 0 && typeof normalized.ext != "boolean")
7
- throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
8
- if (normalized.key_ops !== void 0) {
9
- const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
10
- if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length)
11
- throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
12
- normalized.key_ops = keyOps;
13
- }
14
- return normalized;
15
- }
16
- export {
17
- normalizeJwk,
18
- snapshotJwk
19
- };
@@ -1,10 +0,0 @@
1
- import { JOSENotSupported } from "../util/errors.js";
2
- async function jwkToKey(entry, jwk) {
3
- if (!entry.kty.includes(jwk.kty))
4
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
5
- const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk };
6
- return keyData.kty !== "AKP" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
7
- }
8
- export {
9
- jwkToKey
10
- };
@@ -1,8 +0,0 @@
1
- function validateExtractableOption(extractable) {
2
- if (extractable !== void 0 && typeof extractable != "boolean")
3
- throw new TypeError('"extractable" option must be a boolean');
4
- return extractable;
5
- }
6
- export {
7
- validateExtractableOption
8
- };