jose 3.17.0 → 3.20.1
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 +10 -3
- package/dist/browser/jwe/compact/decrypt.js +5 -1
- package/dist/browser/jwe/flattened/decrypt.js +5 -0
- package/dist/browser/jwk/embedded.js +3 -3
- package/dist/browser/jwk/from_key_like.js +2 -2
- package/dist/browser/jwk/parse.js +2 -31
- package/dist/browser/jwks/remote.js +7 -10
- package/dist/browser/jws/compact/verify.js +5 -1
- package/dist/browser/jws/flattened/verify.js +5 -0
- package/dist/browser/jwt/decrypt.js +5 -1
- package/dist/browser/jwt/encrypt.js +1 -1
- package/dist/browser/{lib/jwt_producer.js → jwt/produce.js} +4 -4
- package/dist/browser/jwt/sign.js +1 -1
- package/dist/browser/jwt/unsecured.js +1 -1
- package/dist/browser/jwt/verify.js +5 -1
- package/dist/browser/key/export.js +12 -0
- package/dist/browser/key/import.js +119 -0
- package/dist/browser/lib/check_key_type.js +33 -16
- package/dist/browser/lib/decrypt_key_management.js +37 -37
- package/dist/browser/lib/encrypt_key_management.js +2 -2
- package/dist/browser/lib/format_pem.js +4 -0
- package/dist/browser/runtime/asn1.js +119 -0
- package/dist/browser/runtime/base64url.js +12 -7
- package/dist/browser/runtime/fetch_jwks.js +18 -5
- package/dist/browser/runtime/is_key_like.js +5 -0
- package/dist/browser/util/errors.js +10 -3
- package/dist/node/cjs/jwe/compact/decrypt.js +5 -1
- package/dist/node/cjs/jwe/flattened/decrypt.js +5 -0
- package/dist/node/cjs/jwk/embedded.js +3 -3
- package/dist/node/cjs/jwk/from_key_like.js +2 -2
- package/dist/node/cjs/jwk/parse.js +2 -31
- package/dist/node/cjs/jwks/remote.js +7 -10
- package/dist/node/cjs/jws/compact/verify.js +5 -1
- package/dist/node/cjs/jws/flattened/verify.js +5 -0
- package/dist/node/cjs/jwt/decrypt.js +5 -1
- package/dist/node/cjs/jwt/encrypt.js +2 -2
- package/dist/node/cjs/{lib/jwt_producer.js → jwt/produce.js} +5 -4
- package/dist/node/cjs/jwt/sign.js +2 -2
- package/dist/node/cjs/jwt/unsecured.js +2 -2
- package/dist/node/cjs/jwt/verify.js +5 -1
- package/dist/node/cjs/key/export.js +18 -0
- package/dist/node/cjs/key/import.js +126 -0
- package/dist/node/cjs/lib/check_key_type.js +33 -16
- package/dist/node/cjs/lib/decrypt_key_management.js +37 -37
- package/dist/node/cjs/lib/encrypt_key_management.js +2 -2
- package/dist/node/cjs/lib/format_pem.js +6 -0
- package/dist/node/cjs/runtime/asn1.js +46 -0
- package/dist/node/cjs/runtime/base64url.js +5 -1
- package/dist/node/cjs/runtime/fetch_jwks.js +5 -1
- package/dist/node/cjs/runtime/is_key_like.js +11 -0
- package/dist/node/cjs/util/errors.js +12 -4
- package/dist/node/esm/jwe/compact/decrypt.js +5 -1
- package/dist/node/esm/jwe/flattened/decrypt.js +5 -0
- package/dist/node/esm/jwk/embedded.js +3 -3
- package/dist/node/esm/jwk/from_key_like.js +2 -2
- package/dist/node/esm/jwk/parse.js +2 -31
- package/dist/node/esm/jwks/remote.js +7 -10
- package/dist/node/esm/jws/compact/verify.js +5 -1
- package/dist/node/esm/jws/flattened/verify.js +5 -0
- package/dist/node/esm/jwt/decrypt.js +5 -1
- package/dist/node/esm/jwt/encrypt.js +1 -1
- package/dist/node/esm/{lib/jwt_producer.js → jwt/produce.js} +4 -4
- package/dist/node/esm/jwt/sign.js +1 -1
- package/dist/node/esm/jwt/unsecured.js +1 -1
- package/dist/node/esm/jwt/verify.js +5 -1
- package/dist/node/esm/key/export.js +12 -0
- package/dist/node/esm/key/import.js +119 -0
- package/dist/node/esm/lib/check_key_type.js +33 -16
- package/dist/node/esm/lib/decrypt_key_management.js +37 -37
- package/dist/node/esm/lib/encrypt_key_management.js +2 -2
- package/dist/node/esm/lib/format_pem.js +4 -0
- package/dist/node/esm/runtime/asn1.js +39 -0
- package/dist/node/esm/runtime/base64url.js +2 -0
- package/dist/node/esm/runtime/fetch_jwks.js +6 -2
- package/dist/node/esm/runtime/is_key_like.js +8 -0
- package/dist/node/esm/util/errors.js +10 -3
- package/dist/types/jwe/compact/decrypt.d.ts +3 -2
- package/dist/types/jwe/compact/encrypt.d.ts +1 -1
- package/dist/types/jwe/flattened/decrypt.d.ts +3 -2
- package/dist/types/jwe/flattened/encrypt.d.ts +1 -1
- package/dist/types/jwe/general/decrypt.d.ts +3 -2
- package/dist/types/jwk/embedded.d.ts +2 -3
- package/dist/types/jwk/from_key_like.d.ts +1 -1
- package/dist/types/jwk/parse.d.ts +1 -1
- package/dist/types/jws/compact/sign.d.ts +1 -1
- package/dist/types/jws/compact/verify.d.ts +3 -2
- package/dist/types/jws/flattened/sign.d.ts +1 -1
- package/dist/types/jws/flattened/verify.d.ts +3 -2
- package/dist/types/jws/general/sign.d.ts +1 -1
- package/dist/types/jws/general/verify.d.ts +3 -2
- package/dist/types/jwt/decrypt.d.ts +3 -2
- package/dist/types/jwt/encrypt.d.ts +2 -2
- package/dist/types/{lib/jwt_producer.d.ts → jwt/produce.d.ts} +1 -1
- package/dist/types/jwt/sign.d.ts +2 -2
- package/dist/types/jwt/unsecured.d.ts +1 -1
- package/dist/types/jwt/verify.d.ts +3 -2
- package/dist/types/key/export.d.ts +5 -0
- package/dist/types/key/import.d.ts +9 -0
- package/dist/types/types.d.ts +101 -5
- package/dist/types/util/errors.d.ts +5 -0
- package/dist/types/util/generate_key_pair.d.ts +2 -2
- package/dist/types/util/generate_secret.d.ts +1 -1
- package/package.json +20 -8
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import globalThis, { isCloudflareWorkers, isNodeJs } from './global.js';
|
|
2
|
+
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
3
|
+
import invalidKeyInput from './invalid_key_input.js';
|
|
4
|
+
import { encodeBase64 } from './base64url.js';
|
|
5
|
+
import formatPEM from '../lib/format_pem.js';
|
|
6
|
+
import { JOSENotSupported } from '../util/errors.js';
|
|
7
|
+
const genericExport = async (keyType, keyFormat, key) => {
|
|
8
|
+
if (!isCryptoKey(key)) {
|
|
9
|
+
throw new TypeError(invalidKeyInput(key, 'CryptoKey'));
|
|
10
|
+
}
|
|
11
|
+
if (!key.extractable) {
|
|
12
|
+
throw new TypeError('CryptoKey is not extractable');
|
|
13
|
+
}
|
|
14
|
+
if (key.type !== keyType) {
|
|
15
|
+
throw new TypeError(`key is not a ${keyType} key`);
|
|
16
|
+
}
|
|
17
|
+
return formatPEM(encodeBase64(new Uint8Array(await crypto.subtle.exportKey(keyFormat, key))), `${keyType.toUpperCase()} KEY`);
|
|
18
|
+
};
|
|
19
|
+
export const toSPKI = (key) => {
|
|
20
|
+
return genericExport('public', 'spki', key);
|
|
21
|
+
};
|
|
22
|
+
export const toPKCS8 = (key) => {
|
|
23
|
+
return genericExport('private', 'pkcs8', key);
|
|
24
|
+
};
|
|
25
|
+
const getNamedCurve = (keyData) => {
|
|
26
|
+
const keyDataStr = keyData.toString();
|
|
27
|
+
switch (true) {
|
|
28
|
+
case keyDataStr.includes(new Uint8Array([
|
|
29
|
+
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
|
|
30
|
+
0x3d, 0x03, 0x01, 0x07,
|
|
31
|
+
]).toString()):
|
|
32
|
+
return 'P-256';
|
|
33
|
+
case keyDataStr.includes(new Uint8Array([
|
|
34
|
+
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
|
|
35
|
+
0x22,
|
|
36
|
+
]).toString()):
|
|
37
|
+
return 'P-384';
|
|
38
|
+
case keyDataStr.includes(new Uint8Array([
|
|
39
|
+
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
|
|
40
|
+
0x23,
|
|
41
|
+
]).toString()):
|
|
42
|
+
return 'P-521';
|
|
43
|
+
case (isCloudflareWorkers() || isNodeJs()) &&
|
|
44
|
+
keyDataStr.includes(new Uint8Array([0x06, 0x03, 0x2b, 0x65, 0x70]).toString()):
|
|
45
|
+
return 'Ed25519';
|
|
46
|
+
case isNodeJs() &&
|
|
47
|
+
keyDataStr.includes(new Uint8Array([0x06, 0x03, 0x2b, 0x65, 0x71]).toString()):
|
|
48
|
+
return 'Ed448';
|
|
49
|
+
default:
|
|
50
|
+
throw new JOSENotSupported('Invalid or unsupported EC Key Curve or OKP Key Sub Type');
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const genericImport = async (replace, keyFormat, pem, alg, options) => {
|
|
54
|
+
var _a;
|
|
55
|
+
let algorithm;
|
|
56
|
+
let keyUsages;
|
|
57
|
+
const keyData = new Uint8Array(globalThis
|
|
58
|
+
.atob(pem.replace(replace, ''))
|
|
59
|
+
.split('')
|
|
60
|
+
.map((c) => c.charCodeAt(0)));
|
|
61
|
+
const isPublic = keyFormat === 'spki';
|
|
62
|
+
switch (alg) {
|
|
63
|
+
case 'PS256':
|
|
64
|
+
case 'PS384':
|
|
65
|
+
case 'PS512':
|
|
66
|
+
algorithm = { name: 'RSA-PSS', hash: { name: `SHA-${alg.substr(-3)}` } };
|
|
67
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
68
|
+
break;
|
|
69
|
+
case 'RS256':
|
|
70
|
+
case 'RS384':
|
|
71
|
+
case 'RS512':
|
|
72
|
+
algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: `SHA-${alg.substr(-3)}` } };
|
|
73
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
74
|
+
break;
|
|
75
|
+
case 'RSA-OAEP':
|
|
76
|
+
case 'RSA-OAEP-256':
|
|
77
|
+
case 'RSA-OAEP-384':
|
|
78
|
+
case 'RSA-OAEP-512':
|
|
79
|
+
algorithm = {
|
|
80
|
+
name: 'RSA-OAEP',
|
|
81
|
+
hash: { name: `SHA-${parseInt(alg.substr(-3), 10) || 1}` },
|
|
82
|
+
};
|
|
83
|
+
keyUsages = isPublic ? ['encrypt', 'wrapKey'] : ['decrypt', 'unwrapKey'];
|
|
84
|
+
break;
|
|
85
|
+
case 'ES256':
|
|
86
|
+
algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
|
|
87
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
88
|
+
break;
|
|
89
|
+
case 'ES384':
|
|
90
|
+
algorithm = { name: 'ECDSA', namedCurve: 'P-384' };
|
|
91
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
92
|
+
break;
|
|
93
|
+
case 'ES512':
|
|
94
|
+
algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
|
|
95
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
96
|
+
break;
|
|
97
|
+
case 'ECDH-ES':
|
|
98
|
+
case 'ECDH-ES+A128KW':
|
|
99
|
+
case 'ECDH-ES+A192KW':
|
|
100
|
+
case 'ECDH-ES+A256KW':
|
|
101
|
+
algorithm = { name: 'ECDH', namedCurve: getNamedCurve(keyData) };
|
|
102
|
+
keyUsages = isPublic ? [] : ['deriveBits'];
|
|
103
|
+
break;
|
|
104
|
+
case (isCloudflareWorkers() || isNodeJs()) && 'EdDSA':
|
|
105
|
+
const namedCurve = getNamedCurve(keyData).toUpperCase();
|
|
106
|
+
algorithm = { name: `NODE-${namedCurve}`, namedCurve: `NODE-${namedCurve}` };
|
|
107
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
108
|
+
break;
|
|
109
|
+
default:
|
|
110
|
+
throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value');
|
|
111
|
+
}
|
|
112
|
+
return crypto.subtle.importKey(keyFormat, keyData, algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, keyUsages);
|
|
113
|
+
};
|
|
114
|
+
export const fromPKCS8 = (pem, alg, options) => {
|
|
115
|
+
return genericImport(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, 'pkcs8', pem, alg, options);
|
|
116
|
+
};
|
|
117
|
+
export const fromSPKI = (pem, alg, options) => {
|
|
118
|
+
return genericImport(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, 'spki', pem, alg, options);
|
|
119
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { encoder, decoder } from '../lib/buffer_utils.js';
|
|
2
2
|
import globalThis from './global.js';
|
|
3
|
-
export const
|
|
3
|
+
export const encodeBase64 = (input) => {
|
|
4
4
|
let unencoded = input;
|
|
5
5
|
if (typeof unencoded === 'string') {
|
|
6
6
|
unencoded = encoder.encode(unencoded);
|
|
@@ -10,8 +10,16 @@ export const encode = (input) => {
|
|
|
10
10
|
for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) {
|
|
11
11
|
arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE)));
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
return globalThis.btoa(arr.join(''));
|
|
14
|
+
};
|
|
15
|
+
export const encode = (input) => {
|
|
16
|
+
return encodeBase64(input).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
|
17
|
+
};
|
|
18
|
+
export const decodeBase64 = (encoded) => {
|
|
19
|
+
return new Uint8Array(globalThis
|
|
20
|
+
.atob(encoded)
|
|
21
|
+
.split('')
|
|
22
|
+
.map((c) => c.charCodeAt(0)));
|
|
15
23
|
};
|
|
16
24
|
export const decode = (input) => {
|
|
17
25
|
let encoded = input;
|
|
@@ -20,10 +28,7 @@ export const decode = (input) => {
|
|
|
20
28
|
}
|
|
21
29
|
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '');
|
|
22
30
|
try {
|
|
23
|
-
return
|
|
24
|
-
.atob(encoded)
|
|
25
|
-
.split('')
|
|
26
|
-
.map((c) => c.charCodeAt(0)));
|
|
31
|
+
return decodeBase64(encoded);
|
|
27
32
|
}
|
|
28
33
|
catch (_a) {
|
|
29
34
|
throw new TypeError('The input to be decoded is not correctly encoded.');
|
|
@@ -1,23 +1,36 @@
|
|
|
1
|
-
import { JOSEError } from '../util/errors.js';
|
|
2
|
-
import globalThis from './global.js';
|
|
1
|
+
import { JOSEError, JWKSTimeout } from '../util/errors.js';
|
|
2
|
+
import globalThis, { isCloudflareWorkers } from './global.js';
|
|
3
3
|
const fetchJwks = async (url, timeout) => {
|
|
4
4
|
let controller;
|
|
5
|
+
let id;
|
|
6
|
+
let timedOut = false;
|
|
5
7
|
if (typeof AbortController === 'function') {
|
|
6
8
|
controller = new AbortController();
|
|
7
|
-
setTimeout(() =>
|
|
9
|
+
id = setTimeout(() => {
|
|
10
|
+
timedOut = true;
|
|
11
|
+
controller.abort();
|
|
12
|
+
}, timeout);
|
|
8
13
|
}
|
|
9
|
-
const response = await globalThis
|
|
14
|
+
const response = await globalThis
|
|
15
|
+
.fetch(url.href, {
|
|
10
16
|
signal: controller ? controller.signal : undefined,
|
|
11
17
|
redirect: 'manual',
|
|
12
18
|
method: 'GET',
|
|
13
|
-
...(
|
|
19
|
+
...(!isCloudflareWorkers()
|
|
14
20
|
? {
|
|
15
21
|
referrerPolicy: 'no-referrer',
|
|
16
22
|
credentials: 'omit',
|
|
17
23
|
mode: 'cors',
|
|
18
24
|
}
|
|
19
25
|
: undefined),
|
|
26
|
+
})
|
|
27
|
+
.catch((err) => {
|
|
28
|
+
if (timedOut)
|
|
29
|
+
throw new JWKSTimeout();
|
|
30
|
+
throw err;
|
|
20
31
|
});
|
|
32
|
+
if (id !== undefined)
|
|
33
|
+
clearTimeout(id);
|
|
21
34
|
if (response.status !== 200) {
|
|
22
35
|
throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response');
|
|
23
36
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export class JOSEError extends Error {
|
|
2
2
|
constructor(message) {
|
|
3
|
+
var _a;
|
|
3
4
|
super(message);
|
|
4
5
|
this.code = JOSEError.code;
|
|
5
6
|
this.name = this.constructor.name;
|
|
6
|
-
|
|
7
|
-
Error.captureStackTrace(this, this.constructor);
|
|
8
|
-
}
|
|
7
|
+
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
9
8
|
}
|
|
10
9
|
}
|
|
11
10
|
JOSEError.code = 'ERR_JOSE_GENERIC';
|
|
@@ -91,6 +90,14 @@ export class JWKSMultipleMatchingKeys extends JOSEError {
|
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
92
|
JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';
|
|
93
|
+
export class JWKSTimeout extends JOSEError {
|
|
94
|
+
constructor() {
|
|
95
|
+
super(...arguments);
|
|
96
|
+
this.code = JWKSTimeout.code;
|
|
97
|
+
this.message = 'request timed out';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
JWKSTimeout.code = 'ERR_JWKS_TIMEOUT';
|
|
94
101
|
export class JWSSignatureVerificationFailed extends JOSEError {
|
|
95
102
|
constructor() {
|
|
96
103
|
super(...arguments);
|
|
@@ -22,7 +22,11 @@ async function compactDecrypt(jwe, key, options) {
|
|
|
22
22
|
tag: (tag || undefined),
|
|
23
23
|
encrypted_key: encryptedKey || undefined,
|
|
24
24
|
}, key, options);
|
|
25
|
-
|
|
25
|
+
const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };
|
|
26
|
+
if (typeof key === 'function') {
|
|
27
|
+
return { ...result, key: decrypted.key };
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
26
30
|
}
|
|
27
31
|
exports.compactDecrypt = compactDecrypt;
|
|
28
32
|
exports.default = compactDecrypt;
|
|
@@ -95,8 +95,10 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
95
95
|
if (jwe.encrypted_key !== undefined) {
|
|
96
96
|
encryptedKey = (0, base64url_js_1.decode)(jwe.encrypted_key);
|
|
97
97
|
}
|
|
98
|
+
let resolvedKey = false;
|
|
98
99
|
if (typeof key === 'function') {
|
|
99
100
|
key = await key(parsedProt, jwe);
|
|
101
|
+
resolvedKey = true;
|
|
100
102
|
}
|
|
101
103
|
let cek;
|
|
102
104
|
try {
|
|
@@ -135,6 +137,9 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
135
137
|
if (jwe.header !== undefined) {
|
|
136
138
|
result.unprotectedHeader = jwe.header;
|
|
137
139
|
}
|
|
140
|
+
if (resolvedKey) {
|
|
141
|
+
return { ...result, key };
|
|
142
|
+
}
|
|
138
143
|
return result;
|
|
139
144
|
}
|
|
140
145
|
exports.flattenedDecrypt = flattenedDecrypt;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EmbeddedJWK = void 0;
|
|
4
|
-
const
|
|
4
|
+
const import_js_1 = require("../key/import.js");
|
|
5
5
|
const is_object_js_1 = require("../lib/is_object.js");
|
|
6
6
|
const errors_js_1 = require("../util/errors.js");
|
|
7
7
|
async function EmbeddedJWK(protectedHeader, token) {
|
|
@@ -12,8 +12,8 @@ async function EmbeddedJWK(protectedHeader, token) {
|
|
|
12
12
|
if (!(0, is_object_js_1.default)(joseHeader.jwk)) {
|
|
13
13
|
throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object');
|
|
14
14
|
}
|
|
15
|
-
const key = await (0,
|
|
16
|
-
if (key.type !== 'public') {
|
|
15
|
+
const key = await (0, import_js_1.importJWK)({ ...joseHeader.jwk, ext: true }, joseHeader.alg, true);
|
|
16
|
+
if (key instanceof Uint8Array || key.type !== 'public') {
|
|
17
17
|
throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key');
|
|
18
18
|
}
|
|
19
19
|
return key;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fromKeyLike = void 0;
|
|
4
|
-
const
|
|
4
|
+
const export_js_1 = require("../key/export.js");
|
|
5
5
|
async function fromKeyLike(key) {
|
|
6
|
-
return (0,
|
|
6
|
+
return (0, export_js_1.exportJWK)(key);
|
|
7
7
|
}
|
|
8
8
|
exports.fromKeyLike = fromKeyLike;
|
|
9
9
|
exports.default = fromKeyLike;
|
|
@@ -1,38 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseJwk = void 0;
|
|
4
|
-
const
|
|
5
|
-
const jwk_to_key_js_1 = require("../runtime/jwk_to_key.js");
|
|
6
|
-
const errors_js_1 = require("../util/errors.js");
|
|
7
|
-
const is_object_js_1 = require("../lib/is_object.js");
|
|
4
|
+
const import_js_1 = require("../key/import.js");
|
|
8
5
|
async function parseJwk(jwk, alg, octAsKeyObject) {
|
|
9
|
-
|
|
10
|
-
throw new TypeError('JWK must be an object');
|
|
11
|
-
}
|
|
12
|
-
alg || (alg = jwk.alg);
|
|
13
|
-
if (typeof alg !== 'string' || !alg) {
|
|
14
|
-
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|
15
|
-
}
|
|
16
|
-
switch (jwk.kty) {
|
|
17
|
-
case 'oct':
|
|
18
|
-
if (typeof jwk.k !== 'string' || !jwk.k) {
|
|
19
|
-
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
20
|
-
}
|
|
21
|
-
octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
|
|
22
|
-
if (octAsKeyObject) {
|
|
23
|
-
return (0, jwk_to_key_js_1.default)({ ...jwk, alg, ext: false });
|
|
24
|
-
}
|
|
25
|
-
return (0, base64url_js_1.decode)(jwk.k);
|
|
26
|
-
case 'RSA':
|
|
27
|
-
if (jwk.oth !== undefined) {
|
|
28
|
-
throw new errors_js_1.JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
|
|
29
|
-
}
|
|
30
|
-
case 'EC':
|
|
31
|
-
case 'OKP':
|
|
32
|
-
return (0, jwk_to_key_js_1.default)({ ...jwk, alg });
|
|
33
|
-
default:
|
|
34
|
-
throw new errors_js_1.JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
35
|
-
}
|
|
6
|
+
return (0, import_js_1.importJWK)(jwk, alg, octAsKeyObject);
|
|
36
7
|
}
|
|
37
8
|
exports.parseJwk = parseJwk;
|
|
38
9
|
exports.default = parseJwk;
|
|
@@ -2,11 +2,11 @@
|
|
|
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 import_js_1 = require("../key/import.js");
|
|
6
6
|
const errors_js_1 = require("../util/errors.js");
|
|
7
7
|
const is_object_js_1 = require("../lib/is_object.js");
|
|
8
8
|
function getKtyFromAlg(alg) {
|
|
9
|
-
switch (alg.substr(0, 2)) {
|
|
9
|
+
switch (typeof alg === 'string' && alg.substr(0, 2)) {
|
|
10
10
|
case 'RS':
|
|
11
11
|
case 'PS':
|
|
12
12
|
return 'RSA';
|
|
@@ -35,7 +35,7 @@ class RemoteJWKSet {
|
|
|
35
35
|
typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000;
|
|
36
36
|
}
|
|
37
37
|
coolingDown() {
|
|
38
|
-
if (
|
|
38
|
+
if (!this._cooldownStarted) {
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
41
|
return Date.now() < this._cooldownStarted + this._cooldownDuration;
|
|
@@ -59,7 +59,7 @@ class RemoteJWKSet {
|
|
|
59
59
|
candidate = jwk.key_ops.includes('verify');
|
|
60
60
|
}
|
|
61
61
|
if (candidate && protectedHeader.alg === 'EdDSA') {
|
|
62
|
-
candidate =
|
|
62
|
+
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
63
63
|
}
|
|
64
64
|
if (candidate) {
|
|
65
65
|
switch (protectedHeader.alg) {
|
|
@@ -91,13 +91,10 @@ class RemoteJWKSet {
|
|
|
91
91
|
else if (length !== 1) {
|
|
92
92
|
throw new errors_js_1.JWKSMultipleMatchingKeys();
|
|
93
93
|
}
|
|
94
|
-
|
|
95
|
-
this._cached.set(jwk, {});
|
|
96
|
-
}
|
|
97
|
-
const cached = this._cached.get(jwk);
|
|
94
|
+
const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
|
|
98
95
|
if (cached[protectedHeader.alg] === undefined) {
|
|
99
|
-
const keyObject = await (0,
|
|
100
|
-
if (keyObject.type !== 'public') {
|
|
96
|
+
const keyObject = await (0, import_js_1.importJWK)({ ...jwk, ext: true }, protectedHeader.alg);
|
|
97
|
+
if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
|
|
101
98
|
throw new errors_js_1.JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
102
99
|
}
|
|
103
100
|
cached[protectedHeader.alg] = keyObject;
|
|
@@ -20,7 +20,11 @@ async function compactVerify(jws, key, options) {
|
|
|
20
20
|
protected: protectedHeader || undefined,
|
|
21
21
|
signature: (signature || undefined),
|
|
22
22
|
}, key, options);
|
|
23
|
-
|
|
23
|
+
const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
|
|
24
|
+
if (typeof key === 'function') {
|
|
25
|
+
return { ...result, key: verified.key };
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
24
28
|
}
|
|
25
29
|
exports.compactVerify = compactVerify;
|
|
26
30
|
exports.default = compactVerify;
|
|
@@ -73,8 +73,10 @@ async function flattenedVerify(jws, key, options) {
|
|
|
73
73
|
else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) {
|
|
74
74
|
throw new errors_js_1.JWSInvalid('JWS Payload must be a string or an Uint8Array instance');
|
|
75
75
|
}
|
|
76
|
+
let resolvedKey = false;
|
|
76
77
|
if (typeof key === 'function') {
|
|
77
78
|
key = await key(parsedProt, jws);
|
|
79
|
+
resolvedKey = true;
|
|
78
80
|
}
|
|
79
81
|
(0, check_key_type_js_1.default)(alg, key, 'verify');
|
|
80
82
|
const data = (0, buffer_utils_js_1.concat)(buffer_utils_js_1.encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), buffer_utils_js_1.encoder.encode('.'), typeof jws.payload === 'string' ? buffer_utils_js_1.encoder.encode(jws.payload) : jws.payload);
|
|
@@ -100,6 +102,9 @@ async function flattenedVerify(jws, key, options) {
|
|
|
100
102
|
if (jws.header !== undefined) {
|
|
101
103
|
result.unprotectedHeader = jws.header;
|
|
102
104
|
}
|
|
105
|
+
if (resolvedKey) {
|
|
106
|
+
return { ...result, key };
|
|
107
|
+
}
|
|
103
108
|
return result;
|
|
104
109
|
}
|
|
105
110
|
exports.flattenedVerify = flattenedVerify;
|
|
@@ -18,7 +18,11 @@ async function jwtDecrypt(jwt, key, options) {
|
|
|
18
18
|
JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) {
|
|
19
19
|
throw new errors_js_1.JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch');
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
const result = { payload, protectedHeader };
|
|
22
|
+
if (typeof key === 'function') {
|
|
23
|
+
return { ...result, key: decrypted.key };
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
22
26
|
}
|
|
23
27
|
exports.jwtDecrypt = jwtDecrypt;
|
|
24
28
|
exports.default = jwtDecrypt;
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.EncryptJWT = void 0;
|
|
4
4
|
const encrypt_js_1 = require("../jwe/compact/encrypt.js");
|
|
5
5
|
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
|
|
6
|
-
const
|
|
7
|
-
class EncryptJWT extends
|
|
6
|
+
const produce_js_1 = require("./produce.js");
|
|
7
|
+
class EncryptJWT extends produce_js_1.ProduceJWT {
|
|
8
8
|
setProtectedHeader(protectedHeader) {
|
|
9
9
|
if (this._protectedHeader) {
|
|
10
10
|
throw new TypeError('setProtectedHeader can only be called once');
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
3
|
+
exports.ProduceJWT = void 0;
|
|
4
|
+
const epoch_js_1 = require("../lib/epoch.js");
|
|
5
|
+
const is_object_js_1 = require("../lib/is_object.js");
|
|
6
|
+
const secs_js_1 = require("../lib/secs.js");
|
|
6
7
|
class ProduceJWT {
|
|
7
8
|
constructor(payload) {
|
|
8
9
|
if (!(0, is_object_js_1.default)(payload)) {
|
|
@@ -54,4 +55,4 @@ class ProduceJWT {
|
|
|
54
55
|
return this;
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
|
-
exports.
|
|
58
|
+
exports.ProduceJWT = ProduceJWT;
|
|
@@ -4,8 +4,8 @@ exports.SignJWT = void 0;
|
|
|
4
4
|
const sign_js_1 = require("../jws/compact/sign.js");
|
|
5
5
|
const errors_js_1 = require("../util/errors.js");
|
|
6
6
|
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
|
|
7
|
-
const
|
|
8
|
-
class SignJWT extends
|
|
7
|
+
const produce_js_1 = require("./produce.js");
|
|
8
|
+
class SignJWT extends produce_js_1.ProduceJWT {
|
|
9
9
|
setProtectedHeader(protectedHeader) {
|
|
10
10
|
this._protectedHeader = protectedHeader;
|
|
11
11
|
return this;
|
|
@@ -5,8 +5,8 @@ const base64url = require("../runtime/base64url.js");
|
|
|
5
5
|
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
|
|
6
6
|
const errors_js_1 = require("../util/errors.js");
|
|
7
7
|
const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js");
|
|
8
|
-
const
|
|
9
|
-
class UnsecuredJWT extends
|
|
8
|
+
const produce_js_1 = require("./produce.js");
|
|
9
|
+
class UnsecuredJWT extends produce_js_1.ProduceJWT {
|
|
10
10
|
encode() {
|
|
11
11
|
const header = base64url.encode(JSON.stringify({ alg: 'none' }));
|
|
12
12
|
const payload = base64url.encode(JSON.stringify(this._payload));
|
|
@@ -11,7 +11,11 @@ async function jwtVerify(jwt, key, options) {
|
|
|
11
11
|
throw new errors_js_1.JWTInvalid('JWTs MUST NOT use unencoded payload');
|
|
12
12
|
}
|
|
13
13
|
const payload = (0, jwt_claims_set_js_1.default)(verified.protectedHeader, verified.payload, options);
|
|
14
|
-
|
|
14
|
+
const result = { payload, protectedHeader: verified.protectedHeader };
|
|
15
|
+
if (typeof key === 'function') {
|
|
16
|
+
return { ...result, key: verified.key };
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
15
19
|
}
|
|
16
20
|
exports.jwtVerify = jwtVerify;
|
|
17
21
|
exports.default = jwtVerify;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exportJWK = exports.exportPKCS8 = exports.exportSPKI = void 0;
|
|
4
|
+
const asn1_js_1 = require("../runtime/asn1.js");
|
|
5
|
+
const asn1_js_2 = require("../runtime/asn1.js");
|
|
6
|
+
const key_to_jwk_js_1 = require("../runtime/key_to_jwk.js");
|
|
7
|
+
async function exportSPKI(key) {
|
|
8
|
+
return (0, asn1_js_1.toSPKI)(key);
|
|
9
|
+
}
|
|
10
|
+
exports.exportSPKI = exportSPKI;
|
|
11
|
+
async function exportPKCS8(key) {
|
|
12
|
+
return (0, asn1_js_2.toPKCS8)(key);
|
|
13
|
+
}
|
|
14
|
+
exports.exportPKCS8 = exportPKCS8;
|
|
15
|
+
async function exportJWK(key) {
|
|
16
|
+
return (0, key_to_jwk_js_1.default)(key);
|
|
17
|
+
}
|
|
18
|
+
exports.exportJWK = exportJWK;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.importJWK = exports.importPKCS8 = exports.importX509 = exports.importSPKI = void 0;
|
|
4
|
+
const base64url_js_1 = require("../runtime/base64url.js");
|
|
5
|
+
const asn1_js_1 = require("../runtime/asn1.js");
|
|
6
|
+
const asn1_js_2 = require("../runtime/asn1.js");
|
|
7
|
+
const jwk_to_key_js_1 = require("../runtime/jwk_to_key.js");
|
|
8
|
+
const errors_js_1 = require("../util/errors.js");
|
|
9
|
+
const format_pem_js_1 = require("../lib/format_pem.js");
|
|
10
|
+
const is_object_js_1 = require("../lib/is_object.js");
|
|
11
|
+
function getElement(seq) {
|
|
12
|
+
let result = [];
|
|
13
|
+
let next = 0;
|
|
14
|
+
while (next < seq.length) {
|
|
15
|
+
let nextPart = parseElement(seq.subarray(next));
|
|
16
|
+
result.push(nextPart);
|
|
17
|
+
next += nextPart.byteLength;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function parseElement(bytes) {
|
|
22
|
+
let position = 0;
|
|
23
|
+
let tag = bytes[0] & 0x1f;
|
|
24
|
+
position++;
|
|
25
|
+
if (tag === 0x1f) {
|
|
26
|
+
tag = 0;
|
|
27
|
+
while (bytes[position] >= 0x80) {
|
|
28
|
+
tag = tag * 128 + bytes[position] - 0x80;
|
|
29
|
+
position++;
|
|
30
|
+
}
|
|
31
|
+
tag = tag * 128 + bytes[position] - 0x80;
|
|
32
|
+
position++;
|
|
33
|
+
}
|
|
34
|
+
let length = 0;
|
|
35
|
+
if (bytes[position] < 0x80) {
|
|
36
|
+
length = bytes[position];
|
|
37
|
+
position++;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
let numberOfDigits = bytes[position] & 0x7f;
|
|
41
|
+
position++;
|
|
42
|
+
length = 0;
|
|
43
|
+
for (let i = 0; i < numberOfDigits; i++) {
|
|
44
|
+
length = length * 256 + bytes[position];
|
|
45
|
+
position++;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (length === 0x80) {
|
|
49
|
+
length = 0;
|
|
50
|
+
while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) {
|
|
51
|
+
length++;
|
|
52
|
+
}
|
|
53
|
+
const byteLength = position + length + 2;
|
|
54
|
+
return {
|
|
55
|
+
byteLength,
|
|
56
|
+
contents: bytes.subarray(position, position + length),
|
|
57
|
+
raw: bytes.subarray(0, byteLength),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const byteLength = position + length;
|
|
61
|
+
return {
|
|
62
|
+
byteLength,
|
|
63
|
+
contents: bytes.subarray(position, byteLength),
|
|
64
|
+
raw: bytes.subarray(0, byteLength),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function spkiFromX509(buf) {
|
|
68
|
+
return (0, base64url_js_1.encodeBase64)(getElement(getElement(parseElement(buf).contents)[0].contents)[6].raw);
|
|
69
|
+
}
|
|
70
|
+
function getSPKI(x509) {
|
|
71
|
+
const pem = x509.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, '');
|
|
72
|
+
const raw = (0, base64url_js_1.decodeBase64)(pem);
|
|
73
|
+
return (0, format_pem_js_1.default)(spkiFromX509(raw), 'PUBLIC KEY');
|
|
74
|
+
}
|
|
75
|
+
async function importSPKI(spki, alg, options) {
|
|
76
|
+
if (typeof spki !== 'string' || spki.indexOf('-----BEGIN PUBLIC KEY-----') !== 0) {
|
|
77
|
+
throw new TypeError('"spki" must be SPKI formatted string');
|
|
78
|
+
}
|
|
79
|
+
return (0, asn1_js_1.fromSPKI)(spki, alg, options);
|
|
80
|
+
}
|
|
81
|
+
exports.importSPKI = importSPKI;
|
|
82
|
+
async function importX509(x509, alg, options) {
|
|
83
|
+
if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {
|
|
84
|
+
throw new TypeError('"x509" must be X.509 formatted string');
|
|
85
|
+
}
|
|
86
|
+
const spki = getSPKI(x509);
|
|
87
|
+
return (0, asn1_js_1.fromSPKI)(spki, alg, options);
|
|
88
|
+
}
|
|
89
|
+
exports.importX509 = importX509;
|
|
90
|
+
async function importPKCS8(pkcs8, alg, options) {
|
|
91
|
+
if (typeof pkcs8 !== 'string' || pkcs8.indexOf('-----BEGIN PRIVATE KEY-----') !== 0) {
|
|
92
|
+
throw new TypeError('"pkcs8" must be PCKS8 formatted string');
|
|
93
|
+
}
|
|
94
|
+
return (0, asn1_js_2.fromPKCS8)(pkcs8, alg, options);
|
|
95
|
+
}
|
|
96
|
+
exports.importPKCS8 = importPKCS8;
|
|
97
|
+
async function importJWK(jwk, alg, octAsKeyObject) {
|
|
98
|
+
if (!(0, is_object_js_1.default)(jwk)) {
|
|
99
|
+
throw new TypeError('JWK must be an object');
|
|
100
|
+
}
|
|
101
|
+
alg || (alg = jwk.alg);
|
|
102
|
+
if (typeof alg !== 'string' || !alg) {
|
|
103
|
+
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|
104
|
+
}
|
|
105
|
+
switch (jwk.kty) {
|
|
106
|
+
case 'oct':
|
|
107
|
+
if (typeof jwk.k !== 'string' || !jwk.k) {
|
|
108
|
+
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
109
|
+
}
|
|
110
|
+
octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
|
|
111
|
+
if (octAsKeyObject) {
|
|
112
|
+
return (0, jwk_to_key_js_1.default)({ ...jwk, alg, ext: false });
|
|
113
|
+
}
|
|
114
|
+
return (0, base64url_js_1.decode)(jwk.k);
|
|
115
|
+
case 'RSA':
|
|
116
|
+
if (jwk.oth !== undefined) {
|
|
117
|
+
throw new errors_js_1.JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
|
|
118
|
+
}
|
|
119
|
+
case 'EC':
|
|
120
|
+
case 'OKP':
|
|
121
|
+
return (0, jwk_to_key_js_1.default)({ ...jwk, alg });
|
|
122
|
+
default:
|
|
123
|
+
throw new errors_js_1.JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.importJWK = importJWK;
|