@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.
Files changed (137) hide show
  1. package/bin/suveren-gateway.js +86 -5
  2. package/content/integrations/calendar.json +116 -22
  3. package/content/integrations/deploy-github.json +164 -0
  4. package/content/integrations/gmail.json +13 -4
  5. package/content/integrations/index.json +2 -1
  6. package/dist/control-plane/index.mjs +84 -7
  7. package/dist/mcp-server/http.mjs +147 -21
  8. package/dist/ui/assets/index-DecSrutK.js +105 -0
  9. package/dist/ui/index.html +1 -1
  10. package/node_modules/@hap/core/dist/index.d.mts +21 -0
  11. package/node_modules/@hap/core/dist/index.d.ts +21 -0
  12. package/node_modules/@hap/core/dist/index.js +17 -0
  13. package/node_modules/@hap/core/dist/index.mjs +17 -0
  14. package/node_modules/@hap/core/package.json +1 -1
  15. package/node_modules/@hap/core/src/gatekeeper.ts +28 -0
  16. package/node_modules/@hap/core/src/types.ts +21 -0
  17. package/node_modules/fast-uri/index.js +37 -1
  18. package/node_modules/fast-uri/package.json +1 -1
  19. package/node_modules/fast-uri/test/security.test.js +136 -0
  20. package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
  21. package/node_modules/hono/dist/cjs/jsx/base.js +1 -9
  22. package/node_modules/hono/dist/cjs/jsx/hooks/index.js +14 -11
  23. package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
  24. package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
  25. package/node_modules/hono/dist/cjs/utils/cookie.js +2 -1
  26. package/node_modules/hono/dist/helper/proxy/index.js +4 -0
  27. package/node_modules/hono/dist/jsx/base.js +1 -9
  28. package/node_modules/hono/dist/jsx/hooks/index.js +14 -11
  29. package/node_modules/hono/dist/middleware/cors/index.js +1 -1
  30. package/node_modules/hono/dist/middleware/language/language.js +10 -6
  31. package/node_modules/hono/dist/utils/cookie.js +2 -1
  32. package/node_modules/hono/package.json +2 -3
  33. package/node_modules/ip-address/README.md +142 -128
  34. package/node_modules/ip-address/dist/common.d.ts +6 -0
  35. package/node_modules/ip-address/dist/common.js +17 -1
  36. package/node_modules/ip-address/dist/common.js.map +1 -1
  37. package/node_modules/ip-address/dist/ipv4.js +3 -12
  38. package/node_modules/ip-address/dist/ipv4.js.map +1 -1
  39. package/node_modules/ip-address/dist/ipv6.d.ts +9 -2
  40. package/node_modules/ip-address/dist/ipv6.js +35 -16
  41. package/node_modules/ip-address/dist/ipv6.js.map +1 -1
  42. package/node_modules/ip-address/package.json +5 -3
  43. package/node_modules/jose/README.md +13 -13
  44. package/node_modules/jose/dist/types/index.d.ts +6 -5
  45. package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +17 -11
  46. package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +7 -19
  47. package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +17 -11
  48. package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +7 -19
  49. package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +18 -13
  50. package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +20 -21
  51. package/node_modules/jose/dist/types/jwk/embedded.d.ts +8 -12
  52. package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +0 -15
  53. package/node_modules/jose/dist/types/jwks/local.d.ts +12 -21
  54. package/node_modules/jose/dist/types/jwks/remote.d.ts +34 -165
  55. package/node_modules/jose/dist/types/jws/compact/sign.d.ts +2 -13
  56. package/node_modules/jose/dist/types/jws/compact/verify.d.ts +17 -13
  57. package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +2 -13
  58. package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +17 -13
  59. package/node_modules/jose/dist/types/jws/general/sign.d.ts +16 -17
  60. package/node_modules/jose/dist/types/jws/general/verify.d.ts +18 -15
  61. package/node_modules/jose/dist/types/jwt/decrypt.d.ts +17 -11
  62. package/node_modules/jose/dist/types/jwt/encrypt.d.ts +10 -34
  63. package/node_modules/jose/dist/types/jwt/sign.d.ts +2 -13
  64. package/node_modules/jose/dist/types/jwt/unsecured.d.ts +4 -13
  65. package/node_modules/jose/dist/types/jwt/verify.d.ts +14 -13
  66. package/node_modules/jose/dist/types/key/export.d.ts +0 -14
  67. package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +7 -14
  68. package/node_modules/jose/dist/types/key/generate_secret.d.ts +16 -14
  69. package/node_modules/jose/dist/types/key/import.d.ts +18 -28
  70. package/node_modules/jose/dist/types/types.d.ts +239 -222
  71. package/node_modules/jose/dist/types/util/base64url.d.ts +11 -4
  72. package/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -9
  73. package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +0 -8
  74. package/node_modules/jose/dist/types/util/errors.d.ts +128 -121
  75. package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +4 -22
  76. package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +5 -153
  77. package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +16 -111
  78. package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +15 -3
  79. package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +65 -81
  80. package/node_modules/jose/dist/webapi/jwk/embedded.js +5 -3
  81. package/node_modules/jose/dist/webapi/jwks/local.js +31 -72
  82. package/node_modules/jose/dist/webapi/jwks/remote.js +19 -28
  83. package/node_modules/jose/dist/webapi/jws/compact/sign.js +5 -2
  84. package/node_modules/jose/dist/webapi/jws/compact/verify.js +4 -16
  85. package/node_modules/jose/dist/webapi/jws/flattened/sign.js +7 -65
  86. package/node_modules/jose/dist/webapi/jws/flattened/verify.js +3 -89
  87. package/node_modules/jose/dist/webapi/jws/general/sign.js +19 -15
  88. package/node_modules/jose/dist/webapi/jws/general/verify.js +29 -9
  89. package/node_modules/jose/dist/webapi/jwt/decrypt.js +5 -5
  90. package/node_modules/jose/dist/webapi/jwt/sign.js +2 -3
  91. package/node_modules/jose/dist/webapi/jwt/unsecured.js +4 -3
  92. package/node_modules/jose/dist/webapi/jwt/verify.js +6 -6
  93. package/node_modules/jose/dist/webapi/key/export.js +37 -4
  94. package/node_modules/jose/dist/webapi/key/generate_key_pair.js +33 -82
  95. package/node_modules/jose/dist/webapi/key/import.js +8 -8
  96. package/node_modules/jose/dist/webapi/lib/asn1.js +53 -122
  97. package/node_modules/jose/dist/webapi/lib/buffer_utils.js +1 -0
  98. package/node_modules/jose/dist/webapi/lib/content_encryption.js +34 -109
  99. package/node_modules/jose/dist/webapi/lib/crypto_key.js +18 -126
  100. package/node_modules/jose/dist/webapi/lib/helpers.js +23 -0
  101. package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +0 -1
  102. package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +116 -0
  103. package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +186 -0
  104. package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +110 -0
  105. package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +8 -98
  106. package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +76 -0
  107. package/node_modules/jose/dist/webapi/lib/jws_sign.js +74 -0
  108. package/node_modules/jose/dist/webapi/lib/jws_verify.js +107 -0
  109. package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +68 -109
  110. package/node_modules/jose/dist/webapi/lib/key.js +132 -0
  111. package/node_modules/jose/dist/webapi/lib/key_algorithm.js +10 -0
  112. package/node_modules/jose/dist/webapi/lib/key_descriptor.js +7 -0
  113. package/node_modules/jose/dist/webapi/lib/key_management.js +162 -92
  114. package/node_modules/jose/dist/webapi/lib/options.js +48 -0
  115. package/node_modules/jose/dist/webapi/lib/signing.js +14 -56
  116. package/node_modules/jose/dist/webapi/lib/type_checks.js +13 -18
  117. package/node_modules/jose/dist/webapi/util/base64url.js +13 -4
  118. package/node_modules/jose/dist/webapi/util/decode_jwt.js +2 -2
  119. package/node_modules/jose/dist/webapi/util/decode_protected_header.js +5 -15
  120. package/node_modules/jose/dist/webapi/util/errors.js +1 -1
  121. package/node_modules/jose/package.json +2 -4
  122. package/package.json +2 -2
  123. package/profiles/deploy/0.6.profile.json +168 -0
  124. package/profiles/deploy/0.7.profile.json +168 -0
  125. package/profiles/email/0.4.profile.json +9 -2
  126. package/profiles/index.json +3 -1
  127. package/dist/ui/assets/index-Cog54HOo.js +0 -105
  128. package/node_modules/jose/dist/webapi/lib/aesgcmkw.js +0 -15
  129. package/node_modules/jose/dist/webapi/lib/aeskw.js +0 -25
  130. package/node_modules/jose/dist/webapi/lib/check_key_type.js +0 -122
  131. package/node_modules/jose/dist/webapi/lib/ecdhes.js +0 -52
  132. package/node_modules/jose/dist/webapi/lib/key_to_jwk.js +0 -34
  133. package/node_modules/jose/dist/webapi/lib/normalize_key.js +0 -166
  134. package/node_modules/jose/dist/webapi/lib/pbes2kw.js +0 -42
  135. package/node_modules/jose/dist/webapi/lib/rsaes.js +0 -24
  136. package/node_modules/jose/dist/webapi/lib/validate_algorithms.js +0 -10
  137. package/node_modules/jose/dist/webapi/lib/validate_crit.js +0 -33
@@ -0,0 +1,132 @@
1
+ import { withAlg as invalidKeyInput } from './invalid_key_input.js';
2
+ import { isKeyLike, isCryptoKey } from './is_key_like.js';
3
+ import * as jwk from './type_checks.js';
4
+ import { decode } from '../util/base64url.js';
5
+ import { jwkToKey } from './jwk_to_key.js';
6
+ const tag = (key) => key[Symbol.toStringTag];
7
+ const jwkMatchesOp = (entry, key, usage) => {
8
+ const { alg } = entry;
9
+ if (key.use !== undefined) {
10
+ const expected = usage === 'sign' || usage === 'verify' ? 'sig' : 'enc';
11
+ if (key.use !== expected) {
12
+ throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
13
+ }
14
+ }
15
+ if (key.alg !== undefined && key.alg !== alg) {
16
+ throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
17
+ }
18
+ if (Array.isArray(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)) {
21
+ throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
22
+ }
23
+ }
24
+ };
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];
30
+ if (jwk.isJWK(key)) {
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`);
35
+ }
36
+ jwkMatchesOp(entry, key, usage);
37
+ return [JWK, key];
38
+ }
39
+ if (!isKeyLike(key)) {
40
+ throw new TypeError(secret
41
+ ? invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')
42
+ : invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
43
+ }
44
+ if (secret) {
45
+ if (key.type !== 'secret') {
46
+ throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
47
+ }
48
+ }
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}"`);
61
+ }
62
+ }
63
+ return isCryptoKey(key) ? [CRYPTO, key] : [KEYOBJECT, key];
64
+ }
65
+ const BYTES = 0;
66
+ const CRYPTO = 1;
67
+ const KEYOBJECT = 2;
68
+ const JWK = 3;
69
+ let cache;
70
+ const nist = {
71
+ __proto__: null,
72
+ prime256v1: 'P-256',
73
+ secp384r1: 'P-384',
74
+ secp521r1: 'P-521',
75
+ };
76
+ function cached(key, alg, value) {
77
+ cache ||= new WeakMap();
78
+ const entry = cache.get(key);
79
+ if (value) {
80
+ if (entry) {
81
+ entry[alg] = value;
82
+ }
83
+ else {
84
+ cache.set(key, { [alg]: value });
85
+ }
86
+ }
87
+ return value ?? entry?.[alg];
88
+ }
89
+ const handleJWK = async (key, jwk, entry) => cached(key, entry.alg) ??
90
+ cached(key, entry.alg, await jwkToKey(entry, { ...jwk, alg: entry.alg }));
91
+ const handleKeyObject = (keyObject, entry) => {
92
+ const hit = cached(keyObject, entry.alg);
93
+ if (hit)
94
+ return hit;
95
+ const isPublic = keyObject.type === 'public';
96
+ const usages = entry.usages[isPublic ? 0 : 1];
97
+ const { asymmetricKeyType } = keyObject;
98
+ const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve];
99
+ const params = entry.resolve?.({ crv, asymmetricKeyType }) ?? entry.subtle;
100
+ return cached(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages));
101
+ };
102
+ export async function prepareKey(entry, key, usage) {
103
+ const tagged = checkKeyType(entry, key, usage);
104
+ switch (tagged[0]) {
105
+ case BYTES:
106
+ case CRYPTO:
107
+ return tagged[1];
108
+ case JWK: {
109
+ const key = tagged[1];
110
+ if (key.k) {
111
+ return decode(key.k);
112
+ }
113
+ if (!Object.isFrozen(key)) {
114
+ const { key_ops } = key;
115
+ if (Array.isArray(key_ops))
116
+ Object.freeze(key_ops);
117
+ Object.freeze(key);
118
+ }
119
+ return handleJWK(key, key, entry);
120
+ }
121
+ case KEYOBJECT: {
122
+ const keyObject = tagged[1];
123
+ if (keyObject.type === 'secret') {
124
+ return keyObject.export();
125
+ }
126
+ if ('toCryptoKey' in keyObject && typeof keyObject.toCryptoKey === 'function') {
127
+ return handleKeyObject(keyObject, entry);
128
+ }
129
+ return handleJWK(keyObject, keyObject.export({ format: 'jwk' }), entry);
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,10 @@
1
+ import { JOSENotSupported } from '../util/errors.js';
2
+ import { maybeJWSAlgorithm } from './jws_algorithms.js';
3
+ import { maybeJWEAlgorithm } from './jwe_algorithms.js';
4
+ export function keyAlgorithm(alg) {
5
+ const entry = typeof alg === 'string' ? (maybeJWSAlgorithm(alg) ?? maybeJWEAlgorithm(alg)) : undefined;
6
+ if (!entry) {
7
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
8
+ }
9
+ return entry;
10
+ }
@@ -0,0 +1,7 @@
1
+ export function table(entries) {
2
+ const out = { __proto__: null };
3
+ for (const alg in entries) {
4
+ out[alg] = { ...entries[alg], alg };
5
+ }
6
+ return out;
7
+ }
@@ -1,42 +1,129 @@
1
- import * as aeskw from './aeskw.js';
2
- import * as ecdhes from './ecdhes.js';
3
- import * as pbes2kw from './pbes2kw.js';
4
- import * as rsaes from './rsaes.js';
5
1
  import { encode as b64u } from '../util/base64url.js';
6
- import { normalizeKey } from './normalize_key.js';
2
+ import { prepareKey } from './key.js';
3
+ import { jwkToKey } from './jwk_to_key.js';
4
+ import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js';
7
5
  import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
8
- import { decodeBase64url } from './helpers.js';
9
- import { generateCek, cekLength } from './content_encryption.js';
10
- import { importJWK } from '../key/import.js';
11
- import { exportJWK } from '../key/export.js';
6
+ import { decodeBase64url, digest } from './helpers.js';
7
+ import { generateCek, encrypt, decrypt } from './content_encryption.js';
12
8
  import { isObject } from './type_checks.js';
13
- import { wrap as aesGcmKwWrap, unwrap as aesGcmKwUnwrap } from './aesgcmkw.js';
9
+ import { checkCryptoKey, checkModulusLength, checkUsage } from './crypto_key.js';
10
+ import { concat, encode, uint32be } from './buffer_utils.js';
14
11
  import { assertCryptoKey } from './is_key_like.js';
15
- const unsupportedAlgHeader = 'Invalid or unsupported "alg" (JWE Algorithm) header value';
12
+ function checkEcdhCryptoKey(key, usage) {
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');
15
+ }
16
+ checkUsage(key, usage);
17
+ }
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;
27
+ }
28
+ async function aeskwWrap(alg, key, cek) {
29
+ const cryptoKey = await aeskwCryptoKey(key, alg, 'wrapKey');
30
+ const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
31
+ return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW'));
32
+ }
33
+ async function aeskwUnwrap(alg, key, encryptedKey) {
34
+ const cryptoKey = await aeskwCryptoKey(key, alg, 'unwrapKey');
35
+ const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
36
+ return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek));
37
+ }
38
+ function checkRsaKey(alg, key, usage) {
39
+ checkCryptoKey(key, jweAlgorithm(alg).subtle, usage);
40
+ checkModulusLength(alg, key);
41
+ }
42
+ function pbes2CryptoKey(key, alg) {
43
+ if (key instanceof Uint8Array) {
44
+ return crypto.subtle.importKey('raw', key, 'PBKDF2', false, [
45
+ 'deriveBits',
46
+ ]);
47
+ }
48
+ checkCryptoKey(key, jweAlgorithm(alg).subtle, 'deriveBits');
49
+ return key;
50
+ }
51
+ async function deriveKey(p2s, alg, p2c, key) {
52
+ if (!(p2s instanceof Uint8Array) || p2s.length < 8) {
53
+ throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets');
54
+ }
55
+ if (!Number.isSafeInteger(p2c) || Math.sign(p2c) !== 1) {
56
+ throw new JWEInvalid('PBES2 Count Input must be a positive integer');
57
+ }
58
+ const salt = concat(encode(alg), Uint8Array.of(0), p2s);
59
+ const keylen = parseInt(alg.slice(13, 16), 10);
60
+ const subtleAlg = {
61
+ hash: `SHA-${alg.slice(8, 11)}`,
62
+ iterations: p2c,
63
+ name: 'PBKDF2',
64
+ salt,
65
+ };
66
+ const cryptoKey = await pbes2CryptoKey(key, alg);
67
+ return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
68
+ }
69
+ function lengthAndInput(input) {
70
+ return concat(uint32be(input.length), input);
71
+ }
72
+ async function concatKdf(Z, L, OtherInfo) {
73
+ const dkLen = L >> 3;
74
+ const hashLen = 32;
75
+ const reps = Math.ceil(dkLen / hashLen);
76
+ const dk = new Uint8Array(reps * hashLen);
77
+ for (let i = 1; i <= reps; i++) {
78
+ const hashResult = await digest('sha256', concat(uint32be(i), Z, OtherInfo));
79
+ dk.set(hashResult, (i - 1) * hashLen);
80
+ }
81
+ return dk.slice(0, dkLen);
82
+ }
83
+ async function ecdhesDeriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) {
84
+ checkEcdhCryptoKey(publicKey);
85
+ checkEcdhCryptoKey(privateKey, 'deriveBits');
86
+ const otherInfo = concat(lengthAndInput(encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
87
+ const Z = new Uint8Array(await crypto.subtle.deriveBits({
88
+ name: publicKey.algorithm.name,
89
+ public: publicKey,
90
+ }, privateKey, publicKey.algorithm.name === 'X25519'
91
+ ? 256
92
+ : Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3));
93
+ return concatKdf(Z, keyLength, otherInfo);
94
+ }
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');
103
+ }
104
+ }
16
105
  function assertEncryptedKey(encryptedKey) {
17
106
  if (encryptedKey === undefined)
18
107
  throw new JWEInvalid('JWE Encrypted Key missing');
19
108
  }
20
- export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options) {
21
- switch (alg) {
22
- case 'dir': {
23
- if (encryptedKey !== undefined)
24
- throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
25
- return key;
26
- }
27
- case 'ECDH-ES':
28
- if (encryptedKey !== undefined)
29
- throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
30
- case 'ECDH-ES+A128KW':
31
- case 'ECDH-ES+A192KW':
32
- case 'ECDH-ES+A256KW': {
109
+ function assertNoEncryptedKey(encryptedKey) {
110
+ if (encryptedKey !== undefined)
111
+ throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
112
+ }
113
+ export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHeader, options) {
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);
33
123
  if (!isObject(joseHeader.epk))
34
124
  throw new JWEInvalid(`JOSE Header "epk" (Ephemeral Public Key) missing or invalid`);
35
- assertCryptoKey(key);
36
- if (!ecdhes.allowed(key))
37
- throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
38
- const epk = await importJWK(joseHeader.epk, alg);
39
- assertCryptoKey(epk);
125
+ assertEcdhKey(key);
126
+ const epk = await jwkToKey(entry, joseHeader.epk);
40
127
  let partyUInfo;
41
128
  let partyVInfo;
42
129
  if (joseHeader.apu !== undefined) {
@@ -49,23 +136,19 @@ export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, o
49
136
  throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
50
137
  partyVInfo = decodeBase64url(joseHeader.apv, 'apv', JWEInvalid);
51
138
  }
52
- const sharedSecret = await ecdhes.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
139
+ const sharedSecret = await ecdhesDeriveKey(epk, key, alg === 'ECDH-ES' ? enc.alg : alg, alg === 'ECDH-ES' ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);
53
140
  if (alg === 'ECDH-ES')
54
141
  return sharedSecret;
55
142
  assertEncryptedKey(encryptedKey);
56
- return aeskw.unwrap(alg.slice(-6), sharedSecret, encryptedKey);
143
+ return aeskwUnwrap(alg.slice(-6), sharedSecret, encryptedKey);
57
144
  }
58
- case 'RSA-OAEP':
59
- case 'RSA-OAEP-256':
60
- case 'RSA-OAEP-384':
61
- case 'RSA-OAEP-512': {
145
+ case 'RSA-OAEP': {
62
146
  assertEncryptedKey(encryptedKey);
63
147
  assertCryptoKey(key);
64
- return rsaes.decrypt(alg, key, encryptedKey);
148
+ checkRsaKey(alg, key, 'decrypt');
149
+ return new Uint8Array(await crypto.subtle.decrypt('RSA-OAEP', key, encryptedKey));
65
150
  }
66
- case 'PBES2-HS256+A128KW':
67
- case 'PBES2-HS384+A192KW':
68
- case 'PBES2-HS512+A256KW': {
151
+ case 'PBKDF2': {
69
152
  assertEncryptedKey(encryptedKey);
70
153
  if (typeof joseHeader.p2c !== 'number')
71
154
  throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`);
@@ -74,19 +157,15 @@ export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, o
74
157
  throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`);
75
158
  if (typeof joseHeader.p2s !== 'string')
76
159
  throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
77
- let p2s;
78
- p2s = decodeBase64url(joseHeader.p2s, 'p2s', JWEInvalid);
79
- return pbes2kw.unwrap(alg, key, encryptedKey, joseHeader.p2c, p2s);
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);
80
163
  }
81
- case 'A128KW':
82
- case 'A192KW':
83
- case 'A256KW': {
164
+ case 'AES-KW': {
84
165
  assertEncryptedKey(encryptedKey);
85
- return aeskw.unwrap(alg, key, encryptedKey);
166
+ return aeskwUnwrap(alg, key, encryptedKey);
86
167
  }
87
- case 'A128GCMKW':
88
- case 'A192GCMKW':
89
- case 'A256GCMKW': {
168
+ case 'AES-GCM': {
90
169
  assertEncryptedKey(encryptedKey);
91
170
  if (typeof joseHeader.iv !== 'string')
92
171
  throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
@@ -96,10 +175,7 @@ export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, o
96
175
  iv = decodeBase64url(joseHeader.iv, 'iv', JWEInvalid);
97
176
  let tag;
98
177
  tag = decodeBase64url(joseHeader.tag, 'tag', JWEInvalid);
99
- return aesGcmKwUnwrap(alg, key, encryptedKey, iv, tag);
100
- }
101
- default: {
102
- throw new JOSENotSupported(unsupportedAlgHeader);
178
+ return decrypt(jweEncryption(alg.slice(0, -2)), key, encryptedKey, iv, tag, new Uint8Array());
103
179
  }
104
180
  }
105
181
  }
@@ -107,29 +183,30 @@ export async function encryptKeyManagement(alg, enc, key, providedCek, providedP
107
183
  let encryptedKey;
108
184
  let parameters;
109
185
  let cek;
110
- switch (alg) {
111
- case 'dir': {
112
- cek = key;
113
- break;
114
- }
115
- case 'ECDH-ES':
116
- case 'ECDH-ES+A128KW':
117
- case 'ECDH-ES+A192KW':
118
- case 'ECDH-ES+A256KW': {
119
- assertCryptoKey(key);
120
- if (!ecdhes.allowed(key)) {
121
- throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');
122
- }
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);
123
192
  const { apu, apv } = providedParameters;
124
193
  let ephemeralKey;
125
194
  if (providedParameters.epk) {
126
- ephemeralKey = (await normalizeKey(providedParameters.epk, alg));
195
+ ephemeralKey = (await prepareKey(entry, providedParameters.epk, 'decrypt'));
127
196
  }
128
197
  else {
129
198
  ephemeralKey = (await crypto.subtle.generateKey(key.algorithm, true, ['deriveBits'])).privateKey;
130
199
  }
131
- const { x, y, crv, kty } = await exportJWK(ephemeralKey);
132
- const sharedSecret = await ecdhes.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? cekLength(enc) : parseInt(alg.slice(-5, -2), 10), apu, apv);
200
+ const subtle = crypto.subtle;
201
+ let exportableEpk = ephemeralKey;
202
+ if (!exportableEpk.extractable) {
203
+ if (typeof subtle.getPublicKey !== 'function') {
204
+ throw new TypeError('CryptoKey for "epk" must be extractable');
205
+ }
206
+ exportableEpk = await subtle.getPublicKey(ephemeralKey, []);
207
+ }
208
+ const { x, y, crv, kty } = (await subtle.exportKey('jwk', exportableEpk));
209
+ const sharedSecret = await ecdhesDeriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc.alg : alg, alg === 'ECDH-ES' ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), apu, apv);
133
210
  parameters = { epk: { x, crv, kty } };
134
211
  if (kty === 'EC')
135
212
  parameters.epk.y = y;
@@ -143,44 +220,37 @@ export async function encryptKeyManagement(alg, enc, key, providedCek, providedP
143
220
  }
144
221
  cek = providedCek || generateCek(enc);
145
222
  const kwAlg = alg.slice(-6);
146
- encryptedKey = await aeskw.wrap(kwAlg, sharedSecret, cek);
223
+ encryptedKey = await aeskwWrap(kwAlg, sharedSecret, cek);
147
224
  break;
148
225
  }
149
- case 'RSA-OAEP':
150
- case 'RSA-OAEP-256':
151
- case 'RSA-OAEP-384':
152
- case 'RSA-OAEP-512': {
226
+ case 'RSA-OAEP': {
153
227
  cek = providedCek || generateCek(enc);
154
228
  assertCryptoKey(key);
155
- encryptedKey = await rsaes.encrypt(alg, key, cek);
229
+ checkRsaKey(alg, key, 'encrypt');
230
+ encryptedKey = new Uint8Array(await crypto.subtle.encrypt('RSA-OAEP', key, cek));
156
231
  break;
157
232
  }
158
- case 'PBES2-HS256+A128KW':
159
- case 'PBES2-HS384+A192KW':
160
- case 'PBES2-HS512+A256KW': {
233
+ case 'PBKDF2': {
161
234
  cek = providedCek || generateCek(enc);
162
- const { p2c, p2s } = providedParameters;
163
- ({ encryptedKey, ...parameters } = await pbes2kw.wrap(alg, key, cek, p2c, p2s));
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) };
164
239
  break;
165
240
  }
166
- case 'A128KW':
167
- case 'A192KW':
168
- case 'A256KW': {
241
+ case 'AES-KW': {
169
242
  cek = providedCek || generateCek(enc);
170
- encryptedKey = await aeskw.wrap(alg, key, cek);
243
+ encryptedKey = await aeskwWrap(alg, key, cek);
171
244
  break;
172
245
  }
173
- case 'A128GCMKW':
174
- case 'A192GCMKW':
175
- case 'A256GCMKW': {
246
+ case 'AES-GCM': {
176
247
  cek = providedCek || generateCek(enc);
177
248
  const { iv } = providedParameters;
178
- ({ encryptedKey, ...parameters } = await aesGcmKwWrap(alg, key, cek, iv));
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) };
179
252
  break;
180
253
  }
181
- default: {
182
- throw new JOSENotSupported(unsupportedAlgHeader);
183
- }
184
254
  }
185
- return { cek, encryptedKey, parameters };
255
+ return [cek, encryptedKey, parameters];
186
256
  }
@@ -0,0 +1,48 @@
1
+ import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js';
2
+ export const JWS_RECOGNIZED = { __proto__: null, b64: true };
3
+ export const JWE_RECOGNIZED = { __proto__: null };
4
+ export function validateAlgorithms(option, algorithms) {
5
+ if (algorithms !== undefined &&
6
+ (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) {
7
+ throw new TypeError(`"${option}" option must be an array of strings`);
8
+ }
9
+ if (!algorithms) {
10
+ return undefined;
11
+ }
12
+ return new Set(algorithms);
13
+ }
14
+ export function validateCritDuplicates(Err, protectedHeader) {
15
+ const { crit } = protectedHeader ?? {};
16
+ if (Array.isArray(crit) && new Set(crit).size !== crit.length) {
17
+ throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values');
18
+ }
19
+ }
20
+ export function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
21
+ if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {
22
+ throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
23
+ }
24
+ if (!protectedHeader || protectedHeader.crit === undefined) {
25
+ return [];
26
+ }
27
+ if (!Array.isArray(protectedHeader.crit) ||
28
+ protectedHeader.crit.length === 0 ||
29
+ protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) {
30
+ throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
31
+ }
32
+ const recognized = recognizedOption === undefined
33
+ ? recognizedDefault
34
+ : { __proto__: null, ...recognizedOption, ...recognizedDefault };
35
+ for (const parameter of protectedHeader.crit) {
36
+ if (!(parameter in recognized)) {
37
+ throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
38
+ }
39
+ if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === undefined) {
40
+ throw new Err(`Extension Header Parameter "${parameter}" is missing`);
41
+ }
42
+ if (recognized[parameter] &&
43
+ (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === undefined)) {
44
+ throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
45
+ }
46
+ }
47
+ return protectedHeader.crit;
48
+ }
@@ -1,66 +1,24 @@
1
- import { JOSENotSupported } from '../util/errors.js';
2
- import { checkSigCryptoKey } from './crypto_key.js';
3
- import { invalidKeyInput } from './invalid_key_input.js';
4
- export function checkKeyLength(alg, key) {
5
- if (alg.startsWith('RS') || alg.startsWith('PS')) {
6
- const { modulusLength } = key.algorithm;
7
- if (typeof modulusLength !== 'number' || modulusLength < 2048) {
8
- throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
9
- }
10
- }
11
- }
12
- function subtleAlgorithm(alg, algorithm) {
13
- const hash = `SHA-${alg.slice(-3)}`;
14
- switch (alg) {
15
- case 'HS256':
16
- case 'HS384':
17
- case 'HS512':
18
- return { hash, name: 'HMAC' };
19
- case 'PS256':
20
- case 'PS384':
21
- case 'PS512':
22
- return { hash, name: 'RSA-PSS', saltLength: parseInt(alg.slice(-3), 10) >> 3 };
23
- case 'RS256':
24
- case 'RS384':
25
- case 'RS512':
26
- return { hash, name: 'RSASSA-PKCS1-v1_5' };
27
- case 'ES256':
28
- case 'ES384':
29
- case 'ES512':
30
- return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
31
- case 'Ed25519':
32
- case 'EdDSA':
33
- return { name: 'Ed25519' };
34
- case 'ML-DSA-44':
35
- case 'ML-DSA-65':
36
- case 'ML-DSA-87':
37
- return { name: alg };
38
- default:
39
- throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
40
- }
41
- }
42
- async function getSigKey(alg, key, usage) {
1
+ import { checkCryptoKey, checkModulusLength } from './crypto_key.js';
2
+ async function getSigKey(entry, key, usage) {
43
3
  if (key instanceof Uint8Array) {
44
- if (!alg.startsWith('HS')) {
45
- throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
46
- }
47
- return crypto.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]);
4
+ return crypto.subtle.importKey('raw', key, entry.subtle, false, [
5
+ usage,
6
+ ]);
48
7
  }
49
- checkSigCryptoKey(key, alg, usage);
8
+ checkCryptoKey(key, entry.subtle, usage);
9
+ if (entry.minRsaBits)
10
+ checkModulusLength(entry.alg, key);
50
11
  return key;
51
12
  }
52
- export async function sign(alg, key, data) {
53
- const cryptoKey = await getSigKey(alg, key, 'sign');
54
- checkKeyLength(alg, cryptoKey);
55
- const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);
13
+ export async function sign(entry, key, data) {
14
+ const cryptoKey = await getSigKey(entry, key, 'sign');
15
+ const signature = await crypto.subtle.sign(entry.signing, cryptoKey, data);
56
16
  return new Uint8Array(signature);
57
17
  }
58
- export async function verify(alg, key, signature, data) {
59
- const cryptoKey = await getSigKey(alg, key, 'verify');
60
- checkKeyLength(alg, cryptoKey);
61
- const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);
18
+ export async function verify(entry, key, signature, data) {
19
+ const cryptoKey = await getSigKey(entry, key, 'verify');
62
20
  try {
63
- return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
21
+ return await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
64
22
  }
65
23
  catch {
66
24
  return false;
@@ -1,34 +1,29 @@
1
- const isObjectLike = (value) => typeof value === 'object' && value !== null;
2
1
  export function isObject(input) {
3
- if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {
2
+ if (typeof input !== 'object' ||
3
+ input === null ||
4
+ Object.prototype.toString.call(input) !== '[object Object]') {
4
5
  return false;
5
6
  }
6
- if (Object.getPrototypeOf(input) === null) {
7
+ const prototype = Object.getPrototypeOf(input);
8
+ if (prototype === null) {
7
9
  return true;
8
10
  }
9
- let proto = input;
11
+ let proto = prototype;
10
12
  while (Object.getPrototypeOf(proto) !== null) {
11
13
  proto = Object.getPrototypeOf(proto);
12
14
  }
13
- return Object.getPrototypeOf(input) === proto;
15
+ return prototype === proto;
14
16
  }
15
17
  export function isDisjoint(...headers) {
16
- const sources = headers.filter(Boolean);
17
- if (sources.length === 0 || sources.length === 1) {
18
- return true;
19
- }
20
- let acc;
21
- for (const header of sources) {
22
- const parameters = Object.keys(header);
23
- if (!acc || acc.size === 0) {
24
- acc = new Set(parameters);
18
+ const parameters = new Set();
19
+ for (const header of headers) {
20
+ if (!header)
25
21
  continue;
26
- }
27
- for (const parameter of parameters) {
28
- if (acc.has(parameter)) {
22
+ for (const parameter of Object.keys(header)) {
23
+ if (parameters.has(parameter)) {
29
24
  return false;
30
25
  }
31
- acc.add(parameter);
26
+ parameters.add(parameter);
32
27
  }
33
28
  }
34
29
  return true;