jose 3.16.0 → 3.19.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 +22 -114
- package/dist/browser/jwe/compact/decrypt.js +5 -1
- package/dist/browser/jwe/flattened/decrypt.js +10 -5
- package/dist/browser/jwe/flattened/encrypt.js +5 -2
- package/dist/browser/jwk/embedded.js +2 -2
- package/dist/browser/jwk/from_key_like.js +2 -2
- package/dist/browser/jwk/parse.js +2 -31
- package/dist/browser/jwk/thumbprint.js +1 -1
- package/dist/browser/jwks/remote.js +2 -2
- package/dist/browser/jws/compact/verify.js +5 -1
- package/dist/browser/jws/flattened/sign.js +5 -2
- package/dist/browser/jws/flattened/verify.js +7 -2
- package/dist/browser/jwt/decrypt.js +5 -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/decrypt_key_management.js +4 -4
- package/dist/browser/lib/encrypt_key_management.js +3 -3
- package/dist/browser/lib/format_pem.js +4 -0
- package/dist/browser/runtime/aeskw.js +1 -1
- package/dist/browser/runtime/asn1.js +119 -0
- package/dist/browser/runtime/base64url.js +12 -7
- package/dist/browser/runtime/decrypt.js +1 -1
- package/dist/browser/runtime/encrypt.js +1 -1
- package/dist/browser/runtime/fetch_jwks.js +2 -2
- package/dist/browser/runtime/generate.js +18 -2
- package/dist/browser/runtime/global.js +17 -0
- package/dist/browser/runtime/jwk_to_key.js +29 -5
- package/dist/browser/runtime/sign.js +1 -1
- package/dist/browser/runtime/subtle_dsa.js +4 -1
- package/dist/browser/runtime/verify.js +1 -1
- package/dist/node/cjs/jwe/compact/decrypt.js +5 -1
- package/dist/node/cjs/jwe/flattened/decrypt.js +10 -5
- package/dist/node/cjs/jwe/flattened/encrypt.js +5 -2
- package/dist/node/cjs/jwk/embedded.js +2 -2
- package/dist/node/cjs/jwk/from_key_like.js +2 -2
- package/dist/node/cjs/jwk/parse.js +2 -31
- package/dist/node/cjs/jwk/thumbprint.js +1 -1
- package/dist/node/cjs/jwks/remote.js +2 -2
- package/dist/node/cjs/jws/compact/verify.js +5 -1
- package/dist/node/cjs/jws/flattened/sign.js +5 -2
- package/dist/node/cjs/jws/flattened/verify.js +7 -2
- package/dist/node/cjs/jwt/decrypt.js +5 -1
- package/dist/node/cjs/jwt/unsecured.js +1 -1
- 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/decrypt_key_management.js +4 -4
- package/dist/node/cjs/lib/encrypt_key_management.js +3 -3
- package/dist/node/cjs/lib/format_pem.js +6 -0
- package/dist/node/cjs/runtime/aeskw.js +1 -1
- package/dist/node/cjs/runtime/asn1.js +46 -0
- package/dist/node/cjs/runtime/asn1_sequence_encoder.js +1 -1
- package/dist/node/cjs/runtime/base64url.js +5 -1
- package/dist/node/cjs/runtime/decrypt.js +1 -1
- package/dist/node/cjs/runtime/ecdhes.js +28 -16
- package/dist/node/cjs/runtime/encrypt.js +1 -1
- package/dist/node/cjs/runtime/generate.js +2 -2
- package/dist/node/cjs/runtime/get_named_curve.js +12 -8
- package/dist/node/cjs/runtime/is_key_object.js +3 -12
- package/dist/node/cjs/runtime/jwk_to_key.js +1 -1
- package/dist/node/cjs/runtime/key_to_jwk.js +3 -3
- package/dist/node/cjs/runtime/webcrypto.js +12 -18
- package/dist/node/esm/jwe/compact/decrypt.js +5 -1
- package/dist/node/esm/jwe/flattened/decrypt.js +10 -5
- package/dist/node/esm/jwe/flattened/encrypt.js +5 -2
- package/dist/node/esm/jwk/embedded.js +2 -2
- package/dist/node/esm/jwk/from_key_like.js +2 -2
- package/dist/node/esm/jwk/parse.js +2 -31
- package/dist/node/esm/jwk/thumbprint.js +1 -1
- package/dist/node/esm/jwks/remote.js +2 -2
- package/dist/node/esm/jws/compact/verify.js +5 -1
- package/dist/node/esm/jws/flattened/sign.js +5 -2
- package/dist/node/esm/jws/flattened/verify.js +7 -2
- package/dist/node/esm/jwt/decrypt.js +5 -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/decrypt_key_management.js +4 -4
- package/dist/node/esm/lib/encrypt_key_management.js +3 -3
- package/dist/node/esm/lib/format_pem.js +4 -0
- package/dist/node/esm/runtime/aeskw.js +1 -1
- package/dist/node/esm/runtime/asn1.js +39 -0
- package/dist/node/esm/runtime/asn1_sequence_encoder.js +1 -1
- package/dist/node/esm/runtime/base64url.js +2 -0
- package/dist/node/esm/runtime/decrypt.js +1 -1
- package/dist/node/esm/runtime/ecdhes.js +28 -16
- package/dist/node/esm/runtime/encrypt.js +1 -1
- package/dist/node/esm/runtime/generate.js +2 -2
- package/dist/node/esm/runtime/get_named_curve.js +12 -8
- package/dist/node/esm/runtime/is_key_object.js +3 -12
- package/dist/node/esm/runtime/jwk_to_key.js +1 -1
- package/dist/node/esm/runtime/key_to_jwk.js +3 -3
- package/dist/node/esm/runtime/webcrypto.js +12 -18
- package/dist/types/jwe/compact/decrypt.d.ts +3 -2
- package/dist/types/jwe/flattened/decrypt.d.ts +3 -2
- package/dist/types/jwe/general/decrypt.d.ts +3 -2
- package/dist/types/jws/compact/verify.d.ts +3 -2
- package/dist/types/jws/flattened/verify.d.ts +3 -2
- package/dist/types/jws/general/verify.d.ts +3 -2
- package/dist/types/jwt/decrypt.d.ts +3 -2
- 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 +3 -0
- package/package.json +18 -115
|
@@ -3,7 +3,7 @@ import crypto, { isCryptoKey } from './webcrypto.js';
|
|
|
3
3
|
import invalidKeyInput from './invalid_key_input.js';
|
|
4
4
|
function checkKeySize(key, alg) {
|
|
5
5
|
if (key.algorithm.length !== parseInt(alg.substr(1, 3), 10)) {
|
|
6
|
-
throw new TypeError(`
|
|
6
|
+
throw new TypeError(`Invalid key size for alg: ${alg}`);
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
function getCryptoKey(key, usage) {
|
|
@@ -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.');
|
|
@@ -66,7 +66,7 @@ const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => {
|
|
|
66
66
|
case 'A256GCM':
|
|
67
67
|
return gcmDecrypt(cek, ciphertext, iv, tag, aad);
|
|
68
68
|
default:
|
|
69
|
-
throw new JOSENotSupported('
|
|
69
|
+
throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
72
|
export default decrypt;
|
|
@@ -49,7 +49,7 @@ const encrypt = async (enc, plaintext, cek, iv, aad) => {
|
|
|
49
49
|
case 'A256GCM':
|
|
50
50
|
return gcmEncrypt(plaintext, cek, iv, aad);
|
|
51
51
|
default:
|
|
52
|
-
throw new JOSENotSupported('
|
|
52
|
+
throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
55
|
export default encrypt;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JOSEError } from '../util/errors.js';
|
|
2
|
-
import globalThis from './global.js';
|
|
2
|
+
import globalThis, { isCloudflareWorkers } from './global.js';
|
|
3
3
|
const fetchJwks = async (url, timeout) => {
|
|
4
4
|
let controller;
|
|
5
5
|
if (typeof AbortController === 'function') {
|
|
@@ -10,7 +10,7 @@ const fetchJwks = async (url, timeout) => {
|
|
|
10
10
|
signal: controller ? controller.signal : undefined,
|
|
11
11
|
redirect: 'manual',
|
|
12
12
|
method: 'GET',
|
|
13
|
-
...(
|
|
13
|
+
...(!isCloudflareWorkers()
|
|
14
14
|
? {
|
|
15
15
|
referrerPolicy: 'no-referrer',
|
|
16
16
|
credentials: 'omit',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCloudflareWorkers, isNodeJs } from './global.js';
|
|
1
2
|
import crypto from './webcrypto.js';
|
|
2
3
|
import { JOSENotSupported } from '../util/errors.js';
|
|
3
4
|
import random from './random.js';
|
|
@@ -37,7 +38,7 @@ export async function generateSecret(alg, options) {
|
|
|
37
38
|
keyUsages = ['encrypt', 'decrypt'];
|
|
38
39
|
break;
|
|
39
40
|
default:
|
|
40
|
-
throw new JOSENotSupported('
|
|
41
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
41
42
|
}
|
|
42
43
|
return crypto.subtle.generateKey(algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, keyUsages);
|
|
43
44
|
}
|
|
@@ -100,6 +101,21 @@ export async function generateKeyPair(alg, options) {
|
|
|
100
101
|
algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
|
|
101
102
|
keyUsages = ['sign', 'verify'];
|
|
102
103
|
break;
|
|
104
|
+
case (isCloudflareWorkers() || isNodeJs()) && 'EdDSA':
|
|
105
|
+
switch (options === null || options === void 0 ? void 0 : options.crv) {
|
|
106
|
+
case undefined:
|
|
107
|
+
case 'Ed25519':
|
|
108
|
+
algorithm = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
|
|
109
|
+
keyUsages = ['sign', 'verify'];
|
|
110
|
+
break;
|
|
111
|
+
case isNodeJs() && 'Ed448':
|
|
112
|
+
algorithm = { name: 'NODE-ED448', namedCurve: 'NODE-ED448' };
|
|
113
|
+
keyUsages = ['sign', 'verify'];
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are Ed25519 and Ed448');
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
103
119
|
case 'ECDH-ES':
|
|
104
120
|
case 'ECDH-ES+A128KW':
|
|
105
121
|
case 'ECDH-ES+A192KW':
|
|
@@ -108,7 +124,7 @@ export async function generateKeyPair(alg, options) {
|
|
|
108
124
|
keyUsages = ['deriveKey', 'deriveBits'];
|
|
109
125
|
break;
|
|
110
126
|
default:
|
|
111
|
-
throw new JOSENotSupported('
|
|
127
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
112
128
|
}
|
|
113
129
|
return (crypto.subtle.generateKey(algorithm, (_b = options === null || options === void 0 ? void 0 : options.extractable) !== null && _b !== void 0 ? _b : false, keyUsages));
|
|
114
130
|
}
|
|
@@ -8,3 +8,20 @@ function getGlobal() {
|
|
|
8
8
|
throw new Error('unable to locate global object');
|
|
9
9
|
}
|
|
10
10
|
export default getGlobal();
|
|
11
|
+
export function isCloudflareWorkers() {
|
|
12
|
+
try {
|
|
13
|
+
return getGlobal().WebSocketPair !== undefined;
|
|
14
|
+
}
|
|
15
|
+
catch (_a) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function isNodeJs() {
|
|
20
|
+
var _a, _b;
|
|
21
|
+
try {
|
|
22
|
+
return ((_b = (_a = getGlobal().process) === null || _a === void 0 ? void 0 : _a.versions) === null || _b === void 0 ? void 0 : _b.node) !== undefined;
|
|
23
|
+
}
|
|
24
|
+
catch (_c) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCloudflareWorkers, isNodeJs } from './global.js';
|
|
1
2
|
import crypto from './webcrypto.js';
|
|
2
3
|
import { JOSENotSupported } from '../util/errors.js';
|
|
3
4
|
import { decode as base64url } from './base64url.js';
|
|
@@ -39,7 +40,7 @@ function subtleMapping(jwk) {
|
|
|
39
40
|
keyUsages = ['deriveBits'];
|
|
40
41
|
break;
|
|
41
42
|
default:
|
|
42
|
-
throw new JOSENotSupported('
|
|
43
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
43
44
|
}
|
|
44
45
|
break;
|
|
45
46
|
}
|
|
@@ -68,16 +69,22 @@ function subtleMapping(jwk) {
|
|
|
68
69
|
keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey'];
|
|
69
70
|
break;
|
|
70
71
|
default:
|
|
71
|
-
throw new JOSENotSupported('
|
|
72
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
72
73
|
}
|
|
73
74
|
break;
|
|
74
75
|
}
|
|
75
76
|
case 'EC': {
|
|
76
77
|
switch (jwk.alg) {
|
|
77
78
|
case 'ES256':
|
|
79
|
+
algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
|
|
80
|
+
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
81
|
+
break;
|
|
78
82
|
case 'ES384':
|
|
83
|
+
algorithm = { name: 'ECDSA', namedCurve: 'P-384' };
|
|
84
|
+
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
85
|
+
break;
|
|
79
86
|
case 'ES512':
|
|
80
|
-
algorithm = { name: 'ECDSA', namedCurve:
|
|
87
|
+
algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
|
|
81
88
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
82
89
|
break;
|
|
83
90
|
case 'ECDH-ES':
|
|
@@ -88,12 +95,29 @@ function subtleMapping(jwk) {
|
|
|
88
95
|
keyUsages = jwk.d ? ['deriveBits'] : [];
|
|
89
96
|
break;
|
|
90
97
|
default:
|
|
91
|
-
throw new JOSENotSupported('
|
|
98
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
92
99
|
}
|
|
93
100
|
break;
|
|
94
101
|
}
|
|
102
|
+
case (isCloudflareWorkers() || isNodeJs()) && 'OKP':
|
|
103
|
+
if (jwk.alg !== 'EdDSA') {
|
|
104
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
105
|
+
}
|
|
106
|
+
switch (jwk.crv) {
|
|
107
|
+
case 'Ed25519':
|
|
108
|
+
algorithm = { name: 'NODE-ED25519', namedCurve: 'NODE-ED25519' };
|
|
109
|
+
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
110
|
+
break;
|
|
111
|
+
case isNodeJs() && 'Ed448':
|
|
112
|
+
algorithm = { name: 'NODE-ED448', namedCurve: 'NODE-ED448' };
|
|
113
|
+
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "crv" (Subtype of Key Pair) Parameter value');
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
95
119
|
default:
|
|
96
|
-
throw new JOSENotSupported('
|
|
120
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
|
|
97
121
|
}
|
|
98
122
|
return { algorithm, keyUsages };
|
|
99
123
|
}
|
|
@@ -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, data);
|
|
8
|
+
const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm.namedCurve), cryptoKey, data);
|
|
9
9
|
return new Uint8Array(signature);
|
|
10
10
|
};
|
|
11
11
|
export default sign;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { isCloudflareWorkers, isNodeJs } from './global.js';
|
|
1
2
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
|
-
export default function subtleDsa(alg) {
|
|
3
|
+
export default function subtleDsa(alg, crv) {
|
|
3
4
|
switch (alg) {
|
|
4
5
|
case 'HS256':
|
|
5
6
|
return { hash: { name: 'SHA-256' }, name: 'HMAC' };
|
|
@@ -37,6 +38,8 @@ export default function subtleDsa(alg) {
|
|
|
37
38
|
return { hash: { name: 'SHA-384' }, name: 'ECDSA', namedCurve: 'P-384' };
|
|
38
39
|
case 'ES512':
|
|
39
40
|
return { hash: { name: 'SHA-512' }, name: 'ECDSA', namedCurve: 'P-521' };
|
|
41
|
+
case (isCloudflareWorkers() || isNodeJs()) && 'EdDSA':
|
|
42
|
+
return { name: crv, namedCurve: crv };
|
|
40
43
|
default:
|
|
41
44
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
42
45
|
}
|
|
@@ -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);
|
|
8
|
+
const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm.namedCurve);
|
|
9
9
|
try {
|
|
10
10
|
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
|
|
11
11
|
}
|
|
@@ -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;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.flattenedDecrypt = void 0;
|
|
4
|
-
const errors_js_1 = require("../../util/errors.js");
|
|
5
|
-
const is_disjoint_js_1 = require("../../lib/is_disjoint.js");
|
|
6
|
-
const is_object_js_1 = require("../../lib/is_object.js");
|
|
7
4
|
const base64url_js_1 = require("../../runtime/base64url.js");
|
|
8
5
|
const decrypt_js_1 = require("../../runtime/decrypt.js");
|
|
9
6
|
const zlib_js_1 = require("../../runtime/zlib.js");
|
|
7
|
+
const random_js_1 = require("../../runtime/random.js");
|
|
8
|
+
const errors_js_1 = require("../../util/errors.js");
|
|
9
|
+
const is_disjoint_js_1 = require("../../lib/is_disjoint.js");
|
|
10
|
+
const is_object_js_1 = require("../../lib/is_object.js");
|
|
10
11
|
const decrypt_key_management_js_1 = require("../../lib/decrypt_key_management.js");
|
|
11
12
|
const buffer_utils_js_1 = require("../../lib/buffer_utils.js");
|
|
12
13
|
const cek_js_1 = require("../../lib/cek.js");
|
|
13
|
-
const random_js_1 = require("../../runtime/random.js");
|
|
14
14
|
const validate_crit_js_1 = require("../../lib/validate_crit.js");
|
|
15
15
|
const validate_algorithms_js_1 = require("../../lib/validate_algorithms.js");
|
|
16
16
|
const generateCek = (0, cek_js_1.default)(random_js_1.default);
|
|
@@ -73,7 +73,7 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
73
73
|
throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
74
74
|
}
|
|
75
75
|
if (joseHeader.zip !== 'DEF') {
|
|
76
|
-
throw new errors_js_1.JOSENotSupported('
|
|
76
|
+
throw new errors_js_1.JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value');
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
const { alg, enc } = joseHeader;
|
|
@@ -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,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FlattenedEncrypt = void 0;
|
|
4
|
-
const iv_js_1 = require("../../lib/iv.js");
|
|
5
4
|
const base64url_js_1 = require("../../runtime/base64url.js");
|
|
6
5
|
const random_js_1 = require("../../runtime/random.js");
|
|
7
6
|
const encrypt_js_1 = require("../../runtime/encrypt.js");
|
|
8
7
|
const zlib_js_1 = require("../../runtime/zlib.js");
|
|
8
|
+
const iv_js_1 = require("../../lib/iv.js");
|
|
9
9
|
const encrypt_key_management_js_1 = require("../../lib/encrypt_key_management.js");
|
|
10
10
|
const errors_js_1 = require("../../util/errors.js");
|
|
11
11
|
const is_disjoint_js_1 = require("../../lib/is_disjoint.js");
|
|
@@ -15,6 +15,9 @@ const generateIv = (0, iv_js_1.default)(random_js_1.default);
|
|
|
15
15
|
const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWEInvalid, new Map());
|
|
16
16
|
class FlattenedEncrypt {
|
|
17
17
|
constructor(plaintext) {
|
|
18
|
+
if (!(plaintext instanceof Uint8Array)) {
|
|
19
|
+
throw new TypeError('plaintext must be an instance of Uint8Array');
|
|
20
|
+
}
|
|
18
21
|
this._plaintext = plaintext;
|
|
19
22
|
}
|
|
20
23
|
setKeyManagementParameters(parameters) {
|
|
@@ -81,7 +84,7 @@ class FlattenedEncrypt {
|
|
|
81
84
|
throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
82
85
|
}
|
|
83
86
|
if (joseHeader.zip !== 'DEF') {
|
|
84
|
-
throw new errors_js_1.JOSENotSupported('
|
|
87
|
+
throw new errors_js_1.JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value');
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
const { alg, enc } = joseHeader;
|
|
@@ -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,7 +12,7 @@ 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,
|
|
15
|
+
const key = (await (0, import_js_1.importJWK)({ ...joseHeader.jwk, ext: true }, joseHeader.alg, true));
|
|
16
16
|
if (key.type !== 'public') {
|
|
17
17
|
throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key');
|
|
18
18
|
}
|
|
@@ -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;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.calculateThumbprint = void 0;
|
|
4
|
-
const errors_js_1 = require("../util/errors.js");
|
|
5
4
|
const digest_js_1 = require("../runtime/digest.js");
|
|
6
5
|
const base64url_js_1 = require("../runtime/base64url.js");
|
|
6
|
+
const errors_js_1 = require("../util/errors.js");
|
|
7
7
|
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
|
|
8
8
|
const is_object_js_1 = require("../lib/is_object.js");
|
|
9
9
|
const check = (value, description) => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createRemoteJWKSet = void 0;
|
|
4
|
+
const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
|
|
4
5
|
const parse_js_1 = require("../jwk/parse.js");
|
|
5
6
|
const errors_js_1 = require("../util/errors.js");
|
|
6
|
-
const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
|
|
7
7
|
const is_object_js_1 = require("../lib/is_object.js");
|
|
8
8
|
function getKtyFromAlg(alg) {
|
|
9
9
|
switch (alg.substr(0, 2)) {
|
|
@@ -96,7 +96,7 @@ class RemoteJWKSet {
|
|
|
96
96
|
}
|
|
97
97
|
const cached = this._cached.get(jwk);
|
|
98
98
|
if (cached[protectedHeader.alg] === undefined) {
|
|
99
|
-
const keyObject = await (0, parse_js_1.default)({ ...jwk, alg: protectedHeader.alg });
|
|
99
|
+
const keyObject = (await (0, parse_js_1.default)({ ...jwk, alg: protectedHeader.alg, ext: true }));
|
|
100
100
|
if (keyObject.type !== 'public') {
|
|
101
101
|
throw new errors_js_1.JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
102
102
|
}
|
|
@@ -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;
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FlattenedSign = void 0;
|
|
4
|
+
const base64url_js_1 = require("../../runtime/base64url.js");
|
|
5
|
+
const sign_js_1 = require("../../runtime/sign.js");
|
|
4
6
|
const is_disjoint_js_1 = require("../../lib/is_disjoint.js");
|
|
5
7
|
const errors_js_1 = require("../../util/errors.js");
|
|
6
8
|
const buffer_utils_js_1 = require("../../lib/buffer_utils.js");
|
|
7
|
-
const base64url_js_1 = require("../../runtime/base64url.js");
|
|
8
|
-
const sign_js_1 = require("../../runtime/sign.js");
|
|
9
9
|
const check_key_type_js_1 = require("../../lib/check_key_type.js");
|
|
10
10
|
const validate_crit_js_1 = require("../../lib/validate_crit.js");
|
|
11
11
|
const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWSInvalid, new Map([['b64', true]]));
|
|
12
12
|
class FlattenedSign {
|
|
13
13
|
constructor(payload) {
|
|
14
|
+
if (!(payload instanceof Uint8Array)) {
|
|
15
|
+
throw new TypeError('payload must be an instance of Uint8Array');
|
|
16
|
+
}
|
|
14
17
|
this._payload = payload;
|
|
15
18
|
}
|
|
16
19
|
setProtectedHeader(protectedHeader) {
|