jose 4.3.6 → 4.4.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 +1 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/jwks/local.js +101 -0
- package/dist/browser/jwks/remote.js +15 -82
- package/dist/browser/lib/aesgcmkw.js +2 -2
- package/dist/browser/lib/crypto_key.js +7 -7
- package/dist/browser/lib/decrypt_key_management.js +2 -2
- package/dist/browser/lib/encrypt_key_management.js +6 -4
- package/dist/browser/runtime/aeskw.js +1 -1
- package/dist/browser/runtime/asn1.js +21 -20
- package/dist/browser/runtime/decrypt.js +3 -3
- package/dist/browser/runtime/digest.js +1 -1
- package/dist/browser/runtime/ecdhes.js +8 -9
- package/dist/browser/runtime/encrypt.js +3 -3
- package/dist/browser/runtime/generate.js +7 -7
- package/dist/browser/runtime/get_sign_verify_key.js +1 -1
- package/dist/browser/runtime/jwk_to_key.js +4 -4
- package/dist/browser/runtime/pbes2kw.js +4 -4
- package/dist/browser/runtime/sign.js +1 -1
- package/dist/browser/runtime/subtle_dsa.js +7 -6
- package/dist/browser/runtime/verify.js +1 -1
- package/dist/node/cjs/index.js +3 -1
- package/dist/node/cjs/jwks/local.js +107 -0
- package/dist/node/cjs/jwks/remote.js +14 -81
- package/dist/node/cjs/lib/aesgcmkw.js +2 -2
- package/dist/node/cjs/lib/crypto_key.js +7 -7
- package/dist/node/cjs/lib/decrypt_key_management.js +2 -2
- package/dist/node/cjs/lib/encrypt_key_management.js +6 -4
- package/dist/node/cjs/runtime/aeskw.js +4 -5
- package/dist/node/cjs/runtime/check_cek_length.js +2 -2
- package/dist/node/cjs/runtime/decrypt.js +3 -3
- package/dist/node/cjs/runtime/ecdhes.js +7 -7
- package/dist/node/cjs/runtime/encrypt.js +3 -3
- package/dist/node/cjs/runtime/generate.js +2 -2
- package/dist/node/cjs/runtime/get_named_curve.js +2 -2
- package/dist/node/cjs/runtime/get_sign_verify_key.js +1 -2
- package/dist/node/cjs/runtime/jwk_to_key.js +1 -1
- package/dist/node/cjs/runtime/key_to_jwk.js +1 -1
- package/dist/node/cjs/runtime/node_key.js +2 -2
- package/dist/node/cjs/runtime/pbes2kw.js +6 -6
- package/dist/node/cjs/runtime/verify.js +1 -1
- package/dist/node/esm/index.js +1 -0
- package/dist/node/esm/jwks/local.js +101 -0
- package/dist/node/esm/jwks/remote.js +15 -82
- package/dist/node/esm/lib/aesgcmkw.js +2 -2
- package/dist/node/esm/lib/crypto_key.js +7 -7
- package/dist/node/esm/lib/decrypt_key_management.js +2 -2
- package/dist/node/esm/lib/encrypt_key_management.js +6 -4
- package/dist/node/esm/runtime/aeskw.js +5 -6
- package/dist/node/esm/runtime/check_cek_length.js +2 -2
- package/dist/node/esm/runtime/decrypt.js +3 -3
- package/dist/node/esm/runtime/ecdhes.js +7 -7
- package/dist/node/esm/runtime/encrypt.js +3 -3
- package/dist/node/esm/runtime/generate.js +2 -2
- package/dist/node/esm/runtime/get_named_curve.js +2 -2
- package/dist/node/esm/runtime/get_sign_verify_key.js +2 -3
- package/dist/node/esm/runtime/jwk_to_key.js +1 -1
- package/dist/node/esm/runtime/key_to_jwk.js +1 -1
- package/dist/node/esm/runtime/node_key.js +2 -2
- package/dist/node/esm/runtime/pbes2kw.js +6 -6
- package/dist/node/esm/runtime/verify.js +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/jwks/local.d.ts +9 -0
- package/dist/types/types.d.ts +4 -1
- package/package.json +1 -1
- package/dist/node/cjs/runtime/secret_key.js +0 -14
- package/dist/node/esm/runtime/secret_key.js +0 -11
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const crypto_1 = require("crypto");
|
|
4
4
|
const webcrypto_js_1 = require("./webcrypto.js");
|
|
5
5
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
6
|
-
const secret_key_js_1 = require("./secret_key.js");
|
|
7
6
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
8
7
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
9
8
|
function getSignVerifyKey(alg, key, usage) {
|
|
@@ -11,7 +10,7 @@ function getSignVerifyKey(alg, key, usage) {
|
|
|
11
10
|
if (!alg.startsWith('HS')) {
|
|
12
11
|
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types));
|
|
13
12
|
}
|
|
14
|
-
return (0,
|
|
13
|
+
return (0, crypto_1.createSecretKey)(key);
|
|
15
14
|
}
|
|
16
15
|
if (key instanceof crypto_1.KeyObject) {
|
|
17
16
|
return key;
|
|
@@ -8,7 +8,7 @@ const get_named_curve_js_1 = require("./get_named_curve.js");
|
|
|
8
8
|
const check_modulus_length_js_1 = require("./check_modulus_length.js");
|
|
9
9
|
const asn1_sequence_encoder_js_1 = require("./asn1_sequence_encoder.js");
|
|
10
10
|
const [major, minor] = process.version
|
|
11
|
-
.
|
|
11
|
+
.slice(1)
|
|
12
12
|
.split('.')
|
|
13
13
|
.map((str) => parseInt(str, 10));
|
|
14
14
|
const jwkImportSupported = major >= 16 || (major === 15 && minor >= 12);
|
|
@@ -10,7 +10,7 @@ const is_key_object_js_1 = require("./is_key_object.js");
|
|
|
10
10
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
11
11
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
12
12
|
const [major, minor] = process.version
|
|
13
|
-
.
|
|
13
|
+
.slice(1)
|
|
14
14
|
.split('.')
|
|
15
15
|
.map((str) => parseInt(str, 10));
|
|
16
16
|
const jwkExportSupported = major >= 16 || (major === 15 && minor >= 9);
|
|
@@ -5,7 +5,7 @@ const get_named_curve_js_1 = require("./get_named_curve.js");
|
|
|
5
5
|
const errors_js_1 = require("../util/errors.js");
|
|
6
6
|
const check_modulus_length_js_1 = require("./check_modulus_length.js");
|
|
7
7
|
const [major, minor] = process.version
|
|
8
|
-
.
|
|
8
|
+
.slice(1)
|
|
9
9
|
.split('.')
|
|
10
10
|
.map((str) => parseInt(str, 10));
|
|
11
11
|
const electron = 'electron' in process.versions;
|
|
@@ -40,7 +40,7 @@ function keyForCrypto(alg, key) {
|
|
|
40
40
|
case rsaPssParams && 'PS512':
|
|
41
41
|
if (key.asymmetricKeyType === 'rsa-pss') {
|
|
42
42
|
const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails;
|
|
43
|
-
const length = parseInt(alg.
|
|
43
|
+
const length = parseInt(alg.slice(-3), 10);
|
|
44
44
|
if (hashAlgorithm !== undefined &&
|
|
45
45
|
(hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm)) {
|
|
46
46
|
throw new TypeError(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${alg}`);
|
|
@@ -30,19 +30,19 @@ function getPassword(key, alg) {
|
|
|
30
30
|
const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = (0, random_js_1.default)(new Uint8Array(16))) => {
|
|
31
31
|
(0, check_p2s_js_1.default)(p2s);
|
|
32
32
|
const salt = (0, buffer_utils_js_1.p2s)(alg, p2s);
|
|
33
|
-
const keylen = parseInt(alg.
|
|
33
|
+
const keylen = parseInt(alg.slice(13, 16), 10) >> 3;
|
|
34
34
|
const password = getPassword(key, alg);
|
|
35
|
-
const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.
|
|
36
|
-
const encryptedKey = await (0, aeskw_js_1.wrap)(alg.
|
|
35
|
+
const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.slice(8, 11)}`);
|
|
36
|
+
const encryptedKey = await (0, aeskw_js_1.wrap)(alg.slice(-6), derivedKey, cek);
|
|
37
37
|
return { encryptedKey, p2c, p2s: (0, base64url_js_1.encode)(p2s) };
|
|
38
38
|
};
|
|
39
39
|
exports.encrypt = encrypt;
|
|
40
40
|
const decrypt = async (alg, key, encryptedKey, p2c, p2s) => {
|
|
41
41
|
(0, check_p2s_js_1.default)(p2s);
|
|
42
42
|
const salt = (0, buffer_utils_js_1.p2s)(alg, p2s);
|
|
43
|
-
const keylen = parseInt(alg.
|
|
43
|
+
const keylen = parseInt(alg.slice(13, 16), 10) >> 3;
|
|
44
44
|
const password = getPassword(key, alg);
|
|
45
|
-
const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.
|
|
46
|
-
return (0, aeskw_js_1.unwrap)(alg.
|
|
45
|
+
const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.slice(8, 11)}`);
|
|
46
|
+
return (0, aeskw_js_1.unwrap)(alg.slice(-6), derivedKey, encryptedKey);
|
|
47
47
|
};
|
|
48
48
|
exports.decrypt = decrypt;
|
|
@@ -7,7 +7,7 @@ const node_key_js_1 = require("./node_key.js");
|
|
|
7
7
|
const sign_js_1 = require("./sign.js");
|
|
8
8
|
const get_sign_verify_key_js_1 = require("./get_sign_verify_key.js");
|
|
9
9
|
const [major, minor] = process.version
|
|
10
|
-
.
|
|
10
|
+
.slice(1)
|
|
11
11
|
.split('.')
|
|
12
12
|
.map((str) => parseInt(str, 10));
|
|
13
13
|
const oneShotCallbackSupported = major >= 16 || (major === 15 && minor >= 13);
|
package/dist/node/esm/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { SignJWT } from './jwt/sign.js';
|
|
|
16
16
|
export { EncryptJWT } from './jwt/encrypt.js';
|
|
17
17
|
export { calculateJwkThumbprint } from './jwk/thumbprint.js';
|
|
18
18
|
export { EmbeddedJWK } from './jwk/embedded.js';
|
|
19
|
+
export { createLocalJWKSet } from './jwks/local.js';
|
|
19
20
|
export { createRemoteJWKSet } from './jwks/remote.js';
|
|
20
21
|
export { UnsecuredJWT } from './jwt/unsecured.js';
|
|
21
22
|
export { exportPKCS8, exportSPKI, exportJWK } from './key/export.js';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { importJWK } from '../key/import.js';
|
|
2
|
+
import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js';
|
|
3
|
+
import isObject from '../lib/is_object.js';
|
|
4
|
+
function getKtyFromAlg(alg) {
|
|
5
|
+
switch (typeof alg === 'string' && alg.slice(0, 2)) {
|
|
6
|
+
case 'RS':
|
|
7
|
+
case 'PS':
|
|
8
|
+
return 'RSA';
|
|
9
|
+
case 'ES':
|
|
10
|
+
return 'EC';
|
|
11
|
+
case 'Ed':
|
|
12
|
+
return 'OKP';
|
|
13
|
+
default:
|
|
14
|
+
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function isJWKSLike(jwks) {
|
|
18
|
+
return (jwks &&
|
|
19
|
+
typeof jwks === 'object' &&
|
|
20
|
+
Array.isArray(jwks.keys) &&
|
|
21
|
+
jwks.keys.every(isJWKLike));
|
|
22
|
+
}
|
|
23
|
+
function isJWKLike(key) {
|
|
24
|
+
return isObject(key);
|
|
25
|
+
}
|
|
26
|
+
function clone(obj) {
|
|
27
|
+
if (typeof structuredClone === 'function') {
|
|
28
|
+
return structuredClone(obj);
|
|
29
|
+
}
|
|
30
|
+
return JSON.parse(JSON.stringify(obj));
|
|
31
|
+
}
|
|
32
|
+
export class LocalJWKSet {
|
|
33
|
+
constructor(jwks) {
|
|
34
|
+
this._cached = new WeakMap();
|
|
35
|
+
if (!isJWKSLike(jwks)) {
|
|
36
|
+
throw new JWKSInvalid('JSON Web Key Set malformed');
|
|
37
|
+
}
|
|
38
|
+
this._jwks = clone(jwks);
|
|
39
|
+
}
|
|
40
|
+
async getKey(protectedHeader, token) {
|
|
41
|
+
const joseHeader = {
|
|
42
|
+
...protectedHeader,
|
|
43
|
+
...token.header,
|
|
44
|
+
};
|
|
45
|
+
const candidates = this._jwks.keys.filter((jwk) => {
|
|
46
|
+
let candidate = jwk.kty === getKtyFromAlg(joseHeader.alg);
|
|
47
|
+
if (candidate && typeof joseHeader.kid === 'string') {
|
|
48
|
+
candidate = joseHeader.kid === jwk.kid;
|
|
49
|
+
}
|
|
50
|
+
if (candidate && typeof jwk.alg === 'string') {
|
|
51
|
+
candidate = joseHeader.alg === jwk.alg;
|
|
52
|
+
}
|
|
53
|
+
if (candidate && typeof jwk.use === 'string') {
|
|
54
|
+
candidate = jwk.use === 'sig';
|
|
55
|
+
}
|
|
56
|
+
if (candidate && Array.isArray(jwk.key_ops)) {
|
|
57
|
+
candidate = jwk.key_ops.includes('verify');
|
|
58
|
+
}
|
|
59
|
+
if (candidate && joseHeader.alg === 'EdDSA') {
|
|
60
|
+
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
61
|
+
}
|
|
62
|
+
if (candidate) {
|
|
63
|
+
switch (joseHeader.alg) {
|
|
64
|
+
case 'ES256':
|
|
65
|
+
candidate = jwk.crv === 'P-256';
|
|
66
|
+
break;
|
|
67
|
+
case 'ES256K':
|
|
68
|
+
candidate = jwk.crv === 'secp256k1';
|
|
69
|
+
break;
|
|
70
|
+
case 'ES384':
|
|
71
|
+
candidate = jwk.crv === 'P-384';
|
|
72
|
+
break;
|
|
73
|
+
case 'ES512':
|
|
74
|
+
candidate = jwk.crv === 'P-521';
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return candidate;
|
|
80
|
+
});
|
|
81
|
+
const { 0: jwk, length } = candidates;
|
|
82
|
+
if (length === 0) {
|
|
83
|
+
throw new JWKSNoMatchingKey();
|
|
84
|
+
}
|
|
85
|
+
else if (length !== 1) {
|
|
86
|
+
throw new JWKSMultipleMatchingKeys();
|
|
87
|
+
}
|
|
88
|
+
const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
|
|
89
|
+
if (cached[joseHeader.alg] === undefined) {
|
|
90
|
+
const keyObject = await importJWK({ ...jwk, ext: true }, joseHeader.alg);
|
|
91
|
+
if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
|
|
92
|
+
throw new JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
93
|
+
}
|
|
94
|
+
cached[joseHeader.alg] = keyObject;
|
|
95
|
+
}
|
|
96
|
+
return cached[joseHeader.alg];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export function createLocalJWKSet(jwks) {
|
|
100
|
+
return LocalJWKSet.prototype.getKey.bind(new LocalJWKSet(jwks));
|
|
101
|
+
}
|
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
import fetchJwks from '../runtime/fetch_jwks.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
function getKtyFromAlg(alg) {
|
|
6
|
-
switch (typeof alg === 'string' && alg.substr(0, 2)) {
|
|
7
|
-
case 'RS':
|
|
8
|
-
case 'PS':
|
|
9
|
-
return 'RSA';
|
|
10
|
-
case 'ES':
|
|
11
|
-
return 'EC';
|
|
12
|
-
case 'Ed':
|
|
13
|
-
return 'OKP';
|
|
14
|
-
default:
|
|
15
|
-
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function isJWKLike(key) {
|
|
19
|
-
return isObject(key);
|
|
20
|
-
}
|
|
21
|
-
class RemoteJWKSet {
|
|
2
|
+
import { JWKSInvalid, JWKSNoMatchingKey } from '../util/errors.js';
|
|
3
|
+
import { isJWKSLike, LocalJWKSet } from './local.js';
|
|
4
|
+
class RemoteJWKSet extends LocalJWKSet {
|
|
22
5
|
constructor(url, options) {
|
|
23
|
-
|
|
6
|
+
super({ keys: [] });
|
|
7
|
+
this._jwks = undefined;
|
|
24
8
|
if (!(url instanceof URL)) {
|
|
25
9
|
throw new TypeError('url must be an instance of URL');
|
|
26
10
|
}
|
|
@@ -38,78 +22,27 @@ class RemoteJWKSet {
|
|
|
38
22
|
return Date.now() < this._cooldownStarted + this._cooldownDuration;
|
|
39
23
|
}
|
|
40
24
|
async getKey(protectedHeader, token) {
|
|
41
|
-
const joseHeader = {
|
|
42
|
-
...protectedHeader,
|
|
43
|
-
...token.header,
|
|
44
|
-
};
|
|
45
25
|
if (!this._jwks) {
|
|
46
26
|
await this.reload();
|
|
47
27
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (candidate && typeof joseHeader.kid === 'string') {
|
|
51
|
-
candidate = joseHeader.kid === jwk.kid;
|
|
52
|
-
}
|
|
53
|
-
if (candidate && typeof jwk.alg === 'string') {
|
|
54
|
-
candidate = joseHeader.alg === jwk.alg;
|
|
55
|
-
}
|
|
56
|
-
if (candidate && typeof jwk.use === 'string') {
|
|
57
|
-
candidate = jwk.use === 'sig';
|
|
58
|
-
}
|
|
59
|
-
if (candidate && Array.isArray(jwk.key_ops)) {
|
|
60
|
-
candidate = jwk.key_ops.includes('verify');
|
|
61
|
-
}
|
|
62
|
-
if (candidate && joseHeader.alg === 'EdDSA') {
|
|
63
|
-
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
64
|
-
}
|
|
65
|
-
if (candidate) {
|
|
66
|
-
switch (joseHeader.alg) {
|
|
67
|
-
case 'ES256':
|
|
68
|
-
candidate = jwk.crv === 'P-256';
|
|
69
|
-
break;
|
|
70
|
-
case 'ES256K':
|
|
71
|
-
candidate = jwk.crv === 'secp256k1';
|
|
72
|
-
break;
|
|
73
|
-
case 'ES384':
|
|
74
|
-
candidate = jwk.crv === 'P-384';
|
|
75
|
-
break;
|
|
76
|
-
case 'ES512':
|
|
77
|
-
candidate = jwk.crv === 'P-521';
|
|
78
|
-
break;
|
|
79
|
-
default:
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return candidate;
|
|
83
|
-
});
|
|
84
|
-
const { 0: jwk, length } = candidates;
|
|
85
|
-
if (length === 0) {
|
|
86
|
-
if (this.coolingDown() === false) {
|
|
87
|
-
await this.reload();
|
|
88
|
-
return this.getKey(protectedHeader, token);
|
|
89
|
-
}
|
|
90
|
-
throw new JWKSNoMatchingKey();
|
|
91
|
-
}
|
|
92
|
-
else if (length !== 1) {
|
|
93
|
-
throw new JWKSMultipleMatchingKeys();
|
|
28
|
+
try {
|
|
29
|
+
return await super.getKey(protectedHeader, token);
|
|
94
30
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err instanceof JWKSNoMatchingKey) {
|
|
33
|
+
if (this.coolingDown() === false) {
|
|
34
|
+
await this.reload();
|
|
35
|
+
return super.getKey(protectedHeader, token);
|
|
36
|
+
}
|
|
100
37
|
}
|
|
101
|
-
|
|
38
|
+
throw err;
|
|
102
39
|
}
|
|
103
|
-
return cached[joseHeader.alg];
|
|
104
40
|
}
|
|
105
41
|
async reload() {
|
|
106
42
|
if (!this._pendingFetch) {
|
|
107
43
|
this._pendingFetch = fetchJwks(this._url, this._timeoutDuration, this._options)
|
|
108
44
|
.then((json) => {
|
|
109
|
-
if (
|
|
110
|
-
!json ||
|
|
111
|
-
!Array.isArray(json.keys) ||
|
|
112
|
-
!json.keys.every(isJWKLike)) {
|
|
45
|
+
if (!isJWKSLike(json)) {
|
|
113
46
|
throw new JWKSInvalid('JSON Web Key Set malformed');
|
|
114
47
|
}
|
|
115
48
|
this._jwks = { keys: json.keys };
|
|
@@ -3,12 +3,12 @@ import decrypt from '../runtime/decrypt.js';
|
|
|
3
3
|
import generateIv from './iv.js';
|
|
4
4
|
import { encode as base64url } from '../runtime/base64url.js';
|
|
5
5
|
export async function wrap(alg, key, cek, iv) {
|
|
6
|
-
const jweAlgorithm = alg.
|
|
6
|
+
const jweAlgorithm = alg.slice(0, 7);
|
|
7
7
|
iv || (iv = generateIv(jweAlgorithm));
|
|
8
8
|
const { ciphertext: encryptedKey, tag } = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0));
|
|
9
9
|
return { encryptedKey, iv: base64url(iv), tag: base64url(tag) };
|
|
10
10
|
}
|
|
11
11
|
export async function unwrap(alg, key, encryptedKey, iv, tag) {
|
|
12
|
-
const jweAlgorithm = alg.
|
|
12
|
+
const jweAlgorithm = alg.slice(0, 7);
|
|
13
13
|
return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0));
|
|
14
14
|
}
|
|
@@ -6,7 +6,7 @@ function isAlgorithm(algorithm, name) {
|
|
|
6
6
|
return algorithm.name === name;
|
|
7
7
|
}
|
|
8
8
|
function getHashLength(hash) {
|
|
9
|
-
return parseInt(hash.name.
|
|
9
|
+
return parseInt(hash.name.slice(4), 10);
|
|
10
10
|
}
|
|
11
11
|
function getNamedCurve(alg) {
|
|
12
12
|
switch (alg) {
|
|
@@ -43,7 +43,7 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
43
43
|
case 'HS512': {
|
|
44
44
|
if (!isAlgorithm(key.algorithm, 'HMAC'))
|
|
45
45
|
throw unusable('HMAC');
|
|
46
|
-
const expected = parseInt(alg.
|
|
46
|
+
const expected = parseInt(alg.slice(2), 10);
|
|
47
47
|
const actual = getHashLength(key.algorithm.hash);
|
|
48
48
|
if (actual !== expected)
|
|
49
49
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -54,7 +54,7 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
54
54
|
case 'RS512': {
|
|
55
55
|
if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))
|
|
56
56
|
throw unusable('RSASSA-PKCS1-v1_5');
|
|
57
|
-
const expected = parseInt(alg.
|
|
57
|
+
const expected = parseInt(alg.slice(2), 10);
|
|
58
58
|
const actual = getHashLength(key.algorithm.hash);
|
|
59
59
|
if (actual !== expected)
|
|
60
60
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -65,7 +65,7 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
65
65
|
case 'PS512': {
|
|
66
66
|
if (!isAlgorithm(key.algorithm, 'RSA-PSS'))
|
|
67
67
|
throw unusable('RSA-PSS');
|
|
68
|
-
const expected = parseInt(alg.
|
|
68
|
+
const expected = parseInt(alg.slice(2), 10);
|
|
69
69
|
const actual = getHashLength(key.algorithm.hash);
|
|
70
70
|
if (actual !== expected)
|
|
71
71
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -104,7 +104,7 @@ export function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
104
104
|
case 'A256GCM': {
|
|
105
105
|
if (!isAlgorithm(key.algorithm, 'AES-GCM'))
|
|
106
106
|
throw unusable('AES-GCM');
|
|
107
|
-
const expected = parseInt(alg.
|
|
107
|
+
const expected = parseInt(alg.slice(1, 4), 10);
|
|
108
108
|
const actual = key.algorithm.length;
|
|
109
109
|
if (actual !== expected)
|
|
110
110
|
throw unusable(expected, 'algorithm.length');
|
|
@@ -115,7 +115,7 @@ export function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
115
115
|
case 'A256KW': {
|
|
116
116
|
if (!isAlgorithm(key.algorithm, 'AES-KW'))
|
|
117
117
|
throw unusable('AES-KW');
|
|
118
|
-
const expected = parseInt(alg.
|
|
118
|
+
const expected = parseInt(alg.slice(1, 4), 10);
|
|
119
119
|
const actual = key.algorithm.length;
|
|
120
120
|
if (actual !== expected)
|
|
121
121
|
throw unusable(expected, 'algorithm.length');
|
|
@@ -137,7 +137,7 @@ export function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
137
137
|
case 'RSA-OAEP-512': {
|
|
138
138
|
if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))
|
|
139
139
|
throw unusable('RSA-OAEP');
|
|
140
|
-
const expected = parseInt(alg.
|
|
140
|
+
const expected = parseInt(alg.slice(9), 10) || 1;
|
|
141
141
|
const actual = getHashLength(key.algorithm.hash);
|
|
142
142
|
if (actual !== expected)
|
|
143
143
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -40,12 +40,12 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) {
|
|
|
40
40
|
throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
|
|
41
41
|
partyVInfo = base64url(joseHeader.apv);
|
|
42
42
|
}
|
|
43
|
-
const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.
|
|
43
|
+
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
44
|
if (alg === 'ECDH-ES')
|
|
45
45
|
return sharedSecret;
|
|
46
46
|
if (encryptedKey === undefined)
|
|
47
47
|
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
48
|
-
return aesKw(alg.
|
|
48
|
+
return aesKw(alg.slice(-6), sharedSecret, encryptedKey);
|
|
49
49
|
}
|
|
50
50
|
case 'RSA1_5':
|
|
51
51
|
case 'RSA-OAEP':
|
|
@@ -27,10 +27,12 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
|
|
|
27
27
|
}
|
|
28
28
|
const { apu, apv } = providedParameters;
|
|
29
29
|
let { epk: ephemeralKey } = providedParameters;
|
|
30
|
-
ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key));
|
|
30
|
+
ephemeralKey || (ephemeralKey = (await ECDH.generateEpk(key)).privateKey);
|
|
31
31
|
const { x, y, crv, kty } = await exportJWK(ephemeralKey);
|
|
32
|
-
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? cekLength(enc) : parseInt(alg.
|
|
33
|
-
parameters = { epk: { x,
|
|
32
|
+
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? cekLength(enc) : parseInt(alg.slice(-5, -2), 10), apu, apv);
|
|
33
|
+
parameters = { epk: { x, crv, kty } };
|
|
34
|
+
if (kty === 'EC')
|
|
35
|
+
parameters.epk.y = y;
|
|
34
36
|
if (apu)
|
|
35
37
|
parameters.apu = base64url(apu);
|
|
36
38
|
if (apv)
|
|
@@ -40,7 +42,7 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
|
|
|
40
42
|
break;
|
|
41
43
|
}
|
|
42
44
|
cek = providedCek || generateCek(enc);
|
|
43
|
-
const kwAlg = alg.
|
|
45
|
+
const kwAlg = alg.slice(-6);
|
|
44
46
|
encryptedKey = await aesKw(kwAlg, sharedSecret, cek);
|
|
45
47
|
break;
|
|
46
48
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
-
import { KeyObject, createDecipheriv, createCipheriv } from 'crypto';
|
|
2
|
+
import { KeyObject, createDecipheriv, createCipheriv, createSecretKey } from 'crypto';
|
|
3
3
|
import { JOSENotSupported } from '../util/errors.js';
|
|
4
4
|
import { concat } from '../lib/buffer_utils.js';
|
|
5
|
-
import getSecretKey from './secret_key.js';
|
|
6
5
|
import { isCryptoKey } from './webcrypto.js';
|
|
7
6
|
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
8
7
|
import isKeyObject from './is_key_object.js';
|
|
@@ -10,7 +9,7 @@ import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
|
10
9
|
import supported from './ciphers.js';
|
|
11
10
|
import { types } from './is_key_like.js';
|
|
12
11
|
function checkKeySize(key, alg) {
|
|
13
|
-
if (key.symmetricKeySize << 3 !== parseInt(alg.
|
|
12
|
+
if (key.symmetricKeySize << 3 !== parseInt(alg.slice(1, 4), 10)) {
|
|
14
13
|
throw new TypeError(`Invalid key size for alg: ${alg}`);
|
|
15
14
|
}
|
|
16
15
|
}
|
|
@@ -19,7 +18,7 @@ function ensureKeyObject(key, alg, usage) {
|
|
|
19
18
|
return key;
|
|
20
19
|
}
|
|
21
20
|
if (key instanceof Uint8Array) {
|
|
22
|
-
return
|
|
21
|
+
return createSecretKey(key);
|
|
23
22
|
}
|
|
24
23
|
if (isCryptoKey(key)) {
|
|
25
24
|
checkEncCryptoKey(key, alg, usage);
|
|
@@ -28,7 +27,7 @@ function ensureKeyObject(key, alg, usage) {
|
|
|
28
27
|
throw new TypeError(invalidKeyInput(key, ...types, 'Uint8Array'));
|
|
29
28
|
}
|
|
30
29
|
export const wrap = (alg, key, cek) => {
|
|
31
|
-
const size = parseInt(alg.
|
|
30
|
+
const size = parseInt(alg.slice(1, 4), 10);
|
|
32
31
|
const algorithm = `aes${size}-wrap`;
|
|
33
32
|
if (!supported(algorithm)) {
|
|
34
33
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -39,7 +38,7 @@ export const wrap = (alg, key, cek) => {
|
|
|
39
38
|
return concat(cipher.update(cek), cipher.final());
|
|
40
39
|
};
|
|
41
40
|
export const unwrap = (alg, key, encryptedKey) => {
|
|
42
|
-
const size = parseInt(alg.
|
|
41
|
+
const size = parseInt(alg.slice(1, 4), 10);
|
|
43
42
|
const algorithm = `aes${size}-wrap`;
|
|
44
43
|
if (!supported(algorithm)) {
|
|
45
44
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -6,12 +6,12 @@ const checkCekLength = (enc, cek) => {
|
|
|
6
6
|
case 'A128CBC-HS256':
|
|
7
7
|
case 'A192CBC-HS384':
|
|
8
8
|
case 'A256CBC-HS512':
|
|
9
|
-
expected = parseInt(enc.
|
|
9
|
+
expected = parseInt(enc.slice(-3), 10);
|
|
10
10
|
break;
|
|
11
11
|
case 'A128GCM':
|
|
12
12
|
case 'A192GCM':
|
|
13
13
|
case 'A256GCM':
|
|
14
|
-
expected = parseInt(enc.
|
|
14
|
+
expected = parseInt(enc.slice(1, 4), 10);
|
|
15
15
|
break;
|
|
16
16
|
default:
|
|
17
17
|
throw new JOSENotSupported(`Content Encryption Algorithm ${enc} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -12,13 +12,13 @@ import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
|
12
12
|
import supported from './ciphers.js';
|
|
13
13
|
import { types } from './is_key_like.js';
|
|
14
14
|
function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
15
|
-
const keySize = parseInt(enc.
|
|
15
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
16
16
|
if (isKeyObject(cek)) {
|
|
17
17
|
cek = cek.export();
|
|
18
18
|
}
|
|
19
19
|
const encKey = cek.subarray(keySize >> 3);
|
|
20
20
|
const macKey = cek.subarray(0, keySize >> 3);
|
|
21
|
-
const macSize = parseInt(enc.
|
|
21
|
+
const macSize = parseInt(enc.slice(-3), 10);
|
|
22
22
|
const algorithm = `aes-${keySize}-cbc`;
|
|
23
23
|
if (!supported(algorithm)) {
|
|
24
24
|
throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`);
|
|
@@ -46,7 +46,7 @@ function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
46
46
|
return plaintext;
|
|
47
47
|
}
|
|
48
48
|
function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
49
|
-
const keySize = parseInt(enc.
|
|
49
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
50
50
|
const algorithm = `aes-${keySize}-gcm`;
|
|
51
51
|
if (!supported(algorithm)) {
|
|
52
52
|
throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`);
|
|
@@ -10,7 +10,7 @@ import isKeyObject from './is_key_object.js';
|
|
|
10
10
|
import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
11
11
|
import { types } from './is_key_like.js';
|
|
12
12
|
const generateKeyPair = promisify(generateKeyPairCb);
|
|
13
|
-
export
|
|
13
|
+
export async function deriveKey(publicKee, privateKee, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) {
|
|
14
14
|
let publicKey;
|
|
15
15
|
if (isCryptoKey(publicKee)) {
|
|
16
16
|
checkEncCryptoKey(publicKee, 'ECDH-ES');
|
|
@@ -36,8 +36,8 @@ export const deriveKey = (publicKee, privateKee, algorithm, keyLength, apu = new
|
|
|
36
36
|
const value = concat(lengthAndInput(encoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
|
|
37
37
|
const sharedSecret = diffieHellman({ privateKey, publicKey });
|
|
38
38
|
return concatKdf(digest, sharedSecret, keyLength, value);
|
|
39
|
-
}
|
|
40
|
-
export
|
|
39
|
+
}
|
|
40
|
+
export async function generateEpk(kee) {
|
|
41
41
|
let key;
|
|
42
42
|
if (isCryptoKey(kee)) {
|
|
43
43
|
key = KeyObject.from(kee);
|
|
@@ -50,16 +50,16 @@ export const generateEpk = async (kee) => {
|
|
|
50
50
|
}
|
|
51
51
|
switch (key.asymmetricKeyType) {
|
|
52
52
|
case 'x25519':
|
|
53
|
-
return
|
|
53
|
+
return generateKeyPair('x25519');
|
|
54
54
|
case 'x448': {
|
|
55
|
-
return
|
|
55
|
+
return generateKeyPair('x448');
|
|
56
56
|
}
|
|
57
57
|
case 'ec': {
|
|
58
58
|
const namedCurve = getNamedCurve(key);
|
|
59
|
-
return
|
|
59
|
+
return generateKeyPair('ec', { namedCurve });
|
|
60
60
|
}
|
|
61
61
|
default:
|
|
62
62
|
throw new JOSENotSupported('Invalid or unsupported EPK');
|
|
63
63
|
}
|
|
64
|
-
}
|
|
64
|
+
}
|
|
65
65
|
export const ecdhAllowed = (key) => ['P-256', 'P-384', 'P-521', 'X25519', 'X448'].includes(getNamedCurve(key));
|
|
@@ -11,7 +11,7 @@ import { JOSENotSupported } from '../util/errors.js';
|
|
|
11
11
|
import supported from './ciphers.js';
|
|
12
12
|
import { types } from './is_key_like.js';
|
|
13
13
|
function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
14
|
-
const keySize = parseInt(enc.
|
|
14
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
15
15
|
if (isKeyObject(cek)) {
|
|
16
16
|
cek = cek.export();
|
|
17
17
|
}
|
|
@@ -23,12 +23,12 @@ function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
23
23
|
}
|
|
24
24
|
const cipher = createCipheriv(algorithm, encKey, iv);
|
|
25
25
|
const ciphertext = concat(cipher.update(plaintext), cipher.final());
|
|
26
|
-
const macSize = parseInt(enc.
|
|
26
|
+
const macSize = parseInt(enc.slice(-3), 10);
|
|
27
27
|
const tag = cbcTag(aad, iv, ciphertext, macSize, macKey, keySize);
|
|
28
28
|
return { ciphertext, tag };
|
|
29
29
|
}
|
|
30
30
|
function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
31
|
-
const keySize = parseInt(enc.
|
|
31
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
32
32
|
const algorithm = `aes-${keySize}-gcm`;
|
|
33
33
|
if (!supported(algorithm)) {
|
|
34
34
|
throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`);
|
|
@@ -13,7 +13,7 @@ export async function generateSecret(alg, options) {
|
|
|
13
13
|
case 'A128CBC-HS256':
|
|
14
14
|
case 'A192CBC-HS384':
|
|
15
15
|
case 'A256CBC-HS512':
|
|
16
|
-
length = parseInt(alg.
|
|
16
|
+
length = parseInt(alg.slice(-3), 10);
|
|
17
17
|
break;
|
|
18
18
|
case 'A128KW':
|
|
19
19
|
case 'A192KW':
|
|
@@ -24,7 +24,7 @@ export async function generateSecret(alg, options) {
|
|
|
24
24
|
case 'A128GCM':
|
|
25
25
|
case 'A192GCM':
|
|
26
26
|
case 'A256GCM':
|
|
27
|
-
length = parseInt(alg.
|
|
27
|
+
length = parseInt(alg.slice(1, 4), 10);
|
|
28
28
|
break;
|
|
29
29
|
default:
|
|
30
30
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
@@ -42,10 +42,10 @@ const getNamedCurve = (kee, raw) => {
|
|
|
42
42
|
switch (key.asymmetricKeyType) {
|
|
43
43
|
case 'ed25519':
|
|
44
44
|
case 'ed448':
|
|
45
|
-
return `Ed${key.asymmetricKeyType.
|
|
45
|
+
return `Ed${key.asymmetricKeyType.slice(2)}`;
|
|
46
46
|
case 'x25519':
|
|
47
47
|
case 'x448':
|
|
48
|
-
return `X${key.asymmetricKeyType.
|
|
48
|
+
return `X${key.asymmetricKeyType.slice(1)}`;
|
|
49
49
|
case 'ec': {
|
|
50
50
|
if (weakMap.has(key)) {
|
|
51
51
|
return weakMap.get(key);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { KeyObject } from 'crypto';
|
|
1
|
+
import { KeyObject, createSecretKey } from 'crypto';
|
|
2
2
|
import { isCryptoKey } from './webcrypto.js';
|
|
3
3
|
import { checkSigCryptoKey } from '../lib/crypto_key.js';
|
|
4
|
-
import getSecretKey from './secret_key.js';
|
|
5
4
|
import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
6
5
|
import { types } from './is_key_like.js';
|
|
7
6
|
export default function getSignVerifyKey(alg, key, usage) {
|
|
@@ -9,7 +8,7 @@ export default function getSignVerifyKey(alg, key, usage) {
|
|
|
9
8
|
if (!alg.startsWith('HS')) {
|
|
10
9
|
throw new TypeError(invalidKeyInput(key, ...types));
|
|
11
10
|
}
|
|
12
|
-
return
|
|
11
|
+
return createSecretKey(key);
|
|
13
12
|
}
|
|
14
13
|
if (key instanceof KeyObject) {
|
|
15
14
|
return key;
|