jose 4.14.3 → 4.14.5

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 (33) hide show
  1. package/README.md +1 -1
  2. package/dist/browser/jwe/flattened/decrypt.js +34 -5
  3. package/dist/browser/jwks/remote.js +5 -1
  4. package/dist/browser/jws/flattened/verify.js +13 -2
  5. package/dist/browser/lib/crypto_key.js +0 -6
  6. package/dist/browser/lib/decrypt_key_management.js +34 -5
  7. package/dist/browser/runtime/asn1.js +3 -15
  8. package/dist/browser/runtime/generate.js +2 -14
  9. package/dist/browser/runtime/jwk_to_key.js +1 -13
  10. package/dist/browser/runtime/subtle_dsa.js +0 -4
  11. package/dist/browser/util/decode_jwt.js +1 -1
  12. package/dist/node/cjs/jwe/flattened/decrypt.js +34 -5
  13. package/dist/node/cjs/jwks/remote.js +6 -2
  14. package/dist/node/cjs/jws/flattened/verify.js +13 -2
  15. package/dist/node/cjs/lib/crypto_key.js +0 -6
  16. package/dist/node/cjs/lib/decrypt_key_management.js +34 -5
  17. package/dist/node/cjs/runtime/base64url.js +0 -1
  18. package/dist/node/cjs/util/decode_jwt.js +1 -1
  19. package/dist/node/esm/jwe/flattened/decrypt.js +34 -5
  20. package/dist/node/esm/jwks/remote.js +5 -1
  21. package/dist/node/esm/jws/flattened/verify.js +13 -2
  22. package/dist/node/esm/lib/crypto_key.js +0 -6
  23. package/dist/node/esm/lib/decrypt_key_management.js +34 -5
  24. package/dist/node/esm/util/decode_jwt.js +1 -1
  25. package/dist/types/jwe/compact/encrypt.d.ts +2 -0
  26. package/dist/types/jwe/flattened/encrypt.d.ts +2 -0
  27. package/dist/types/jwk/thumbprint.d.ts +2 -0
  28. package/dist/types/jwt/encrypt.d.ts +2 -0
  29. package/dist/types/types.d.ts +3 -0
  30. package/package.json +2 -3
  31. package/dist/browser/runtime/env.js +0 -5
  32. package/dist/node/cjs/runtime/env.js +0 -7
  33. package/dist/node/esm/runtime/env.js +0 -3
package/README.md CHANGED
@@ -129,4 +129,4 @@ Please note that certain algorithms may not be available depending on the runtim
129
129
  | Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ |
130
130
  | ------- | --------- | -------- | -------- |
131
131
  | [v4.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ✅ | ✅ |
132
- | [v3.x](https://github.com/panva/jose/tree/v3.x), [v2.x](https://github.com/panva/jose/tree/v2.x), [v1.x](https://github.com/panva/jose/tree/v1.x) | ✅ | ❌ | ❌ |
132
+ | [v2.x](https://github.com/panva/jose/tree/v2.x) | ✅ | ❌ | ❌ |
@@ -86,7 +86,12 @@ export async function flattenedDecrypt(jwe, key, options) {
86
86
  }
87
87
  let encryptedKey;
88
88
  if (jwe.encrypted_key !== undefined) {
89
- encryptedKey = base64url(jwe.encrypted_key);
89
+ try {
90
+ encryptedKey = base64url(jwe.encrypted_key);
91
+ }
92
+ catch (_c) {
93
+ throw new JWEInvalid('Failed to base64url decode the encrypted_key');
94
+ }
90
95
  }
91
96
  let resolvedKey = false;
92
97
  if (typeof key === 'function') {
@@ -103,8 +108,20 @@ export async function flattenedDecrypt(jwe, key, options) {
103
108
  }
104
109
  cek = generateCek(enc);
105
110
  }
106
- const iv = base64url(jwe.iv);
107
- const tag = base64url(jwe.tag);
111
+ let iv;
112
+ let tag;
113
+ try {
114
+ iv = base64url(jwe.iv);
115
+ }
116
+ catch (_d) {
117
+ throw new JWEInvalid('Failed to base64url decode the iv');
118
+ }
119
+ try {
120
+ tag = base64url(jwe.tag);
121
+ }
122
+ catch (_e) {
123
+ throw new JWEInvalid('Failed to base64url decode the tag');
124
+ }
108
125
  const protectedHeader = encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : '');
109
126
  let additionalData;
110
127
  if (jwe.aad !== undefined) {
@@ -113,7 +130,14 @@ export async function flattenedDecrypt(jwe, key, options) {
113
130
  else {
114
131
  additionalData = protectedHeader;
115
132
  }
116
- let plaintext = await decrypt(enc, cek, base64url(jwe.ciphertext), iv, tag, additionalData);
133
+ let ciphertext;
134
+ try {
135
+ ciphertext = base64url(jwe.ciphertext);
136
+ }
137
+ catch (_f) {
138
+ throw new JWEInvalid('Failed to base64url decode the ciphertext');
139
+ }
140
+ let plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
117
141
  if (joseHeader.zip === 'DEF') {
118
142
  plaintext = await ((options === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext);
119
143
  }
@@ -122,7 +146,12 @@ export async function flattenedDecrypt(jwe, key, options) {
122
146
  result.protectedHeader = parsedProt;
123
147
  }
124
148
  if (jwe.aad !== undefined) {
125
- result.additionalAuthenticatedData = base64url(jwe.aad);
149
+ try {
150
+ result.additionalAuthenticatedData = base64url(jwe.aad);
151
+ }
152
+ catch (_g) {
153
+ throw new JWEInvalid('Failed to base64url decode the aad');
154
+ }
126
155
  }
127
156
  if (jwe.unprotected !== undefined) {
128
157
  result.sharedUnprotectedHeader = jwe.unprotected;
@@ -1,7 +1,11 @@
1
1
  import fetchJwks from '../runtime/fetch_jwks.js';
2
- import { isCloudflareWorkers } from '../runtime/env.js';
3
2
  import { JWKSInvalid, JWKSNoMatchingKey } from '../util/errors.js';
4
3
  import { isJWKSLike, LocalJWKSet } from './local.js';
4
+ function isCloudflareWorkers() {
5
+ return (typeof WebSocketPair !== 'undefined' ||
6
+ (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
7
+ (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
8
+ }
5
9
  class RemoteJWKSet extends LocalJWKSet {
6
10
  constructor(url, options) {
7
11
  super({ keys: [] });
@@ -75,14 +75,25 @@ export async function flattenedVerify(jws, key, options) {
75
75
  }
76
76
  checkKeyType(alg, key, 'verify');
77
77
  const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
78
- const signature = base64url(jws.signature);
78
+ let signature;
79
+ try {
80
+ signature = base64url(jws.signature);
81
+ }
82
+ catch (_c) {
83
+ throw new JWSInvalid('Failed to base64url decode the signature');
84
+ }
79
85
  const verified = await verify(alg, key, signature, data);
80
86
  if (!verified) {
81
87
  throw new JWSSignatureVerificationFailed();
82
88
  }
83
89
  let payload;
84
90
  if (b64) {
85
- payload = base64url(jws.payload);
91
+ try {
92
+ payload = base64url(jws.payload);
93
+ }
94
+ catch (_d) {
95
+ throw new JWSInvalid('Failed to base64url decode the payload');
96
+ }
86
97
  }
87
98
  else if (typeof jws.payload === 'string') {
88
99
  payload = encoder.encode(jws.payload);
@@ -1,4 +1,3 @@
1
- import { isCloudflareWorkers } from '../runtime/env.js';
2
1
  function unusable(name, prop = 'algorithm.name') {
3
2
  return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
4
3
  }
@@ -73,11 +72,6 @@ export function checkSigCryptoKey(key, alg, ...usages) {
73
72
  }
74
73
  case 'EdDSA': {
75
74
  if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
76
- if (isCloudflareWorkers()) {
77
- if (isAlgorithm(key.algorithm, 'NODE-ED25519'))
78
- break;
79
- throw unusable('Ed25519, Ed448, or NODE-ED25519');
80
- }
81
75
  throw unusable('Ed25519 or Ed448');
82
76
  }
83
77
  break;
@@ -33,12 +33,22 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
33
33
  if (joseHeader.apu !== undefined) {
34
34
  if (typeof joseHeader.apu !== 'string')
35
35
  throw new JWEInvalid(`JOSE Header "apu" (Agreement PartyUInfo) invalid`);
36
- partyUInfo = base64url(joseHeader.apu);
36
+ try {
37
+ partyUInfo = base64url(joseHeader.apu);
38
+ }
39
+ catch (_a) {
40
+ throw new JWEInvalid('Failed to base64url decode the apu');
41
+ }
37
42
  }
38
43
  if (joseHeader.apv !== undefined) {
39
44
  if (typeof joseHeader.apv !== 'string')
40
45
  throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
41
- partyVInfo = base64url(joseHeader.apv);
46
+ try {
47
+ partyVInfo = base64url(joseHeader.apv);
48
+ }
49
+ catch (_b) {
50
+ throw new JWEInvalid('Failed to base64url decode the apv');
51
+ }
42
52
  }
43
53
  const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
44
54
  if (alg === 'ECDH-ES')
@@ -68,7 +78,14 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
68
78
  throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
69
79
  if (typeof joseHeader.p2s !== 'string')
70
80
  throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
71
- return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, base64url(joseHeader.p2s));
81
+ let p2s;
82
+ try {
83
+ p2s = base64url(joseHeader.p2s);
84
+ }
85
+ catch (_c) {
86
+ throw new JWEInvalid('Failed to base64url decode the p2s');
87
+ }
88
+ return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, p2s);
72
89
  }
73
90
  case 'A128KW':
74
91
  case 'A192KW':
@@ -86,8 +103,20 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
86
103
  throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
87
104
  if (typeof joseHeader.tag !== 'string')
88
105
  throw new JWEInvalid(`JOSE Header "tag" (Authentication Tag) missing or invalid`);
89
- const iv = base64url(joseHeader.iv);
90
- const tag = base64url(joseHeader.tag);
106
+ let iv;
107
+ try {
108
+ iv = base64url(joseHeader.iv);
109
+ }
110
+ catch (_d) {
111
+ throw new JWEInvalid('Failed to base64url decode the iv');
112
+ }
113
+ let tag;
114
+ try {
115
+ tag = base64url(joseHeader.tag);
116
+ }
117
+ catch (_e) {
118
+ throw new JWEInvalid('Failed to base64url decode the tag');
119
+ }
91
120
  return aesGcmKw(alg, key, encryptedKey, iv, tag);
92
121
  }
93
122
  default: {
@@ -1,4 +1,3 @@
1
- import { isCloudflareWorkers } from './env.js';
2
1
  import crypto, { isCryptoKey } from './webcrypto.js';
3
2
  import invalidKeyInput from '../lib/invalid_key_input.js';
4
3
  import { encodeBase64, decodeBase64 } from './base64url.js';
@@ -57,7 +56,7 @@ const getNamedCurve = (keyData) => {
57
56
  }
58
57
  };
59
58
  const genericImport = async (replace, keyFormat, pem, alg, options) => {
60
- var _a, _b;
59
+ var _a;
61
60
  let algorithm;
62
61
  let keyUsages;
63
62
  const keyData = new Uint8Array(atob(pem.replace(replace, ''))
@@ -115,18 +114,7 @@ const genericImport = async (replace, keyFormat, pem, alg, options) => {
115
114
  default:
116
115
  throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value');
117
116
  }
118
- try {
119
- return await crypto.subtle.importKey(keyFormat, keyData, algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, keyUsages);
120
- }
121
- catch (err) {
122
- if (algorithm.name === 'Ed25519' &&
123
- (err === null || err === void 0 ? void 0 : err.name) === 'NotSupportedError' &&
124
- isCloudflareWorkers()) {
125
- algorithm = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
126
- return await crypto.subtle.importKey(keyFormat, keyData, algorithm, (_b = options === null || options === void 0 ? void 0 : options.extractable) !== null && _b !== void 0 ? _b : false, keyUsages);
127
- }
128
- throw err;
129
- }
117
+ return crypto.subtle.importKey(keyFormat, keyData, algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, keyUsages);
130
118
  };
131
119
  export const fromPKCS8 = (pem, alg, options) => {
132
120
  return genericImport(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, 'pkcs8', pem, alg, options);
@@ -208,7 +196,7 @@ export const fromX509 = (pem, alg, options) => {
208
196
  spki = getSPKI(pem);
209
197
  }
210
198
  catch (cause) {
211
- throw new TypeError('failed to parse the X.509 certificate', { cause });
199
+ throw new TypeError('Failed to parse the X.509 certificate', { cause });
212
200
  }
213
201
  return fromSPKI(spki, alg, options);
214
202
  };
@@ -1,4 +1,3 @@
1
- import { isCloudflareWorkers } from './env.js';
2
1
  import crypto from './webcrypto.js';
3
2
  import { JOSENotSupported } from '../util/errors.js';
4
3
  import random from './random.js';
@@ -51,7 +50,7 @@ function getModulusLengthOption(options) {
51
50
  return modulusLength;
52
51
  }
53
52
  export async function generateKeyPair(alg, options) {
54
- var _a, _b, _c, _d;
53
+ var _a, _b, _c;
55
54
  let algorithm;
56
55
  let keyUsages;
57
56
  switch (alg) {
@@ -138,16 +137,5 @@ export async function generateKeyPair(alg, options) {
138
137
  default:
139
138
  throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
140
139
  }
141
- try {
142
- return (await crypto.subtle.generateKey(algorithm, (_c = options === null || options === void 0 ? void 0 : options.extractable) !== null && _c !== void 0 ? _c : false, keyUsages));
143
- }
144
- catch (err) {
145
- if (algorithm.name === 'Ed25519' &&
146
- (err === null || err === void 0 ? void 0 : err.name) === 'NotSupportedError' &&
147
- isCloudflareWorkers()) {
148
- algorithm = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
149
- return (await crypto.subtle.generateKey(algorithm, (_d = options === null || options === void 0 ? void 0 : options.extractable) !== null && _d !== void 0 ? _d : false, keyUsages));
150
- }
151
- throw err;
152
- }
140
+ return (crypto.subtle.generateKey(algorithm, (_c = options === null || options === void 0 ? void 0 : options.extractable) !== null && _c !== void 0 ? _c : false, keyUsages));
153
141
  }
@@ -1,4 +1,3 @@
1
- import { isCloudflareWorkers } from './env.js';
2
1
  import crypto from './webcrypto.js';
3
2
  import { JOSENotSupported } from '../util/errors.js';
4
3
  import { decode as base64url } from './base64url.js';
@@ -139,17 +138,6 @@ const parse = async (jwk) => {
139
138
  const keyData = { ...jwk };
140
139
  delete keyData.alg;
141
140
  delete keyData.use;
142
- try {
143
- return await crypto.subtle.importKey('jwk', keyData, ...rest);
144
- }
145
- catch (err) {
146
- if (algorithm.name === 'Ed25519' &&
147
- (err === null || err === void 0 ? void 0 : err.name) === 'NotSupportedError' &&
148
- isCloudflareWorkers()) {
149
- rest[0] = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
150
- return await crypto.subtle.importKey('jwk', keyData, ...rest);
151
- }
152
- throw err;
153
- }
141
+ return crypto.subtle.importKey('jwk', keyData, ...rest);
154
142
  };
155
143
  export default parse;
@@ -1,4 +1,3 @@
1
- import { isCloudflareWorkers } from './env.js';
2
1
  import { JOSENotSupported } from '../util/errors.js';
3
2
  export default function subtleDsa(alg, algorithm) {
4
3
  const hash = `SHA-${alg.slice(-3)}`;
@@ -20,9 +19,6 @@ export default function subtleDsa(alg, algorithm) {
20
19
  case 'ES512':
21
20
  return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
22
21
  case 'EdDSA':
23
- if (isCloudflareWorkers() && algorithm.name === 'NODE-ED25519') {
24
- return { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
25
- }
26
22
  return { name: algorithm.name };
27
23
  default:
28
24
  throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
@@ -17,7 +17,7 @@ export function decodeJwt(jwt) {
17
17
  decoded = base64url(payload);
18
18
  }
19
19
  catch (_a) {
20
- throw new JWTInvalid('Failed to parse the base64url encoded payload');
20
+ throw new JWTInvalid('Failed to base64url decode the payload');
21
21
  }
22
22
  let result;
23
23
  try {
@@ -89,7 +89,12 @@ async function flattenedDecrypt(jwe, key, options) {
89
89
  }
90
90
  let encryptedKey;
91
91
  if (jwe.encrypted_key !== undefined) {
92
- encryptedKey = (0, base64url_js_1.decode)(jwe.encrypted_key);
92
+ try {
93
+ encryptedKey = (0, base64url_js_1.decode)(jwe.encrypted_key);
94
+ }
95
+ catch {
96
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the encrypted_key');
97
+ }
93
98
  }
94
99
  let resolvedKey = false;
95
100
  if (typeof key === 'function') {
@@ -106,8 +111,20 @@ async function flattenedDecrypt(jwe, key, options) {
106
111
  }
107
112
  cek = (0, cek_js_1.default)(enc);
108
113
  }
109
- const iv = (0, base64url_js_1.decode)(jwe.iv);
110
- const tag = (0, base64url_js_1.decode)(jwe.tag);
114
+ let iv;
115
+ let tag;
116
+ try {
117
+ iv = (0, base64url_js_1.decode)(jwe.iv);
118
+ }
119
+ catch {
120
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the iv');
121
+ }
122
+ try {
123
+ tag = (0, base64url_js_1.decode)(jwe.tag);
124
+ }
125
+ catch {
126
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the tag');
127
+ }
111
128
  const protectedHeader = buffer_utils_js_1.encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : '');
112
129
  let additionalData;
113
130
  if (jwe.aad !== undefined) {
@@ -116,7 +133,14 @@ async function flattenedDecrypt(jwe, key, options) {
116
133
  else {
117
134
  additionalData = protectedHeader;
118
135
  }
119
- let plaintext = await (0, decrypt_js_1.default)(enc, cek, (0, base64url_js_1.decode)(jwe.ciphertext), iv, tag, additionalData);
136
+ let ciphertext;
137
+ try {
138
+ ciphertext = (0, base64url_js_1.decode)(jwe.ciphertext);
139
+ }
140
+ catch {
141
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the ciphertext');
142
+ }
143
+ let plaintext = await (0, decrypt_js_1.default)(enc, cek, ciphertext, iv, tag, additionalData);
120
144
  if (joseHeader.zip === 'DEF') {
121
145
  plaintext = await ((options === null || options === void 0 ? void 0 : options.inflateRaw) || zlib_js_1.inflate)(plaintext);
122
146
  }
@@ -125,7 +149,12 @@ async function flattenedDecrypt(jwe, key, options) {
125
149
  result.protectedHeader = parsedProt;
126
150
  }
127
151
  if (jwe.aad !== undefined) {
128
- result.additionalAuthenticatedData = (0, base64url_js_1.decode)(jwe.aad);
152
+ try {
153
+ result.additionalAuthenticatedData = (0, base64url_js_1.decode)(jwe.aad);
154
+ }
155
+ catch {
156
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the aad');
157
+ }
129
158
  }
130
159
  if (jwe.unprotected !== undefined) {
131
160
  result.sharedUnprotectedHeader = jwe.unprotected;
@@ -2,9 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createRemoteJWKSet = void 0;
4
4
  const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
5
- const env_js_1 = require("../runtime/env.js");
6
5
  const errors_js_1 = require("../util/errors.js");
7
6
  const local_js_1 = require("./local.js");
7
+ function isCloudflareWorkers() {
8
+ return (typeof WebSocketPair !== 'undefined' ||
9
+ (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
10
+ (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
11
+ }
8
12
  class RemoteJWKSet extends local_js_1.LocalJWKSet {
9
13
  constructor(url, options) {
10
14
  super({ keys: [] });
@@ -48,7 +52,7 @@ class RemoteJWKSet extends local_js_1.LocalJWKSet {
48
52
  }
49
53
  }
50
54
  async reload() {
51
- if (this._pendingFetch && (0, env_js_1.isCloudflareWorkers)()) {
55
+ if (this._pendingFetch && isCloudflareWorkers()) {
52
56
  this._pendingFetch = undefined;
53
57
  }
54
58
  this._pendingFetch || (this._pendingFetch = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options)
@@ -78,14 +78,25 @@ async function flattenedVerify(jws, key, options) {
78
78
  }
79
79
  (0, check_key_type_js_1.default)(alg, key, 'verify');
80
80
  const data = (0, buffer_utils_js_1.concat)(buffer_utils_js_1.encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), buffer_utils_js_1.encoder.encode('.'), typeof jws.payload === 'string' ? buffer_utils_js_1.encoder.encode(jws.payload) : jws.payload);
81
- const signature = (0, base64url_js_1.decode)(jws.signature);
81
+ let signature;
82
+ try {
83
+ signature = (0, base64url_js_1.decode)(jws.signature);
84
+ }
85
+ catch {
86
+ throw new errors_js_1.JWSInvalid('Failed to base64url decode the signature');
87
+ }
82
88
  const verified = await (0, verify_js_1.default)(alg, key, signature, data);
83
89
  if (!verified) {
84
90
  throw new errors_js_1.JWSSignatureVerificationFailed();
85
91
  }
86
92
  let payload;
87
93
  if (b64) {
88
- payload = (0, base64url_js_1.decode)(jws.payload);
94
+ try {
95
+ payload = (0, base64url_js_1.decode)(jws.payload);
96
+ }
97
+ catch {
98
+ throw new errors_js_1.JWSInvalid('Failed to base64url decode the payload');
99
+ }
89
100
  }
90
101
  else if (typeof jws.payload === 'string') {
91
102
  payload = buffer_utils_js_1.encoder.encode(jws.payload);
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkEncCryptoKey = exports.checkSigCryptoKey = void 0;
4
- const env_js_1 = require("../runtime/env.js");
5
4
  function unusable(name, prop = 'algorithm.name') {
6
5
  return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
7
6
  }
@@ -76,11 +75,6 @@ function checkSigCryptoKey(key, alg, ...usages) {
76
75
  }
77
76
  case 'EdDSA': {
78
77
  if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
79
- if ((0, env_js_1.isCloudflareWorkers)()) {
80
- if (isAlgorithm(key.algorithm, 'NODE-ED25519'))
81
- break;
82
- throw unusable('Ed25519, Ed448, or NODE-ED25519');
83
- }
84
78
  throw unusable('Ed25519 or Ed448');
85
79
  }
86
80
  break;
@@ -35,12 +35,22 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
35
35
  if (joseHeader.apu !== undefined) {
36
36
  if (typeof joseHeader.apu !== 'string')
37
37
  throw new errors_js_1.JWEInvalid(`JOSE Header "apu" (Agreement PartyUInfo) invalid`);
38
- partyUInfo = (0, base64url_js_1.decode)(joseHeader.apu);
38
+ try {
39
+ partyUInfo = (0, base64url_js_1.decode)(joseHeader.apu);
40
+ }
41
+ catch {
42
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the apu');
43
+ }
39
44
  }
40
45
  if (joseHeader.apv !== undefined) {
41
46
  if (typeof joseHeader.apv !== 'string')
42
47
  throw new errors_js_1.JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
43
- partyVInfo = (0, base64url_js_1.decode)(joseHeader.apv);
48
+ try {
49
+ partyVInfo = (0, base64url_js_1.decode)(joseHeader.apv);
50
+ }
51
+ catch {
52
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the apv');
53
+ }
44
54
  }
45
55
  const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? (0, cek_js_1.bitLength)(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
46
56
  if (alg === 'ECDH-ES')
@@ -70,7 +80,14 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
70
80
  throw new errors_js_1.JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
71
81
  if (typeof joseHeader.p2s !== 'string')
72
82
  throw new errors_js_1.JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
73
- return (0, pbes2kw_js_1.decrypt)(alg, key, encryptedKey, joseHeader.p2c, (0, base64url_js_1.decode)(joseHeader.p2s));
83
+ let p2s;
84
+ try {
85
+ p2s = (0, base64url_js_1.decode)(joseHeader.p2s);
86
+ }
87
+ catch {
88
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the p2s');
89
+ }
90
+ return (0, pbes2kw_js_1.decrypt)(alg, key, encryptedKey, joseHeader.p2c, p2s);
74
91
  }
75
92
  case 'A128KW':
76
93
  case 'A192KW':
@@ -88,8 +105,20 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
88
105
  throw new errors_js_1.JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
89
106
  if (typeof joseHeader.tag !== 'string')
90
107
  throw new errors_js_1.JWEInvalid(`JOSE Header "tag" (Authentication Tag) missing or invalid`);
91
- const iv = (0, base64url_js_1.decode)(joseHeader.iv);
92
- const tag = (0, base64url_js_1.decode)(joseHeader.tag);
108
+ let iv;
109
+ try {
110
+ iv = (0, base64url_js_1.decode)(joseHeader.iv);
111
+ }
112
+ catch {
113
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the iv');
114
+ }
115
+ let tag;
116
+ try {
117
+ tag = (0, base64url_js_1.decode)(joseHeader.tag);
118
+ }
119
+ catch {
120
+ throw new errors_js_1.JWEInvalid('Failed to base64url decode the tag');
121
+ }
93
122
  return (0, aesgcmkw_js_1.unwrap)(alg, key, encryptedKey, iv, tag);
94
123
  }
95
124
  default: {
@@ -4,7 +4,6 @@ exports.decode = exports.encode = exports.encodeBase64 = exports.decodeBase64 =
4
4
  const buffer_1 = require("buffer");
5
5
  const buffer_utils_js_1 = require("../lib/buffer_utils.js");
6
6
  let encode;
7
- exports.encode = encode;
8
7
  function normalize(input) {
9
8
  let encoded = input;
10
9
  if (encoded instanceof Uint8Array) {
@@ -20,7 +20,7 @@ function decodeJwt(jwt) {
20
20
  decoded = (0, base64url_js_1.decode)(payload);
21
21
  }
22
22
  catch {
23
- throw new errors_js_1.JWTInvalid('Failed to parse the base64url encoded payload');
23
+ throw new errors_js_1.JWTInvalid('Failed to base64url decode the payload');
24
24
  }
25
25
  let result;
26
26
  try {
@@ -86,7 +86,12 @@ export async function flattenedDecrypt(jwe, key, options) {
86
86
  }
87
87
  let encryptedKey;
88
88
  if (jwe.encrypted_key !== undefined) {
89
- encryptedKey = base64url(jwe.encrypted_key);
89
+ try {
90
+ encryptedKey = base64url(jwe.encrypted_key);
91
+ }
92
+ catch {
93
+ throw new JWEInvalid('Failed to base64url decode the encrypted_key');
94
+ }
90
95
  }
91
96
  let resolvedKey = false;
92
97
  if (typeof key === 'function') {
@@ -103,8 +108,20 @@ export async function flattenedDecrypt(jwe, key, options) {
103
108
  }
104
109
  cek = generateCek(enc);
105
110
  }
106
- const iv = base64url(jwe.iv);
107
- const tag = base64url(jwe.tag);
111
+ let iv;
112
+ let tag;
113
+ try {
114
+ iv = base64url(jwe.iv);
115
+ }
116
+ catch {
117
+ throw new JWEInvalid('Failed to base64url decode the iv');
118
+ }
119
+ try {
120
+ tag = base64url(jwe.tag);
121
+ }
122
+ catch {
123
+ throw new JWEInvalid('Failed to base64url decode the tag');
124
+ }
108
125
  const protectedHeader = encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : '');
109
126
  let additionalData;
110
127
  if (jwe.aad !== undefined) {
@@ -113,7 +130,14 @@ export async function flattenedDecrypt(jwe, key, options) {
113
130
  else {
114
131
  additionalData = protectedHeader;
115
132
  }
116
- let plaintext = await decrypt(enc, cek, base64url(jwe.ciphertext), iv, tag, additionalData);
133
+ let ciphertext;
134
+ try {
135
+ ciphertext = base64url(jwe.ciphertext);
136
+ }
137
+ catch {
138
+ throw new JWEInvalid('Failed to base64url decode the ciphertext');
139
+ }
140
+ let plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
117
141
  if (joseHeader.zip === 'DEF') {
118
142
  plaintext = await ((options === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext);
119
143
  }
@@ -122,7 +146,12 @@ export async function flattenedDecrypt(jwe, key, options) {
122
146
  result.protectedHeader = parsedProt;
123
147
  }
124
148
  if (jwe.aad !== undefined) {
125
- result.additionalAuthenticatedData = base64url(jwe.aad);
149
+ try {
150
+ result.additionalAuthenticatedData = base64url(jwe.aad);
151
+ }
152
+ catch {
153
+ throw new JWEInvalid('Failed to base64url decode the aad');
154
+ }
126
155
  }
127
156
  if (jwe.unprotected !== undefined) {
128
157
  result.sharedUnprotectedHeader = jwe.unprotected;
@@ -1,7 +1,11 @@
1
1
  import fetchJwks from '../runtime/fetch_jwks.js';
2
- import { isCloudflareWorkers } from '../runtime/env.js';
3
2
  import { JWKSInvalid, JWKSNoMatchingKey } from '../util/errors.js';
4
3
  import { isJWKSLike, LocalJWKSet } from './local.js';
4
+ function isCloudflareWorkers() {
5
+ return (typeof WebSocketPair !== 'undefined' ||
6
+ (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
7
+ (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
8
+ }
5
9
  class RemoteJWKSet extends LocalJWKSet {
6
10
  constructor(url, options) {
7
11
  super({ keys: [] });
@@ -75,14 +75,25 @@ export async function flattenedVerify(jws, key, options) {
75
75
  }
76
76
  checkKeyType(alg, key, 'verify');
77
77
  const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
78
- const signature = base64url(jws.signature);
78
+ let signature;
79
+ try {
80
+ signature = base64url(jws.signature);
81
+ }
82
+ catch {
83
+ throw new JWSInvalid('Failed to base64url decode the signature');
84
+ }
79
85
  const verified = await verify(alg, key, signature, data);
80
86
  if (!verified) {
81
87
  throw new JWSSignatureVerificationFailed();
82
88
  }
83
89
  let payload;
84
90
  if (b64) {
85
- payload = base64url(jws.payload);
91
+ try {
92
+ payload = base64url(jws.payload);
93
+ }
94
+ catch {
95
+ throw new JWSInvalid('Failed to base64url decode the payload');
96
+ }
86
97
  }
87
98
  else if (typeof jws.payload === 'string') {
88
99
  payload = encoder.encode(jws.payload);
@@ -1,4 +1,3 @@
1
- import { isCloudflareWorkers } from '../runtime/env.js';
2
1
  function unusable(name, prop = 'algorithm.name') {
3
2
  return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
4
3
  }
@@ -73,11 +72,6 @@ export function checkSigCryptoKey(key, alg, ...usages) {
73
72
  }
74
73
  case 'EdDSA': {
75
74
  if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
76
- if (isCloudflareWorkers()) {
77
- if (isAlgorithm(key.algorithm, 'NODE-ED25519'))
78
- break;
79
- throw unusable('Ed25519, Ed448, or NODE-ED25519');
80
- }
81
75
  throw unusable('Ed25519 or Ed448');
82
76
  }
83
77
  break;
@@ -33,12 +33,22 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
33
33
  if (joseHeader.apu !== undefined) {
34
34
  if (typeof joseHeader.apu !== 'string')
35
35
  throw new JWEInvalid(`JOSE Header "apu" (Agreement PartyUInfo) invalid`);
36
- partyUInfo = base64url(joseHeader.apu);
36
+ try {
37
+ partyUInfo = base64url(joseHeader.apu);
38
+ }
39
+ catch {
40
+ throw new JWEInvalid('Failed to base64url decode the apu');
41
+ }
37
42
  }
38
43
  if (joseHeader.apv !== undefined) {
39
44
  if (typeof joseHeader.apv !== 'string')
40
45
  throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
41
- partyVInfo = base64url(joseHeader.apv);
46
+ try {
47
+ partyVInfo = base64url(joseHeader.apv);
48
+ }
49
+ catch {
50
+ throw new JWEInvalid('Failed to base64url decode the apv');
51
+ }
42
52
  }
43
53
  const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
44
54
  if (alg === 'ECDH-ES')
@@ -68,7 +78,14 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
68
78
  throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
69
79
  if (typeof joseHeader.p2s !== 'string')
70
80
  throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
71
- return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, base64url(joseHeader.p2s));
81
+ let p2s;
82
+ try {
83
+ p2s = base64url(joseHeader.p2s);
84
+ }
85
+ catch {
86
+ throw new JWEInvalid('Failed to base64url decode the p2s');
87
+ }
88
+ return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, p2s);
72
89
  }
73
90
  case 'A128KW':
74
91
  case 'A192KW':
@@ -86,8 +103,20 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
86
103
  throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
87
104
  if (typeof joseHeader.tag !== 'string')
88
105
  throw new JWEInvalid(`JOSE Header "tag" (Authentication Tag) missing or invalid`);
89
- const iv = base64url(joseHeader.iv);
90
- const tag = base64url(joseHeader.tag);
106
+ let iv;
107
+ try {
108
+ iv = base64url(joseHeader.iv);
109
+ }
110
+ catch {
111
+ throw new JWEInvalid('Failed to base64url decode the iv');
112
+ }
113
+ let tag;
114
+ try {
115
+ tag = base64url(joseHeader.tag);
116
+ }
117
+ catch {
118
+ throw new JWEInvalid('Failed to base64url decode the tag');
119
+ }
91
120
  return aesGcmKw(alg, key, encryptedKey, iv, tag);
92
121
  }
93
122
  default: {
@@ -17,7 +17,7 @@ export function decodeJwt(jwt) {
17
17
  decoded = base64url(payload);
18
18
  }
19
19
  catch {
20
- throw new JWTInvalid('Failed to parse the base64url encoded payload');
20
+ throw new JWTInvalid('Failed to base64url decode the payload');
21
21
  }
22
22
  let result;
23
23
  try {
@@ -13,6 +13,7 @@ export declare class CompactEncrypt {
13
13
  *
14
14
  * @deprecated You should not use this method. It is only really intended for test and vector
15
15
  * validation purposes.
16
+ *
16
17
  * @param cek JWE Content Encryption Key.
17
18
  */
18
19
  setContentEncryptionKey(cek: Uint8Array): this;
@@ -22,6 +23,7 @@ export declare class CompactEncrypt {
22
23
  *
23
24
  * @deprecated You should not use this method. It is only really intended for test and vector
24
25
  * validation purposes.
26
+ *
25
27
  * @param iv JWE Initialization Vector.
26
28
  */
27
29
  setInitializationVector(iv: Uint8Array): this;
@@ -55,6 +55,7 @@ export declare class FlattenedEncrypt {
55
55
  *
56
56
  * @deprecated You should not use this method. It is only really intended for test and vector
57
57
  * validation purposes.
58
+ *
58
59
  * @param cek JWE Content Encryption Key.
59
60
  */
60
61
  setContentEncryptionKey(cek: Uint8Array): this;
@@ -64,6 +65,7 @@ export declare class FlattenedEncrypt {
64
65
  *
65
66
  * @deprecated You should not use this method. It is only really intended for test and vector
66
67
  * validation purposes.
68
+ *
67
69
  * @param iv JWE Initialization Vector.
68
70
  */
69
71
  setInitializationVector(iv: Uint8Array): this;
@@ -5,6 +5,7 @@ import type { JWK } from '../types';
5
5
  * @param jwk JSON Web Key.
6
6
  * @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is
7
7
  * "sha256".
8
+ *
8
9
  * @see {@link https://www.rfc-editor.org/rfc/rfc7638 RFC7638}
9
10
  */
10
11
  export declare function calculateJwkThumbprint(jwk: JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise<string>;
@@ -14,6 +15,7 @@ export declare function calculateJwkThumbprint(jwk: JWK, digestAlgorithm?: 'sha2
14
15
  * @param jwk JSON Web Key.
15
16
  * @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is
16
17
  * "sha256".
18
+ *
17
19
  * @see {@link https://www.rfc-editor.org/rfc/rfc9278 RFC9278}
18
20
  */
19
21
  export declare function calculateJwkThumbprintUri(jwk: JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise<string>;
@@ -34,6 +34,7 @@ export declare class EncryptJWT extends ProduceJWT {
34
34
  *
35
35
  * @deprecated You should not use this method. It is only really intended for test and vector
36
36
  * validation purposes.
37
+ *
37
38
  * @param cek JWE Content Encryption Key.
38
39
  */
39
40
  setContentEncryptionKey(cek: Uint8Array): this;
@@ -43,6 +44,7 @@ export declare class EncryptJWT extends ProduceJWT {
43
44
  *
44
45
  * @deprecated You should not use this method. It is only really intended for test and vector
45
46
  * validation purposes.
47
+ *
46
48
  * @param iv JWE Initialization Vector.
47
49
  */
48
50
  setInitializationVector(iv: Uint8Array): this;
@@ -299,6 +299,7 @@ export interface JWEHeaderParameters extends JoseHeaderParameters {
299
299
  *
300
300
  * @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed
301
301
  * data often reveals information about the plaintext.
302
+ *
302
303
  * @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs}
303
304
  */
304
305
  zip?: string
@@ -487,6 +488,7 @@ export interface JWTPayload {
487
488
  *
488
489
  * @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed
489
490
  * data often reveals information about the plaintext.
491
+ *
490
492
  * @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs}
491
493
  */
492
494
  export interface DeflateFunction {
@@ -499,6 +501,7 @@ export interface DeflateFunction {
499
501
  *
500
502
  * @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed
501
503
  * data often reveals information about the plaintext.
504
+ *
502
505
  * @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs}
503
506
  */
504
507
  export interface InflateFunction {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jose",
3
- "version": "4.14.3",
3
+ "version": "4.14.5",
4
4
  "description": "'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes",
5
5
  "keywords": [
6
6
  "browser",
@@ -20,7 +20,6 @@
20
20
  "encrypt",
21
21
  "flattened",
22
22
  "general",
23
- "isomorphic",
24
23
  "jose",
25
24
  "json web token",
26
25
  "jsonwebtoken",
@@ -43,11 +42,11 @@
43
42
  "sign",
44
43
  "signature",
45
44
  "spki",
46
- "universal",
47
45
  "validate",
48
46
  "vercel",
49
47
  "verify",
50
48
  "webcrypto",
49
+ "workerd",
51
50
  "workers",
52
51
  "x509"
53
52
  ],
@@ -1,5 +0,0 @@
1
- export function isCloudflareWorkers() {
2
- return (typeof WebSocketPair !== 'undefined' ||
3
- (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
4
- (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
5
- }
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isCloudflareWorkers = void 0;
4
- function isCloudflareWorkers() {
5
- return false;
6
- }
7
- exports.isCloudflareWorkers = isCloudflareWorkers;
@@ -1,3 +0,0 @@
1
- export function isCloudflareWorkers() {
2
- return false;
3
- }