@suveren/gateway 0.4.1 → 0.6.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/bin/suveren-gateway.js +86 -5
- package/content/integrations/calendar.json +116 -22
- package/content/integrations/deploy-github.json +164 -0
- package/content/integrations/gmail.json +13 -4
- package/content/integrations/index.json +2 -1
- package/dist/control-plane/index.mjs +84 -7
- package/dist/mcp-server/http.mjs +147 -21
- package/dist/ui/assets/index-DecSrutK.js +105 -0
- package/dist/ui/index.html +1 -1
- package/node_modules/@hap/core/dist/index.d.mts +21 -0
- package/node_modules/@hap/core/dist/index.d.ts +21 -0
- package/node_modules/@hap/core/dist/index.js +17 -0
- package/node_modules/@hap/core/dist/index.mjs +17 -0
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/gatekeeper.ts +28 -0
- package/node_modules/@hap/core/src/types.ts +21 -0
- package/node_modules/fast-uri/index.js +37 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +136 -0
- package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/cjs/jsx/base.js +1 -9
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +14 -11
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/cjs/utils/cookie.js +2 -1
- package/node_modules/hono/dist/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/jsx/base.js +1 -9
- package/node_modules/hono/dist/jsx/hooks/index.js +14 -11
- package/node_modules/hono/dist/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/utils/cookie.js +2 -1
- package/node_modules/hono/package.json +2 -3
- package/node_modules/ip-address/README.md +142 -128
- package/node_modules/ip-address/dist/common.d.ts +6 -0
- package/node_modules/ip-address/dist/common.js +17 -1
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.js +3 -12
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +9 -2
- package/node_modules/ip-address/dist/ipv6.js +35 -16
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/package.json +5 -3
- package/node_modules/jose/README.md +13 -13
- package/node_modules/jose/dist/types/index.d.ts +6 -5
- package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +17 -11
- package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +7 -19
- package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +17 -11
- package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +7 -19
- package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +18 -13
- package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +20 -21
- package/node_modules/jose/dist/types/jwk/embedded.d.ts +8 -12
- package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +0 -15
- package/node_modules/jose/dist/types/jwks/local.d.ts +12 -21
- package/node_modules/jose/dist/types/jwks/remote.d.ts +34 -165
- package/node_modules/jose/dist/types/jws/compact/sign.d.ts +2 -13
- package/node_modules/jose/dist/types/jws/compact/verify.d.ts +17 -13
- package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +2 -13
- package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +17 -13
- package/node_modules/jose/dist/types/jws/general/sign.d.ts +16 -17
- package/node_modules/jose/dist/types/jws/general/verify.d.ts +18 -15
- package/node_modules/jose/dist/types/jwt/decrypt.d.ts +17 -11
- package/node_modules/jose/dist/types/jwt/encrypt.d.ts +10 -34
- package/node_modules/jose/dist/types/jwt/sign.d.ts +2 -13
- package/node_modules/jose/dist/types/jwt/unsecured.d.ts +4 -13
- package/node_modules/jose/dist/types/jwt/verify.d.ts +14 -13
- package/node_modules/jose/dist/types/key/export.d.ts +0 -14
- package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +7 -14
- package/node_modules/jose/dist/types/key/generate_secret.d.ts +16 -14
- package/node_modules/jose/dist/types/key/import.d.ts +18 -28
- package/node_modules/jose/dist/types/types.d.ts +239 -222
- package/node_modules/jose/dist/types/util/base64url.d.ts +11 -4
- package/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -9
- package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +0 -8
- package/node_modules/jose/dist/types/util/errors.d.ts +128 -121
- package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +4 -22
- package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +5 -153
- package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +16 -111
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +15 -3
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +65 -81
- package/node_modules/jose/dist/webapi/jwk/embedded.js +5 -3
- package/node_modules/jose/dist/webapi/jwks/local.js +31 -72
- package/node_modules/jose/dist/webapi/jwks/remote.js +19 -28
- package/node_modules/jose/dist/webapi/jws/compact/sign.js +5 -2
- package/node_modules/jose/dist/webapi/jws/compact/verify.js +4 -16
- package/node_modules/jose/dist/webapi/jws/flattened/sign.js +7 -65
- package/node_modules/jose/dist/webapi/jws/flattened/verify.js +3 -89
- package/node_modules/jose/dist/webapi/jws/general/sign.js +19 -15
- package/node_modules/jose/dist/webapi/jws/general/verify.js +29 -9
- package/node_modules/jose/dist/webapi/jwt/decrypt.js +5 -5
- package/node_modules/jose/dist/webapi/jwt/sign.js +2 -3
- package/node_modules/jose/dist/webapi/jwt/unsecured.js +4 -3
- package/node_modules/jose/dist/webapi/jwt/verify.js +6 -6
- package/node_modules/jose/dist/webapi/key/export.js +37 -4
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +33 -82
- package/node_modules/jose/dist/webapi/key/import.js +8 -8
- package/node_modules/jose/dist/webapi/lib/asn1.js +53 -122
- package/node_modules/jose/dist/webapi/lib/buffer_utils.js +1 -0
- package/node_modules/jose/dist/webapi/lib/content_encryption.js +34 -109
- package/node_modules/jose/dist/webapi/lib/crypto_key.js +18 -126
- package/node_modules/jose/dist/webapi/lib/helpers.js +23 -0
- package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +0 -1
- package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +116 -0
- package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +186 -0
- package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +110 -0
- package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +8 -98
- package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +76 -0
- package/node_modules/jose/dist/webapi/lib/jws_sign.js +74 -0
- package/node_modules/jose/dist/webapi/lib/jws_verify.js +107 -0
- package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +68 -109
- package/node_modules/jose/dist/webapi/lib/key.js +132 -0
- package/node_modules/jose/dist/webapi/lib/key_algorithm.js +10 -0
- package/node_modules/jose/dist/webapi/lib/key_descriptor.js +7 -0
- package/node_modules/jose/dist/webapi/lib/key_management.js +162 -92
- package/node_modules/jose/dist/webapi/lib/options.js +48 -0
- package/node_modules/jose/dist/webapi/lib/signing.js +14 -56
- package/node_modules/jose/dist/webapi/lib/type_checks.js +13 -18
- package/node_modules/jose/dist/webapi/util/base64url.js +13 -4
- package/node_modules/jose/dist/webapi/util/decode_jwt.js +2 -2
- package/node_modules/jose/dist/webapi/util/decode_protected_header.js +5 -15
- package/node_modules/jose/dist/webapi/util/errors.js +1 -1
- package/node_modules/jose/package.json +2 -4
- package/package.json +2 -2
- package/profiles/deploy/0.6.profile.json +168 -0
- package/profiles/deploy/0.7.profile.json +168 -0
- package/profiles/email/0.4.profile.json +9 -2
- package/profiles/index.json +3 -1
- package/dist/ui/assets/index-Cog54HOo.js +0 -105
- package/node_modules/jose/dist/webapi/lib/aesgcmkw.js +0 -15
- package/node_modules/jose/dist/webapi/lib/aeskw.js +0 -25
- package/node_modules/jose/dist/webapi/lib/check_key_type.js +0 -122
- package/node_modules/jose/dist/webapi/lib/ecdhes.js +0 -52
- package/node_modules/jose/dist/webapi/lib/key_to_jwk.js +0 -34
- package/node_modules/jose/dist/webapi/lib/normalize_key.js +0 -166
- package/node_modules/jose/dist/webapi/lib/pbes2kw.js +0 -42
- package/node_modules/jose/dist/webapi/lib/rsaes.js +0 -24
- package/node_modules/jose/dist/webapi/lib/validate_algorithms.js +0 -10
- package/node_modules/jose/dist/webapi/lib/validate_crit.js +0 -33
|
@@ -1,136 +1,28 @@
|
|
|
1
1
|
const unusable = (name, prop = 'algorithm.name') => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
2
|
-
|
|
3
|
-
function getHashLength(hash) {
|
|
4
|
-
return parseInt(hash.name.slice(4), 10);
|
|
5
|
-
}
|
|
6
|
-
function checkHashLength(algorithm, expected) {
|
|
7
|
-
const actual = getHashLength(algorithm.hash);
|
|
8
|
-
if (actual !== expected)
|
|
9
|
-
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|
10
|
-
}
|
|
11
|
-
function getNamedCurve(alg) {
|
|
12
|
-
switch (alg) {
|
|
13
|
-
case 'ES256':
|
|
14
|
-
return 'P-256';
|
|
15
|
-
case 'ES384':
|
|
16
|
-
return 'P-384';
|
|
17
|
-
case 'ES512':
|
|
18
|
-
return 'P-521';
|
|
19
|
-
default:
|
|
20
|
-
throw new Error('unreachable');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function checkUsage(key, usage) {
|
|
2
|
+
export function checkUsage(key, usage) {
|
|
24
3
|
if (usage && !key.usages.includes(usage)) {
|
|
25
4
|
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
26
5
|
}
|
|
27
6
|
}
|
|
28
|
-
export function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
case 'HS512': {
|
|
33
|
-
if (!isAlgorithm(key.algorithm, 'HMAC'))
|
|
34
|
-
throw unusable('HMAC');
|
|
35
|
-
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
case 'RS256':
|
|
39
|
-
case 'RS384':
|
|
40
|
-
case 'RS512': {
|
|
41
|
-
if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))
|
|
42
|
-
throw unusable('RSASSA-PKCS1-v1_5');
|
|
43
|
-
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
case 'PS256':
|
|
47
|
-
case 'PS384':
|
|
48
|
-
case 'PS512': {
|
|
49
|
-
if (!isAlgorithm(key.algorithm, 'RSA-PSS'))
|
|
50
|
-
throw unusable('RSA-PSS');
|
|
51
|
-
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
case 'Ed25519':
|
|
55
|
-
case 'EdDSA': {
|
|
56
|
-
if (!isAlgorithm(key.algorithm, 'Ed25519'))
|
|
57
|
-
throw unusable('Ed25519');
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
case 'ML-DSA-44':
|
|
61
|
-
case 'ML-DSA-65':
|
|
62
|
-
case 'ML-DSA-87': {
|
|
63
|
-
if (!isAlgorithm(key.algorithm, alg))
|
|
64
|
-
throw unusable(alg);
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
case 'ES256':
|
|
68
|
-
case 'ES384':
|
|
69
|
-
case 'ES512': {
|
|
70
|
-
if (!isAlgorithm(key.algorithm, 'ECDSA'))
|
|
71
|
-
throw unusable('ECDSA');
|
|
72
|
-
const expected = getNamedCurve(alg);
|
|
73
|
-
const actual = key.algorithm.namedCurve;
|
|
74
|
-
if (actual !== expected)
|
|
75
|
-
throw unusable(expected, 'algorithm.namedCurve');
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
default:
|
|
79
|
-
throw new TypeError('CryptoKey does not support this operation');
|
|
7
|
+
export function checkModulusLength(alg, key) {
|
|
8
|
+
const { modulusLength } = key.algorithm;
|
|
9
|
+
if (typeof modulusLength !== 'number' || modulusLength < 2048) {
|
|
10
|
+
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
80
11
|
}
|
|
81
|
-
checkUsage(key, usage);
|
|
82
12
|
}
|
|
83
|
-
export function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
case 'A128KW':
|
|
97
|
-
case 'A192KW':
|
|
98
|
-
case 'A256KW': {
|
|
99
|
-
if (!isAlgorithm(key.algorithm, 'AES-KW'))
|
|
100
|
-
throw unusable('AES-KW');
|
|
101
|
-
const expected = parseInt(alg.slice(1, 4), 10);
|
|
102
|
-
const actual = key.algorithm.length;
|
|
103
|
-
if (actual !== expected)
|
|
104
|
-
throw unusable(expected, 'algorithm.length');
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
case 'ECDH': {
|
|
108
|
-
switch (key.algorithm.name) {
|
|
109
|
-
case 'ECDH':
|
|
110
|
-
case 'X25519':
|
|
111
|
-
break;
|
|
112
|
-
default:
|
|
113
|
-
throw unusable('ECDH or X25519');
|
|
114
|
-
}
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
case 'PBES2-HS256+A128KW':
|
|
118
|
-
case 'PBES2-HS384+A192KW':
|
|
119
|
-
case 'PBES2-HS512+A256KW':
|
|
120
|
-
if (!isAlgorithm(key.algorithm, 'PBKDF2'))
|
|
121
|
-
throw unusable('PBKDF2');
|
|
122
|
-
break;
|
|
123
|
-
case 'RSA-OAEP':
|
|
124
|
-
case 'RSA-OAEP-256':
|
|
125
|
-
case 'RSA-OAEP-384':
|
|
126
|
-
case 'RSA-OAEP-512': {
|
|
127
|
-
if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))
|
|
128
|
-
throw unusable('RSA-OAEP');
|
|
129
|
-
checkHashLength(key.algorithm, parseInt(alg.slice(9), 10) || 1);
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
default:
|
|
133
|
-
throw new TypeError('CryptoKey does not support this operation');
|
|
13
|
+
export function checkCryptoKey(key, expected, usage) {
|
|
14
|
+
const algorithm = key.algorithm;
|
|
15
|
+
if (algorithm.name !== expected.name) {
|
|
16
|
+
throw unusable(expected.name);
|
|
17
|
+
}
|
|
18
|
+
if (expected.hash && algorithm.hash?.name !== expected.hash) {
|
|
19
|
+
throw unusable(expected.hash, 'algorithm.hash');
|
|
20
|
+
}
|
|
21
|
+
if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve) {
|
|
22
|
+
throw unusable(expected.namedCurve, 'algorithm.namedCurve');
|
|
23
|
+
}
|
|
24
|
+
if (expected.length !== undefined && algorithm.length !== expected.length) {
|
|
25
|
+
throw unusable(expected.length, 'algorithm.length');
|
|
134
26
|
}
|
|
135
27
|
checkUsage(key, usage);
|
|
136
28
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { decode } from '../util/base64url.js';
|
|
2
|
+
import { encode, strictDecoder } from './buffer_utils.js';
|
|
3
|
+
import { isObject } from './type_checks.js';
|
|
2
4
|
export const unprotected = Symbol();
|
|
3
5
|
export function assertNotSet(value, name) {
|
|
4
6
|
if (value) {
|
|
@@ -13,7 +15,28 @@ export function decodeBase64url(value, label, ErrorClass) {
|
|
|
13
15
|
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
14
16
|
}
|
|
15
17
|
}
|
|
18
|
+
export function encodeBase64url(value, label, ErrorClass) {
|
|
19
|
+
try {
|
|
20
|
+
return encode(value);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new ErrorClass(`The ${label} is not a valid base64url string`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
16
26
|
export async function digest(algorithm, data) {
|
|
17
27
|
const subtleDigest = `SHA-${algorithm.slice(-3)}`;
|
|
18
28
|
return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));
|
|
19
29
|
}
|
|
30
|
+
export function parseJoseHeader(b64, ErrorClass, message) {
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = JSON.parse(strictDecoder.decode(decode(b64)));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new ErrorClass(message);
|
|
37
|
+
}
|
|
38
|
+
if (!isObject(parsed)) {
|
|
39
|
+
throw new ErrorClass(message);
|
|
40
|
+
}
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { JOSENotSupported } from '../util/errors.js';
|
|
2
|
+
import { table } from './key_descriptor.js';
|
|
3
|
+
const wrap = [
|
|
4
|
+
['encrypt', 'wrapKey'],
|
|
5
|
+
['decrypt', 'unwrapKey'],
|
|
6
|
+
];
|
|
7
|
+
const derive = [[], ['deriveBits']];
|
|
8
|
+
const none = [[], []];
|
|
9
|
+
function rsaes(bits) {
|
|
10
|
+
return {
|
|
11
|
+
kty: ['RSA'],
|
|
12
|
+
subtle: { name: 'RSA-OAEP', hash: `SHA-${bits}` },
|
|
13
|
+
usages: wrap,
|
|
14
|
+
ops: ['wrapKey', 'unwrapKey'],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function ecdh() {
|
|
18
|
+
return {
|
|
19
|
+
kty: ['EC', 'OKP'],
|
|
20
|
+
subtle: { name: 'ECDH' },
|
|
21
|
+
resolve: ({ kty, crv, asymmetricKeyType }) => {
|
|
22
|
+
if (crv === 'X25519' || asymmetricKeyType === 'x25519') {
|
|
23
|
+
return { name: 'X25519' };
|
|
24
|
+
}
|
|
25
|
+
if (kty === 'OKP') {
|
|
26
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
27
|
+
}
|
|
28
|
+
return { name: 'ECDH', namedCurve: crv };
|
|
29
|
+
},
|
|
30
|
+
usages: derive,
|
|
31
|
+
ops: [undefined, 'deriveBits'],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function aeskw(bits, gcm = false) {
|
|
35
|
+
return {
|
|
36
|
+
kty: ['oct'],
|
|
37
|
+
secret: true,
|
|
38
|
+
subtle: { name: gcm ? 'AES-GCM' : 'AES-KW', length: bits },
|
|
39
|
+
usages: none,
|
|
40
|
+
ops: gcm ? ['encrypt', 'decrypt'] : ['wrapKey', 'unwrapKey'],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function pbes2() {
|
|
44
|
+
return {
|
|
45
|
+
kty: ['oct'],
|
|
46
|
+
secret: true,
|
|
47
|
+
subtle: { name: 'PBKDF2' },
|
|
48
|
+
usages: none,
|
|
49
|
+
ops: ['deriveBits', 'deriveBits'],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const JWE = table({
|
|
53
|
+
dir: {
|
|
54
|
+
kty: ['oct'],
|
|
55
|
+
secret: true,
|
|
56
|
+
subtle: { name: 'AES-GCM' },
|
|
57
|
+
usages: none,
|
|
58
|
+
ops: ['encrypt', 'decrypt'],
|
|
59
|
+
},
|
|
60
|
+
'RSA-OAEP': rsaes(1),
|
|
61
|
+
'RSA-OAEP-256': rsaes(256),
|
|
62
|
+
'RSA-OAEP-384': rsaes(384),
|
|
63
|
+
'RSA-OAEP-512': rsaes(512),
|
|
64
|
+
'ECDH-ES': ecdh(),
|
|
65
|
+
'ECDH-ES+A128KW': ecdh(),
|
|
66
|
+
'ECDH-ES+A192KW': ecdh(),
|
|
67
|
+
'ECDH-ES+A256KW': ecdh(),
|
|
68
|
+
A128KW: aeskw(128),
|
|
69
|
+
A192KW: aeskw(192),
|
|
70
|
+
A256KW: aeskw(256),
|
|
71
|
+
A128GCMKW: aeskw(128, true),
|
|
72
|
+
A192GCMKW: aeskw(192, true),
|
|
73
|
+
A256GCMKW: aeskw(256, true),
|
|
74
|
+
'PBES2-HS256+A128KW': pbes2(),
|
|
75
|
+
'PBES2-HS384+A192KW': pbes2(),
|
|
76
|
+
'PBES2-HS512+A256KW': pbes2(),
|
|
77
|
+
});
|
|
78
|
+
const contentOps = ['encrypt', 'decrypt'];
|
|
79
|
+
function contentEncryption(bits, cbc = false) {
|
|
80
|
+
return {
|
|
81
|
+
kty: ['oct'],
|
|
82
|
+
secret: true,
|
|
83
|
+
subtle: { name: cbc ? 'AES-CBC' : 'AES-GCM', length: bits },
|
|
84
|
+
usages: none,
|
|
85
|
+
ops: contentOps,
|
|
86
|
+
cekBits: bits,
|
|
87
|
+
ivBits: cbc ? 128 : 96,
|
|
88
|
+
cbc,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const ENC = table({
|
|
92
|
+
A128GCM: contentEncryption(128),
|
|
93
|
+
A192GCM: contentEncryption(192),
|
|
94
|
+
A256GCM: contentEncryption(256),
|
|
95
|
+
'A128CBC-HS256': contentEncryption(256, true),
|
|
96
|
+
'A192CBC-HS384': contentEncryption(384, true),
|
|
97
|
+
'A256CBC-HS512': contentEncryption(512, true),
|
|
98
|
+
});
|
|
99
|
+
const unsupportedAlg = 'Invalid or unsupported "alg" (JWE Algorithm) header value';
|
|
100
|
+
export function jweAlgorithm(alg) {
|
|
101
|
+
const entry = JWE[alg];
|
|
102
|
+
if (!entry) {
|
|
103
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
104
|
+
}
|
|
105
|
+
return entry;
|
|
106
|
+
}
|
|
107
|
+
export function maybeJWEAlgorithm(alg) {
|
|
108
|
+
return JWE[alg];
|
|
109
|
+
}
|
|
110
|
+
export function jweEncryption(enc) {
|
|
111
|
+
const entry = ENC[enc];
|
|
112
|
+
if (!entry) {
|
|
113
|
+
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${enc}`);
|
|
114
|
+
}
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { decrypt, generateCek } from './content_encryption.js';
|
|
2
|
+
import { decodeBase64url, encodeBase64url, parseJoseHeader } from './helpers.js';
|
|
3
|
+
import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../util/errors.js';
|
|
4
|
+
import { isDisjoint, isObject } from './type_checks.js';
|
|
5
|
+
import { decryptKeyManagement } from './key_management.js';
|
|
6
|
+
import { concat, decoder, encode } from './buffer_utils.js';
|
|
7
|
+
import { validateCrit, validateAlgorithms, JWE_RECOGNIZED } from './options.js';
|
|
8
|
+
import { prepareKey } from './key.js';
|
|
9
|
+
import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js';
|
|
10
|
+
import { decompress } from './deflate.js';
|
|
11
|
+
export function checkShared(jwe) {
|
|
12
|
+
const { ciphertext, protected: encodedProtected, unprotected } = jwe;
|
|
13
|
+
if (jwe.iv !== undefined && typeof jwe.iv !== 'string') {
|
|
14
|
+
throw new JWEInvalid('JWE Initialization Vector incorrect type');
|
|
15
|
+
}
|
|
16
|
+
if (typeof ciphertext !== 'string') {
|
|
17
|
+
throw new JWEInvalid('JWE Ciphertext missing or incorrect type');
|
|
18
|
+
}
|
|
19
|
+
if (jwe.tag !== undefined && typeof jwe.tag !== 'string') {
|
|
20
|
+
throw new JWEInvalid('JWE Authentication Tag incorrect type');
|
|
21
|
+
}
|
|
22
|
+
if (encodedProtected !== undefined && typeof encodedProtected !== 'string') {
|
|
23
|
+
throw new JWEInvalid('JWE Protected Header incorrect type');
|
|
24
|
+
}
|
|
25
|
+
if (jwe.aad !== undefined && typeof jwe.aad !== 'string') {
|
|
26
|
+
throw new JWEInvalid('JWE AAD incorrect type');
|
|
27
|
+
}
|
|
28
|
+
if (unprotected !== undefined && !isObject(unprotected)) {
|
|
29
|
+
throw new JWEInvalid('JWE Shared Unprotected Header incorrect type');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function checkRecipient(jwe) {
|
|
33
|
+
const { encrypted_key: encryptedKey, header } = jwe;
|
|
34
|
+
if (encryptedKey !== undefined && typeof encryptedKey !== 'string') {
|
|
35
|
+
throw new JWEInvalid('JWE Encrypted Key incorrect type');
|
|
36
|
+
}
|
|
37
|
+
if (header !== undefined && !isObject(header)) {
|
|
38
|
+
throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type');
|
|
39
|
+
}
|
|
40
|
+
if (jwe.protected === undefined && header === undefined && jwe.unprotected === undefined) {
|
|
41
|
+
throw new JWEInvalid('JOSE Header missing');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function shareJWE(jwe) {
|
|
45
|
+
const { protected: encodedProtected, ciphertext, iv, tag, aad } = jwe;
|
|
46
|
+
let parsedProt;
|
|
47
|
+
if (encodedProtected) {
|
|
48
|
+
parsedProt = parseJoseHeader(encodedProtected, JWEInvalid, 'JWE Protected Header is invalid');
|
|
49
|
+
}
|
|
50
|
+
const protectedHeader = encodedProtected !== undefined ? encode(encodedProtected) : new Uint8Array();
|
|
51
|
+
return [
|
|
52
|
+
parsedProt,
|
|
53
|
+
decodeBase64url(ciphertext, 'ciphertext', JWEInvalid),
|
|
54
|
+
iv !== undefined ? decodeBase64url(iv, 'iv', JWEInvalid) : undefined,
|
|
55
|
+
tag !== undefined ? decodeBase64url(tag, 'tag', JWEInvalid) : undefined,
|
|
56
|
+
aad !== undefined
|
|
57
|
+
? concat(protectedHeader, encode('.'), encodeBase64url(aad, 'aad', JWEInvalid))
|
|
58
|
+
: protectedHeader,
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
export function decryptResult(jwe, decrypted) {
|
|
62
|
+
const [plaintext, parsedProt, key, resolvedKey] = decrypted;
|
|
63
|
+
const { protected: encodedProtected, aad, unprotected, header } = jwe;
|
|
64
|
+
const result = { plaintext };
|
|
65
|
+
if (encodedProtected !== undefined) {
|
|
66
|
+
result.protectedHeader = parsedProt;
|
|
67
|
+
}
|
|
68
|
+
if (aad !== undefined) {
|
|
69
|
+
result.additionalAuthenticatedData = decodeBase64url(aad, 'aad', JWEInvalid);
|
|
70
|
+
}
|
|
71
|
+
if (unprotected !== undefined) {
|
|
72
|
+
result.sharedUnprotectedHeader = unprotected;
|
|
73
|
+
}
|
|
74
|
+
if (header !== undefined) {
|
|
75
|
+
result.unprotectedHeader = header;
|
|
76
|
+
}
|
|
77
|
+
if (resolvedKey) {
|
|
78
|
+
return { ...result, key };
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
export function prepareDecrypt(options) {
|
|
83
|
+
return [
|
|
84
|
+
options && validateAlgorithms('keyManagementAlgorithms', options.keyManagementAlgorithms),
|
|
85
|
+
options &&
|
|
86
|
+
validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms),
|
|
87
|
+
options,
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
export async function decryptRecipient(jwe, token, shared, key) {
|
|
91
|
+
const [keyManagementAlgorithms, contentEncryptionAlgorithms, options] = shared;
|
|
92
|
+
const [parsedProt, ciphertext, iv, tag, additionalData] = token;
|
|
93
|
+
const { encrypted_key: encodedKey, header, unprotected } = jwe;
|
|
94
|
+
let joseHeader;
|
|
95
|
+
if (header !== undefined || unprotected !== undefined) {
|
|
96
|
+
if (!isDisjoint(parsedProt, header, unprotected)) {
|
|
97
|
+
throw new JWEInvalid('JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint');
|
|
98
|
+
}
|
|
99
|
+
joseHeader = { ...parsedProt, ...header, ...unprotected };
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
joseHeader = parsedProt ?? {};
|
|
103
|
+
}
|
|
104
|
+
validateCrit(JWEInvalid, JWE_RECOGNIZED, options?.crit, parsedProt, joseHeader);
|
|
105
|
+
if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') {
|
|
106
|
+
throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.');
|
|
107
|
+
}
|
|
108
|
+
if (joseHeader.zip !== undefined && !parsedProt?.zip) {
|
|
109
|
+
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.');
|
|
110
|
+
}
|
|
111
|
+
const { alg, enc } = joseHeader;
|
|
112
|
+
if (typeof alg !== 'string' || !alg) {
|
|
113
|
+
throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header');
|
|
114
|
+
}
|
|
115
|
+
if (typeof enc !== 'string' || !enc) {
|
|
116
|
+
throw new JWEInvalid('missing JWE Encryption Algorithm (enc) in JWE Header');
|
|
117
|
+
}
|
|
118
|
+
if ((keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) ||
|
|
119
|
+
(!keyManagementAlgorithms && alg.startsWith('PBES2'))) {
|
|
120
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
121
|
+
}
|
|
122
|
+
if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) {
|
|
123
|
+
throw new JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter value not allowed');
|
|
124
|
+
}
|
|
125
|
+
const encEntry = jweEncryption(enc);
|
|
126
|
+
let encryptedKey;
|
|
127
|
+
if (encodedKey !== undefined) {
|
|
128
|
+
encryptedKey = decodeBase64url(encodedKey, 'encrypted_key', JWEInvalid);
|
|
129
|
+
}
|
|
130
|
+
let resolvedKey = false;
|
|
131
|
+
if (typeof key === 'function') {
|
|
132
|
+
key = await key(parsedProt, jwe);
|
|
133
|
+
resolvedKey = true;
|
|
134
|
+
}
|
|
135
|
+
const algEntry = jweAlgorithm(alg);
|
|
136
|
+
const k = await prepareKey(alg === 'dir' ? encEntry : algEntry, key, 'decrypt');
|
|
137
|
+
let cek;
|
|
138
|
+
try {
|
|
139
|
+
cek = await decryptKeyManagement(alg, encEntry, k, encryptedKey, joseHeader, options);
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
if (err instanceof TypeError || err instanceof JWEInvalid || err instanceof JOSENotSupported) {
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
cek = generateCek(encEntry);
|
|
146
|
+
}
|
|
147
|
+
let plaintext = await decrypt(encEntry, cek, ciphertext, iv, tag, additionalData);
|
|
148
|
+
if (joseHeader.zip === 'DEF') {
|
|
149
|
+
const maxDecompressedLength = options?.maxDecompressedLength ?? 250_000;
|
|
150
|
+
if (maxDecompressedLength === 0) {
|
|
151
|
+
throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported.');
|
|
152
|
+
}
|
|
153
|
+
if (maxDecompressedLength !== Infinity &&
|
|
154
|
+
(!Number.isSafeInteger(maxDecompressedLength) || maxDecompressedLength < 1)) {
|
|
155
|
+
throw new TypeError('maxDecompressedLength must be 0, a positive safe integer, or Infinity');
|
|
156
|
+
}
|
|
157
|
+
plaintext = await decompress(plaintext, maxDecompressedLength).catch((cause) => {
|
|
158
|
+
if (cause instanceof JWEInvalid)
|
|
159
|
+
throw cause;
|
|
160
|
+
throw new JWEInvalid('Failed to decompress plaintext', { cause });
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return [plaintext, parsedProt, k, resolvedKey];
|
|
164
|
+
}
|
|
165
|
+
export async function decryptJWE(jwe, shared, key) {
|
|
166
|
+
return decryptRecipient(jwe, shareJWE(jwe), shared, key);
|
|
167
|
+
}
|
|
168
|
+
export async function decryptCompact(jwe, shared, key) {
|
|
169
|
+
if (jwe instanceof Uint8Array) {
|
|
170
|
+
jwe = decoder.decode(jwe);
|
|
171
|
+
}
|
|
172
|
+
if (typeof jwe !== 'string') {
|
|
173
|
+
throw new JWEInvalid('Compact JWE must be a string or Uint8Array');
|
|
174
|
+
}
|
|
175
|
+
const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length, } = jwe.split('.');
|
|
176
|
+
if (length !== 5) {
|
|
177
|
+
throw new JWEInvalid('Invalid Compact JWE');
|
|
178
|
+
}
|
|
179
|
+
return decryptJWE({
|
|
180
|
+
ciphertext,
|
|
181
|
+
iv: iv || undefined,
|
|
182
|
+
protected: protectedHeader,
|
|
183
|
+
tag: tag || undefined,
|
|
184
|
+
encrypted_key: encryptedKey || undefined,
|
|
185
|
+
}, shared, key);
|
|
186
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { encode as b64u } from '../util/base64url.js';
|
|
2
|
+
import { encrypt } from './content_encryption.js';
|
|
3
|
+
import { encryptKeyManagement } from './key_management.js';
|
|
4
|
+
import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
|
|
5
|
+
import { isDisjoint } from './type_checks.js';
|
|
6
|
+
import { concat, encode } from './buffer_utils.js';
|
|
7
|
+
import { validateCrit, JWE_RECOGNIZED } from './options.js';
|
|
8
|
+
import { prepareKey } from './key.js';
|
|
9
|
+
import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js';
|
|
10
|
+
import { compress } from './deflate.js';
|
|
11
|
+
export function checkEncryptHeaders(input) {
|
|
12
|
+
const [, protectedHeader, unprotectedHeader, sharedUnprotectedHeader, , , , , crit] = input;
|
|
13
|
+
if (!isDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader)) {
|
|
14
|
+
throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');
|
|
15
|
+
}
|
|
16
|
+
const joseHeader = {
|
|
17
|
+
...protectedHeader,
|
|
18
|
+
...unprotectedHeader,
|
|
19
|
+
...sharedUnprotectedHeader,
|
|
20
|
+
};
|
|
21
|
+
validateCrit(JWEInvalid, JWE_RECOGNIZED, crit, protectedHeader, joseHeader);
|
|
22
|
+
if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') {
|
|
23
|
+
throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.');
|
|
24
|
+
}
|
|
25
|
+
if (joseHeader.zip !== undefined && !protectedHeader?.zip) {
|
|
26
|
+
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.');
|
|
27
|
+
}
|
|
28
|
+
const { alg, enc } = joseHeader;
|
|
29
|
+
if (typeof alg !== 'string' || !alg) {
|
|
30
|
+
throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid');
|
|
31
|
+
}
|
|
32
|
+
if (typeof enc !== 'string' || !enc) {
|
|
33
|
+
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
|
|
34
|
+
}
|
|
35
|
+
return [joseHeader, alg, enc, jweEncryption(enc)];
|
|
36
|
+
}
|
|
37
|
+
export async function encryptJWE(input, checked, key) {
|
|
38
|
+
const [joseHeader, alg, , encEntry] = checked;
|
|
39
|
+
const [inputPlaintext, inputProtectedHeader, inputUnprotectedHeader, sharedUnprotectedHeader, aad, providedCek, inputIv, keyManagementParameters, , unprotectedParameters,] = input;
|
|
40
|
+
let protectedHeader = inputProtectedHeader;
|
|
41
|
+
let unprotectedHeader = inputUnprotectedHeader;
|
|
42
|
+
if (providedCek && (alg === 'dir' || alg === 'ECDH-ES')) {
|
|
43
|
+
throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
|
|
44
|
+
}
|
|
45
|
+
const algEntry = jweAlgorithm(alg);
|
|
46
|
+
const k = await prepareKey(alg === 'dir' ? encEntry : algEntry, key, 'encrypt');
|
|
47
|
+
const [cek, encryptedKey, parameters] = await encryptKeyManagement(alg, encEntry, k, providedCek, keyManagementParameters);
|
|
48
|
+
if (parameters) {
|
|
49
|
+
if (unprotectedParameters) {
|
|
50
|
+
unprotectedHeader = unprotectedHeader ? { ...unprotectedHeader, ...parameters } : parameters;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
protectedHeader = protectedHeader ? { ...protectedHeader, ...parameters } : parameters;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let protectedHeaderS;
|
|
57
|
+
let protectedHeaderB;
|
|
58
|
+
if (protectedHeader) {
|
|
59
|
+
protectedHeaderS = b64u(JSON.stringify(protectedHeader));
|
|
60
|
+
protectedHeaderB = encode(protectedHeaderS);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
protectedHeaderS = '';
|
|
64
|
+
protectedHeaderB = new Uint8Array();
|
|
65
|
+
}
|
|
66
|
+
let additionalData;
|
|
67
|
+
let aadMember;
|
|
68
|
+
if (aad?.byteLength) {
|
|
69
|
+
aadMember = b64u(aad);
|
|
70
|
+
additionalData = concat(protectedHeaderB, encode('.'), encode(aadMember));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
additionalData = protectedHeaderB;
|
|
74
|
+
}
|
|
75
|
+
let plaintext = inputPlaintext;
|
|
76
|
+
if (joseHeader.zip === 'DEF') {
|
|
77
|
+
plaintext = await compress(plaintext).catch((cause) => {
|
|
78
|
+
throw new JWEInvalid('Failed to compress plaintext', { cause });
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const { ciphertext, tag, iv } = await encrypt(encEntry, plaintext, cek, inputIv, additionalData);
|
|
82
|
+
const jwe = {
|
|
83
|
+
ciphertext: b64u(ciphertext),
|
|
84
|
+
};
|
|
85
|
+
if (iv) {
|
|
86
|
+
jwe.iv = b64u(iv);
|
|
87
|
+
}
|
|
88
|
+
if (tag) {
|
|
89
|
+
jwe.tag = b64u(tag);
|
|
90
|
+
}
|
|
91
|
+
if (encryptedKey) {
|
|
92
|
+
jwe.encrypted_key = b64u(encryptedKey);
|
|
93
|
+
}
|
|
94
|
+
if (aadMember) {
|
|
95
|
+
jwe.aad = aadMember;
|
|
96
|
+
}
|
|
97
|
+
if (protectedHeader) {
|
|
98
|
+
jwe.protected = protectedHeaderS;
|
|
99
|
+
}
|
|
100
|
+
if (sharedUnprotectedHeader) {
|
|
101
|
+
jwe.unprotected = sharedUnprotectedHeader;
|
|
102
|
+
}
|
|
103
|
+
if (unprotectedHeader) {
|
|
104
|
+
jwe.header = unprotectedHeader;
|
|
105
|
+
}
|
|
106
|
+
return jwe;
|
|
107
|
+
}
|
|
108
|
+
export async function createJWE(input, key) {
|
|
109
|
+
return encryptJWE(input, checkEncryptHeaders(input), key);
|
|
110
|
+
}
|