jose 4.3.7 → 4.5.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 +5 -3
- package/dist/browser/index.js +2 -0
- package/dist/browser/jwks/local.js +97 -0
- package/dist/browser/jwks/remote.js +29 -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/browser/util/decode_jwt.js +32 -0
- package/dist/node/cjs/index.js +5 -1
- package/dist/node/cjs/jwks/local.js +103 -0
- package/dist/node/cjs/jwks/remote.js +28 -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 +3 -3
- package/dist/node/cjs/runtime/base64url.js +4 -4
- 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/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/cjs/util/decode_jwt.js +36 -0
- package/dist/node/esm/index.js +2 -0
- package/dist/node/esm/jwks/local.js +97 -0
- package/dist/node/esm/jwks/remote.js +29 -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 +3 -3
- package/dist/node/esm/runtime/base64url.js +4 -4
- 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/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/node/esm/util/decode_jwt.js +32 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/jwks/local.d.ts +9 -0
- package/dist/types/types.d.ts +3 -0
- package/dist/types/util/decode_jwt.d.ts +2 -0
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ function subtleMapping(jwk) {
|
|
|
11
11
|
case 'HS256':
|
|
12
12
|
case 'HS384':
|
|
13
13
|
case 'HS512':
|
|
14
|
-
algorithm = { name: 'HMAC', hash: `SHA-${jwk.alg.
|
|
14
|
+
algorithm = { name: 'HMAC', hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
15
15
|
keyUsages = ['sign', 'verify'];
|
|
16
16
|
break;
|
|
17
17
|
case 'A128CBC-HS256':
|
|
@@ -49,13 +49,13 @@ function subtleMapping(jwk) {
|
|
|
49
49
|
case 'PS256':
|
|
50
50
|
case 'PS384':
|
|
51
51
|
case 'PS512':
|
|
52
|
-
algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.
|
|
52
|
+
algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
53
53
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
54
54
|
break;
|
|
55
55
|
case 'RS256':
|
|
56
56
|
case 'RS384':
|
|
57
57
|
case 'RS512':
|
|
58
|
-
algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.
|
|
58
|
+
algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
59
59
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
60
60
|
break;
|
|
61
61
|
case 'RSA-OAEP':
|
|
@@ -64,7 +64,7 @@ function subtleMapping(jwk) {
|
|
|
64
64
|
case 'RSA-OAEP-512':
|
|
65
65
|
algorithm = {
|
|
66
66
|
name: 'RSA-OAEP',
|
|
67
|
-
hash: `SHA-${parseInt(jwk.alg.
|
|
67
|
+
hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`,
|
|
68
68
|
};
|
|
69
69
|
keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey'];
|
|
70
70
|
break;
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { decode as base64url } from './base64url.js';
|
|
2
|
+
import { decoder } from '../lib/buffer_utils.js';
|
|
3
|
+
import isObject from '../lib/is_object.js';
|
|
4
|
+
import { JWTInvalid } from './errors.js';
|
|
5
|
+
export function decodeJwt(jwt) {
|
|
6
|
+
if (typeof jwt !== 'string')
|
|
7
|
+
throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
|
|
8
|
+
const { 1: payload, length } = jwt.split('.');
|
|
9
|
+
if (length === 5)
|
|
10
|
+
throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
|
|
11
|
+
if (length !== 3)
|
|
12
|
+
throw new JWTInvalid('Invalid JWT');
|
|
13
|
+
if (!payload)
|
|
14
|
+
throw new JWTInvalid('JWTs must contain a payload');
|
|
15
|
+
let decoded;
|
|
16
|
+
try {
|
|
17
|
+
decoded = base64url(payload);
|
|
18
|
+
}
|
|
19
|
+
catch (_a) {
|
|
20
|
+
throw new JWTInvalid('Failed to parse the base64url encoded payload');
|
|
21
|
+
}
|
|
22
|
+
let result;
|
|
23
|
+
try {
|
|
24
|
+
result = JSON.parse(decoder.decode(decoded));
|
|
25
|
+
}
|
|
26
|
+
catch (_b) {
|
|
27
|
+
throw new JWTInvalid('Failed to parse the decoded payload as JSON');
|
|
28
|
+
}
|
|
29
|
+
if (!isObject(result))
|
|
30
|
+
throw new JWTInvalid('Invalid JWT Claims Set');
|
|
31
|
+
return result;
|
|
32
|
+
}
|
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.decodeJwt = 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");
|
|
@@ -52,6 +54,8 @@ Object.defineProperty(exports, "importX509", { enumerable: true, get: function (
|
|
|
52
54
|
Object.defineProperty(exports, "importJWK", { enumerable: true, get: function () { return import_js_1.importJWK; } });
|
|
53
55
|
var decode_protected_header_js_1 = require("./util/decode_protected_header.js");
|
|
54
56
|
Object.defineProperty(exports, "decodeProtectedHeader", { enumerable: true, get: function () { return decode_protected_header_js_1.decodeProtectedHeader; } });
|
|
57
|
+
var decode_jwt_js_1 = require("./util/decode_jwt.js");
|
|
58
|
+
Object.defineProperty(exports, "decodeJwt", { enumerable: true, get: function () { return decode_jwt_js_1.decodeJwt; } });
|
|
55
59
|
exports.errors = require("./util/errors.js");
|
|
56
60
|
var generate_key_pair_js_1 = require("./key/generate_key_pair.js");
|
|
57
61
|
Object.defineProperty(exports, "generateKeyPair", { enumerable: true, get: function () { return generate_key_pair_js_1.generateKeyPair; } });
|
|
@@ -0,0 +1,103 @@
|
|
|
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 { alg, kid } = { ...protectedHeader, ...token.header };
|
|
46
|
+
const candidates = this._jwks.keys.filter((jwk) => {
|
|
47
|
+
let candidate = jwk.kty === getKtyFromAlg(alg);
|
|
48
|
+
if (candidate && typeof kid === 'string') {
|
|
49
|
+
candidate = kid === jwk.kid;
|
|
50
|
+
}
|
|
51
|
+
if (candidate && typeof jwk.alg === 'string') {
|
|
52
|
+
candidate = alg === jwk.alg;
|
|
53
|
+
}
|
|
54
|
+
if (candidate && typeof jwk.use === 'string') {
|
|
55
|
+
candidate = jwk.use === 'sig';
|
|
56
|
+
}
|
|
57
|
+
if (candidate && Array.isArray(jwk.key_ops)) {
|
|
58
|
+
candidate = jwk.key_ops.includes('verify');
|
|
59
|
+
}
|
|
60
|
+
if (candidate && alg === 'EdDSA') {
|
|
61
|
+
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
62
|
+
}
|
|
63
|
+
if (candidate) {
|
|
64
|
+
switch (alg) {
|
|
65
|
+
case 'ES256':
|
|
66
|
+
candidate = jwk.crv === 'P-256';
|
|
67
|
+
break;
|
|
68
|
+
case 'ES256K':
|
|
69
|
+
candidate = jwk.crv === 'secp256k1';
|
|
70
|
+
break;
|
|
71
|
+
case 'ES384':
|
|
72
|
+
candidate = jwk.crv === 'P-384';
|
|
73
|
+
break;
|
|
74
|
+
case 'ES512':
|
|
75
|
+
candidate = jwk.crv === 'P-521';
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return candidate;
|
|
80
|
+
});
|
|
81
|
+
const { 0: jwk, length } = candidates;
|
|
82
|
+
if (length === 0) {
|
|
83
|
+
throw new errors_js_1.JWKSNoMatchingKey();
|
|
84
|
+
}
|
|
85
|
+
else if (length !== 1) {
|
|
86
|
+
throw new errors_js_1.JWKSMultipleMatchingKeys();
|
|
87
|
+
}
|
|
88
|
+
const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
|
|
89
|
+
if (cached[alg] === undefined) {
|
|
90
|
+
const keyObject = await (0, import_js_1.importJWK)({ ...jwk, ext: true }, alg);
|
|
91
|
+
if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
|
|
92
|
+
throw new errors_js_1.JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
93
|
+
}
|
|
94
|
+
cached[alg] = keyObject;
|
|
95
|
+
}
|
|
96
|
+
return cached[alg];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.LocalJWKSet = LocalJWKSet;
|
|
100
|
+
function createLocalJWKSet(jwks) {
|
|
101
|
+
return LocalJWKSet.prototype.getKey.bind(new LocalJWKSet(jwks));
|
|
102
|
+
}
|
|
103
|
+
exports.createLocalJWKSet = createLocalJWKSet;
|
|
@@ -2,28 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createRemoteJWKSet = void 0;
|
|
4
4
|
const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
|
|
5
|
-
const
|
|
5
|
+
const env_js_1 = require("../runtime/env.js");
|
|
6
6
|
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 {
|
|
7
|
+
const local_js_1 = require("./local.js");
|
|
8
|
+
class RemoteJWKSet extends local_js_1.LocalJWKSet {
|
|
25
9
|
constructor(url, options) {
|
|
26
|
-
|
|
10
|
+
super({ keys: [] });
|
|
11
|
+
this._jwks = undefined;
|
|
27
12
|
if (!(url instanceof URL)) {
|
|
28
13
|
throw new TypeError('url must be an instance of URL');
|
|
29
14
|
}
|
|
@@ -41,78 +26,40 @@ class RemoteJWKSet {
|
|
|
41
26
|
return Date.now() < this._cooldownStarted + this._cooldownDuration;
|
|
42
27
|
}
|
|
43
28
|
async getKey(protectedHeader, token) {
|
|
44
|
-
const joseHeader = {
|
|
45
|
-
...protectedHeader,
|
|
46
|
-
...token.header,
|
|
47
|
-
};
|
|
48
29
|
if (!this._jwks) {
|
|
49
30
|
await this.reload();
|
|
50
31
|
}
|
|
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();
|
|
32
|
+
try {
|
|
33
|
+
return await super.getKey(protectedHeader, token);
|
|
97
34
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (err instanceof errors_js_1.JWKSNoMatchingKey) {
|
|
37
|
+
if (this.coolingDown() === false) {
|
|
38
|
+
await this.reload();
|
|
39
|
+
return super.getKey(protectedHeader, token);
|
|
40
|
+
}
|
|
103
41
|
}
|
|
104
|
-
|
|
42
|
+
throw err;
|
|
105
43
|
}
|
|
106
|
-
return cached[joseHeader.alg];
|
|
107
44
|
}
|
|
108
45
|
async reload() {
|
|
46
|
+
if (this._pendingFetch && (0, env_js_1.isCloudflareWorkers)()) {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
const isDone = () => {
|
|
49
|
+
if (this._pendingFetch === undefined) {
|
|
50
|
+
resolve();
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
setTimeout(isDone, 5);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
isDone();
|
|
57
|
+
});
|
|
58
|
+
}
|
|
109
59
|
if (!this._pendingFetch) {
|
|
110
60
|
this._pendingFetch = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options)
|
|
111
61
|
.then((json) => {
|
|
112
|
-
if (
|
|
113
|
-
!json ||
|
|
114
|
-
!Array.isArray(json.keys) ||
|
|
115
|
-
!json.keys.every(isJWKLike)) {
|
|
62
|
+
if (!(0, local_js_1.isJWKSLike)(json)) {
|
|
116
63
|
throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed');
|
|
117
64
|
}
|
|
118
65
|
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
|
}
|
|
@@ -12,7 +12,7 @@ const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
|
12
12
|
const ciphers_js_1 = require("./ciphers.js");
|
|
13
13
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
14
14
|
function checkKeySize(key, alg) {
|
|
15
|
-
if (key.symmetricKeySize << 3 !== parseInt(alg.
|
|
15
|
+
if (key.symmetricKeySize << 3 !== parseInt(alg.slice(1, 4), 10)) {
|
|
16
16
|
throw new TypeError(`Invalid key size for alg: ${alg}`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -30,7 +30,7 @@ function ensureKeyObject(key, alg, usage) {
|
|
|
30
30
|
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
31
31
|
}
|
|
32
32
|
const wrap = (alg, key, cek) => {
|
|
33
|
-
const size = parseInt(alg.
|
|
33
|
+
const size = parseInt(alg.slice(1, 4), 10);
|
|
34
34
|
const algorithm = `aes${size}-wrap`;
|
|
35
35
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
36
36
|
throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -42,7 +42,7 @@ const wrap = (alg, key, cek) => {
|
|
|
42
42
|
};
|
|
43
43
|
exports.wrap = wrap;
|
|
44
44
|
const unwrap = (alg, key, encryptedKey) => {
|
|
45
|
-
const size = parseInt(alg.
|
|
45
|
+
const size = parseInt(alg.slice(1, 4), 10);
|
|
46
46
|
const algorithm = `aes${size}-wrap`;
|
|
47
47
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
48
48
|
throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.decode = exports.encode = exports.encodeBase64 = exports.decodeBase64 = void 0;
|
|
4
4
|
const buffer_1 = require("buffer");
|
|
5
5
|
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
|
|
6
|
-
let
|
|
6
|
+
let encode;
|
|
7
|
+
exports.encode = encode;
|
|
7
8
|
function normalize(input) {
|
|
8
9
|
let encoded = input;
|
|
9
10
|
if (encoded instanceof Uint8Array) {
|
|
@@ -12,15 +13,14 @@ function normalize(input) {
|
|
|
12
13
|
return encoded;
|
|
13
14
|
}
|
|
14
15
|
if (buffer_1.Buffer.isEncoding('base64url')) {
|
|
15
|
-
|
|
16
|
+
exports.encode = encode = (input) => buffer_1.Buffer.from(input).toString('base64url');
|
|
16
17
|
}
|
|
17
18
|
else {
|
|
18
|
-
|
|
19
|
+
exports.encode = encode = (input) => buffer_1.Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
|
19
20
|
}
|
|
20
21
|
const decodeBase64 = (input) => buffer_1.Buffer.from(input, 'base64');
|
|
21
22
|
exports.decodeBase64 = decodeBase64;
|
|
22
23
|
const encodeBase64 = (input) => buffer_1.Buffer.from(input).toString('base64');
|
|
23
24
|
exports.encodeBase64 = encodeBase64;
|
|
24
|
-
exports.encode = encodeImpl;
|
|
25
25
|
const decode = (input) => buffer_1.Buffer.from(normalize(input), 'base64');
|
|
26
26
|
exports.decode = decode;
|
|
@@ -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`);
|