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
|
@@ -20,9 +20,9 @@ function getCryptoKey(key, alg) {
|
|
|
20
20
|
async function deriveKey(p2s, alg, p2c, key) {
|
|
21
21
|
checkP2s(p2s);
|
|
22
22
|
const salt = concatSalt(alg, p2s);
|
|
23
|
-
const keylen = parseInt(alg.
|
|
23
|
+
const keylen = parseInt(alg.slice(13, 16), 10);
|
|
24
24
|
const subtleAlg = {
|
|
25
|
-
hash: `SHA-${alg.
|
|
25
|
+
hash: `SHA-${alg.slice(8, 11)}`,
|
|
26
26
|
iterations: p2c,
|
|
27
27
|
name: 'PBKDF2',
|
|
28
28
|
salt,
|
|
@@ -42,10 +42,10 @@ async function deriveKey(p2s, alg, p2c, key) {
|
|
|
42
42
|
}
|
|
43
43
|
export const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = random(new Uint8Array(16))) => {
|
|
44
44
|
const derived = await deriveKey(p2s, alg, p2c, key);
|
|
45
|
-
const encryptedKey = await wrap(alg.
|
|
45
|
+
const encryptedKey = await wrap(alg.slice(-6), derived, cek);
|
|
46
46
|
return { encryptedKey, p2c, p2s: base64url(p2s) };
|
|
47
47
|
};
|
|
48
48
|
export const decrypt = async (alg, key, encryptedKey, p2c, p2s) => {
|
|
49
49
|
const derived = await deriveKey(p2s, alg, p2c, key);
|
|
50
|
-
return unwrap(alg.
|
|
50
|
+
return unwrap(alg.slice(-6), derived, encryptedKey);
|
|
51
51
|
};
|
|
@@ -5,7 +5,7 @@ import getSignKey from './get_sign_verify_key.js';
|
|
|
5
5
|
const sign = async (alg, key, data) => {
|
|
6
6
|
const cryptoKey = await getSignKey(alg, key, 'sign');
|
|
7
7
|
checkKeyLength(alg, cryptoKey);
|
|
8
|
-
const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm
|
|
8
|
+
const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);
|
|
9
9
|
return new Uint8Array(signature);
|
|
10
10
|
};
|
|
11
11
|
export default sign;
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { isCloudflareWorkers, isNodeJs } from './env.js';
|
|
2
2
|
import { JOSENotSupported } from '../util/errors.js';
|
|
3
|
-
export default function subtleDsa(alg,
|
|
4
|
-
const
|
|
3
|
+
export default function subtleDsa(alg, algorithm) {
|
|
4
|
+
const hash = `SHA-${alg.slice(-3)}`;
|
|
5
5
|
switch (alg) {
|
|
6
6
|
case 'HS256':
|
|
7
7
|
case 'HS384':
|
|
8
8
|
case 'HS512':
|
|
9
|
-
return { hash
|
|
9
|
+
return { hash, name: 'HMAC' };
|
|
10
10
|
case 'PS256':
|
|
11
11
|
case 'PS384':
|
|
12
12
|
case 'PS512':
|
|
13
|
-
return { hash
|
|
13
|
+
return { hash, name: 'RSA-PSS', saltLength: alg.slice(-3) >> 3 };
|
|
14
14
|
case 'RS256':
|
|
15
15
|
case 'RS384':
|
|
16
16
|
case 'RS512':
|
|
17
|
-
return { hash
|
|
17
|
+
return { hash, name: 'RSASSA-PKCS1-v1_5' };
|
|
18
18
|
case 'ES256':
|
|
19
19
|
case 'ES384':
|
|
20
20
|
case 'ES512':
|
|
21
|
-
return { hash
|
|
21
|
+
return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
|
|
22
22
|
case (isCloudflareWorkers() || isNodeJs()) && 'EdDSA':
|
|
23
|
+
const { namedCurve } = algorithm;
|
|
23
24
|
return { name: namedCurve, namedCurve };
|
|
24
25
|
default:
|
|
25
26
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -5,7 +5,7 @@ import getVerifyKey from './get_sign_verify_key.js';
|
|
|
5
5
|
const verify = async (alg, key, signature, data) => {
|
|
6
6
|
const cryptoKey = await getVerifyKey(alg, key, 'verify');
|
|
7
7
|
checkKeyLength(alg, cryptoKey);
|
|
8
|
-
const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm
|
|
8
|
+
const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);
|
|
9
9
|
try {
|
|
10
10
|
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
|
|
11
11
|
}
|
package/dist/node/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.base64url = exports.generateSecret = exports.generateKeyPair = exports.errors = exports.decodeProtectedHeader = exports.importJWK = exports.importX509 = exports.importPKCS8 = exports.importSPKI = exports.exportJWK = exports.exportSPKI = exports.exportPKCS8 = exports.UnsecuredJWT = exports.createRemoteJWKSet = exports.EmbeddedJWK = exports.calculateJwkThumbprint = exports.EncryptJWT = exports.SignJWT = exports.GeneralSign = exports.FlattenedSign = exports.CompactSign = exports.FlattenedEncrypt = exports.CompactEncrypt = exports.jwtDecrypt = exports.jwtVerify = exports.generalVerify = exports.flattenedVerify = exports.compactVerify = exports.GeneralEncrypt = exports.generalDecrypt = exports.flattenedDecrypt = exports.compactDecrypt = void 0;
|
|
3
|
+
exports.base64url = exports.generateSecret = exports.generateKeyPair = exports.errors = exports.decodeProtectedHeader = exports.importJWK = exports.importX509 = exports.importPKCS8 = exports.importSPKI = exports.exportJWK = exports.exportSPKI = exports.exportPKCS8 = exports.UnsecuredJWT = exports.createRemoteJWKSet = exports.createLocalJWKSet = exports.EmbeddedJWK = exports.calculateJwkThumbprint = exports.EncryptJWT = exports.SignJWT = exports.GeneralSign = exports.FlattenedSign = exports.CompactSign = exports.FlattenedEncrypt = exports.CompactEncrypt = exports.jwtDecrypt = exports.jwtVerify = exports.generalVerify = exports.flattenedVerify = exports.compactVerify = exports.GeneralEncrypt = exports.generalDecrypt = exports.flattenedDecrypt = exports.compactDecrypt = void 0;
|
|
4
4
|
var decrypt_js_1 = require("./jwe/compact/decrypt.js");
|
|
5
5
|
Object.defineProperty(exports, "compactDecrypt", { enumerable: true, get: function () { return decrypt_js_1.compactDecrypt; } });
|
|
6
6
|
var decrypt_js_2 = require("./jwe/flattened/decrypt.js");
|
|
@@ -37,6 +37,8 @@ var thumbprint_js_1 = require("./jwk/thumbprint.js");
|
|
|
37
37
|
Object.defineProperty(exports, "calculateJwkThumbprint", { enumerable: true, get: function () { return thumbprint_js_1.calculateJwkThumbprint; } });
|
|
38
38
|
var embedded_js_1 = require("./jwk/embedded.js");
|
|
39
39
|
Object.defineProperty(exports, "EmbeddedJWK", { enumerable: true, get: function () { return embedded_js_1.EmbeddedJWK; } });
|
|
40
|
+
var local_js_1 = require("./jwks/local.js");
|
|
41
|
+
Object.defineProperty(exports, "createLocalJWKSet", { enumerable: true, get: function () { return local_js_1.createLocalJWKSet; } });
|
|
40
42
|
var remote_js_1 = require("./jwks/remote.js");
|
|
41
43
|
Object.defineProperty(exports, "createRemoteJWKSet", { enumerable: true, get: function () { return remote_js_1.createRemoteJWKSet; } });
|
|
42
44
|
var unsecured_js_1 = require("./jwt/unsecured.js");
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLocalJWKSet = exports.LocalJWKSet = exports.isJWKSLike = void 0;
|
|
4
|
+
const import_js_1 = require("../key/import.js");
|
|
5
|
+
const errors_js_1 = require("../util/errors.js");
|
|
6
|
+
const is_object_js_1 = require("../lib/is_object.js");
|
|
7
|
+
function getKtyFromAlg(alg) {
|
|
8
|
+
switch (typeof alg === 'string' && alg.slice(0, 2)) {
|
|
9
|
+
case 'RS':
|
|
10
|
+
case 'PS':
|
|
11
|
+
return 'RSA';
|
|
12
|
+
case 'ES':
|
|
13
|
+
return 'EC';
|
|
14
|
+
case 'Ed':
|
|
15
|
+
return 'OKP';
|
|
16
|
+
default:
|
|
17
|
+
throw new errors_js_1.JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function isJWKSLike(jwks) {
|
|
21
|
+
return (jwks &&
|
|
22
|
+
typeof jwks === 'object' &&
|
|
23
|
+
Array.isArray(jwks.keys) &&
|
|
24
|
+
jwks.keys.every(isJWKLike));
|
|
25
|
+
}
|
|
26
|
+
exports.isJWKSLike = isJWKSLike;
|
|
27
|
+
function isJWKLike(key) {
|
|
28
|
+
return (0, is_object_js_1.default)(key);
|
|
29
|
+
}
|
|
30
|
+
function clone(obj) {
|
|
31
|
+
if (typeof structuredClone === 'function') {
|
|
32
|
+
return structuredClone(obj);
|
|
33
|
+
}
|
|
34
|
+
return JSON.parse(JSON.stringify(obj));
|
|
35
|
+
}
|
|
36
|
+
class LocalJWKSet {
|
|
37
|
+
constructor(jwks) {
|
|
38
|
+
this._cached = new WeakMap();
|
|
39
|
+
if (!isJWKSLike(jwks)) {
|
|
40
|
+
throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed');
|
|
41
|
+
}
|
|
42
|
+
this._jwks = clone(jwks);
|
|
43
|
+
}
|
|
44
|
+
async getKey(protectedHeader, token) {
|
|
45
|
+
const joseHeader = {
|
|
46
|
+
...protectedHeader,
|
|
47
|
+
...token.header,
|
|
48
|
+
};
|
|
49
|
+
const candidates = this._jwks.keys.filter((jwk) => {
|
|
50
|
+
let candidate = jwk.kty === getKtyFromAlg(joseHeader.alg);
|
|
51
|
+
if (candidate && typeof joseHeader.kid === 'string') {
|
|
52
|
+
candidate = joseHeader.kid === jwk.kid;
|
|
53
|
+
}
|
|
54
|
+
if (candidate && typeof jwk.alg === 'string') {
|
|
55
|
+
candidate = joseHeader.alg === jwk.alg;
|
|
56
|
+
}
|
|
57
|
+
if (candidate && typeof jwk.use === 'string') {
|
|
58
|
+
candidate = jwk.use === 'sig';
|
|
59
|
+
}
|
|
60
|
+
if (candidate && Array.isArray(jwk.key_ops)) {
|
|
61
|
+
candidate = jwk.key_ops.includes('verify');
|
|
62
|
+
}
|
|
63
|
+
if (candidate && joseHeader.alg === 'EdDSA') {
|
|
64
|
+
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
65
|
+
}
|
|
66
|
+
if (candidate) {
|
|
67
|
+
switch (joseHeader.alg) {
|
|
68
|
+
case 'ES256':
|
|
69
|
+
candidate = jwk.crv === 'P-256';
|
|
70
|
+
break;
|
|
71
|
+
case 'ES256K':
|
|
72
|
+
candidate = jwk.crv === 'secp256k1';
|
|
73
|
+
break;
|
|
74
|
+
case 'ES384':
|
|
75
|
+
candidate = jwk.crv === 'P-384';
|
|
76
|
+
break;
|
|
77
|
+
case 'ES512':
|
|
78
|
+
candidate = jwk.crv === 'P-521';
|
|
79
|
+
break;
|
|
80
|
+
default:
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return candidate;
|
|
84
|
+
});
|
|
85
|
+
const { 0: jwk, length } = candidates;
|
|
86
|
+
if (length === 0) {
|
|
87
|
+
throw new errors_js_1.JWKSNoMatchingKey();
|
|
88
|
+
}
|
|
89
|
+
else if (length !== 1) {
|
|
90
|
+
throw new errors_js_1.JWKSMultipleMatchingKeys();
|
|
91
|
+
}
|
|
92
|
+
const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
|
|
93
|
+
if (cached[joseHeader.alg] === undefined) {
|
|
94
|
+
const keyObject = await (0, import_js_1.importJWK)({ ...jwk, ext: true }, joseHeader.alg);
|
|
95
|
+
if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
|
|
96
|
+
throw new errors_js_1.JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
97
|
+
}
|
|
98
|
+
cached[joseHeader.alg] = keyObject;
|
|
99
|
+
}
|
|
100
|
+
return cached[joseHeader.alg];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.LocalJWKSet = LocalJWKSet;
|
|
104
|
+
function createLocalJWKSet(jwks) {
|
|
105
|
+
return LocalJWKSet.prototype.getKey.bind(new LocalJWKSet(jwks));
|
|
106
|
+
}
|
|
107
|
+
exports.createLocalJWKSet = createLocalJWKSet;
|
|
@@ -2,28 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createRemoteJWKSet = void 0;
|
|
4
4
|
const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
|
|
5
|
-
const import_js_1 = require("../key/import.js");
|
|
6
5
|
const errors_js_1 = require("../util/errors.js");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
switch (typeof alg === 'string' && alg.substr(0, 2)) {
|
|
10
|
-
case 'RS':
|
|
11
|
-
case 'PS':
|
|
12
|
-
return 'RSA';
|
|
13
|
-
case 'ES':
|
|
14
|
-
return 'EC';
|
|
15
|
-
case 'Ed':
|
|
16
|
-
return 'OKP';
|
|
17
|
-
default:
|
|
18
|
-
throw new errors_js_1.JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
function isJWKLike(key) {
|
|
22
|
-
return (0, is_object_js_1.default)(key);
|
|
23
|
-
}
|
|
24
|
-
class RemoteJWKSet {
|
|
6
|
+
const local_js_1 = require("./local.js");
|
|
7
|
+
class RemoteJWKSet extends local_js_1.LocalJWKSet {
|
|
25
8
|
constructor(url, options) {
|
|
26
|
-
|
|
9
|
+
super({ keys: [] });
|
|
10
|
+
this._jwks = undefined;
|
|
27
11
|
if (!(url instanceof URL)) {
|
|
28
12
|
throw new TypeError('url must be an instance of URL');
|
|
29
13
|
}
|
|
@@ -41,78 +25,27 @@ class RemoteJWKSet {
|
|
|
41
25
|
return Date.now() < this._cooldownStarted + this._cooldownDuration;
|
|
42
26
|
}
|
|
43
27
|
async getKey(protectedHeader, token) {
|
|
44
|
-
const joseHeader = {
|
|
45
|
-
...protectedHeader,
|
|
46
|
-
...token.header,
|
|
47
|
-
};
|
|
48
28
|
if (!this._jwks) {
|
|
49
29
|
await this.reload();
|
|
50
30
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (candidate && typeof joseHeader.kid === 'string') {
|
|
54
|
-
candidate = joseHeader.kid === jwk.kid;
|
|
55
|
-
}
|
|
56
|
-
if (candidate && typeof jwk.alg === 'string') {
|
|
57
|
-
candidate = joseHeader.alg === jwk.alg;
|
|
58
|
-
}
|
|
59
|
-
if (candidate && typeof jwk.use === 'string') {
|
|
60
|
-
candidate = jwk.use === 'sig';
|
|
61
|
-
}
|
|
62
|
-
if (candidate && Array.isArray(jwk.key_ops)) {
|
|
63
|
-
candidate = jwk.key_ops.includes('verify');
|
|
64
|
-
}
|
|
65
|
-
if (candidate && joseHeader.alg === 'EdDSA') {
|
|
66
|
-
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
67
|
-
}
|
|
68
|
-
if (candidate) {
|
|
69
|
-
switch (joseHeader.alg) {
|
|
70
|
-
case 'ES256':
|
|
71
|
-
candidate = jwk.crv === 'P-256';
|
|
72
|
-
break;
|
|
73
|
-
case 'ES256K':
|
|
74
|
-
candidate = jwk.crv === 'secp256k1';
|
|
75
|
-
break;
|
|
76
|
-
case 'ES384':
|
|
77
|
-
candidate = jwk.crv === 'P-384';
|
|
78
|
-
break;
|
|
79
|
-
case 'ES512':
|
|
80
|
-
candidate = jwk.crv === 'P-521';
|
|
81
|
-
break;
|
|
82
|
-
default:
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return candidate;
|
|
86
|
-
});
|
|
87
|
-
const { 0: jwk, length } = candidates;
|
|
88
|
-
if (length === 0) {
|
|
89
|
-
if (this.coolingDown() === false) {
|
|
90
|
-
await this.reload();
|
|
91
|
-
return this.getKey(protectedHeader, token);
|
|
92
|
-
}
|
|
93
|
-
throw new errors_js_1.JWKSNoMatchingKey();
|
|
94
|
-
}
|
|
95
|
-
else if (length !== 1) {
|
|
96
|
-
throw new errors_js_1.JWKSMultipleMatchingKeys();
|
|
31
|
+
try {
|
|
32
|
+
return await super.getKey(protectedHeader, token);
|
|
97
33
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (err instanceof errors_js_1.JWKSNoMatchingKey) {
|
|
36
|
+
if (this.coolingDown() === false) {
|
|
37
|
+
await this.reload();
|
|
38
|
+
return super.getKey(protectedHeader, token);
|
|
39
|
+
}
|
|
103
40
|
}
|
|
104
|
-
|
|
41
|
+
throw err;
|
|
105
42
|
}
|
|
106
|
-
return cached[joseHeader.alg];
|
|
107
43
|
}
|
|
108
44
|
async reload() {
|
|
109
45
|
if (!this._pendingFetch) {
|
|
110
46
|
this._pendingFetch = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options)
|
|
111
47
|
.then((json) => {
|
|
112
|
-
if (
|
|
113
|
-
!json ||
|
|
114
|
-
!Array.isArray(json.keys) ||
|
|
115
|
-
!json.keys.every(isJWKLike)) {
|
|
48
|
+
if (!(0, local_js_1.isJWKSLike)(json)) {
|
|
116
49
|
throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed');
|
|
117
50
|
}
|
|
118
51
|
this._jwks = { keys: json.keys };
|
|
@@ -6,14 +6,14 @@ const decrypt_js_1 = require("../runtime/decrypt.js");
|
|
|
6
6
|
const iv_js_1 = require("./iv.js");
|
|
7
7
|
const base64url_js_1 = require("../runtime/base64url.js");
|
|
8
8
|
async function wrap(alg, key, cek, iv) {
|
|
9
|
-
const jweAlgorithm = alg.
|
|
9
|
+
const jweAlgorithm = alg.slice(0, 7);
|
|
10
10
|
iv || (iv = (0, iv_js_1.default)(jweAlgorithm));
|
|
11
11
|
const { ciphertext: encryptedKey, tag } = await (0, encrypt_js_1.default)(jweAlgorithm, cek, key, iv, new Uint8Array(0));
|
|
12
12
|
return { encryptedKey, iv: (0, base64url_js_1.encode)(iv), tag: (0, base64url_js_1.encode)(tag) };
|
|
13
13
|
}
|
|
14
14
|
exports.wrap = wrap;
|
|
15
15
|
async function unwrap(alg, key, encryptedKey, iv, tag) {
|
|
16
|
-
const jweAlgorithm = alg.
|
|
16
|
+
const jweAlgorithm = alg.slice(0, 7);
|
|
17
17
|
return (0, decrypt_js_1.default)(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0));
|
|
18
18
|
}
|
|
19
19
|
exports.unwrap = unwrap;
|
|
@@ -9,7 +9,7 @@ function isAlgorithm(algorithm, name) {
|
|
|
9
9
|
return algorithm.name === name;
|
|
10
10
|
}
|
|
11
11
|
function getHashLength(hash) {
|
|
12
|
-
return parseInt(hash.name.
|
|
12
|
+
return parseInt(hash.name.slice(4), 10);
|
|
13
13
|
}
|
|
14
14
|
function getNamedCurve(alg) {
|
|
15
15
|
switch (alg) {
|
|
@@ -46,7 +46,7 @@ function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
46
46
|
case 'HS512': {
|
|
47
47
|
if (!isAlgorithm(key.algorithm, 'HMAC'))
|
|
48
48
|
throw unusable('HMAC');
|
|
49
|
-
const expected = parseInt(alg.
|
|
49
|
+
const expected = parseInt(alg.slice(2), 10);
|
|
50
50
|
const actual = getHashLength(key.algorithm.hash);
|
|
51
51
|
if (actual !== expected)
|
|
52
52
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -57,7 +57,7 @@ function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
57
57
|
case 'RS512': {
|
|
58
58
|
if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))
|
|
59
59
|
throw unusable('RSASSA-PKCS1-v1_5');
|
|
60
|
-
const expected = parseInt(alg.
|
|
60
|
+
const expected = parseInt(alg.slice(2), 10);
|
|
61
61
|
const actual = getHashLength(key.algorithm.hash);
|
|
62
62
|
if (actual !== expected)
|
|
63
63
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -68,7 +68,7 @@ function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
68
68
|
case 'PS512': {
|
|
69
69
|
if (!isAlgorithm(key.algorithm, 'RSA-PSS'))
|
|
70
70
|
throw unusable('RSA-PSS');
|
|
71
|
-
const expected = parseInt(alg.
|
|
71
|
+
const expected = parseInt(alg.slice(2), 10);
|
|
72
72
|
const actual = getHashLength(key.algorithm.hash);
|
|
73
73
|
if (actual !== expected)
|
|
74
74
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -108,7 +108,7 @@ function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
108
108
|
case 'A256GCM': {
|
|
109
109
|
if (!isAlgorithm(key.algorithm, 'AES-GCM'))
|
|
110
110
|
throw unusable('AES-GCM');
|
|
111
|
-
const expected = parseInt(alg.
|
|
111
|
+
const expected = parseInt(alg.slice(1, 4), 10);
|
|
112
112
|
const actual = key.algorithm.length;
|
|
113
113
|
if (actual !== expected)
|
|
114
114
|
throw unusable(expected, 'algorithm.length');
|
|
@@ -119,7 +119,7 @@ function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
119
119
|
case 'A256KW': {
|
|
120
120
|
if (!isAlgorithm(key.algorithm, 'AES-KW'))
|
|
121
121
|
throw unusable('AES-KW');
|
|
122
|
-
const expected = parseInt(alg.
|
|
122
|
+
const expected = parseInt(alg.slice(1, 4), 10);
|
|
123
123
|
const actual = key.algorithm.length;
|
|
124
124
|
if (actual !== expected)
|
|
125
125
|
throw unusable(expected, 'algorithm.length');
|
|
@@ -141,7 +141,7 @@ function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
141
141
|
case 'RSA-OAEP-512': {
|
|
142
142
|
if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))
|
|
143
143
|
throw unusable('RSA-OAEP');
|
|
144
|
-
const expected = parseInt(alg.
|
|
144
|
+
const expected = parseInt(alg.slice(9), 10) || 1;
|
|
145
145
|
const actual = getHashLength(key.algorithm.hash);
|
|
146
146
|
if (actual !== expected)
|
|
147
147
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
@@ -42,12 +42,12 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) {
|
|
|
42
42
|
throw new errors_js_1.JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
|
|
43
43
|
partyVInfo = (0, base64url_js_1.decode)(joseHeader.apv);
|
|
44
44
|
}
|
|
45
|
-
const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? (0, cek_js_1.bitLength)(joseHeader.enc) : parseInt(alg.
|
|
45
|
+
const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? (0, cek_js_1.bitLength)(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
|
|
46
46
|
if (alg === 'ECDH-ES')
|
|
47
47
|
return sharedSecret;
|
|
48
48
|
if (encryptedKey === undefined)
|
|
49
49
|
throw new errors_js_1.JWEInvalid('JWE Encrypted Key missing');
|
|
50
|
-
return (0, aeskw_js_1.unwrap)(alg.
|
|
50
|
+
return (0, aeskw_js_1.unwrap)(alg.slice(-6), sharedSecret, encryptedKey);
|
|
51
51
|
}
|
|
52
52
|
case 'RSA1_5':
|
|
53
53
|
case 'RSA-OAEP':
|
|
@@ -29,10 +29,12 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
|
|
|
29
29
|
}
|
|
30
30
|
const { apu, apv } = providedParameters;
|
|
31
31
|
let { epk: ephemeralKey } = providedParameters;
|
|
32
|
-
ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key));
|
|
32
|
+
ephemeralKey || (ephemeralKey = (await ECDH.generateEpk(key)).privateKey);
|
|
33
33
|
const { x, y, crv, kty } = await (0, export_js_1.exportJWK)(ephemeralKey);
|
|
34
|
-
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? (0, cek_js_1.bitLength)(enc) : parseInt(alg.
|
|
35
|
-
parameters = { epk: { x,
|
|
34
|
+
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? (0, cek_js_1.bitLength)(enc) : parseInt(alg.slice(-5, -2), 10), apu, apv);
|
|
35
|
+
parameters = { epk: { x, crv, kty } };
|
|
36
|
+
if (kty === 'EC')
|
|
37
|
+
parameters.epk.y = y;
|
|
36
38
|
if (apu)
|
|
37
39
|
parameters.apu = (0, base64url_js_1.encode)(apu);
|
|
38
40
|
if (apv)
|
|
@@ -42,7 +44,7 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
|
|
|
42
44
|
break;
|
|
43
45
|
}
|
|
44
46
|
cek = providedCek || (0, cek_js_1.default)(enc);
|
|
45
|
-
const kwAlg = alg.
|
|
47
|
+
const kwAlg = alg.slice(-6);
|
|
46
48
|
encryptedKey = await (0, aeskw_js_1.wrap)(kwAlg, sharedSecret, cek);
|
|
47
49
|
break;
|
|
48
50
|
}
|
|
@@ -5,7 +5,6 @@ const buffer_1 = require("buffer");
|
|
|
5
5
|
const crypto_1 = require("crypto");
|
|
6
6
|
const errors_js_1 = require("../util/errors.js");
|
|
7
7
|
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
|
|
8
|
-
const secret_key_js_1 = require("./secret_key.js");
|
|
9
8
|
const webcrypto_js_1 = require("./webcrypto.js");
|
|
10
9
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
11
10
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
@@ -13,7 +12,7 @@ const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
|
13
12
|
const ciphers_js_1 = require("./ciphers.js");
|
|
14
13
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
15
14
|
function checkKeySize(key, alg) {
|
|
16
|
-
if (key.symmetricKeySize << 3 !== parseInt(alg.
|
|
15
|
+
if (key.symmetricKeySize << 3 !== parseInt(alg.slice(1, 4), 10)) {
|
|
17
16
|
throw new TypeError(`Invalid key size for alg: ${alg}`);
|
|
18
17
|
}
|
|
19
18
|
}
|
|
@@ -22,7 +21,7 @@ function ensureKeyObject(key, alg, usage) {
|
|
|
22
21
|
return key;
|
|
23
22
|
}
|
|
24
23
|
if (key instanceof Uint8Array) {
|
|
25
|
-
return (0,
|
|
24
|
+
return (0, crypto_1.createSecretKey)(key);
|
|
26
25
|
}
|
|
27
26
|
if ((0, webcrypto_js_1.isCryptoKey)(key)) {
|
|
28
27
|
(0, crypto_key_js_1.checkEncCryptoKey)(key, alg, usage);
|
|
@@ -31,7 +30,7 @@ function ensureKeyObject(key, alg, usage) {
|
|
|
31
30
|
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
32
31
|
}
|
|
33
32
|
const wrap = (alg, key, cek) => {
|
|
34
|
-
const size = parseInt(alg.
|
|
33
|
+
const size = parseInt(alg.slice(1, 4), 10);
|
|
35
34
|
const algorithm = `aes${size}-wrap`;
|
|
36
35
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
37
36
|
throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -43,7 +42,7 @@ const wrap = (alg, key, cek) => {
|
|
|
43
42
|
};
|
|
44
43
|
exports.wrap = wrap;
|
|
45
44
|
const unwrap = (alg, key, encryptedKey) => {
|
|
46
|
-
const size = parseInt(alg.
|
|
45
|
+
const size = parseInt(alg.slice(1, 4), 10);
|
|
47
46
|
const algorithm = `aes${size}-wrap`;
|
|
48
47
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
49
48
|
throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -8,12 +8,12 @@ const checkCekLength = (enc, cek) => {
|
|
|
8
8
|
case 'A128CBC-HS256':
|
|
9
9
|
case 'A192CBC-HS384':
|
|
10
10
|
case 'A256CBC-HS512':
|
|
11
|
-
expected = parseInt(enc.
|
|
11
|
+
expected = parseInt(enc.slice(-3), 10);
|
|
12
12
|
break;
|
|
13
13
|
case 'A128GCM':
|
|
14
14
|
case 'A192GCM':
|
|
15
15
|
case 'A256GCM':
|
|
16
|
-
expected = parseInt(enc.
|
|
16
|
+
expected = parseInt(enc.slice(1, 4), 10);
|
|
17
17
|
break;
|
|
18
18
|
default:
|
|
19
19
|
throw new errors_js_1.JOSENotSupported(`Content Encryption Algorithm ${enc} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -14,13 +14,13 @@ const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
|
14
14
|
const ciphers_js_1 = require("./ciphers.js");
|
|
15
15
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
16
16
|
function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
17
|
-
const keySize = parseInt(enc.
|
|
17
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
18
18
|
if ((0, is_key_object_js_1.default)(cek)) {
|
|
19
19
|
cek = cek.export();
|
|
20
20
|
}
|
|
21
21
|
const encKey = cek.subarray(keySize >> 3);
|
|
22
22
|
const macKey = cek.subarray(0, keySize >> 3);
|
|
23
|
-
const macSize = parseInt(enc.
|
|
23
|
+
const macSize = parseInt(enc.slice(-3), 10);
|
|
24
24
|
const algorithm = `aes-${keySize}-cbc`;
|
|
25
25
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
26
26
|
throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`);
|
|
@@ -48,7 +48,7 @@ function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
48
48
|
return plaintext;
|
|
49
49
|
}
|
|
50
50
|
function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
51
|
-
const keySize = parseInt(enc.
|
|
51
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
52
52
|
const algorithm = `aes-${keySize}-gcm`;
|
|
53
53
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
54
54
|
throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`);
|
|
@@ -13,7 +13,7 @@ const is_key_object_js_1 = require("./is_key_object.js");
|
|
|
13
13
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
14
14
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
15
15
|
const generateKeyPair = (0, util_1.promisify)(crypto_1.generateKeyPair);
|
|
16
|
-
|
|
16
|
+
async function deriveKey(publicKee, privateKee, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) {
|
|
17
17
|
let publicKey;
|
|
18
18
|
if ((0, webcrypto_js_1.isCryptoKey)(publicKee)) {
|
|
19
19
|
(0, crypto_key_js_1.checkEncCryptoKey)(publicKee, 'ECDH-ES');
|
|
@@ -39,9 +39,9 @@ const deriveKey = (publicKee, privateKee, algorithm, keyLength, apu = new Uint8A
|
|
|
39
39
|
const value = (0, buffer_utils_js_1.concat)((0, buffer_utils_js_1.lengthAndInput)(buffer_utils_js_1.encoder.encode(algorithm)), (0, buffer_utils_js_1.lengthAndInput)(apu), (0, buffer_utils_js_1.lengthAndInput)(apv), (0, buffer_utils_js_1.uint32be)(keyLength));
|
|
40
40
|
const sharedSecret = (0, crypto_1.diffieHellman)({ privateKey, publicKey });
|
|
41
41
|
return (0, buffer_utils_js_1.concatKdf)(digest_js_1.default, sharedSecret, keyLength, value);
|
|
42
|
-
}
|
|
42
|
+
}
|
|
43
43
|
exports.deriveKey = deriveKey;
|
|
44
|
-
|
|
44
|
+
async function generateEpk(kee) {
|
|
45
45
|
let key;
|
|
46
46
|
if ((0, webcrypto_js_1.isCryptoKey)(kee)) {
|
|
47
47
|
key = crypto_1.KeyObject.from(kee);
|
|
@@ -54,18 +54,18 @@ const generateEpk = async (kee) => {
|
|
|
54
54
|
}
|
|
55
55
|
switch (key.asymmetricKeyType) {
|
|
56
56
|
case 'x25519':
|
|
57
|
-
return
|
|
57
|
+
return generateKeyPair('x25519');
|
|
58
58
|
case 'x448': {
|
|
59
|
-
return
|
|
59
|
+
return generateKeyPair('x448');
|
|
60
60
|
}
|
|
61
61
|
case 'ec': {
|
|
62
62
|
const namedCurve = (0, get_named_curve_js_1.default)(key);
|
|
63
|
-
return
|
|
63
|
+
return generateKeyPair('ec', { namedCurve });
|
|
64
64
|
}
|
|
65
65
|
default:
|
|
66
66
|
throw new errors_js_1.JOSENotSupported('Invalid or unsupported EPK');
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|
|
69
69
|
exports.generateEpk = generateEpk;
|
|
70
70
|
const ecdhAllowed = (key) => ['P-256', 'P-384', 'P-521', 'X25519', 'X448'].includes((0, get_named_curve_js_1.default)(key));
|
|
71
71
|
exports.ecdhAllowed = ecdhAllowed;
|
|
@@ -13,7 +13,7 @@ const errors_js_1 = require("../util/errors.js");
|
|
|
13
13
|
const ciphers_js_1 = require("./ciphers.js");
|
|
14
14
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
15
15
|
function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
16
|
-
const keySize = parseInt(enc.
|
|
16
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
17
17
|
if ((0, is_key_object_js_1.default)(cek)) {
|
|
18
18
|
cek = cek.export();
|
|
19
19
|
}
|
|
@@ -25,12 +25,12 @@ function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
25
25
|
}
|
|
26
26
|
const cipher = (0, crypto_1.createCipheriv)(algorithm, encKey, iv);
|
|
27
27
|
const ciphertext = (0, buffer_utils_js_1.concat)(cipher.update(plaintext), cipher.final());
|
|
28
|
-
const macSize = parseInt(enc.
|
|
28
|
+
const macSize = parseInt(enc.slice(-3), 10);
|
|
29
29
|
const tag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize);
|
|
30
30
|
return { ciphertext, tag };
|
|
31
31
|
}
|
|
32
32
|
function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
33
|
-
const keySize = parseInt(enc.
|
|
33
|
+
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
34
34
|
const algorithm = `aes-${keySize}-gcm`;
|
|
35
35
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
36
36
|
throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`);
|
|
@@ -16,7 +16,7 @@ async function generateSecret(alg, options) {
|
|
|
16
16
|
case 'A128CBC-HS256':
|
|
17
17
|
case 'A192CBC-HS384':
|
|
18
18
|
case 'A256CBC-HS512':
|
|
19
|
-
length = parseInt(alg.
|
|
19
|
+
length = parseInt(alg.slice(-3), 10);
|
|
20
20
|
break;
|
|
21
21
|
case 'A128KW':
|
|
22
22
|
case 'A192KW':
|
|
@@ -27,7 +27,7 @@ async function generateSecret(alg, options) {
|
|
|
27
27
|
case 'A128GCM':
|
|
28
28
|
case 'A192GCM':
|
|
29
29
|
case 'A256GCM':
|
|
30
|
-
length = parseInt(alg.
|
|
30
|
+
length = parseInt(alg.slice(1, 4), 10);
|
|
31
31
|
break;
|
|
32
32
|
default:
|
|
33
33
|
throw new errors_js_1.JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
@@ -45,10 +45,10 @@ const getNamedCurve = (kee, raw) => {
|
|
|
45
45
|
switch (key.asymmetricKeyType) {
|
|
46
46
|
case 'ed25519':
|
|
47
47
|
case 'ed448':
|
|
48
|
-
return `Ed${key.asymmetricKeyType.
|
|
48
|
+
return `Ed${key.asymmetricKeyType.slice(2)}`;
|
|
49
49
|
case 'x25519':
|
|
50
50
|
case 'x448':
|
|
51
|
-
return `X${key.asymmetricKeyType.
|
|
51
|
+
return `X${key.asymmetricKeyType.slice(1)}`;
|
|
52
52
|
case 'ec': {
|
|
53
53
|
if (exports.weakMap.has(key)) {
|
|
54
54
|
return exports.weakMap.get(key);
|