jose 3.17.0 → 3.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +10 -3
  2. package/dist/browser/jwe/compact/decrypt.js +5 -1
  3. package/dist/browser/jwe/flattened/decrypt.js +5 -0
  4. package/dist/browser/jwk/embedded.js +3 -3
  5. package/dist/browser/jwk/from_key_like.js +2 -2
  6. package/dist/browser/jwk/parse.js +2 -31
  7. package/dist/browser/jwks/remote.js +7 -10
  8. package/dist/browser/jws/compact/verify.js +5 -1
  9. package/dist/browser/jws/flattened/verify.js +5 -0
  10. package/dist/browser/jwt/decrypt.js +5 -1
  11. package/dist/browser/jwt/encrypt.js +1 -1
  12. package/dist/browser/{lib/jwt_producer.js → jwt/produce.js} +4 -4
  13. package/dist/browser/jwt/sign.js +1 -1
  14. package/dist/browser/jwt/unsecured.js +1 -1
  15. package/dist/browser/jwt/verify.js +5 -1
  16. package/dist/browser/key/export.js +12 -0
  17. package/dist/browser/key/import.js +119 -0
  18. package/dist/browser/lib/check_key_type.js +33 -16
  19. package/dist/browser/lib/decrypt_key_management.js +37 -37
  20. package/dist/browser/lib/encrypt_key_management.js +2 -2
  21. package/dist/browser/lib/format_pem.js +4 -0
  22. package/dist/browser/runtime/asn1.js +119 -0
  23. package/dist/browser/runtime/base64url.js +12 -7
  24. package/dist/browser/runtime/fetch_jwks.js +18 -5
  25. package/dist/browser/runtime/is_key_like.js +5 -0
  26. package/dist/browser/util/errors.js +10 -3
  27. package/dist/node/cjs/jwe/compact/decrypt.js +5 -1
  28. package/dist/node/cjs/jwe/flattened/decrypt.js +5 -0
  29. package/dist/node/cjs/jwk/embedded.js +3 -3
  30. package/dist/node/cjs/jwk/from_key_like.js +2 -2
  31. package/dist/node/cjs/jwk/parse.js +2 -31
  32. package/dist/node/cjs/jwks/remote.js +7 -10
  33. package/dist/node/cjs/jws/compact/verify.js +5 -1
  34. package/dist/node/cjs/jws/flattened/verify.js +5 -0
  35. package/dist/node/cjs/jwt/decrypt.js +5 -1
  36. package/dist/node/cjs/jwt/encrypt.js +2 -2
  37. package/dist/node/cjs/{lib/jwt_producer.js → jwt/produce.js} +5 -4
  38. package/dist/node/cjs/jwt/sign.js +2 -2
  39. package/dist/node/cjs/jwt/unsecured.js +2 -2
  40. package/dist/node/cjs/jwt/verify.js +5 -1
  41. package/dist/node/cjs/key/export.js +18 -0
  42. package/dist/node/cjs/key/import.js +126 -0
  43. package/dist/node/cjs/lib/check_key_type.js +33 -16
  44. package/dist/node/cjs/lib/decrypt_key_management.js +37 -37
  45. package/dist/node/cjs/lib/encrypt_key_management.js +2 -2
  46. package/dist/node/cjs/lib/format_pem.js +6 -0
  47. package/dist/node/cjs/runtime/asn1.js +46 -0
  48. package/dist/node/cjs/runtime/base64url.js +5 -1
  49. package/dist/node/cjs/runtime/fetch_jwks.js +5 -1
  50. package/dist/node/cjs/runtime/is_key_like.js +11 -0
  51. package/dist/node/cjs/util/errors.js +12 -4
  52. package/dist/node/esm/jwe/compact/decrypt.js +5 -1
  53. package/dist/node/esm/jwe/flattened/decrypt.js +5 -0
  54. package/dist/node/esm/jwk/embedded.js +3 -3
  55. package/dist/node/esm/jwk/from_key_like.js +2 -2
  56. package/dist/node/esm/jwk/parse.js +2 -31
  57. package/dist/node/esm/jwks/remote.js +7 -10
  58. package/dist/node/esm/jws/compact/verify.js +5 -1
  59. package/dist/node/esm/jws/flattened/verify.js +5 -0
  60. package/dist/node/esm/jwt/decrypt.js +5 -1
  61. package/dist/node/esm/jwt/encrypt.js +1 -1
  62. package/dist/node/esm/{lib/jwt_producer.js → jwt/produce.js} +4 -4
  63. package/dist/node/esm/jwt/sign.js +1 -1
  64. package/dist/node/esm/jwt/unsecured.js +1 -1
  65. package/dist/node/esm/jwt/verify.js +5 -1
  66. package/dist/node/esm/key/export.js +12 -0
  67. package/dist/node/esm/key/import.js +119 -0
  68. package/dist/node/esm/lib/check_key_type.js +33 -16
  69. package/dist/node/esm/lib/decrypt_key_management.js +37 -37
  70. package/dist/node/esm/lib/encrypt_key_management.js +2 -2
  71. package/dist/node/esm/lib/format_pem.js +4 -0
  72. package/dist/node/esm/runtime/asn1.js +39 -0
  73. package/dist/node/esm/runtime/base64url.js +2 -0
  74. package/dist/node/esm/runtime/fetch_jwks.js +6 -2
  75. package/dist/node/esm/runtime/is_key_like.js +8 -0
  76. package/dist/node/esm/util/errors.js +10 -3
  77. package/dist/types/jwe/compact/decrypt.d.ts +3 -2
  78. package/dist/types/jwe/compact/encrypt.d.ts +1 -1
  79. package/dist/types/jwe/flattened/decrypt.d.ts +3 -2
  80. package/dist/types/jwe/flattened/encrypt.d.ts +1 -1
  81. package/dist/types/jwe/general/decrypt.d.ts +3 -2
  82. package/dist/types/jwk/embedded.d.ts +2 -3
  83. package/dist/types/jwk/from_key_like.d.ts +1 -1
  84. package/dist/types/jwk/parse.d.ts +1 -1
  85. package/dist/types/jws/compact/sign.d.ts +1 -1
  86. package/dist/types/jws/compact/verify.d.ts +3 -2
  87. package/dist/types/jws/flattened/sign.d.ts +1 -1
  88. package/dist/types/jws/flattened/verify.d.ts +3 -2
  89. package/dist/types/jws/general/sign.d.ts +1 -1
  90. package/dist/types/jws/general/verify.d.ts +3 -2
  91. package/dist/types/jwt/decrypt.d.ts +3 -2
  92. package/dist/types/jwt/encrypt.d.ts +2 -2
  93. package/dist/types/{lib/jwt_producer.d.ts → jwt/produce.d.ts} +1 -1
  94. package/dist/types/jwt/sign.d.ts +2 -2
  95. package/dist/types/jwt/unsecured.d.ts +1 -1
  96. package/dist/types/jwt/verify.d.ts +3 -2
  97. package/dist/types/key/export.d.ts +5 -0
  98. package/dist/types/key/import.d.ts +9 -0
  99. package/dist/types/types.d.ts +101 -5
  100. package/dist/types/util/errors.d.ts +5 -0
  101. package/dist/types/util/generate_key_pair.d.ts +2 -2
  102. package/dist/types/util/generate_secret.d.ts +1 -1
  103. package/package.json +20 -8
package/README.md CHANGED
@@ -31,6 +31,11 @@ If you or your business use `jose`, please consider becoming a [sponsor][support
31
31
  - Encrypted JSON Web Tokens
32
32
  - [Encryption](docs/classes/jwt_encrypt.EncryptJWT.md#readme)
33
33
  - [Decryption & Claims Set Validation](docs/functions/jwt_decrypt.jwtDecrypt.md#readme)
34
+ - Key Import
35
+ - [JWK Import](docs/functions/key_import.importJWK.md#readme)
36
+ - [Public Key Import (SPKI)](docs/functions/key_import.importSPKI.md#readme)
37
+ - [Public Key Import (X.509 Certificate)](docs/functions/key_import.importX509.md#readme)
38
+ - [Private Key Import (PKCS #8)](docs/functions/key_import.importPKCS8.md#readme)
34
39
  - JSON Web Encryption (JWE)
35
40
  - Encryption - [Compact](docs/classes/jwe_compact_encrypt.CompactEncrypt.md#readme), [Flattened](docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md#readme)
36
41
  - Decryption - [Compact](docs/functions/jwe_compact_decrypt.compactDecrypt.md#readme), [Flattened](docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md#readme), [General](docs/functions/jwe_general_decrypt.generalDecrypt.md#readme)
@@ -38,15 +43,17 @@ If you or your business use `jose`, please consider becoming a [sponsor][support
38
43
  - Signing - [Compact](docs/classes/jws_compact_sign.CompactSign.md#readme), [Flattened](docs/classes/jws_flattened_sign.FlattenedSign.md#readme), [General](docs/classes/jws_general_sign.GeneralSign.md#readme)
39
44
  - Verification - [Compact](docs/functions/jws_compact_verify.compactVerify.md#readme), [Flattened](docs/functions/jws_flattened_verify.flattenedVerify.md#readme), [General](docs/functions/jws_general_verify.generalVerify.md#readme)
40
45
  - JSON Web Key (JWK)
41
- - [Parsing (JWK to KeyLike)](docs/functions/jwk_parse.parseJwk.md#readme)
42
- - [Conversion (KeyLike to JWK)](docs/functions/jwk_from_key_like.fromKeyLike.md#readme)
43
46
  - [Thumbprints](docs/functions/jwk_thumbprint.calculateThumbprint.md#readme)
44
47
  - [EmbeddedJWK](docs/functions/jwk_embedded.EmbeddedJWK.md#readme)
45
48
  - JSON Web Key Set (JWKS)
46
49
  - [Verify using a remote JWKSet](docs/functions/jwks_remote.createRemoteJWKSet.md#readme)
47
- - Key Pair or Secret Generation (Generate KeyLike)
50
+ - Key Pair or Secret Generation
48
51
  - [Asymmetric Key Pair Generation](docs/functions/util_generate_key_pair.generateKeyPair.md#readme)
49
52
  - [Symmetric Secret Generation](docs/functions/util_generate_secret.generateSecret.md#readme)
53
+ - Key Export
54
+ - [JWK Export](docs/functions/key_export.exportJWK.md#readme)
55
+ - [Private Key Export](docs/functions/key_export.exportPKCS8.md#readme)
56
+ - [Public Key Export](docs/functions/key_export.exportSPKI.md#readme)
50
57
  - Utilities
51
58
  - [Decoding Token's Protected Header](docs/functions/util_decode_protected_header.decodeProtectedHeader.md#readme)
52
59
  - [Unsecured JWT](docs/classes/jwt_unsecured.UnsecuredJWT.md#readme)
@@ -19,7 +19,11 @@ async function compactDecrypt(jwe, key, options) {
19
19
  tag: (tag || undefined),
20
20
  encrypted_key: encryptedKey || undefined,
21
21
  }, key, options);
22
- return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };
22
+ const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };
23
+ if (typeof key === 'function') {
24
+ return { ...result, key: decrypted.key };
25
+ }
26
+ return result;
23
27
  }
24
28
  export { compactDecrypt };
25
29
  export default compactDecrypt;
@@ -92,8 +92,10 @@ async function flattenedDecrypt(jwe, key, options) {
92
92
  if (jwe.encrypted_key !== undefined) {
93
93
  encryptedKey = base64url(jwe.encrypted_key);
94
94
  }
95
+ let resolvedKey = false;
95
96
  if (typeof key === 'function') {
96
97
  key = await key(parsedProt, jwe);
98
+ resolvedKey = true;
97
99
  }
98
100
  let cek;
99
101
  try {
@@ -132,6 +134,9 @@ async function flattenedDecrypt(jwe, key, options) {
132
134
  if (jwe.header !== undefined) {
133
135
  result.unprotectedHeader = jwe.header;
134
136
  }
137
+ if (resolvedKey) {
138
+ return { ...result, key };
139
+ }
135
140
  return result;
136
141
  }
137
142
  export { flattenedDecrypt };
@@ -1,4 +1,4 @@
1
- import parseJwk from './parse.js';
1
+ import { importJWK } from '../key/import.js';
2
2
  import isObject from '../lib/is_object.js';
3
3
  import { JWSInvalid } from '../util/errors.js';
4
4
  async function EmbeddedJWK(protectedHeader, token) {
@@ -9,8 +9,8 @@ async function EmbeddedJWK(protectedHeader, token) {
9
9
  if (!isObject(joseHeader.jwk)) {
10
10
  throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object');
11
11
  }
12
- const key = await parseJwk(joseHeader.jwk, joseHeader.alg, true);
13
- if (key.type !== 'public') {
12
+ const key = await importJWK({ ...joseHeader.jwk, ext: true }, joseHeader.alg, true);
13
+ if (key instanceof Uint8Array || key.type !== 'public') {
14
14
  throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key');
15
15
  }
16
16
  return key;
@@ -1,6 +1,6 @@
1
- import asJWK from '../runtime/key_to_jwk.js';
1
+ import { exportJWK } from '../key/export.js';
2
2
  async function fromKeyLike(key) {
3
- return asJWK(key);
3
+ return exportJWK(key);
4
4
  }
5
5
  export { fromKeyLike };
6
6
  export default fromKeyLike;
@@ -1,35 +1,6 @@
1
- import { decode as base64url } from '../runtime/base64url.js';
2
- import asKeyObject from '../runtime/jwk_to_key.js';
3
- import { JOSENotSupported } from '../util/errors.js';
4
- import isObject from '../lib/is_object.js';
1
+ import { importJWK } from '../key/import.js';
5
2
  async function parseJwk(jwk, alg, octAsKeyObject) {
6
- if (!isObject(jwk)) {
7
- throw new TypeError('JWK must be an object');
8
- }
9
- alg || (alg = jwk.alg);
10
- if (typeof alg !== 'string' || !alg) {
11
- throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
12
- }
13
- switch (jwk.kty) {
14
- case 'oct':
15
- if (typeof jwk.k !== 'string' || !jwk.k) {
16
- throw new TypeError('missing "k" (Key Value) Parameter value');
17
- }
18
- octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
19
- if (octAsKeyObject) {
20
- return asKeyObject({ ...jwk, alg, ext: false });
21
- }
22
- return base64url(jwk.k);
23
- case 'RSA':
24
- if (jwk.oth !== undefined) {
25
- throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
26
- }
27
- case 'EC':
28
- case 'OKP':
29
- return asKeyObject({ ...jwk, alg });
30
- default:
31
- throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
32
- }
3
+ return importJWK(jwk, alg, octAsKeyObject);
33
4
  }
34
5
  export { parseJwk };
35
6
  export default parseJwk;
@@ -1,9 +1,9 @@
1
1
  import fetchJwks from '../runtime/fetch_jwks.js';
2
- import parseJWK from '../jwk/parse.js';
2
+ import { importJWK } from '../key/import.js';
3
3
  import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js';
4
4
  import isObject from '../lib/is_object.js';
5
5
  function getKtyFromAlg(alg) {
6
- switch (alg.substr(0, 2)) {
6
+ switch (typeof alg === 'string' && alg.substr(0, 2)) {
7
7
  case 'RS':
8
8
  case 'PS':
9
9
  return 'RSA';
@@ -32,7 +32,7 @@ class RemoteJWKSet {
32
32
  typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000;
33
33
  }
34
34
  coolingDown() {
35
- if (typeof this._cooldownStarted === 'undefined') {
35
+ if (!this._cooldownStarted) {
36
36
  return false;
37
37
  }
38
38
  return Date.now() < this._cooldownStarted + this._cooldownDuration;
@@ -56,7 +56,7 @@ class RemoteJWKSet {
56
56
  candidate = jwk.key_ops.includes('verify');
57
57
  }
58
58
  if (candidate && protectedHeader.alg === 'EdDSA') {
59
- candidate = ['Ed25519', 'Ed448'].includes(jwk.crv);
59
+ candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
60
60
  }
61
61
  if (candidate) {
62
62
  switch (protectedHeader.alg) {
@@ -88,13 +88,10 @@ class RemoteJWKSet {
88
88
  else if (length !== 1) {
89
89
  throw new JWKSMultipleMatchingKeys();
90
90
  }
91
- if (!this._cached.has(jwk)) {
92
- this._cached.set(jwk, {});
93
- }
94
- const cached = this._cached.get(jwk);
91
+ const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
95
92
  if (cached[protectedHeader.alg] === undefined) {
96
- const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg });
97
- if (keyObject.type !== 'public') {
93
+ const keyObject = await importJWK({ ...jwk, ext: true }, protectedHeader.alg);
94
+ if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
98
95
  throw new JWKSInvalid('JSON Web Key Set members must be public keys');
99
96
  }
100
97
  cached[protectedHeader.alg] = keyObject;
@@ -17,7 +17,11 @@ async function compactVerify(jws, key, options) {
17
17
  protected: protectedHeader || undefined,
18
18
  signature: (signature || undefined),
19
19
  }, key, options);
20
- return { payload: verified.payload, protectedHeader: verified.protectedHeader };
20
+ const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
21
+ if (typeof key === 'function') {
22
+ return { ...result, key: verified.key };
23
+ }
24
+ return result;
21
25
  }
22
26
  export { compactVerify };
23
27
  export default compactVerify;
@@ -70,8 +70,10 @@ async function flattenedVerify(jws, key, options) {
70
70
  else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) {
71
71
  throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance');
72
72
  }
73
+ let resolvedKey = false;
73
74
  if (typeof key === 'function') {
74
75
  key = await key(parsedProt, jws);
76
+ resolvedKey = true;
75
77
  }
76
78
  checkKeyType(alg, key, 'verify');
77
79
  const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
@@ -97,6 +99,9 @@ async function flattenedVerify(jws, key, options) {
97
99
  if (jws.header !== undefined) {
98
100
  result.unprotectedHeader = jws.header;
99
101
  }
102
+ if (resolvedKey) {
103
+ return { ...result, key };
104
+ }
100
105
  return result;
101
106
  }
102
107
  export { flattenedVerify };
@@ -15,7 +15,11 @@ async function jwtDecrypt(jwt, key, options) {
15
15
  JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) {
16
16
  throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch');
17
17
  }
18
- return { payload, protectedHeader };
18
+ const result = { payload, protectedHeader };
19
+ if (typeof key === 'function') {
20
+ return { ...result, key: decrypted.key };
21
+ }
22
+ return result;
19
23
  }
20
24
  export { jwtDecrypt };
21
25
  export default jwtDecrypt;
@@ -1,6 +1,6 @@
1
1
  import CompactEncrypt from '../jwe/compact/encrypt.js';
2
2
  import { encoder } from '../lib/buffer_utils.js';
3
- import ProduceJWT from '../lib/jwt_producer.js';
3
+ import { ProduceJWT } from './produce.js';
4
4
  class EncryptJWT extends ProduceJWT {
5
5
  setProtectedHeader(protectedHeader) {
6
6
  if (this._protectedHeader) {
@@ -1,7 +1,7 @@
1
- import epoch from './epoch.js';
2
- import isObject from './is_object.js';
3
- import secs from './secs.js';
4
- export default class ProduceJWT {
1
+ import epoch from '../lib/epoch.js';
2
+ import isObject from '../lib/is_object.js';
3
+ import secs from '../lib/secs.js';
4
+ export class ProduceJWT {
5
5
  constructor(payload) {
6
6
  if (!isObject(payload)) {
7
7
  throw new TypeError('JWT Claims Set MUST be an object');
@@ -1,7 +1,7 @@
1
1
  import CompactSign from '../jws/compact/sign.js';
2
2
  import { JWTInvalid } from '../util/errors.js';
3
3
  import { encoder } from '../lib/buffer_utils.js';
4
- import ProduceJWT from '../lib/jwt_producer.js';
4
+ import { ProduceJWT } from './produce.js';
5
5
  class SignJWT extends ProduceJWT {
6
6
  setProtectedHeader(protectedHeader) {
7
7
  this._protectedHeader = protectedHeader;
@@ -2,7 +2,7 @@ import * as base64url from '../runtime/base64url.js';
2
2
  import { decoder } from '../lib/buffer_utils.js';
3
3
  import { JWTInvalid } from '../util/errors.js';
4
4
  import jwtPayload from '../lib/jwt_claims_set.js';
5
- import ProduceJWT from '../lib/jwt_producer.js';
5
+ import { ProduceJWT } from './produce.js';
6
6
  class UnsecuredJWT extends ProduceJWT {
7
7
  encode() {
8
8
  const header = base64url.encode(JSON.stringify({ alg: 'none' }));
@@ -8,7 +8,11 @@ async function jwtVerify(jwt, key, options) {
8
8
  throw new JWTInvalid('JWTs MUST NOT use unencoded payload');
9
9
  }
10
10
  const payload = jwtPayload(verified.protectedHeader, verified.payload, options);
11
- return { payload, protectedHeader: verified.protectedHeader };
11
+ const result = { payload, protectedHeader: verified.protectedHeader };
12
+ if (typeof key === 'function') {
13
+ return { ...result, key: verified.key };
14
+ }
15
+ return result;
12
16
  }
13
17
  export { jwtVerify };
14
18
  export default jwtVerify;
@@ -0,0 +1,12 @@
1
+ import { toSPKI as exportPublic } from '../runtime/asn1.js';
2
+ import { toPKCS8 as exportPrivate } from '../runtime/asn1.js';
3
+ import keyToJWK from '../runtime/key_to_jwk.js';
4
+ export async function exportSPKI(key) {
5
+ return exportPublic(key);
6
+ }
7
+ export async function exportPKCS8(key) {
8
+ return exportPrivate(key);
9
+ }
10
+ export async function exportJWK(key) {
11
+ return keyToJWK(key);
12
+ }
@@ -0,0 +1,119 @@
1
+ import { decode as decodeBase64URL, encodeBase64, decodeBase64 } from '../runtime/base64url.js';
2
+ import { fromSPKI as importPublic } from '../runtime/asn1.js';
3
+ import { fromPKCS8 as importPrivate } from '../runtime/asn1.js';
4
+ import asKeyObject from '../runtime/jwk_to_key.js';
5
+ import { JOSENotSupported } from '../util/errors.js';
6
+ import formatPEM from '../lib/format_pem.js';
7
+ import isObject from '../lib/is_object.js';
8
+ function getElement(seq) {
9
+ let result = [];
10
+ let next = 0;
11
+ while (next < seq.length) {
12
+ let nextPart = parseElement(seq.subarray(next));
13
+ result.push(nextPart);
14
+ next += nextPart.byteLength;
15
+ }
16
+ return result;
17
+ }
18
+ function parseElement(bytes) {
19
+ let position = 0;
20
+ let tag = bytes[0] & 0x1f;
21
+ position++;
22
+ if (tag === 0x1f) {
23
+ tag = 0;
24
+ while (bytes[position] >= 0x80) {
25
+ tag = tag * 128 + bytes[position] - 0x80;
26
+ position++;
27
+ }
28
+ tag = tag * 128 + bytes[position] - 0x80;
29
+ position++;
30
+ }
31
+ let length = 0;
32
+ if (bytes[position] < 0x80) {
33
+ length = bytes[position];
34
+ position++;
35
+ }
36
+ else {
37
+ let numberOfDigits = bytes[position] & 0x7f;
38
+ position++;
39
+ length = 0;
40
+ for (let i = 0; i < numberOfDigits; i++) {
41
+ length = length * 256 + bytes[position];
42
+ position++;
43
+ }
44
+ }
45
+ if (length === 0x80) {
46
+ length = 0;
47
+ while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) {
48
+ length++;
49
+ }
50
+ const byteLength = position + length + 2;
51
+ return {
52
+ byteLength,
53
+ contents: bytes.subarray(position, position + length),
54
+ raw: bytes.subarray(0, byteLength),
55
+ };
56
+ }
57
+ const byteLength = position + length;
58
+ return {
59
+ byteLength,
60
+ contents: bytes.subarray(position, byteLength),
61
+ raw: bytes.subarray(0, byteLength),
62
+ };
63
+ }
64
+ function spkiFromX509(buf) {
65
+ return encodeBase64(getElement(getElement(parseElement(buf).contents)[0].contents)[6].raw);
66
+ }
67
+ function getSPKI(x509) {
68
+ const pem = x509.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, '');
69
+ const raw = decodeBase64(pem);
70
+ return formatPEM(spkiFromX509(raw), 'PUBLIC KEY');
71
+ }
72
+ export async function importSPKI(spki, alg, options) {
73
+ if (typeof spki !== 'string' || spki.indexOf('-----BEGIN PUBLIC KEY-----') !== 0) {
74
+ throw new TypeError('"spki" must be SPKI formatted string');
75
+ }
76
+ return importPublic(spki, alg, options);
77
+ }
78
+ export async function importX509(x509, alg, options) {
79
+ if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {
80
+ throw new TypeError('"x509" must be X.509 formatted string');
81
+ }
82
+ const spki = getSPKI(x509);
83
+ return importPublic(spki, alg, options);
84
+ }
85
+ export async function importPKCS8(pkcs8, alg, options) {
86
+ if (typeof pkcs8 !== 'string' || pkcs8.indexOf('-----BEGIN PRIVATE KEY-----') !== 0) {
87
+ throw new TypeError('"pkcs8" must be PCKS8 formatted string');
88
+ }
89
+ return importPrivate(pkcs8, alg, options);
90
+ }
91
+ export async function importJWK(jwk, alg, octAsKeyObject) {
92
+ if (!isObject(jwk)) {
93
+ throw new TypeError('JWK must be an object');
94
+ }
95
+ alg || (alg = jwk.alg);
96
+ if (typeof alg !== 'string' || !alg) {
97
+ throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
98
+ }
99
+ switch (jwk.kty) {
100
+ case 'oct':
101
+ if (typeof jwk.k !== 'string' || !jwk.k) {
102
+ throw new TypeError('missing "k" (Key Value) Parameter value');
103
+ }
104
+ octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
105
+ if (octAsKeyObject) {
106
+ return asKeyObject({ ...jwk, alg, ext: false });
107
+ }
108
+ return decodeBase64URL(jwk.k);
109
+ case 'RSA':
110
+ if (jwk.oth !== undefined) {
111
+ throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
112
+ }
113
+ case 'EC':
114
+ case 'OKP':
115
+ return asKeyObject({ ...jwk, alg });
116
+ default:
117
+ throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
118
+ }
119
+ }
@@ -1,28 +1,45 @@
1
1
  import invalidKeyInput from '../runtime/invalid_key_input.js';
2
- const checkKeyType = (alg, key, usage) => {
3
- if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) {
4
- throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array'));
2
+ import isKeyLike, { types } from '../runtime/is_key_like.js';
3
+ const symmetricTypeCheck = (key) => {
4
+ if (key instanceof Uint8Array)
5
+ return;
6
+ if (!isKeyLike(key)) {
7
+ throw new TypeError(invalidKeyInput(key, ...types, 'Uint8Array'));
5
8
  }
6
- if (alg.startsWith('HS') ||
7
- alg === 'dir' ||
8
- alg.startsWith('PBES2') ||
9
- alg.match(/^A\d{3}(?:GCM)?KW$/)) {
10
- if (key instanceof Uint8Array || key.type === 'secret') {
11
- return;
12
- }
13
- throw new TypeError('CryptoKey or KeyObject instances for symmetric algorithms must be of type "secret"');
9
+ if (key.type !== 'secret') {
10
+ throw new TypeError(`${types.join(' or ')} instances for symmetric algorithms must be of type "secret"`);
14
11
  }
15
- if (key instanceof Uint8Array) {
16
- throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey'));
12
+ };
13
+ const asymmetricTypeCheck = (key, usage) => {
14
+ if (!isKeyLike(key)) {
15
+ throw new TypeError(invalidKeyInput(key, ...types));
17
16
  }
18
17
  if (key.type === 'secret') {
19
- throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"');
18
+ throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithms must not be of type "secret"`);
20
19
  }
21
20
  if (usage === 'sign' && key.type === 'public') {
22
- throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"');
21
+ throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm signing must be of type "private"`);
23
22
  }
24
23
  if (usage === 'decrypt' && key.type === 'public') {
25
- throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"');
24
+ throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm decryption must be of type "private"`);
25
+ }
26
+ if (key.algorithm && usage === 'verify' && key.type === 'private') {
27
+ throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm verifying must be of type "public"`);
28
+ }
29
+ if (key.algorithm && usage === 'encrypt' && key.type === 'private') {
30
+ throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm encryption must be of type "public"`);
31
+ }
32
+ };
33
+ const checkKeyType = (alg, key, usage) => {
34
+ const symmetric = alg.startsWith('HS') ||
35
+ alg === 'dir' ||
36
+ alg.startsWith('PBES2') ||
37
+ /^A\d{3}(?:GCM)?KW$/.test(alg);
38
+ if (symmetric) {
39
+ symmetricTypeCheck(key);
40
+ }
41
+ else {
42
+ asymmetricTypeCheck(key, usage);
26
43
  }
27
44
  };
28
45
  export default checkKeyType;
@@ -6,83 +6,83 @@ import { unwrap as aesGcmKw } from '../runtime/aesgcmkw.js';
6
6
  import { decode as base64url } from '../runtime/base64url.js';
7
7
  import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
8
8
  import { bitLengths as cekLengths } from '../lib/cek.js';
9
- import { parseJwk } from '../jwk/parse.js';
9
+ import { importJWK } from '../key/import.js';
10
10
  import checkKeyType from './check_key_type.js';
11
- function assertEnryptedKey(encryptedKey) {
12
- if (!encryptedKey) {
13
- throw new JWEInvalid('JWE Encrypted Key missing');
14
- }
15
- }
16
- function assertHeaderParameter(joseHeader, parameter, name) {
17
- if (joseHeader[parameter] === undefined) {
18
- throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`);
19
- }
20
- }
11
+ import isObject from './is_object.js';
21
12
  async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) {
22
13
  checkKeyType(alg, key, 'decrypt');
23
14
  switch (alg) {
24
15
  case 'dir': {
25
- if (encryptedKey !== undefined) {
16
+ if (encryptedKey !== undefined)
26
17
  throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
27
- }
28
18
  return key;
29
19
  }
30
20
  case 'ECDH-ES':
31
- if (encryptedKey !== undefined) {
21
+ if (encryptedKey !== undefined)
32
22
  throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');
33
- }
34
23
  case 'ECDH-ES+A128KW':
35
24
  case 'ECDH-ES+A192KW':
36
25
  case 'ECDH-ES+A256KW': {
37
- assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key');
38
- if (!ECDH.ecdhAllowed(key)) {
26
+ if (!isObject(joseHeader.epk))
27
+ throw new JWEInvalid(`JOSE Header "epk" (Ephemeral Public Key) missing or invalid`);
28
+ if (!ECDH.ecdhAllowed(key))
39
29
  throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime');
40
- }
41
- const epk = await parseJwk(joseHeader.epk, alg);
30
+ const epk = await importJWK(joseHeader.epk, alg);
42
31
  let partyUInfo;
43
32
  let partyVInfo;
44
- if (joseHeader.apu !== undefined)
33
+ if (joseHeader.apu !== undefined) {
34
+ if (typeof joseHeader.apu !== 'string')
35
+ throw new JWEInvalid(`JOSE Header "apu" (Agreement PartyUInfo) invalid`);
45
36
  partyUInfo = base64url(joseHeader.apu);
46
- if (joseHeader.apv !== undefined)
37
+ }
38
+ if (joseHeader.apv !== undefined) {
39
+ if (typeof joseHeader.apv !== 'string')
40
+ throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
47
41
  partyVInfo = base64url(joseHeader.apv);
42
+ }
48
43
  const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc), partyUInfo, partyVInfo);
49
- if (alg === 'ECDH-ES') {
44
+ if (alg === 'ECDH-ES')
50
45
  return sharedSecret;
51
- }
52
- assertEnryptedKey(encryptedKey);
53
- const kwAlg = alg.substr(-6);
54
- return aesKw(kwAlg, sharedSecret, encryptedKey);
46
+ if (encryptedKey === undefined)
47
+ throw new JWEInvalid('JWE Encrypted Key missing');
48
+ return aesKw(alg.substr(-6), sharedSecret, encryptedKey);
55
49
  }
56
50
  case 'RSA1_5':
57
51
  case 'RSA-OAEP':
58
52
  case 'RSA-OAEP-256':
59
53
  case 'RSA-OAEP-384':
60
54
  case 'RSA-OAEP-512': {
61
- assertEnryptedKey(encryptedKey);
55
+ if (encryptedKey === undefined)
56
+ throw new JWEInvalid('JWE Encrypted Key missing');
62
57
  return rsaEs(alg, key, encryptedKey);
63
58
  }
64
59
  case 'PBES2-HS256+A128KW':
65
60
  case 'PBES2-HS384+A192KW':
66
61
  case 'PBES2-HS512+A256KW': {
67
- assertEnryptedKey(encryptedKey);
68
- assertHeaderParameter(joseHeader, 'p2c', 'PBES2 Count');
69
- assertHeaderParameter(joseHeader, 'p2s', 'PBES2 Salt');
70
- const { p2c } = joseHeader;
71
- const p2s = base64url(joseHeader.p2s);
72
- return pbes2Kw(alg, key, encryptedKey, p2c, p2s);
62
+ if (encryptedKey === undefined)
63
+ throw new JWEInvalid('JWE Encrypted Key missing');
64
+ if (typeof joseHeader.p2c !== 'number')
65
+ throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`);
66
+ if (typeof joseHeader.p2s !== 'string')
67
+ throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`);
68
+ return pbes2Kw(alg, key, encryptedKey, joseHeader.p2c, base64url(joseHeader.p2s));
73
69
  }
74
70
  case 'A128KW':
75
71
  case 'A192KW':
76
72
  case 'A256KW': {
77
- assertEnryptedKey(encryptedKey);
73
+ if (encryptedKey === undefined)
74
+ throw new JWEInvalid('JWE Encrypted Key missing');
78
75
  return aesKw(alg, key, encryptedKey);
79
76
  }
80
77
  case 'A128GCMKW':
81
78
  case 'A192GCMKW':
82
79
  case 'A256GCMKW': {
83
- assertEnryptedKey(encryptedKey);
84
- assertHeaderParameter(joseHeader, 'iv', 'Initialization Vector');
85
- assertHeaderParameter(joseHeader, 'tag', 'Authentication Tag');
80
+ if (encryptedKey === undefined)
81
+ throw new JWEInvalid('JWE Encrypted Key missing');
82
+ if (typeof joseHeader.iv !== 'string')
83
+ throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`);
84
+ if (typeof joseHeader.tag !== 'string')
85
+ throw new JWEInvalid(`JOSE Header "tag" (Authentication Tag) missing or invalid`);
86
86
  const iv = base64url(joseHeader.iv);
87
87
  const tag = base64url(joseHeader.tag);
88
88
  return aesGcmKw(alg, key, encryptedKey, iv, tag);
@@ -7,7 +7,7 @@ import { wrap as aesGcmKw } from '../runtime/aesgcmkw.js';
7
7
  import { encode as base64url } from '../runtime/base64url.js';
8
8
  import cekFactory, { bitLengths as cekLengths } from '../lib/cek.js';
9
9
  import { JOSENotSupported } from '../util/errors.js';
10
- import { fromKeyLike } from '../jwk/from_key_like.js';
10
+ import { exportJWK } from '../key/export.js';
11
11
  import checkKeyType from './check_key_type.js';
12
12
  const generateCek = cekFactory(random);
13
13
  async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) {
@@ -30,7 +30,7 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
30
30
  const { apu, apv } = providedParameters;
31
31
  let { epk: ephemeralKey } = providedParameters;
32
32
  ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key));
33
- const { x, y, crv, kty } = await fromKeyLike(ephemeralKey);
33
+ const { x, y, crv, kty } = await exportJWK(ephemeralKey);
34
34
  const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), apu, apv);
35
35
  parameters = { epk: { x, y, crv, kty } };
36
36
  if (apu)
@@ -0,0 +1,4 @@
1
+ export default (b64, descriptor) => {
2
+ const newlined = (b64.match(/.{1,64}/g) || []).join('\n');
3
+ return `-----BEGIN ${descriptor}-----\n${newlined}\n-----END ${descriptor}-----`;
4
+ };