jose 3.19.0 → 3.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/jwe/flattened/decrypt.js +5 -9
- package/dist/browser/jwe/flattened/encrypt.js +2 -5
- package/dist/browser/jwk/embedded.js +2 -2
- package/dist/browser/jwks/remote.js +7 -10
- package/dist/browser/jws/flattened/sign.js +1 -2
- package/dist/browser/jws/flattened/verify.js +2 -4
- package/dist/browser/jwt/encrypt.js +1 -1
- package/dist/browser/{lib/jwt_producer.js → jwt/produce.js} +4 -4
- package/dist/browser/jwt/sign.js +1 -1
- package/dist/browser/jwt/unsecured.js +1 -1
- package/dist/browser/lib/cek.js +3 -2
- package/dist/browser/lib/check_key_type.js +33 -16
- package/dist/browser/lib/decrypt_key_management.js +35 -35
- package/dist/browser/lib/encrypt_key_management.js +3 -5
- package/dist/browser/lib/iv.js +3 -2
- package/dist/browser/runtime/aesgcmkw.js +1 -3
- package/dist/browser/runtime/fetch_jwks.js +16 -3
- package/dist/browser/runtime/is_key_like.js +5 -0
- package/dist/browser/runtime/random.js +1 -2
- package/dist/browser/util/errors.js +73 -34
- package/dist/node/cjs/jwe/flattened/decrypt.js +5 -9
- package/dist/node/cjs/jwe/flattened/encrypt.js +2 -5
- package/dist/node/cjs/jwk/embedded.js +2 -2
- package/dist/node/cjs/jwks/remote.js +7 -10
- package/dist/node/cjs/jws/flattened/sign.js +1 -2
- package/dist/node/cjs/jws/flattened/verify.js +2 -4
- package/dist/node/cjs/jwt/encrypt.js +2 -2
- package/dist/node/cjs/{lib/jwt_producer.js → jwt/produce.js} +5 -4
- package/dist/node/cjs/jwt/sign.js +2 -2
- package/dist/node/cjs/jwt/unsecured.js +2 -2
- package/dist/node/cjs/lib/cek.js +4 -3
- package/dist/node/cjs/lib/check_key_type.js +33 -16
- package/dist/node/cjs/lib/decrypt_key_management.js +35 -35
- package/dist/node/cjs/lib/encrypt_key_management.js +7 -9
- package/dist/node/cjs/lib/iv.js +4 -3
- package/dist/node/cjs/runtime/aesgcmkw.js +1 -3
- package/dist/node/cjs/runtime/fetch_jwks.js +5 -1
- package/dist/node/cjs/runtime/is_key_like.js +11 -0
- package/dist/node/cjs/runtime/random.js +3 -2
- package/dist/node/cjs/util/errors.js +77 -37
- package/dist/node/esm/jwe/flattened/decrypt.js +5 -9
- package/dist/node/esm/jwe/flattened/encrypt.js +2 -5
- package/dist/node/esm/jwk/embedded.js +2 -2
- package/dist/node/esm/jwks/remote.js +7 -10
- package/dist/node/esm/jws/flattened/sign.js +1 -2
- package/dist/node/esm/jws/flattened/verify.js +2 -4
- package/dist/node/esm/jwt/encrypt.js +1 -1
- package/dist/node/esm/{lib/jwt_producer.js → jwt/produce.js} +4 -4
- package/dist/node/esm/jwt/sign.js +1 -1
- package/dist/node/esm/jwt/unsecured.js +1 -1
- package/dist/node/esm/lib/cek.js +3 -2
- package/dist/node/esm/lib/check_key_type.js +33 -16
- package/dist/node/esm/lib/decrypt_key_management.js +35 -35
- package/dist/node/esm/lib/encrypt_key_management.js +3 -5
- package/dist/node/esm/lib/iv.js +3 -2
- package/dist/node/esm/runtime/aesgcmkw.js +1 -3
- package/dist/node/esm/runtime/fetch_jwks.js +6 -2
- package/dist/node/esm/runtime/is_key_like.js +8 -0
- package/dist/node/esm/runtime/random.js +1 -2
- package/dist/node/esm/util/errors.js +73 -34
- package/dist/types/jwe/compact/decrypt.d.ts +1 -1
- package/dist/types/jwe/compact/encrypt.d.ts +1 -1
- package/dist/types/jwe/flattened/decrypt.d.ts +1 -1
- package/dist/types/jwe/flattened/encrypt.d.ts +1 -1
- package/dist/types/jwe/general/decrypt.d.ts +1 -1
- package/dist/types/jwk/embedded.d.ts +2 -3
- package/dist/types/jwk/from_key_like.d.ts +1 -1
- package/dist/types/jwk/parse.d.ts +1 -1
- package/dist/types/jws/compact/sign.d.ts +1 -1
- package/dist/types/jws/compact/verify.d.ts +1 -1
- package/dist/types/jws/flattened/sign.d.ts +1 -1
- package/dist/types/jws/flattened/verify.d.ts +1 -1
- package/dist/types/jws/general/sign.d.ts +1 -1
- package/dist/types/jws/general/verify.d.ts +1 -1
- package/dist/types/jwt/decrypt.d.ts +1 -1
- package/dist/types/jwt/encrypt.d.ts +2 -2
- package/dist/types/{lib/jwt_producer.d.ts → jwt/produce.d.ts} +1 -1
- package/dist/types/jwt/sign.d.ts +2 -2
- package/dist/types/jwt/unsecured.d.ts +1 -1
- package/dist/types/jwt/verify.d.ts +1 -1
- package/dist/types/key/export.d.ts +3 -3
- package/dist/types/key/import.d.ts +4 -4
- package/dist/types/types.d.ts +99 -6
- package/dist/types/util/errors.d.ts +24 -16
- package/dist/types/util/generate_key_pair.d.ts +2 -2
- package/dist/types/util/generate_secret.d.ts +1 -1
- package/package.json +3 -4
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { decode as base64url } from '../../runtime/base64url.js';
|
|
2
2
|
import decrypt from '../../runtime/decrypt.js';
|
|
3
3
|
import { inflate } from '../../runtime/zlib.js';
|
|
4
|
-
import random from '../../runtime/random.js';
|
|
5
4
|
import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
6
5
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
7
6
|
import isObject from '../../lib/is_object.js';
|
|
8
7
|
import decryptKeyManagement from '../../lib/decrypt_key_management.js';
|
|
9
8
|
import { encoder, decoder, concat } from '../../lib/buffer_utils.js';
|
|
10
|
-
import
|
|
9
|
+
import generateCek from '../../lib/cek.js';
|
|
11
10
|
import validateCrit from '../../lib/validate_crit.js';
|
|
12
11
|
import validateAlgorithms from '../../lib/validate_algorithms.js';
|
|
13
|
-
const generateCek = cekFactory(random);
|
|
14
|
-
const checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map());
|
|
15
|
-
const checkAlgOption = validateAlgorithms.bind(undefined, 'keyManagementAlgorithms');
|
|
16
|
-
const checkEncOption = validateAlgorithms.bind(undefined, 'contentEncryptionAlgorithms');
|
|
17
12
|
async function flattenedDecrypt(jwe, key, options) {
|
|
18
13
|
var _a;
|
|
19
14
|
if (!isObject(jwe)) {
|
|
@@ -64,7 +59,7 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
64
59
|
...jwe.header,
|
|
65
60
|
...jwe.unprotected,
|
|
66
61
|
};
|
|
67
|
-
|
|
62
|
+
validateCrit(JWEInvalid, new Map(), options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader);
|
|
68
63
|
if (joseHeader.zip !== undefined) {
|
|
69
64
|
if (!parsedProt || !parsedProt.zip) {
|
|
70
65
|
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
@@ -80,8 +75,9 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
80
75
|
if (typeof enc !== 'string' || !enc) {
|
|
81
76
|
throw new JWEInvalid('missing JWE Encryption Algorithm (enc) in JWE Header');
|
|
82
77
|
}
|
|
83
|
-
const keyManagementAlgorithms = options &&
|
|
84
|
-
const contentEncryptionAlgorithms = options &&
|
|
78
|
+
const keyManagementAlgorithms = options && validateAlgorithms('keyManagementAlgorithms', options.keyManagementAlgorithms);
|
|
79
|
+
const contentEncryptionAlgorithms = options &&
|
|
80
|
+
validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms);
|
|
85
81
|
if (keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) {
|
|
86
82
|
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed');
|
|
87
83
|
}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { encode as base64url } from '../../runtime/base64url.js';
|
|
2
|
-
import random from '../../runtime/random.js';
|
|
3
2
|
import encrypt from '../../runtime/encrypt.js';
|
|
4
3
|
import { deflate } from '../../runtime/zlib.js';
|
|
5
|
-
import
|
|
4
|
+
import generateIv from '../../lib/iv.js';
|
|
6
5
|
import encryptKeyManagement from '../../lib/encrypt_key_management.js';
|
|
7
6
|
import { JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
8
7
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
9
8
|
import { encoder, decoder, concat } from '../../lib/buffer_utils.js';
|
|
10
9
|
import validateCrit from '../../lib/validate_crit.js';
|
|
11
|
-
const generateIv = ivFactory(random);
|
|
12
|
-
const checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map());
|
|
13
10
|
class FlattenedEncrypt {
|
|
14
11
|
constructor(plaintext) {
|
|
15
12
|
if (!(plaintext instanceof Uint8Array)) {
|
|
@@ -75,7 +72,7 @@ class FlattenedEncrypt {
|
|
|
75
72
|
...this._unprotectedHeader,
|
|
76
73
|
...this._sharedUnprotectedHeader,
|
|
77
74
|
};
|
|
78
|
-
|
|
75
|
+
validateCrit(JWEInvalid, new Map(), options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader);
|
|
79
76
|
if (joseHeader.zip !== undefined) {
|
|
80
77
|
if (!this._protectedHeader || !this._protectedHeader.zip) {
|
|
81
78
|
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
@@ -9,8 +9,8 @@ async function EmbeddedJWK(protectedHeader, token) {
|
|
|
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 =
|
|
13
|
-
if (key.type !== 'public') {
|
|
12
|
+
const key = await importJWK({ ...joseHeader.jwk, ext: true }, joseHeader.alg, true);
|
|
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
|
}
|
|
16
16
|
return key;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fetchJwks from '../runtime/fetch_jwks.js';
|
|
2
|
-
import
|
|
2
|
+
import { importJWK } from '../key/import.js';
|
|
3
3
|
import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js';
|
|
4
4
|
import isObject from '../lib/is_object.js';
|
|
5
5
|
function getKtyFromAlg(alg) {
|
|
6
|
-
switch (alg.substr(0, 2)) {
|
|
6
|
+
switch (typeof alg === 'string' && alg.substr(0, 2)) {
|
|
7
7
|
case 'RS':
|
|
8
8
|
case 'PS':
|
|
9
9
|
return 'RSA';
|
|
@@ -32,7 +32,7 @@ class RemoteJWKSet {
|
|
|
32
32
|
typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000;
|
|
33
33
|
}
|
|
34
34
|
coolingDown() {
|
|
35
|
-
if (
|
|
35
|
+
if (!this._cooldownStarted) {
|
|
36
36
|
return false;
|
|
37
37
|
}
|
|
38
38
|
return Date.now() < this._cooldownStarted + this._cooldownDuration;
|
|
@@ -56,7 +56,7 @@ class RemoteJWKSet {
|
|
|
56
56
|
candidate = jwk.key_ops.includes('verify');
|
|
57
57
|
}
|
|
58
58
|
if (candidate && protectedHeader.alg === 'EdDSA') {
|
|
59
|
-
candidate =
|
|
59
|
+
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
60
60
|
}
|
|
61
61
|
if (candidate) {
|
|
62
62
|
switch (protectedHeader.alg) {
|
|
@@ -88,13 +88,10 @@ class RemoteJWKSet {
|
|
|
88
88
|
else if (length !== 1) {
|
|
89
89
|
throw new JWKSMultipleMatchingKeys();
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
this._cached.set(jwk, {});
|
|
93
|
-
}
|
|
94
|
-
const cached = this._cached.get(jwk);
|
|
91
|
+
const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
|
|
95
92
|
if (cached[protectedHeader.alg] === undefined) {
|
|
96
|
-
const keyObject =
|
|
97
|
-
if (keyObject.type !== 'public') {
|
|
93
|
+
const keyObject = await importJWK({ ...jwk, ext: true }, protectedHeader.alg);
|
|
94
|
+
if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
|
|
98
95
|
throw new JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
99
96
|
}
|
|
100
97
|
cached[protectedHeader.alg] = keyObject;
|
|
@@ -5,7 +5,6 @@ import { JWSInvalid } from '../../util/errors.js';
|
|
|
5
5
|
import { encoder, decoder, concat } from '../../lib/buffer_utils.js';
|
|
6
6
|
import checkKeyType from '../../lib/check_key_type.js';
|
|
7
7
|
import validateCrit from '../../lib/validate_crit.js';
|
|
8
|
-
const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]]));
|
|
9
8
|
class FlattenedSign {
|
|
10
9
|
constructor(payload) {
|
|
11
10
|
if (!(payload instanceof Uint8Array)) {
|
|
@@ -38,7 +37,7 @@ class FlattenedSign {
|
|
|
38
37
|
...this._protectedHeader,
|
|
39
38
|
...this._unprotectedHeader,
|
|
40
39
|
};
|
|
41
|
-
const extensions =
|
|
40
|
+
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader);
|
|
42
41
|
let b64 = true;
|
|
43
42
|
if (extensions.has('b64')) {
|
|
44
43
|
b64 = this._protectedHeader.b64;
|
|
@@ -7,8 +7,6 @@ import isObject from '../../lib/is_object.js';
|
|
|
7
7
|
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
|
-
const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]]));
|
|
11
|
-
const checkAlgOption = validateAlgorithms.bind(undefined, 'algorithms');
|
|
12
10
|
async function flattenedVerify(jws, key, options) {
|
|
13
11
|
var _a;
|
|
14
12
|
if (!isObject(jws)) {
|
|
@@ -46,7 +44,7 @@ async function flattenedVerify(jws, key, options) {
|
|
|
46
44
|
...parsedProt,
|
|
47
45
|
...jws.header,
|
|
48
46
|
};
|
|
49
|
-
const extensions =
|
|
47
|
+
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader);
|
|
50
48
|
let b64 = true;
|
|
51
49
|
if (extensions.has('b64')) {
|
|
52
50
|
b64 = parsedProt.b64;
|
|
@@ -58,7 +56,7 @@ async function flattenedVerify(jws, key, options) {
|
|
|
58
56
|
if (typeof alg !== 'string' || !alg) {
|
|
59
57
|
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
60
58
|
}
|
|
61
|
-
const algorithms = options &&
|
|
59
|
+
const algorithms = options && validateAlgorithms('algorithms', options.algorithms);
|
|
62
60
|
if (algorithms && !algorithms.has(alg)) {
|
|
63
61
|
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed');
|
|
64
62
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import CompactEncrypt from '../jwe/compact/encrypt.js';
|
|
2
2
|
import { encoder } from '../lib/buffer_utils.js';
|
|
3
|
-
import ProduceJWT from '
|
|
3
|
+
import { ProduceJWT } from './produce.js';
|
|
4
4
|
class EncryptJWT extends ProduceJWT {
|
|
5
5
|
setProtectedHeader(protectedHeader) {
|
|
6
6
|
if (this._protectedHeader) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import epoch from '
|
|
2
|
-
import isObject from '
|
|
3
|
-
import secs from '
|
|
4
|
-
export
|
|
1
|
+
import epoch from '../lib/epoch.js';
|
|
2
|
+
import isObject from '../lib/is_object.js';
|
|
3
|
+
import secs from '../lib/secs.js';
|
|
4
|
+
export class ProduceJWT {
|
|
5
5
|
constructor(payload) {
|
|
6
6
|
if (!isObject(payload)) {
|
|
7
7
|
throw new TypeError('JWT Claims Set MUST be an object');
|
package/dist/browser/jwt/sign.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import CompactSign from '../jws/compact/sign.js';
|
|
2
2
|
import { JWTInvalid } from '../util/errors.js';
|
|
3
3
|
import { encoder } from '../lib/buffer_utils.js';
|
|
4
|
-
import ProduceJWT from '
|
|
4
|
+
import { ProduceJWT } from './produce.js';
|
|
5
5
|
class SignJWT extends ProduceJWT {
|
|
6
6
|
setProtectedHeader(protectedHeader) {
|
|
7
7
|
this._protectedHeader = protectedHeader;
|
|
@@ -2,7 +2,7 @@ import * as base64url from '../runtime/base64url.js';
|
|
|
2
2
|
import { decoder } from '../lib/buffer_utils.js';
|
|
3
3
|
import { JWTInvalid } from '../util/errors.js';
|
|
4
4
|
import jwtPayload from '../lib/jwt_claims_set.js';
|
|
5
|
-
import ProduceJWT from '
|
|
5
|
+
import { ProduceJWT } from './produce.js';
|
|
6
6
|
class UnsecuredJWT extends ProduceJWT {
|
|
7
7
|
encode() {
|
|
8
8
|
const header = base64url.encode(JSON.stringify({ alg: 'none' }));
|
package/dist/browser/lib/cek.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
|
+
import random from '../runtime/random.js';
|
|
2
3
|
const bitLengths = new Map([
|
|
3
4
|
['A128CBC-HS256', 256],
|
|
4
5
|
['A128GCM', 128],
|
|
@@ -7,12 +8,12 @@ const bitLengths = new Map([
|
|
|
7
8
|
['A256CBC-HS512', 512],
|
|
8
9
|
['A256GCM', 256],
|
|
9
10
|
]);
|
|
10
|
-
const
|
|
11
|
+
const generateCek = (alg) => {
|
|
11
12
|
const bitLength = bitLengths.get(alg);
|
|
12
13
|
if (!bitLength) {
|
|
13
14
|
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
14
15
|
}
|
|
15
16
|
return random(new Uint8Array(bitLength >> 3));
|
|
16
17
|
};
|
|
17
|
-
export default
|
|
18
|
+
export default generateCek;
|
|
18
19
|
export { bitLengths };
|
|
@@ -1,28 +1,45 @@
|
|
|
1
1
|
import invalidKeyInput from '../runtime/invalid_key_input.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import isKeyLike, { types } from '../runtime/is_key_like.js';
|
|
3
|
+
const symmetricTypeCheck = (key) => {
|
|
4
|
+
if (key instanceof Uint8Array)
|
|
5
|
+
return;
|
|
6
|
+
if (!isKeyLike(key)) {
|
|
7
|
+
throw new TypeError(invalidKeyInput(key, ...types, 'Uint8Array'));
|
|
5
8
|
}
|
|
6
|
-
if (
|
|
7
|
-
|
|
8
|
-
alg.startsWith('PBES2') ||
|
|
9
|
-
alg.match(/^A\d{3}(?:GCM)?KW$/)) {
|
|
10
|
-
if (key instanceof Uint8Array || key.type === 'secret') {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
throw new TypeError('CryptoKey or KeyObject instances for symmetric algorithms must be of type "secret"');
|
|
9
|
+
if (key.type !== 'secret') {
|
|
10
|
+
throw new TypeError(`${types.join(' or ')} instances for symmetric algorithms must be of type "secret"`);
|
|
14
11
|
}
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
};
|
|
13
|
+
const asymmetricTypeCheck = (key, usage) => {
|
|
14
|
+
if (!isKeyLike(key)) {
|
|
15
|
+
throw new TypeError(invalidKeyInput(key, ...types));
|
|
17
16
|
}
|
|
18
17
|
if (key.type === 'secret') {
|
|
19
|
-
throw new TypeError('
|
|
18
|
+
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithms must not be of type "secret"`);
|
|
20
19
|
}
|
|
21
20
|
if (usage === 'sign' && key.type === 'public') {
|
|
22
|
-
throw new TypeError('
|
|
21
|
+
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm signing must be of type "private"`);
|
|
23
22
|
}
|
|
24
23
|
if (usage === 'decrypt' && key.type === 'public') {
|
|
25
|
-
throw new TypeError('
|
|
24
|
+
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm decryption must be of type "private"`);
|
|
25
|
+
}
|
|
26
|
+
if (key.algorithm && usage === 'verify' && key.type === 'private') {
|
|
27
|
+
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm verifying must be of type "public"`);
|
|
28
|
+
}
|
|
29
|
+
if (key.algorithm && usage === 'encrypt' && key.type === 'private') {
|
|
30
|
+
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm encryption must be of type "public"`);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const checkKeyType = (alg, key, usage) => {
|
|
34
|
+
const symmetric = alg.startsWith('HS') ||
|
|
35
|
+
alg === 'dir' ||
|
|
36
|
+
alg.startsWith('PBES2') ||
|
|
37
|
+
/^A\d{3}(?:GCM)?KW$/.test(alg);
|
|
38
|
+
if (symmetric) {
|
|
39
|
+
symmetricTypeCheck(key);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
asymmetricTypeCheck(key, usage);
|
|
26
43
|
}
|
|
27
44
|
};
|
|
28
45
|
export default checkKeyType;
|
|
@@ -8,81 +8,81 @@ import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
|
|
|
8
8
|
import { bitLengths as cekLengths } from '../lib/cek.js';
|
|
9
9
|
import { importJWK } from '../key/import.js';
|
|
10
10
|
import checkKeyType from './check_key_type.js';
|
|
11
|
-
|
|
12
|
-
if (!encryptedKey) {
|
|
13
|
-
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function assertHeaderParameter(joseHeader, parameter, name) {
|
|
17
|
-
if (joseHeader[parameter] === undefined) {
|
|
18
|
-
throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
11
|
+
import isObject from './is_object.js';
|
|
21
12
|
async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) {
|
|
22
13
|
checkKeyType(alg, key, 'decrypt');
|
|
23
14
|
switch (alg) {
|
|
24
15
|
case 'dir': {
|
|
25
|
-
if (encryptedKey !== undefined)
|
|
16
|
+
if (encryptedKey !== undefined)
|
|
26
17
|
throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
|
|
27
|
-
}
|
|
28
18
|
return key;
|
|
29
19
|
}
|
|
30
20
|
case 'ECDH-ES':
|
|
31
|
-
if (encryptedKey !== undefined)
|
|
21
|
+
if (encryptedKey !== undefined)
|
|
32
22
|
throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
|
|
33
|
-
}
|
|
34
23
|
case 'ECDH-ES+A128KW':
|
|
35
24
|
case 'ECDH-ES+A192KW':
|
|
36
25
|
case 'ECDH-ES+A256KW': {
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
if (!isObject(joseHeader.epk))
|
|
27
|
+
throw new JWEInvalid(`JOSE Header "epk" (Ephemeral Public Key) missing or invalid`);
|
|
28
|
+
if (!ECDH.ecdhAllowed(key))
|
|
39
29
|
throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime');
|
|
40
|
-
}
|
|
41
30
|
const epk = await importJWK(joseHeader.epk, alg);
|
|
42
31
|
let partyUInfo;
|
|
43
32
|
let partyVInfo;
|
|
44
|
-
if (joseHeader.apu !== undefined)
|
|
33
|
+
if (joseHeader.apu !== undefined) {
|
|
34
|
+
if (typeof joseHeader.apu !== 'string')
|
|
35
|
+
throw new JWEInvalid(`JOSE Header "apu" (Agreement PartyUInfo) invalid`);
|
|
45
36
|
partyUInfo = base64url(joseHeader.apu);
|
|
46
|
-
|
|
37
|
+
}
|
|
38
|
+
if (joseHeader.apv !== undefined) {
|
|
39
|
+
if (typeof joseHeader.apv !== 'string')
|
|
40
|
+
throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
|
|
47
41
|
partyVInfo = base64url(joseHeader.apv);
|
|
42
|
+
}
|
|
48
43
|
const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc), partyUInfo, partyVInfo);
|
|
49
|
-
if (alg === 'ECDH-ES')
|
|
44
|
+
if (alg === 'ECDH-ES')
|
|
50
45
|
return sharedSecret;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return aesKw(kwAlg, sharedSecret, encryptedKey);
|
|
46
|
+
if (encryptedKey === undefined)
|
|
47
|
+
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
48
|
+
return aesKw(alg.substr(-6), sharedSecret, encryptedKey);
|
|
55
49
|
}
|
|
56
50
|
case 'RSA1_5':
|
|
57
51
|
case 'RSA-OAEP':
|
|
58
52
|
case 'RSA-OAEP-256':
|
|
59
53
|
case 'RSA-OAEP-384':
|
|
60
54
|
case 'RSA-OAEP-512': {
|
|
61
|
-
|
|
55
|
+
if (encryptedKey === undefined)
|
|
56
|
+
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
62
57
|
return rsaEs(alg, key, encryptedKey);
|
|
63
58
|
}
|
|
64
59
|
case 'PBES2-HS256+A128KW':
|
|
65
60
|
case 'PBES2-HS384+A192KW':
|
|
66
61
|
case 'PBES2-HS512+A256KW': {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
if (encryptedKey === undefined)
|
|
63
|
+
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
64
|
+
if (typeof joseHeader.p2c !== 'number')
|
|
65
|
+
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`);
|
|
66
|
+
if (typeof joseHeader.p2s !== 'string')
|
|
67
|
+
throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
|
|
68
|
+
return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, base64url(joseHeader.p2s));
|
|
73
69
|
}
|
|
74
70
|
case 'A128KW':
|
|
75
71
|
case 'A192KW':
|
|
76
72
|
case 'A256KW': {
|
|
77
|
-
|
|
73
|
+
if (encryptedKey === undefined)
|
|
74
|
+
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
78
75
|
return aesKw(alg, key, encryptedKey);
|
|
79
76
|
}
|
|
80
77
|
case 'A128GCMKW':
|
|
81
78
|
case 'A192GCMKW':
|
|
82
79
|
case 'A256GCMKW': {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
if (encryptedKey === undefined)
|
|
81
|
+
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
82
|
+
if (typeof joseHeader.iv !== 'string')
|
|
83
|
+
throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
|
|
84
|
+
if (typeof joseHeader.tag !== 'string')
|
|
85
|
+
throw new JWEInvalid(`JOSE Header "tag" (Authentication Tag) missing or invalid`);
|
|
86
86
|
const iv = base64url(joseHeader.iv);
|
|
87
87
|
const tag = base64url(joseHeader.tag);
|
|
88
88
|
return aesGcmKw(alg, key, encryptedKey, iv, tag);
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import random from '../runtime/random.js';
|
|
2
1
|
import { wrap as aesKw } from '../runtime/aeskw.js';
|
|
3
2
|
import * as ECDH from '../runtime/ecdhes.js';
|
|
4
3
|
import { encrypt as pbes2Kw } from '../runtime/pbes2kw.js';
|
|
5
4
|
import { encrypt as rsaEs } from '../runtime/rsaes.js';
|
|
6
5
|
import { wrap as aesGcmKw } from '../runtime/aesgcmkw.js';
|
|
7
6
|
import { encode as base64url } from '../runtime/base64url.js';
|
|
8
|
-
import
|
|
7
|
+
import generateCek, { bitLengths as cekLengths } from '../lib/cek.js';
|
|
9
8
|
import { JOSENotSupported } from '../util/errors.js';
|
|
10
|
-
import {
|
|
9
|
+
import { exportJWK } from '../key/export.js';
|
|
11
10
|
import checkKeyType from './check_key_type.js';
|
|
12
|
-
const generateCek = cekFactory(random);
|
|
13
11
|
async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) {
|
|
14
12
|
let encryptedKey;
|
|
15
13
|
let parameters;
|
|
@@ -30,7 +28,7 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
|
|
|
30
28
|
const { apu, apv } = providedParameters;
|
|
31
29
|
let { epk: ephemeralKey } = providedParameters;
|
|
32
30
|
ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key));
|
|
33
|
-
const { x, y, crv, kty } = await
|
|
31
|
+
const { x, y, crv, kty } = await exportJWK(ephemeralKey);
|
|
34
32
|
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), apu, apv);
|
|
35
33
|
parameters = { epk: { x, y, crv, kty } };
|
|
36
34
|
if (apu)
|
package/dist/browser/lib/iv.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
|
+
import random from '../runtime/random.js';
|
|
2
3
|
const bitLengths = new Map([
|
|
3
4
|
['A128CBC-HS256', 128],
|
|
4
5
|
['A128GCM', 96],
|
|
@@ -10,12 +11,12 @@ const bitLengths = new Map([
|
|
|
10
11
|
['A256GCM', 96],
|
|
11
12
|
['A256GCMKW', 96],
|
|
12
13
|
]);
|
|
13
|
-
const
|
|
14
|
+
const generateIv = (alg) => {
|
|
14
15
|
const bitLength = bitLengths.get(alg);
|
|
15
16
|
if (!bitLength) {
|
|
16
17
|
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
17
18
|
}
|
|
18
19
|
return random(new Uint8Array(bitLength >> 3));
|
|
19
20
|
};
|
|
20
|
-
export default
|
|
21
|
+
export default generateIv;
|
|
21
22
|
export { bitLengths };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import encrypt from './encrypt.js';
|
|
2
2
|
import decrypt from './decrypt.js';
|
|
3
|
-
import
|
|
4
|
-
import random from './random.js';
|
|
3
|
+
import generateIv from '../lib/iv.js';
|
|
5
4
|
import { encode as base64url } from './base64url.js';
|
|
6
|
-
const generateIv = ivFactory(random);
|
|
7
5
|
export const wrap = async (alg, key, cek, iv) => {
|
|
8
6
|
const jweAlgorithm = alg.substr(0, 7);
|
|
9
7
|
iv || (iv = generateIv(jweAlgorithm));
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { JOSEError } from '../util/errors.js';
|
|
1
|
+
import { JOSEError, JWKSTimeout } from '../util/errors.js';
|
|
2
2
|
import globalThis, { isCloudflareWorkers } from './global.js';
|
|
3
3
|
const fetchJwks = async (url, timeout) => {
|
|
4
4
|
let controller;
|
|
5
|
+
let id;
|
|
6
|
+
let timedOut = false;
|
|
5
7
|
if (typeof AbortController === 'function') {
|
|
6
8
|
controller = new AbortController();
|
|
7
|
-
setTimeout(() =>
|
|
9
|
+
id = setTimeout(() => {
|
|
10
|
+
timedOut = true;
|
|
11
|
+
controller.abort();
|
|
12
|
+
}, timeout);
|
|
8
13
|
}
|
|
9
|
-
const response = await globalThis
|
|
14
|
+
const response = await globalThis
|
|
15
|
+
.fetch(url.href, {
|
|
10
16
|
signal: controller ? controller.signal : undefined,
|
|
11
17
|
redirect: 'manual',
|
|
12
18
|
method: 'GET',
|
|
@@ -17,7 +23,14 @@ const fetchJwks = async (url, timeout) => {
|
|
|
17
23
|
mode: 'cors',
|
|
18
24
|
}
|
|
19
25
|
: undefined),
|
|
26
|
+
})
|
|
27
|
+
.catch((err) => {
|
|
28
|
+
if (timedOut)
|
|
29
|
+
throw new JWKSTimeout();
|
|
30
|
+
throw err;
|
|
20
31
|
});
|
|
32
|
+
if (id !== undefined)
|
|
33
|
+
clearTimeout(id);
|
|
21
34
|
if (response.status !== 200) {
|
|
22
35
|
throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response');
|
|
23
36
|
}
|