@zuplo/cli 6.74.2 → 6.74.6
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/dist/cmds/test.d.ts.map +1 -1
- package/dist/cmds/test.js +8 -0
- package/dist/cmds/test.js.map +1 -1
- package/dist/common/utils/pnpm-lifecycle.d.ts.map +1 -1
- package/dist/common/utils/pnpm-lifecycle.js +1 -4
- package/dist/common/utils/pnpm-lifecycle.js.map +1 -1
- package/dist/common/utils/pnpm-lifecycle.test.js +23 -4
- package/dist/common/utils/pnpm-lifecycle.test.js.map +1 -1
- package/dist/test/handler.d.ts +2 -1
- package/dist/test/handler.d.ts.map +1 -1
- package/dist/test/handler.js.map +1 -1
- package/dist/test/invoke-test.d.ts +3 -2
- package/dist/test/invoke-test.d.ts.map +1 -1
- package/dist/test/invoke-test.js +26 -0
- package/dist/test/invoke-test.js.map +1 -1
- package/dist/test/invoke-test.test.js +16 -0
- package/dist/test/invoke-test.test.js.map +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +12 -12
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/general/encrypt.js +50 -51
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/local.js +10 -31
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/remote.js +17 -26
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/compact/verify.js +2 -2
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/flattened/sign.js +1 -9
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/general/sign.js +12 -21
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/general/verify.js +13 -11
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwt/decrypt.js +3 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwt/verify.js +4 -4
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/key/export.js +3 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/key/generate_key_pair.js +7 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/asn1.js +29 -62
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/content_encryption.js +16 -34
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/crypto_key.js +6 -0
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/invalid_key_input.js +0 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +44 -71
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +46 -41
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +14 -13
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwk_to_key.js +5 -10
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jws_algorithms.js +20 -18
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jws_sign.js +12 -6
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jws_verify.js +26 -27
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +60 -102
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key.js +61 -99
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_algorithm.js +2 -8
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_descriptor.js +1 -1
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_management.js +74 -161
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/options.js +11 -14
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/signing.js +6 -16
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/type_checks.js +13 -18
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/util/base64url.js +4 -3
- package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/package.json +1 -1
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +3 -3
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-B5LJC45G.js → chunk-CKGECOOJ.js} +88 -88
- package/node_modules/@zuplo/runtime/out/esm/chunk-CKGECOOJ.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +5 -1
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/package.json +6 -6
- package/node_modules/@zuplo/runtime/out/esm/chunk-B5LJC45G.js.map +0 -1
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-B5LJC45G.js.LEGAL.txt → chunk-CKGECOOJ.js.LEGAL.txt} +0 -0
|
@@ -7,17 +7,7 @@ const tag = (key) => key[Symbol.toStringTag];
|
|
|
7
7
|
const jwkMatchesOp = (entry, key, usage) => {
|
|
8
8
|
const { alg } = entry;
|
|
9
9
|
if (key.use !== undefined) {
|
|
10
|
-
|
|
11
|
-
switch (usage) {
|
|
12
|
-
case 'sign':
|
|
13
|
-
case 'verify':
|
|
14
|
-
expected = 'sig';
|
|
15
|
-
break;
|
|
16
|
-
case 'encrypt':
|
|
17
|
-
case 'decrypt':
|
|
18
|
-
expected = 'enc';
|
|
19
|
-
break;
|
|
20
|
-
}
|
|
10
|
+
const expected = usage === 'sign' || usage === 'verify' ? 'sig' : 'enc';
|
|
21
11
|
if (key.use !== expected) {
|
|
22
12
|
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
23
13
|
}
|
|
@@ -26,79 +16,56 @@ const jwkMatchesOp = (entry, key, usage) => {
|
|
|
26
16
|
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
27
17
|
}
|
|
28
18
|
if (Array.isArray(key.key_ops)) {
|
|
29
|
-
const expectedKeyOp = usage === 'encrypt' || usage === 'decrypt' ? entry.
|
|
30
|
-
if (expectedKeyOp && key.key_ops
|
|
19
|
+
const expectedKeyOp = usage === 'encrypt' || usage === 'decrypt' ? entry.ops?.[usage === 'encrypt' ? 0 : 1] : usage;
|
|
20
|
+
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp)) {
|
|
31
21
|
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
32
22
|
}
|
|
33
23
|
}
|
|
34
|
-
return true;
|
|
35
|
-
};
|
|
36
|
-
const symmetricTypeCheck = (entry, key, usage) => {
|
|
37
|
-
const { alg } = entry;
|
|
38
|
-
if (key instanceof Uint8Array)
|
|
39
|
-
return { kind: BYTES, key };
|
|
40
|
-
if (jwk.isJWK(key)) {
|
|
41
|
-
if (jwk.isSecretJWK(key) && jwkMatchesOp(entry, key, usage))
|
|
42
|
-
return { kind: JWK, key };
|
|
43
|
-
throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
|
|
44
|
-
}
|
|
45
|
-
if (!isKeyLike(key)) {
|
|
46
|
-
throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array'));
|
|
47
|
-
}
|
|
48
|
-
if (key.type !== 'secret') {
|
|
49
|
-
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
50
|
-
}
|
|
51
|
-
return isCryptoKey(key) ? { kind: CRYPTO, key } : { kind: KEYOBJECT, key };
|
|
52
24
|
};
|
|
53
|
-
|
|
54
|
-
const { alg } = entry;
|
|
25
|
+
export function checkKeyType(entry, key, usage) {
|
|
26
|
+
const { alg, secret } = entry;
|
|
27
|
+
const privateKey = usage === 'decrypt' || usage === 'sign';
|
|
28
|
+
if (secret && key instanceof Uint8Array)
|
|
29
|
+
return [BYTES, key];
|
|
55
30
|
if (jwk.isJWK(key)) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return { kind: JWK, key };
|
|
61
|
-
throw new TypeError(`JSON Web Key for this operation must be a private JWK`);
|
|
62
|
-
case 'encrypt':
|
|
63
|
-
case 'verify':
|
|
64
|
-
if (jwk.isPublicJWK(key) && jwkMatchesOp(entry, key, usage))
|
|
65
|
-
return { kind: JWK, key };
|
|
66
|
-
throw new TypeError(`JSON Web Key for this operation must be a public JWK`);
|
|
31
|
+
if (secret ? !jwk.isSecretJWK(key) : !(privateKey ? jwk.isPrivateJWK(key) : jwk.isPublicJWK(key))) {
|
|
32
|
+
throw new TypeError(secret
|
|
33
|
+
? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`
|
|
34
|
+
: `JSON Web Key for this operation must be a ${privateKey ? 'private' : 'public'} JWK`);
|
|
67
35
|
}
|
|
36
|
+
jwkMatchesOp(entry, key, usage);
|
|
37
|
+
return [JWK, key];
|
|
68
38
|
}
|
|
69
39
|
if (!isKeyLike(key)) {
|
|
70
|
-
throw new TypeError(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
40
|
+
throw new TypeError(secret
|
|
41
|
+
? invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')
|
|
42
|
+
: invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
|
|
74
43
|
}
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
|
|
79
|
-
case 'decrypt':
|
|
80
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
|
|
44
|
+
if (secret) {
|
|
45
|
+
if (key.type !== 'secret') {
|
|
46
|
+
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
81
47
|
}
|
|
82
48
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
49
|
+
else {
|
|
50
|
+
if (key.type === 'secret') {
|
|
51
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
52
|
+
}
|
|
53
|
+
const expectedType = privateKey ? 'private' : 'public';
|
|
54
|
+
if ((key.type === 'public' || key.type === 'private') && key.type !== expectedType) {
|
|
55
|
+
const operation = usage === 'sign'
|
|
56
|
+
? 'signing'
|
|
57
|
+
: usage === 'verify'
|
|
58
|
+
? 'verifying'
|
|
59
|
+
: `${usage.slice(0, -1)}tion`;
|
|
60
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm ${operation} must be of type "${expectedType}"`);
|
|
89
61
|
}
|
|
90
62
|
}
|
|
91
|
-
return isCryptoKey(key) ?
|
|
92
|
-
};
|
|
93
|
-
const BYTES = Symbol();
|
|
94
|
-
const CRYPTO = Symbol();
|
|
95
|
-
const KEYOBJECT = Symbol();
|
|
96
|
-
const JWK = Symbol();
|
|
97
|
-
export function checkKeyType(entry, key, usage) {
|
|
98
|
-
return entry.symmetric
|
|
99
|
-
? symmetricTypeCheck(entry, key, usage)
|
|
100
|
-
: asymmetricTypeCheck(entry, key, usage);
|
|
63
|
+
return isCryptoKey(key) ? [CRYPTO, key] : [KEYOBJECT, key];
|
|
101
64
|
}
|
|
65
|
+
const BYTES = 0;
|
|
66
|
+
const CRYPTO = 1;
|
|
67
|
+
const KEYOBJECT = 2;
|
|
68
|
+
const JWK = 3;
|
|
102
69
|
let cache;
|
|
103
70
|
const nist = {
|
|
104
71
|
__proto__: null,
|
|
@@ -106,58 +73,53 @@ const nist = {
|
|
|
106
73
|
secp384r1: 'P-384',
|
|
107
74
|
secp521r1: 'P-521',
|
|
108
75
|
};
|
|
109
|
-
function cached(key, alg) {
|
|
76
|
+
function cached(key, alg, value) {
|
|
110
77
|
cache ||= new WeakMap();
|
|
111
|
-
return cache.get(key)?.[alg];
|
|
112
|
-
}
|
|
113
|
-
function store(key, alg, cryptoKey) {
|
|
114
78
|
const entry = cache.get(key);
|
|
115
|
-
if (
|
|
116
|
-
entry
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
79
|
+
if (value) {
|
|
80
|
+
if (entry) {
|
|
81
|
+
entry[alg] = value;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
cache.set(key, { [alg]: value });
|
|
85
|
+
}
|
|
120
86
|
}
|
|
121
|
-
return
|
|
87
|
+
return value ?? entry?.[alg];
|
|
122
88
|
}
|
|
123
|
-
const handleJWK = async (key, jwk, entry) =>
|
|
124
|
-
|
|
125
|
-
if (hit)
|
|
126
|
-
return hit;
|
|
127
|
-
const cryptoKey = await jwkToKey(entry, { ...jwk, alg: entry.alg });
|
|
128
|
-
return store(key, entry.alg, cryptoKey);
|
|
129
|
-
};
|
|
89
|
+
const handleJWK = async (key, jwk, entry) => cached(key, entry.alg) ??
|
|
90
|
+
cached(key, entry.alg, await jwkToKey(entry, { ...jwk, alg: entry.alg }));
|
|
130
91
|
const handleKeyObject = (keyObject, entry) => {
|
|
131
92
|
const hit = cached(keyObject, entry.alg);
|
|
132
93
|
if (hit)
|
|
133
94
|
return hit;
|
|
134
95
|
const isPublic = keyObject.type === 'public';
|
|
135
|
-
const usages = isPublic ?
|
|
96
|
+
const usages = entry.usages[isPublic ? 0 : 1];
|
|
136
97
|
const { asymmetricKeyType } = keyObject;
|
|
137
98
|
const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve];
|
|
138
|
-
const params = entry.
|
|
139
|
-
return
|
|
99
|
+
const params = entry.resolve?.({ crv, asymmetricKeyType }) ?? entry.subtle;
|
|
100
|
+
return cached(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages));
|
|
140
101
|
};
|
|
141
102
|
export async function prepareKey(entry, key, usage) {
|
|
142
103
|
const tagged = checkKeyType(entry, key, usage);
|
|
143
|
-
switch (tagged
|
|
104
|
+
switch (tagged[0]) {
|
|
144
105
|
case BYTES:
|
|
145
106
|
case CRYPTO:
|
|
146
|
-
return tagged
|
|
107
|
+
return tagged[1];
|
|
147
108
|
case JWK: {
|
|
148
|
-
|
|
149
|
-
|
|
109
|
+
const key = tagged[1];
|
|
110
|
+
if (key.k) {
|
|
111
|
+
return decode(key.k);
|
|
150
112
|
}
|
|
151
|
-
if (!Object.isFrozen(
|
|
152
|
-
const { key_ops } =
|
|
113
|
+
if (!Object.isFrozen(key)) {
|
|
114
|
+
const { key_ops } = key;
|
|
153
115
|
if (Array.isArray(key_ops))
|
|
154
116
|
Object.freeze(key_ops);
|
|
155
|
-
Object.freeze(
|
|
117
|
+
Object.freeze(key);
|
|
156
118
|
}
|
|
157
|
-
return handleJWK(
|
|
119
|
+
return handleJWK(key, key, entry);
|
|
158
120
|
}
|
|
159
121
|
case KEYOBJECT: {
|
|
160
|
-
const keyObject = tagged
|
|
122
|
+
const keyObject = tagged[1];
|
|
161
123
|
if (keyObject.type === 'secret') {
|
|
162
124
|
return keyObject.export();
|
|
163
125
|
}
|
package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_algorithm.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
2
|
import { maybeJWSAlgorithm } from './jws_algorithms.js';
|
|
3
3
|
import { maybeJWEAlgorithm } from './jwe_algorithms.js';
|
|
4
|
-
function unsupportedAlgorithm() {
|
|
5
|
-
return new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
6
|
-
}
|
|
7
4
|
export function keyAlgorithm(alg) {
|
|
8
|
-
|
|
9
|
-
throw unsupportedAlgorithm();
|
|
10
|
-
}
|
|
11
|
-
const entry = maybeJWSAlgorithm(alg) ?? maybeJWEAlgorithm(alg);
|
|
5
|
+
const entry = typeof alg === 'string' ? (maybeJWSAlgorithm(alg) ?? maybeJWEAlgorithm(alg)) : undefined;
|
|
12
6
|
if (!entry) {
|
|
13
|
-
throw
|
|
7
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
14
8
|
}
|
|
15
9
|
return entry;
|
|
16
10
|
}
|
package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_management.js
CHANGED
|
@@ -6,75 +6,38 @@ import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
|
|
|
6
6
|
import { decodeBase64url, digest } from './helpers.js';
|
|
7
7
|
import { generateCek, encrypt, decrypt } from './content_encryption.js';
|
|
8
8
|
import { isObject } from './type_checks.js';
|
|
9
|
-
import { checkCryptoKey, checkUsage } from './crypto_key.js';
|
|
10
|
-
import { checkModulusLength } from './signing.js';
|
|
9
|
+
import { checkCryptoKey, checkModulusLength, checkUsage } from './crypto_key.js';
|
|
11
10
|
import { concat, encode, uint32be } from './buffer_utils.js';
|
|
12
11
|
import { assertCryptoKey } from './is_key_like.js';
|
|
13
12
|
function checkEcdhCryptoKey(key, usage) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
case 'X25519':
|
|
17
|
-
break;
|
|
18
|
-
default:
|
|
19
|
-
throw new TypeError('CryptoKey does not support this operation, its algorithm.name must be ECDH or X25519');
|
|
13
|
+
if (key.algorithm.name !== 'ECDH' && key.algorithm.name !== 'X25519') {
|
|
14
|
+
throw new TypeError('CryptoKey does not support this operation, its algorithm.name must be ECDH or X25519');
|
|
20
15
|
}
|
|
21
16
|
checkUsage(key, usage);
|
|
22
17
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
checkCryptoKey(key, jweAlgorithm(alg).subtle, usage);
|
|
33
|
-
return key;
|
|
18
|
+
async function aeskwCryptoKey(key, alg, usage) {
|
|
19
|
+
const expected = jweAlgorithm(alg).subtle;
|
|
20
|
+
const cryptoKey = key instanceof Uint8Array
|
|
21
|
+
? await crypto.subtle.importKey('raw', key, 'AES-KW', true, [
|
|
22
|
+
usage,
|
|
23
|
+
])
|
|
24
|
+
: key;
|
|
25
|
+
checkCryptoKey(cryptoKey, expected, usage);
|
|
26
|
+
return cryptoKey;
|
|
34
27
|
}
|
|
35
28
|
async function aeskwWrap(alg, key, cek) {
|
|
36
29
|
const cryptoKey = await aeskwCryptoKey(key, alg, 'wrapKey');
|
|
37
|
-
checkKeySize(cryptoKey, alg);
|
|
38
30
|
const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
|
|
39
31
|
return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW'));
|
|
40
32
|
}
|
|
41
33
|
async function aeskwUnwrap(alg, key, encryptedKey) {
|
|
42
34
|
const cryptoKey = await aeskwCryptoKey(key, alg, 'unwrapKey');
|
|
43
|
-
checkKeySize(cryptoKey, alg);
|
|
44
35
|
const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
|
|
45
36
|
return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek));
|
|
46
37
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
encryptedKey: wrapped.ciphertext,
|
|
51
|
-
iv: b64u(wrapped.iv),
|
|
52
|
-
tag: b64u(wrapped.tag),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
async function aesGcmKwUnwrap(gcm, key, encryptedKey, iv, tag) {
|
|
56
|
-
return decrypt(gcm, key, encryptedKey, iv, tag, new Uint8Array());
|
|
57
|
-
}
|
|
58
|
-
const subtleAlgorithm = (alg) => {
|
|
59
|
-
switch (alg) {
|
|
60
|
-
case 'RSA-OAEP':
|
|
61
|
-
case 'RSA-OAEP-256':
|
|
62
|
-
case 'RSA-OAEP-384':
|
|
63
|
-
case 'RSA-OAEP-512':
|
|
64
|
-
return 'RSA-OAEP';
|
|
65
|
-
default:
|
|
66
|
-
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
async function rsaesEncrypt(alg, key, cek) {
|
|
70
|
-
checkCryptoKey(key, jweAlgorithm(alg).subtle, 'encrypt');
|
|
71
|
-
checkModulusLength(alg, key);
|
|
72
|
-
return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek));
|
|
73
|
-
}
|
|
74
|
-
async function rsaesDecrypt(alg, key, encryptedKey) {
|
|
75
|
-
checkCryptoKey(key, jweAlgorithm(alg).subtle, 'decrypt');
|
|
38
|
+
function checkRsaKey(alg, key, usage) {
|
|
39
|
+
checkCryptoKey(key, jweAlgorithm(alg).subtle, usage);
|
|
76
40
|
checkModulusLength(alg, key);
|
|
77
|
-
return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey));
|
|
78
41
|
}
|
|
79
42
|
function pbes2CryptoKey(key, alg) {
|
|
80
43
|
if (key instanceof Uint8Array) {
|
|
@@ -85,7 +48,6 @@ function pbes2CryptoKey(key, alg) {
|
|
|
85
48
|
checkCryptoKey(key, jweAlgorithm(alg).subtle, 'deriveBits');
|
|
86
49
|
return key;
|
|
87
50
|
}
|
|
88
|
-
const concatSalt = (alg, p2sInput) => concat(encode(alg), Uint8Array.of(0x00), p2sInput);
|
|
89
51
|
async function deriveKey(p2s, alg, p2c, key) {
|
|
90
52
|
if (!(p2s instanceof Uint8Array) || p2s.length < 8) {
|
|
91
53
|
throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets');
|
|
@@ -93,7 +55,7 @@ async function deriveKey(p2s, alg, p2c, key) {
|
|
|
93
55
|
if (!Number.isSafeInteger(p2c) || Math.sign(p2c) !== 1) {
|
|
94
56
|
throw new JWEInvalid('PBES2 Count Input must be a positive integer');
|
|
95
57
|
}
|
|
96
|
-
const salt =
|
|
58
|
+
const salt = concat(encode(alg), Uint8Array.of(0), p2s);
|
|
97
59
|
const keylen = parseInt(alg.slice(13, 16), 10);
|
|
98
60
|
const subtleAlg = {
|
|
99
61
|
hash: `SHA-${alg.slice(8, 11)}`,
|
|
@@ -104,15 +66,6 @@ async function deriveKey(p2s, alg, p2c, key) {
|
|
|
104
66
|
const cryptoKey = await pbes2CryptoKey(key, alg);
|
|
105
67
|
return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
|
|
106
68
|
}
|
|
107
|
-
async function pbes2kwWrap(alg, key, cek, p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16))) {
|
|
108
|
-
const derived = await deriveKey(p2s, alg, p2c, key);
|
|
109
|
-
const encryptedKey = await aeskwWrap(alg.slice(-6), derived, cek);
|
|
110
|
-
return { encryptedKey, p2c, p2s: b64u(p2s) };
|
|
111
|
-
}
|
|
112
|
-
async function pbes2kwUnwrap(alg, key, encryptedKey, p2c, p2s) {
|
|
113
|
-
const derived = await deriveKey(p2s, alg, p2c, key);
|
|
114
|
-
return aeskwUnwrap(alg.slice(-6), derived, encryptedKey);
|
|
115
|
-
}
|
|
116
69
|
function lengthAndInput(input) {
|
|
117
70
|
return concat(uint32be(input.length), input);
|
|
118
71
|
}
|
|
@@ -122,11 +75,7 @@ async function concatKdf(Z, L, OtherInfo) {
|
|
|
122
75
|
const reps = Math.ceil(dkLen / hashLen);
|
|
123
76
|
const dk = new Uint8Array(reps * hashLen);
|
|
124
77
|
for (let i = 1; i <= reps; i++) {
|
|
125
|
-
const
|
|
126
|
-
hashInput.set(uint32be(i), 0);
|
|
127
|
-
hashInput.set(Z, 4);
|
|
128
|
-
hashInput.set(OtherInfo, 4 + Z.length);
|
|
129
|
-
const hashResult = await digest('sha256', hashInput);
|
|
78
|
+
const hashResult = await digest('sha256', concat(uint32be(i), Z, OtherInfo));
|
|
130
79
|
dk.set(hashResult, (i - 1) * hashLen);
|
|
131
80
|
}
|
|
132
81
|
return dk.slice(0, dkLen);
|
|
@@ -134,58 +83,47 @@ async function concatKdf(Z, L, OtherInfo) {
|
|
|
134
83
|
async function ecdhesDeriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) {
|
|
135
84
|
checkEcdhCryptoKey(publicKey);
|
|
136
85
|
checkEcdhCryptoKey(privateKey, 'deriveBits');
|
|
137
|
-
const
|
|
138
|
-
const partyUInfo = lengthAndInput(apu);
|
|
139
|
-
const partyVInfo = lengthAndInput(apv);
|
|
140
|
-
const suppPubInfo = uint32be(keyLength);
|
|
141
|
-
const suppPrivInfo = new Uint8Array();
|
|
142
|
-
const otherInfo = concat(algorithmID, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo);
|
|
86
|
+
const otherInfo = concat(lengthAndInput(encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
|
|
143
87
|
const Z = new Uint8Array(await crypto.subtle.deriveBits({
|
|
144
88
|
name: publicKey.algorithm.name,
|
|
145
89
|
public: publicKey,
|
|
146
|
-
}, privateKey,
|
|
90
|
+
}, privateKey, publicKey.algorithm.name === 'X25519'
|
|
91
|
+
? 256
|
|
92
|
+
: Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3));
|
|
147
93
|
return concatKdf(Z, keyLength, otherInfo);
|
|
148
94
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
case 'P-256':
|
|
158
|
-
case 'P-384':
|
|
159
|
-
case 'P-521':
|
|
160
|
-
return true;
|
|
161
|
-
default:
|
|
162
|
-
return key.algorithm.name === 'X25519';
|
|
95
|
+
function assertEcdhKey(key) {
|
|
96
|
+
assertCryptoKey(key);
|
|
97
|
+
const curve = key.algorithm.namedCurve;
|
|
98
|
+
if (curve !== 'P-256' &&
|
|
99
|
+
curve !== 'P-384' &&
|
|
100
|
+
curve !== 'P-521' &&
|
|
101
|
+
key.algorithm.name !== 'X25519') {
|
|
102
|
+
throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
|
|
163
103
|
}
|
|
164
104
|
}
|
|
165
|
-
const unsupportedAlgHeader = 'Invalid or unsupported "alg" (JWE Algorithm) header value';
|
|
166
105
|
function assertEncryptedKey(encryptedKey) {
|
|
167
106
|
if (encryptedKey === undefined)
|
|
168
107
|
throw new JWEInvalid('JWE Encrypted Key missing');
|
|
169
108
|
}
|
|
109
|
+
function assertNoEncryptedKey(encryptedKey) {
|
|
110
|
+
if (encryptedKey !== undefined)
|
|
111
|
+
throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
|
|
112
|
+
}
|
|
170
113
|
export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHeader, options) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
case 'ECDH
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
case 'ECDH-ES+A128KW':
|
|
181
|
-
case 'ECDH-ES+A192KW':
|
|
182
|
-
case 'ECDH-ES+A256KW': {
|
|
114
|
+
const entry = jweAlgorithm(alg);
|
|
115
|
+
if (alg === 'dir') {
|
|
116
|
+
assertNoEncryptedKey(encryptedKey);
|
|
117
|
+
return key;
|
|
118
|
+
}
|
|
119
|
+
switch (entry.subtle.name) {
|
|
120
|
+
case 'ECDH': {
|
|
121
|
+
if (alg === 'ECDH-ES')
|
|
122
|
+
assertNoEncryptedKey(encryptedKey);
|
|
183
123
|
if (!isObject(joseHeader.epk))
|
|
184
124
|
throw new JWEInvalid(`JOSE Header "epk" (Ephemeral Public Key) missing or invalid`);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
|
|
188
|
-
const epk = await jwkToKey(jweAlgorithm(alg), joseHeader.epk);
|
|
125
|
+
assertEcdhKey(key);
|
|
126
|
+
const epk = await jwkToKey(entry, joseHeader.epk);
|
|
189
127
|
let partyUInfo;
|
|
190
128
|
let partyVInfo;
|
|
191
129
|
if (joseHeader.apu !== undefined) {
|
|
@@ -204,17 +142,13 @@ export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHead
|
|
|
204
142
|
assertEncryptedKey(encryptedKey);
|
|
205
143
|
return aeskwUnwrap(alg.slice(-6), sharedSecret, encryptedKey);
|
|
206
144
|
}
|
|
207
|
-
case 'RSA-OAEP':
|
|
208
|
-
case 'RSA-OAEP-256':
|
|
209
|
-
case 'RSA-OAEP-384':
|
|
210
|
-
case 'RSA-OAEP-512': {
|
|
145
|
+
case 'RSA-OAEP': {
|
|
211
146
|
assertEncryptedKey(encryptedKey);
|
|
212
147
|
assertCryptoKey(key);
|
|
213
|
-
|
|
148
|
+
checkRsaKey(alg, key, 'decrypt');
|
|
149
|
+
return new Uint8Array(await crypto.subtle.decrypt('RSA-OAEP', key, encryptedKey));
|
|
214
150
|
}
|
|
215
|
-
case '
|
|
216
|
-
case 'PBES2-HS384+A192KW':
|
|
217
|
-
case 'PBES2-HS512+A256KW': {
|
|
151
|
+
case 'PBKDF2': {
|
|
218
152
|
assertEncryptedKey(encryptedKey);
|
|
219
153
|
if (typeof joseHeader.p2c !== 'number')
|
|
220
154
|
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`);
|
|
@@ -223,19 +157,15 @@ export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHead
|
|
|
223
157
|
throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
|
|
224
158
|
if (typeof joseHeader.p2s !== 'string')
|
|
225
159
|
throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return
|
|
160
|
+
const p2s = decodeBase64url(joseHeader.p2s, 'p2s', JWEInvalid);
|
|
161
|
+
const derived = await deriveKey(p2s, alg, joseHeader.p2c, key);
|
|
162
|
+
return aeskwUnwrap(alg.slice(-6), derived, encryptedKey);
|
|
229
163
|
}
|
|
230
|
-
case '
|
|
231
|
-
case 'A192KW':
|
|
232
|
-
case 'A256KW': {
|
|
164
|
+
case 'AES-KW': {
|
|
233
165
|
assertEncryptedKey(encryptedKey);
|
|
234
166
|
return aeskwUnwrap(alg, key, encryptedKey);
|
|
235
167
|
}
|
|
236
|
-
case '
|
|
237
|
-
case 'A192GCMKW':
|
|
238
|
-
case 'A256GCMKW': {
|
|
168
|
+
case 'AES-GCM': {
|
|
239
169
|
assertEncryptedKey(encryptedKey);
|
|
240
170
|
if (typeof joseHeader.iv !== 'string')
|
|
241
171
|
throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
|
|
@@ -245,10 +175,7 @@ export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHead
|
|
|
245
175
|
iv = decodeBase64url(joseHeader.iv, 'iv', JWEInvalid);
|
|
246
176
|
let tag;
|
|
247
177
|
tag = decodeBase64url(joseHeader.tag, 'tag', JWEInvalid);
|
|
248
|
-
return
|
|
249
|
-
}
|
|
250
|
-
default: {
|
|
251
|
-
throw new JOSENotSupported(unsupportedAlgHeader);
|
|
178
|
+
return decrypt(jweEncryption(alg.slice(0, -2)), key, encryptedKey, iv, tag, new Uint8Array());
|
|
252
179
|
}
|
|
253
180
|
}
|
|
254
181
|
}
|
|
@@ -256,23 +183,16 @@ export async function encryptKeyManagement(alg, enc, key, providedCek, providedP
|
|
|
256
183
|
let encryptedKey;
|
|
257
184
|
let parameters;
|
|
258
185
|
let cek;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
case 'ECDH-ES+A128KW':
|
|
266
|
-
case 'ECDH-ES+A192KW':
|
|
267
|
-
case 'ECDH-ES+A256KW': {
|
|
268
|
-
assertCryptoKey(key);
|
|
269
|
-
if (!ecdhesAllowed(key)) {
|
|
270
|
-
throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
|
|
271
|
-
}
|
|
186
|
+
const entry = jweAlgorithm(alg);
|
|
187
|
+
if (alg === 'dir')
|
|
188
|
+
return [key, undefined, undefined];
|
|
189
|
+
switch (entry.subtle.name) {
|
|
190
|
+
case 'ECDH': {
|
|
191
|
+
assertEcdhKey(key);
|
|
272
192
|
const { apu, apv } = providedParameters;
|
|
273
193
|
let ephemeralKey;
|
|
274
194
|
if (providedParameters.epk) {
|
|
275
|
-
ephemeralKey = (await prepareKey(
|
|
195
|
+
ephemeralKey = (await prepareKey(entry, providedParameters.epk, 'decrypt'));
|
|
276
196
|
}
|
|
277
197
|
else {
|
|
278
198
|
ephemeralKey = (await crypto.subtle.generateKey(key.algorithm, true, ['deriveBits'])).privateKey;
|
|
@@ -303,41 +223,34 @@ export async function encryptKeyManagement(alg, enc, key, providedCek, providedP
|
|
|
303
223
|
encryptedKey = await aeskwWrap(kwAlg, sharedSecret, cek);
|
|
304
224
|
break;
|
|
305
225
|
}
|
|
306
|
-
case 'RSA-OAEP':
|
|
307
|
-
case 'RSA-OAEP-256':
|
|
308
|
-
case 'RSA-OAEP-384':
|
|
309
|
-
case 'RSA-OAEP-512': {
|
|
226
|
+
case 'RSA-OAEP': {
|
|
310
227
|
cek = providedCek || generateCek(enc);
|
|
311
228
|
assertCryptoKey(key);
|
|
312
|
-
|
|
229
|
+
checkRsaKey(alg, key, 'encrypt');
|
|
230
|
+
encryptedKey = new Uint8Array(await crypto.subtle.encrypt('RSA-OAEP', key, cek));
|
|
313
231
|
break;
|
|
314
232
|
}
|
|
315
|
-
case '
|
|
316
|
-
case 'PBES2-HS384+A192KW':
|
|
317
|
-
case 'PBES2-HS512+A256KW': {
|
|
233
|
+
case 'PBKDF2': {
|
|
318
234
|
cek = providedCek || generateCek(enc);
|
|
319
|
-
const { p2c, p2s } = providedParameters;
|
|
320
|
-
|
|
235
|
+
const { p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16)) } = providedParameters;
|
|
236
|
+
const derived = await deriveKey(p2s, alg, p2c, key);
|
|
237
|
+
encryptedKey = await aeskwWrap(alg.slice(-6), derived, cek);
|
|
238
|
+
parameters = { p2c, p2s: b64u(p2s) };
|
|
321
239
|
break;
|
|
322
240
|
}
|
|
323
|
-
case '
|
|
324
|
-
case 'A192KW':
|
|
325
|
-
case 'A256KW': {
|
|
241
|
+
case 'AES-KW': {
|
|
326
242
|
cek = providedCek || generateCek(enc);
|
|
327
243
|
encryptedKey = await aeskwWrap(alg, key, cek);
|
|
328
244
|
break;
|
|
329
245
|
}
|
|
330
|
-
case '
|
|
331
|
-
case 'A192GCMKW':
|
|
332
|
-
case 'A256GCMKW': {
|
|
246
|
+
case 'AES-GCM': {
|
|
333
247
|
cek = providedCek || generateCek(enc);
|
|
334
248
|
const { iv } = providedParameters;
|
|
335
|
-
|
|
249
|
+
const wrapped = await encrypt(jweEncryption(alg.slice(0, -2)), cek, key, iv, new Uint8Array());
|
|
250
|
+
encryptedKey = wrapped.ciphertext;
|
|
251
|
+
parameters = { iv: b64u(wrapped.iv), tag: b64u(wrapped.tag) };
|
|
336
252
|
break;
|
|
337
253
|
}
|
|
338
|
-
default: {
|
|
339
|
-
throw new JOSENotSupported(unsupportedAlgHeader);
|
|
340
|
-
}
|
|
341
254
|
}
|
|
342
|
-
return
|
|
255
|
+
return [cek, encryptedKey, parameters];
|
|
343
256
|
}
|