jose 4.15.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/browser/index.js +2 -4
- package/dist/browser/jwe/flattened/decrypt.js +13 -22
- package/dist/browser/jwe/flattened/encrypt.js +3 -18
- package/dist/browser/jwe/general/decrypt.js +1 -1
- package/dist/browser/jwe/general/encrypt.js +8 -13
- package/dist/browser/jwk/embedded.js +2 -2
- package/dist/browser/jwk/thumbprint.js +2 -2
- package/dist/browser/jwks/local.js +2 -2
- package/dist/browser/jwks/remote.js +4 -4
- package/dist/browser/jws/flattened/sign.js +1 -1
- package/dist/browser/jws/flattened/verify.js +6 -7
- package/dist/browser/jws/general/verify.js +1 -1
- package/dist/browser/jwt/produce.js +19 -4
- package/dist/browser/jwt/sign.js +1 -2
- package/dist/browser/jwt/unsecured.js +1 -1
- package/dist/browser/jwt/verify.js +1 -2
- package/dist/browser/key/import.js +1 -6
- package/dist/browser/lib/decrypt_key_management.js +6 -6
- package/dist/browser/lib/jwt_claims_set.js +1 -1
- package/dist/browser/runtime/asn1.js +1 -2
- package/dist/browser/runtime/base64url.js +1 -1
- package/dist/browser/runtime/decrypt.js +3 -3
- package/dist/browser/runtime/fetch_jwks.js +1 -1
- package/dist/browser/runtime/generate.js +5 -8
- package/dist/browser/runtime/jwk_to_key.js +2 -45
- package/dist/browser/runtime/verify.js +1 -1
- package/dist/browser/util/decode_jwt.js +2 -2
- package/dist/browser/util/decode_protected_header.js +1 -1
- package/dist/browser/util/errors.js +1 -2
- package/dist/node/cjs/jwe/compact/encrypt.js +1 -0
- package/dist/node/cjs/jwe/flattened/decrypt.js +7 -16
- package/dist/node/cjs/jwe/flattened/encrypt.js +12 -19
- package/dist/node/cjs/jwe/general/encrypt.js +16 -13
- package/dist/node/cjs/jwk/embedded.js +2 -2
- package/dist/node/cjs/jwk/thumbprint.js +2 -2
- package/dist/node/cjs/jwks/local.js +3 -2
- package/dist/node/cjs/jwks/remote.js +13 -6
- package/dist/node/cjs/jws/compact/sign.js +1 -0
- package/dist/node/cjs/jws/flattened/sign.js +4 -1
- package/dist/node/cjs/jws/flattened/verify.js +3 -4
- package/dist/node/cjs/jws/general/sign.js +7 -1
- package/dist/node/cjs/jwt/encrypt.js +7 -0
- package/dist/node/cjs/jwt/produce.js +20 -4
- package/dist/node/cjs/jwt/sign.js +2 -2
- package/dist/node/cjs/jwt/verify.js +1 -2
- package/dist/node/cjs/key/import.js +2 -7
- package/dist/node/cjs/lib/aesgcmkw.js +1 -1
- package/dist/node/cjs/lib/decrypt_key_management.js +1 -1
- package/dist/node/cjs/lib/encrypt_key_management.js +1 -1
- package/dist/node/cjs/runtime/aeskw.js +6 -6
- package/dist/node/cjs/runtime/asn1.js +8 -8
- package/dist/node/cjs/runtime/base64url.js +6 -11
- package/dist/node/cjs/runtime/cbc_tag.js +2 -2
- package/dist/node/cjs/runtime/check_key_length.js +8 -0
- package/dist/node/cjs/runtime/ciphers.js +2 -2
- package/dist/node/cjs/runtime/decrypt.js +4 -4
- package/dist/node/cjs/runtime/digest.js +2 -2
- package/dist/node/cjs/runtime/ecdhes.js +7 -7
- package/dist/node/cjs/runtime/encrypt.js +4 -4
- package/dist/node/cjs/runtime/fetch_jwks.js +4 -4
- package/dist/node/cjs/runtime/generate.js +7 -11
- package/dist/node/cjs/runtime/get_named_curve.js +7 -45
- package/dist/node/cjs/runtime/get_sign_verify_key.js +4 -4
- package/dist/node/cjs/runtime/is_key_like.js +1 -1
- package/dist/node/cjs/runtime/is_key_object.js +2 -5
- package/dist/node/cjs/runtime/jwk_to_key.js +2 -113
- package/dist/node/cjs/runtime/key_to_jwk.js +6 -130
- package/dist/node/cjs/runtime/node_key.js +9 -18
- package/dist/node/cjs/runtime/pbes2kw.js +4 -4
- package/dist/node/cjs/runtime/random.js +2 -2
- package/dist/node/cjs/runtime/rsaes.js +8 -8
- package/dist/node/cjs/runtime/sign.js +3 -9
- package/dist/node/cjs/runtime/timing_safe_equal.js +2 -2
- package/dist/node/cjs/runtime/verify.js +3 -10
- package/dist/node/cjs/runtime/webcrypto.js +4 -6
- package/dist/node/cjs/util/errors.js +26 -59
- package/dist/node/esm/jwe/compact/encrypt.js +1 -0
- package/dist/node/esm/jwe/flattened/decrypt.js +7 -16
- package/dist/node/esm/jwe/flattened/encrypt.js +12 -19
- package/dist/node/esm/jwe/general/encrypt.js +17 -14
- package/dist/node/esm/jwk/embedded.js +2 -2
- package/dist/node/esm/jwk/thumbprint.js +2 -2
- package/dist/node/esm/jwks/local.js +3 -2
- package/dist/node/esm/jwks/remote.js +13 -6
- package/dist/node/esm/jws/compact/sign.js +1 -0
- package/dist/node/esm/jws/flattened/sign.js +4 -1
- package/dist/node/esm/jws/flattened/verify.js +3 -4
- package/dist/node/esm/jws/general/sign.js +7 -1
- package/dist/node/esm/jwt/encrypt.js +7 -0
- package/dist/node/esm/jwt/produce.js +20 -4
- package/dist/node/esm/jwt/sign.js +2 -2
- package/dist/node/esm/jwt/verify.js +1 -2
- package/dist/node/esm/key/import.js +2 -7
- package/dist/node/esm/lib/aesgcmkw.js +1 -1
- package/dist/node/esm/lib/decrypt_key_management.js +1 -1
- package/dist/node/esm/lib/encrypt_key_management.js +1 -1
- package/dist/node/esm/runtime/aeskw.js +2 -2
- package/dist/node/esm/runtime/asn1.js +2 -2
- package/dist/node/esm/runtime/base64url.js +4 -10
- package/dist/node/esm/runtime/cbc_tag.js +1 -1
- package/dist/node/esm/runtime/check_key_length.js +6 -0
- package/dist/node/esm/runtime/ciphers.js +2 -2
- package/dist/node/esm/runtime/decrypt.js +1 -1
- package/dist/node/esm/runtime/digest.js +1 -1
- package/dist/node/esm/runtime/ecdhes.js +2 -2
- package/dist/node/esm/runtime/encrypt.js +1 -1
- package/dist/node/esm/runtime/fetch_jwks.js +3 -3
- package/dist/node/esm/runtime/generate.js +5 -9
- package/dist/node/esm/runtime/get_named_curve.js +5 -42
- package/dist/node/esm/runtime/get_sign_verify_key.js +1 -1
- package/dist/node/esm/runtime/is_key_like.js +1 -1
- package/dist/node/esm/runtime/is_key_object.js +2 -5
- package/dist/node/esm/runtime/jwk_to_key.js +2 -113
- package/dist/node/esm/runtime/key_to_jwk.js +5 -129
- package/dist/node/esm/runtime/node_key.js +7 -16
- package/dist/node/esm/runtime/pbes2kw.js +2 -2
- package/dist/node/esm/runtime/random.js +1 -1
- package/dist/node/esm/runtime/rsaes.js +3 -3
- package/dist/node/esm/runtime/sign.js +3 -9
- package/dist/node/esm/runtime/timing_safe_equal.js +1 -1
- package/dist/node/esm/runtime/verify.js +3 -10
- package/dist/node/esm/runtime/webcrypto.js +3 -6
- package/dist/node/esm/util/errors.js +26 -59
- package/dist/types/index.d.ts +1 -1
- package/dist/types/jwe/compact/decrypt.d.ts +1 -1
- package/dist/types/jwe/flattened/decrypt.d.ts +1 -1
- package/dist/types/jwe/general/decrypt.d.ts +1 -1
- package/dist/types/jwe/general/encrypt.d.ts +3 -7
- package/dist/types/jwk/embedded.d.ts +1 -1
- package/dist/types/jwks/local.d.ts +3 -3
- package/dist/types/jwks/remote.d.ts +1 -1
- package/dist/types/jws/compact/verify.d.ts +1 -1
- package/dist/types/jws/flattened/verify.d.ts +1 -1
- package/dist/types/jws/general/verify.d.ts +1 -1
- package/dist/types/jwt/decrypt.d.ts +3 -3
- package/dist/types/jwt/produce.d.ts +12 -12
- package/dist/types/jwt/unsecured.d.ts +3 -3
- package/dist/types/jwt/verify.d.ts +3 -3
- package/dist/types/key/generate_key_pair.d.ts +7 -5
- package/dist/types/key/generate_secret.d.ts +1 -1
- package/dist/types/key/import.d.ts +4 -6
- package/dist/types/types.d.ts +13 -50
- package/package.json +1 -1
- package/dist/browser/runtime/zlib.js +0 -7
- package/dist/node/cjs/runtime/asn1_sequence_decoder.js +0 -47
- package/dist/node/cjs/runtime/asn1_sequence_encoder.js +0 -91
- package/dist/node/cjs/runtime/check_modulus_length.js +0 -52
- package/dist/node/cjs/runtime/flags.js +0 -8
- package/dist/node/cjs/runtime/zlib.js +0 -11
- package/dist/node/esm/runtime/asn1_sequence_decoder.js +0 -44
- package/dist/node/esm/runtime/asn1_sequence_encoder.js +0 -88
- package/dist/node/esm/runtime/check_modulus_length.js +0 -48
- package/dist/node/esm/runtime/flags.js +0 -5
- package/dist/node/esm/runtime/zlib.js +0 -6
package/README.md
CHANGED
|
@@ -128,5 +128,6 @@ Please note that certain algorithms may not be available depending on the runtim
|
|
|
128
128
|
|
|
129
129
|
| Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ |
|
|
130
130
|
| ------- | --------- | -------- | -------- |
|
|
131
|
-
| [
|
|
131
|
+
| [v5.x](https://github.com/panva/jose/tree/v5.x) | ✅ | ✅ | ✅ |
|
|
132
|
+
| [v4.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ❌ | ❌ |
|
|
132
133
|
| [v2.x](https://github.com/panva/jose/tree/v2.x) | ✅ | ❌ | ❌ |
|
package/dist/browser/index.js
CHANGED
|
@@ -23,10 +23,8 @@ export { exportPKCS8, exportSPKI, exportJWK } from './key/export.js';
|
|
|
23
23
|
export { importSPKI, importPKCS8, importX509, importJWK } from './key/import.js';
|
|
24
24
|
export { decodeProtectedHeader } from './util/decode_protected_header.js';
|
|
25
25
|
export { decodeJwt } from './util/decode_jwt.js';
|
|
26
|
-
|
|
27
|
-
export { errors_1 as errors };
|
|
26
|
+
export * as errors from './util/errors.js';
|
|
28
27
|
export { generateKeyPair } from './key/generate_key_pair.js';
|
|
29
28
|
export { generateSecret } from './key/generate_secret.js';
|
|
30
|
-
|
|
31
|
-
export { base64url_1 as base64url };
|
|
29
|
+
export * as base64url from './util/base64url.js';
|
|
32
30
|
export { default as cryptoRuntime } from './util/runtime.js';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { decode as base64url } from '../../runtime/base64url.js';
|
|
2
2
|
import decrypt from '../../runtime/decrypt.js';
|
|
3
|
-
import { inflate } from '../../runtime/zlib.js';
|
|
4
3
|
import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
5
4
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
6
5
|
import isObject from '../../lib/is_object.js';
|
|
@@ -10,7 +9,6 @@ import generateCek from '../../lib/cek.js';
|
|
|
10
9
|
import validateCrit from '../../lib/validate_crit.js';
|
|
11
10
|
import validateAlgorithms from '../../lib/validate_algorithms.js';
|
|
12
11
|
export async function flattenedDecrypt(jwe, key, options) {
|
|
13
|
-
var _a;
|
|
14
12
|
if (!isObject(jwe)) {
|
|
15
13
|
throw new JWEInvalid('Flattened JWE must be an object');
|
|
16
14
|
}
|
|
@@ -47,7 +45,7 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
47
45
|
const protectedHeader = base64url(jwe.protected);
|
|
48
46
|
parsedProt = JSON.parse(decoder.decode(protectedHeader));
|
|
49
47
|
}
|
|
50
|
-
catch
|
|
48
|
+
catch {
|
|
51
49
|
throw new JWEInvalid('JWE Protected Header is invalid');
|
|
52
50
|
}
|
|
53
51
|
}
|
|
@@ -59,14 +57,9 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
59
57
|
...jwe.header,
|
|
60
58
|
...jwe.unprotected,
|
|
61
59
|
};
|
|
62
|
-
validateCrit(JWEInvalid, new Map(), options
|
|
60
|
+
validateCrit(JWEInvalid, new Map(), options?.crit, parsedProt, joseHeader);
|
|
63
61
|
if (joseHeader.zip !== undefined) {
|
|
64
|
-
|
|
65
|
-
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
66
|
-
}
|
|
67
|
-
if (joseHeader.zip !== 'DEF') {
|
|
68
|
-
throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value');
|
|
69
|
-
}
|
|
62
|
+
throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported.');
|
|
70
63
|
}
|
|
71
64
|
const { alg, enc } = joseHeader;
|
|
72
65
|
if (typeof alg !== 'string' || !alg) {
|
|
@@ -78,18 +71,19 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
78
71
|
const keyManagementAlgorithms = options && validateAlgorithms('keyManagementAlgorithms', options.keyManagementAlgorithms);
|
|
79
72
|
const contentEncryptionAlgorithms = options &&
|
|
80
73
|
validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms);
|
|
81
|
-
if (keyManagementAlgorithms && !keyManagementAlgorithms.has(alg))
|
|
82
|
-
|
|
74
|
+
if ((keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) ||
|
|
75
|
+
(!keyManagementAlgorithms && alg.startsWith('PBES2'))) {
|
|
76
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
83
77
|
}
|
|
84
78
|
if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) {
|
|
85
|
-
throw new JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter not allowed');
|
|
79
|
+
throw new JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter value not allowed');
|
|
86
80
|
}
|
|
87
81
|
let encryptedKey;
|
|
88
82
|
if (jwe.encrypted_key !== undefined) {
|
|
89
83
|
try {
|
|
90
84
|
encryptedKey = base64url(jwe.encrypted_key);
|
|
91
85
|
}
|
|
92
|
-
catch
|
|
86
|
+
catch {
|
|
93
87
|
throw new JWEInvalid('Failed to base64url decode the encrypted_key');
|
|
94
88
|
}
|
|
95
89
|
}
|
|
@@ -113,16 +107,16 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
113
107
|
try {
|
|
114
108
|
iv = base64url(jwe.iv);
|
|
115
109
|
}
|
|
116
|
-
catch
|
|
110
|
+
catch {
|
|
117
111
|
throw new JWEInvalid('Failed to base64url decode the iv');
|
|
118
112
|
}
|
|
119
113
|
try {
|
|
120
114
|
tag = base64url(jwe.tag);
|
|
121
115
|
}
|
|
122
|
-
catch
|
|
116
|
+
catch {
|
|
123
117
|
throw new JWEInvalid('Failed to base64url decode the tag');
|
|
124
118
|
}
|
|
125
|
-
const protectedHeader = encoder.encode(
|
|
119
|
+
const protectedHeader = encoder.encode(jwe.protected ?? '');
|
|
126
120
|
let additionalData;
|
|
127
121
|
if (jwe.aad !== undefined) {
|
|
128
122
|
additionalData = concat(protectedHeader, encoder.encode('.'), encoder.encode(jwe.aad));
|
|
@@ -134,13 +128,10 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
134
128
|
try {
|
|
135
129
|
ciphertext = base64url(jwe.ciphertext);
|
|
136
130
|
}
|
|
137
|
-
catch
|
|
131
|
+
catch {
|
|
138
132
|
throw new JWEInvalid('Failed to base64url decode the ciphertext');
|
|
139
133
|
}
|
|
140
134
|
let plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);
|
|
141
|
-
if (joseHeader.zip === 'DEF') {
|
|
142
|
-
plaintext = await ((options === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext);
|
|
143
|
-
}
|
|
144
135
|
const result = { plaintext };
|
|
145
136
|
if (jwe.protected !== undefined) {
|
|
146
137
|
result.protectedHeader = parsedProt;
|
|
@@ -149,7 +140,7 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
149
140
|
try {
|
|
150
141
|
result.additionalAuthenticatedData = base64url(jwe.aad);
|
|
151
142
|
}
|
|
152
|
-
catch
|
|
143
|
+
catch {
|
|
153
144
|
throw new JWEInvalid('Failed to base64url decode the aad');
|
|
154
145
|
}
|
|
155
146
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { encode as base64url } from '../../runtime/base64url.js';
|
|
2
2
|
import encrypt from '../../runtime/encrypt.js';
|
|
3
|
-
import { deflate } from '../../runtime/zlib.js';
|
|
4
3
|
import generateIv from '../../lib/iv.js';
|
|
5
4
|
import encryptKeyManagement from '../../lib/encrypt_key_management.js';
|
|
6
5
|
import { JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
@@ -73,14 +72,9 @@ export class FlattenedEncrypt {
|
|
|
73
72
|
...this._unprotectedHeader,
|
|
74
73
|
...this._sharedUnprotectedHeader,
|
|
75
74
|
};
|
|
76
|
-
validateCrit(JWEInvalid, new Map(), options
|
|
75
|
+
validateCrit(JWEInvalid, new Map(), options?.crit, this._protectedHeader, joseHeader);
|
|
77
76
|
if (joseHeader.zip !== undefined) {
|
|
78
|
-
|
|
79
|
-
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
80
|
-
}
|
|
81
|
-
if (joseHeader.zip !== 'DEF') {
|
|
82
|
-
throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value');
|
|
83
|
-
}
|
|
77
|
+
throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported.');
|
|
84
78
|
}
|
|
85
79
|
const { alg, enc } = joseHeader;
|
|
86
80
|
if (typeof alg !== 'string' || !alg) {
|
|
@@ -140,16 +134,7 @@ export class FlattenedEncrypt {
|
|
|
140
134
|
else {
|
|
141
135
|
additionalData = protectedHeader;
|
|
142
136
|
}
|
|
143
|
-
|
|
144
|
-
let tag;
|
|
145
|
-
if (joseHeader.zip === 'DEF') {
|
|
146
|
-
const deflated = await ((options === null || options === void 0 ? void 0 : options.deflateRaw) || deflate)(this._plaintext);
|
|
147
|
-
({ ciphertext, tag } = await encrypt(enc, deflated, cek, this._iv, additionalData));
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
;
|
|
151
|
-
({ ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData));
|
|
152
|
-
}
|
|
137
|
+
const { ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData);
|
|
153
138
|
const jwe = {
|
|
154
139
|
ciphertext: base64url(ciphertext),
|
|
155
140
|
iv: base64url(this._iv),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FlattenedEncrypt, unprotected } from '../flattened/encrypt.js';
|
|
2
|
-
import { JWEInvalid } from '../../util/errors.js';
|
|
2
|
+
import { JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
3
3
|
import generateCek from '../../lib/cek.js';
|
|
4
4
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
5
5
|
import encryptKeyManagement from '../../lib/encrypt_key_management.js';
|
|
@@ -34,7 +34,7 @@ export class GeneralEncrypt {
|
|
|
34
34
|
this._plaintext = plaintext;
|
|
35
35
|
}
|
|
36
36
|
addRecipient(key, options) {
|
|
37
|
-
const recipient = new IndividualRecipient(this, key, { crit: options
|
|
37
|
+
const recipient = new IndividualRecipient(this, key, { crit: options?.crit });
|
|
38
38
|
this._recipients.push(recipient);
|
|
39
39
|
return recipient;
|
|
40
40
|
}
|
|
@@ -56,12 +56,10 @@ export class GeneralEncrypt {
|
|
|
56
56
|
this._aad = aad;
|
|
57
57
|
return this;
|
|
58
58
|
}
|
|
59
|
-
async encrypt(
|
|
60
|
-
var _a, _b, _c;
|
|
59
|
+
async encrypt() {
|
|
61
60
|
if (!this._recipients.length) {
|
|
62
61
|
throw new JWEInvalid('at least one recipient must be added');
|
|
63
62
|
}
|
|
64
|
-
options = { deflateRaw: options === null || options === void 0 ? void 0 : options.deflateRaw };
|
|
65
63
|
if (this._recipients.length === 1) {
|
|
66
64
|
const [recipient] = this._recipients;
|
|
67
65
|
const flattened = await new FlattenedEncrypt(this._plaintext)
|
|
@@ -69,7 +67,7 @@ export class GeneralEncrypt {
|
|
|
69
67
|
.setProtectedHeader(this._protectedHeader)
|
|
70
68
|
.setSharedUnprotectedHeader(this._unprotectedHeader)
|
|
71
69
|
.setUnprotectedHeader(recipient.unprotectedHeader)
|
|
72
|
-
.encrypt(recipient.key, { ...recipient.options
|
|
70
|
+
.encrypt(recipient.key, { ...recipient.options });
|
|
73
71
|
let jwe = {
|
|
74
72
|
ciphertext: flattened.ciphertext,
|
|
75
73
|
iv: flattened.iv,
|
|
@@ -117,9 +115,7 @@ export class GeneralEncrypt {
|
|
|
117
115
|
}
|
|
118
116
|
validateCrit(JWEInvalid, new Map(), recipient.options.crit, this._protectedHeader, joseHeader);
|
|
119
117
|
if (joseHeader.zip !== undefined) {
|
|
120
|
-
|
|
121
|
-
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
122
|
-
}
|
|
118
|
+
throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported.');
|
|
123
119
|
}
|
|
124
120
|
}
|
|
125
121
|
const cek = generateCek(enc);
|
|
@@ -149,7 +145,6 @@ export class GeneralEncrypt {
|
|
|
149
145
|
.setKeyManagementParameters({ p2c })
|
|
150
146
|
.encrypt(recipient.key, {
|
|
151
147
|
...recipient.options,
|
|
152
|
-
...options,
|
|
153
148
|
[unprotected]: true,
|
|
154
149
|
});
|
|
155
150
|
jwe.ciphertext = flattened.ciphertext;
|
|
@@ -166,9 +161,9 @@ export class GeneralEncrypt {
|
|
|
166
161
|
target.header = flattened.header;
|
|
167
162
|
continue;
|
|
168
163
|
}
|
|
169
|
-
const { encryptedKey, parameters } = await encryptKeyManagement(
|
|
170
|
-
|
|
171
|
-
|
|
164
|
+
const { encryptedKey, parameters } = await encryptKeyManagement(recipient.unprotectedHeader?.alg ||
|
|
165
|
+
this._protectedHeader?.alg ||
|
|
166
|
+
this._unprotectedHeader?.alg, enc, recipient.key, cek, { p2c });
|
|
172
167
|
target.encrypted_key = base64url(encryptedKey);
|
|
173
168
|
if (recipient.unprotectedHeader || parameters)
|
|
174
169
|
target.header = { ...recipient.unprotectedHeader, ...parameters };
|
|
@@ -4,12 +4,12 @@ import { JWSInvalid } from '../util/errors.js';
|
|
|
4
4
|
export async function EmbeddedJWK(protectedHeader, token) {
|
|
5
5
|
const joseHeader = {
|
|
6
6
|
...protectedHeader,
|
|
7
|
-
...token
|
|
7
|
+
...token?.header,
|
|
8
8
|
};
|
|
9
9
|
if (!isObject(joseHeader.jwk)) {
|
|
10
10
|
throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object');
|
|
11
11
|
}
|
|
12
|
-
const key = await importJWK({ ...joseHeader.jwk, ext: true }, joseHeader.alg
|
|
12
|
+
const key = await importJWK({ ...joseHeader.jwk, ext: true }, joseHeader.alg);
|
|
13
13
|
if (key instanceof Uint8Array || key.type !== 'public') {
|
|
14
14
|
throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key');
|
|
15
15
|
}
|
|
@@ -12,7 +12,7 @@ export async function calculateJwkThumbprint(jwk, digestAlgorithm) {
|
|
|
12
12
|
if (!isObject(jwk)) {
|
|
13
13
|
throw new TypeError('JWK must be an object');
|
|
14
14
|
}
|
|
15
|
-
digestAlgorithm
|
|
15
|
+
digestAlgorithm ?? (digestAlgorithm = 'sha256');
|
|
16
16
|
if (digestAlgorithm !== 'sha256' &&
|
|
17
17
|
digestAlgorithm !== 'sha384' &&
|
|
18
18
|
digestAlgorithm !== 'sha512') {
|
|
@@ -47,7 +47,7 @@ export async function calculateJwkThumbprint(jwk, digestAlgorithm) {
|
|
|
47
47
|
return base64url(await digest(digestAlgorithm, data));
|
|
48
48
|
}
|
|
49
49
|
export async function calculateJwkThumbprintUri(jwk, digestAlgorithm) {
|
|
50
|
-
digestAlgorithm
|
|
50
|
+
digestAlgorithm ?? (digestAlgorithm = 'sha256');
|
|
51
51
|
const thumbprint = await calculateJwkThumbprint(jwk, digestAlgorithm);
|
|
52
52
|
return `urn:ietf:params:oauth:jwk-thumbprint:sha-${digestAlgorithm.slice(-3)}:${thumbprint}`;
|
|
53
53
|
}
|
|
@@ -38,7 +38,7 @@ export class LocalJWKSet {
|
|
|
38
38
|
this._jwks = clone(jwks);
|
|
39
39
|
}
|
|
40
40
|
async getKey(protectedHeader, token) {
|
|
41
|
-
const { alg, kid } = { ...protectedHeader, ...token
|
|
41
|
+
const { alg, kid } = { ...protectedHeader, ...token?.header };
|
|
42
42
|
const kty = getKtyFromAlg(alg);
|
|
43
43
|
const candidates = this._jwks.keys.filter((jwk) => {
|
|
44
44
|
let candidate = kty === jwk.kty;
|
|
@@ -87,7 +87,7 @@ export class LocalJWKSet {
|
|
|
87
87
|
try {
|
|
88
88
|
yield await importWithAlgCache(_cached, jwk, alg);
|
|
89
89
|
}
|
|
90
|
-
catch
|
|
90
|
+
catch {
|
|
91
91
|
continue;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -14,12 +14,12 @@ class RemoteJWKSet extends LocalJWKSet {
|
|
|
14
14
|
throw new TypeError('url must be an instance of URL');
|
|
15
15
|
}
|
|
16
16
|
this._url = new URL(url.href);
|
|
17
|
-
this._options = { agent: options
|
|
17
|
+
this._options = { agent: options?.agent, headers: options?.headers };
|
|
18
18
|
this._timeoutDuration =
|
|
19
|
-
typeof
|
|
19
|
+
typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000;
|
|
20
20
|
this._cooldownDuration =
|
|
21
|
-
typeof
|
|
22
|
-
this._cacheMaxAge = typeof
|
|
21
|
+
typeof options?.cooldownDuration === 'number' ? options?.cooldownDuration : 30000;
|
|
22
|
+
this._cacheMaxAge = typeof options?.cacheMaxAge === 'number' ? options?.cacheMaxAge : 600000;
|
|
23
23
|
}
|
|
24
24
|
coolingDown() {
|
|
25
25
|
return typeof this._jwksTimestamp === 'number'
|
|
@@ -37,7 +37,7 @@ export class FlattenedSign {
|
|
|
37
37
|
...this._protectedHeader,
|
|
38
38
|
...this._unprotectedHeader,
|
|
39
39
|
};
|
|
40
|
-
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options
|
|
40
|
+
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, this._protectedHeader, joseHeader);
|
|
41
41
|
let b64 = true;
|
|
42
42
|
if (extensions.has('b64')) {
|
|
43
43
|
b64 = this._protectedHeader.b64;
|
|
@@ -8,7 +8,6 @@ import checkKeyType from '../../lib/check_key_type.js';
|
|
|
8
8
|
import validateCrit from '../../lib/validate_crit.js';
|
|
9
9
|
import validateAlgorithms from '../../lib/validate_algorithms.js';
|
|
10
10
|
export async function flattenedVerify(jws, key, options) {
|
|
11
|
-
var _a;
|
|
12
11
|
if (!isObject(jws)) {
|
|
13
12
|
throw new JWSInvalid('Flattened JWS must be an object');
|
|
14
13
|
}
|
|
@@ -33,7 +32,7 @@ export async function flattenedVerify(jws, key, options) {
|
|
|
33
32
|
const protectedHeader = base64url(jws.protected);
|
|
34
33
|
parsedProt = JSON.parse(decoder.decode(protectedHeader));
|
|
35
34
|
}
|
|
36
|
-
catch
|
|
35
|
+
catch {
|
|
37
36
|
throw new JWSInvalid('JWS Protected Header is invalid');
|
|
38
37
|
}
|
|
39
38
|
}
|
|
@@ -44,7 +43,7 @@ export async function flattenedVerify(jws, key, options) {
|
|
|
44
43
|
...parsedProt,
|
|
45
44
|
...jws.header,
|
|
46
45
|
};
|
|
47
|
-
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options
|
|
46
|
+
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, parsedProt, joseHeader);
|
|
48
47
|
let b64 = true;
|
|
49
48
|
if (extensions.has('b64')) {
|
|
50
49
|
b64 = parsedProt.b64;
|
|
@@ -58,7 +57,7 @@ export async function flattenedVerify(jws, key, options) {
|
|
|
58
57
|
}
|
|
59
58
|
const algorithms = options && validateAlgorithms('algorithms', options.algorithms);
|
|
60
59
|
if (algorithms && !algorithms.has(alg)) {
|
|
61
|
-
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed');
|
|
60
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
62
61
|
}
|
|
63
62
|
if (b64) {
|
|
64
63
|
if (typeof jws.payload !== 'string') {
|
|
@@ -74,12 +73,12 @@ export async function flattenedVerify(jws, key, options) {
|
|
|
74
73
|
resolvedKey = true;
|
|
75
74
|
}
|
|
76
75
|
checkKeyType(alg, key, 'verify');
|
|
77
|
-
const data = concat(encoder.encode(
|
|
76
|
+
const data = concat(encoder.encode(jws.protected ?? ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
|
|
78
77
|
let signature;
|
|
79
78
|
try {
|
|
80
79
|
signature = base64url(jws.signature);
|
|
81
80
|
}
|
|
82
|
-
catch
|
|
81
|
+
catch {
|
|
83
82
|
throw new JWSInvalid('Failed to base64url decode the signature');
|
|
84
83
|
}
|
|
85
84
|
const verified = await verify(alg, key, signature, data);
|
|
@@ -91,7 +90,7 @@ export async function flattenedVerify(jws, key, options) {
|
|
|
91
90
|
try {
|
|
92
91
|
payload = base64url(jws.payload);
|
|
93
92
|
}
|
|
94
|
-
catch
|
|
93
|
+
catch {
|
|
95
94
|
throw new JWSInvalid('Failed to base64url decode the payload');
|
|
96
95
|
}
|
|
97
96
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import epoch from '../lib/epoch.js';
|
|
2
2
|
import isObject from '../lib/is_object.js';
|
|
3
3
|
import secs from '../lib/secs.js';
|
|
4
|
+
function validateInput(label, input) {
|
|
5
|
+
if (!Number.isFinite(input)) {
|
|
6
|
+
throw new TypeError(`Invalid ${label} input`);
|
|
7
|
+
}
|
|
8
|
+
return input;
|
|
9
|
+
}
|
|
4
10
|
export class ProduceJWT {
|
|
5
|
-
constructor(payload) {
|
|
11
|
+
constructor(payload = {}) {
|
|
6
12
|
if (!isObject(payload)) {
|
|
7
13
|
throw new TypeError('JWT Claims Set MUST be an object');
|
|
8
14
|
}
|
|
@@ -26,7 +32,10 @@ export class ProduceJWT {
|
|
|
26
32
|
}
|
|
27
33
|
setNotBefore(input) {
|
|
28
34
|
if (typeof input === 'number') {
|
|
29
|
-
this._payload = { ...this._payload, nbf: input };
|
|
35
|
+
this._payload = { ...this._payload, nbf: validateInput('setNotBefore', input) };
|
|
36
|
+
}
|
|
37
|
+
else if (input instanceof Date) {
|
|
38
|
+
this._payload = { ...this._payload, nbf: validateInput('setNotBefore', epoch(input)) };
|
|
30
39
|
}
|
|
31
40
|
else {
|
|
32
41
|
this._payload = { ...this._payload, nbf: epoch(new Date()) + secs(input) };
|
|
@@ -35,7 +44,10 @@ export class ProduceJWT {
|
|
|
35
44
|
}
|
|
36
45
|
setExpirationTime(input) {
|
|
37
46
|
if (typeof input === 'number') {
|
|
38
|
-
this._payload = { ...this._payload, exp: input };
|
|
47
|
+
this._payload = { ...this._payload, exp: validateInput('setExpirationTime', input) };
|
|
48
|
+
}
|
|
49
|
+
else if (input instanceof Date) {
|
|
50
|
+
this._payload = { ...this._payload, exp: validateInput('setExpirationTime', epoch(input)) };
|
|
39
51
|
}
|
|
40
52
|
else {
|
|
41
53
|
this._payload = { ...this._payload, exp: epoch(new Date()) + secs(input) };
|
|
@@ -46,8 +58,11 @@ export class ProduceJWT {
|
|
|
46
58
|
if (typeof input === 'undefined') {
|
|
47
59
|
this._payload = { ...this._payload, iat: epoch(new Date()) };
|
|
48
60
|
}
|
|
61
|
+
else if (input instanceof Date) {
|
|
62
|
+
this._payload = { ...this._payload, iat: validateInput('setIssuedAt', epoch(input)) };
|
|
63
|
+
}
|
|
49
64
|
else {
|
|
50
|
-
this._payload = { ...this._payload, iat: input };
|
|
65
|
+
this._payload = { ...this._payload, iat: validateInput('setIssuedAt', input) };
|
|
51
66
|
}
|
|
52
67
|
return this;
|
|
53
68
|
}
|
package/dist/browser/jwt/sign.js
CHANGED
|
@@ -8,10 +8,9 @@ export class SignJWT extends ProduceJWT {
|
|
|
8
8
|
return this;
|
|
9
9
|
}
|
|
10
10
|
async sign(key, options) {
|
|
11
|
-
var _a;
|
|
12
11
|
const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload)));
|
|
13
12
|
sig.setProtectedHeader(this._protectedHeader);
|
|
14
|
-
if (Array.isArray(
|
|
13
|
+
if (Array.isArray(this._protectedHeader?.crit) &&
|
|
15
14
|
this._protectedHeader.crit.includes('b64') &&
|
|
16
15
|
this._protectedHeader.b64 === false) {
|
|
17
16
|
throw new JWTInvalid('JWTs MUST NOT use unencoded payload');
|
|
@@ -23,7 +23,7 @@ export class UnsecuredJWT extends ProduceJWT {
|
|
|
23
23
|
if (header.alg !== 'none')
|
|
24
24
|
throw new Error();
|
|
25
25
|
}
|
|
26
|
-
catch
|
|
26
|
+
catch {
|
|
27
27
|
throw new JWTInvalid('Invalid Unsecured JWT');
|
|
28
28
|
}
|
|
29
29
|
const payload = jwtPayload(header, base64url.decode(encodedPayload), options);
|
|
@@ -2,9 +2,8 @@ import { compactVerify } from '../jws/compact/verify.js';
|
|
|
2
2
|
import jwtPayload from '../lib/jwt_claims_set.js';
|
|
3
3
|
import { JWTInvalid } from '../util/errors.js';
|
|
4
4
|
export async function jwtVerify(jwt, key, options) {
|
|
5
|
-
var _a;
|
|
6
5
|
const verified = await compactVerify(jwt, key, options);
|
|
7
|
-
if (
|
|
6
|
+
if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) {
|
|
8
7
|
throw new JWTInvalid('JWTs MUST NOT use unencoded payload');
|
|
9
8
|
}
|
|
10
9
|
const payload = jwtPayload(verified.protectedHeader, verified.payload, options);
|
|
@@ -21,8 +21,7 @@ export async function importPKCS8(pkcs8, alg, options) {
|
|
|
21
21
|
}
|
|
22
22
|
return fromPKCS8(pkcs8, alg, options);
|
|
23
23
|
}
|
|
24
|
-
export async function importJWK(jwk, alg
|
|
25
|
-
var _a;
|
|
24
|
+
export async function importJWK(jwk, alg) {
|
|
26
25
|
if (!isObject(jwk)) {
|
|
27
26
|
throw new TypeError('JWK must be an object');
|
|
28
27
|
}
|
|
@@ -32,10 +31,6 @@ export async function importJWK(jwk, alg, octAsKeyObject) {
|
|
|
32
31
|
if (typeof jwk.k !== 'string' || !jwk.k) {
|
|
33
32
|
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
34
33
|
}
|
|
35
|
-
octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
|
|
36
|
-
if (octAsKeyObject) {
|
|
37
|
-
return asKeyObject({ ...jwk, alg, ext: (_a = jwk.ext) !== null && _a !== void 0 ? _a : false });
|
|
38
|
-
}
|
|
39
34
|
return decodeBase64URL(jwk.k);
|
|
40
35
|
case 'RSA':
|
|
41
36
|
if (jwk.oth !== undefined) {
|
|
@@ -36,7 +36,7 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
|
|
|
36
36
|
try {
|
|
37
37
|
partyUInfo = base64url(joseHeader.apu);
|
|
38
38
|
}
|
|
39
|
-
catch
|
|
39
|
+
catch {
|
|
40
40
|
throw new JWEInvalid('Failed to base64url decode the apu');
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -46,7 +46,7 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
|
|
|
46
46
|
try {
|
|
47
47
|
partyVInfo = base64url(joseHeader.apv);
|
|
48
48
|
}
|
|
49
|
-
catch
|
|
49
|
+
catch {
|
|
50
50
|
throw new JWEInvalid('Failed to base64url decode the apv');
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -73,7 +73,7 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
|
|
|
73
73
|
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
74
74
|
if (typeof joseHeader.p2c !== 'number')
|
|
75
75
|
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`);
|
|
76
|
-
const p2cLimit =
|
|
76
|
+
const p2cLimit = options?.maxPBES2Count || 10000;
|
|
77
77
|
if (joseHeader.p2c > p2cLimit)
|
|
78
78
|
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
|
|
79
79
|
if (typeof joseHeader.p2s !== 'string')
|
|
@@ -82,7 +82,7 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
|
|
|
82
82
|
try {
|
|
83
83
|
p2s = base64url(joseHeader.p2s);
|
|
84
84
|
}
|
|
85
|
-
catch
|
|
85
|
+
catch {
|
|
86
86
|
throw new JWEInvalid('Failed to base64url decode the p2s');
|
|
87
87
|
}
|
|
88
88
|
return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, p2s);
|
|
@@ -107,14 +107,14 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
|
|
|
107
107
|
try {
|
|
108
108
|
iv = base64url(joseHeader.iv);
|
|
109
109
|
}
|
|
110
|
-
catch
|
|
110
|
+
catch {
|
|
111
111
|
throw new JWEInvalid('Failed to base64url decode the iv');
|
|
112
112
|
}
|
|
113
113
|
let tag;
|
|
114
114
|
try {
|
|
115
115
|
tag = base64url(joseHeader.tag);
|
|
116
116
|
}
|
|
117
|
-
catch
|
|
117
|
+
catch {
|
|
118
118
|
throw new JWEInvalid('Failed to base64url decode the tag');
|
|
119
119
|
}
|
|
120
120
|
return aesGcmKw(alg, key, encryptedKey, iv, tag);
|
|
@@ -24,7 +24,7 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
24
24
|
try {
|
|
25
25
|
payload = JSON.parse(decoder.decode(encodedPayload));
|
|
26
26
|
}
|
|
27
|
-
catch
|
|
27
|
+
catch {
|
|
28
28
|
}
|
|
29
29
|
if (!isObject(payload)) {
|
|
30
30
|
throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
|
|
@@ -56,7 +56,6 @@ const getNamedCurve = (keyData) => {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
const genericImport = async (replace, keyFormat, pem, alg, options) => {
|
|
59
|
-
var _a;
|
|
60
59
|
let algorithm;
|
|
61
60
|
let keyUsages;
|
|
62
61
|
const keyData = new Uint8Array(atob(pem.replace(replace, ''))
|
|
@@ -114,7 +113,7 @@ const genericImport = async (replace, keyFormat, pem, alg, options) => {
|
|
|
114
113
|
default:
|
|
115
114
|
throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value');
|
|
116
115
|
}
|
|
117
|
-
return crypto.subtle.importKey(keyFormat, keyData, algorithm,
|
|
116
|
+
return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? false, keyUsages);
|
|
118
117
|
};
|
|
119
118
|
export const fromPKCS8 = (pem, alg, options) => {
|
|
120
119
|
return genericImport(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, 'pkcs8', pem, alg, options);
|
|
@@ -23,7 +23,7 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
23
23
|
try {
|
|
24
24
|
macCheckPassed = timingSafeEqual(tag, expectedTag);
|
|
25
25
|
}
|
|
26
|
-
catch
|
|
26
|
+
catch {
|
|
27
27
|
}
|
|
28
28
|
if (!macCheckPassed) {
|
|
29
29
|
throw new JWEDecryptionFailed();
|
|
@@ -32,7 +32,7 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
32
32
|
try {
|
|
33
33
|
plaintext = new Uint8Array(await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext));
|
|
34
34
|
}
|
|
35
|
-
catch
|
|
35
|
+
catch {
|
|
36
36
|
}
|
|
37
37
|
if (!plaintext) {
|
|
38
38
|
throw new JWEDecryptionFailed();
|
|
@@ -56,7 +56,7 @@ async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
56
56
|
tagLength: 128,
|
|
57
57
|
}, encKey, concat(ciphertext, tag)));
|
|
58
58
|
}
|
|
59
|
-
catch
|
|
59
|
+
catch {
|
|
60
60
|
throw new JWEDecryptionFailed();
|
|
61
61
|
}
|
|
62
62
|
}
|