jose 4.9.3 → 4.10.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.
- package/README.md +3 -26
- package/dist/browser/key/import.js +20 -11
- package/dist/browser/lib/crypto_key.js +16 -3
- package/dist/browser/runtime/asn1.js +17 -4
- package/dist/browser/runtime/ecdhes.js +16 -3
- package/dist/browser/runtime/env.js +3 -1
- package/dist/browser/runtime/generate.js +31 -4
- package/dist/browser/runtime/jwk_to_key.js +19 -1
- package/dist/browser/runtime/subtle_dsa.js +2 -0
- package/dist/node/cjs/key/import.js +20 -11
- package/dist/node/cjs/lib/crypto_key.js +16 -3
- package/dist/node/esm/key/import.js +20 -11
- package/dist/node/esm/lib/crypto_key.js +16 -3
- package/dist/types/jwk/thumbprint.d.ts +8 -5
- package/dist/types/jwks/remote.d.ts +6 -6
- package/dist/types/jwt/produce.d.ts +2 -1
- package/dist/types/types.d.ts +35 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# jose
|
|
2
2
|
|
|
3
|
-
> "JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK, JWKS
|
|
3
|
+
> "JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, and other Web-interoperable runtimes.
|
|
4
4
|
|
|
5
5
|
## Implemented specs & features
|
|
6
6
|
|
|
@@ -22,6 +22,8 @@ implementation is correct.
|
|
|
22
22
|
|
|
23
23
|
## [💗 Help the project](https://github.com/sponsors/panva)
|
|
24
24
|
|
|
25
|
+
## Dependencies: 0
|
|
26
|
+
|
|
25
27
|
## Documentation
|
|
26
28
|
|
|
27
29
|
**`example`** ESM import
|
|
@@ -94,31 +96,6 @@ import * as jose from 'https://deno.land/x/jose/index.ts'
|
|
|
94
96
|
| [v4.x](https://github.com/panva/jose/tree/v4.x) | ✅ | ✅ | ✅ |
|
|
95
97
|
| [v3.x](https://github.com/panva/jose/tree/v3.x), [v2.x](https://github.com/panva/jose/tree/v2.x), [v1.x](https://github.com/panva/jose/tree/v1.x) | ✅ | ❌ | ❌ |
|
|
96
98
|
|
|
97
|
-
#### Semver?
|
|
98
|
-
|
|
99
|
-
**Yes.** All module's public API is subject to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
|
|
100
|
-
|
|
101
|
-
#### How is it different from [`jws`](https://github.com/brianloveswords/node-jws), [`jwa`](https://github.com/brianloveswords/node-jwa) or [`jsonwebtoken`](https://github.com/auth0/node-jsonwebtoken)?
|
|
102
|
-
|
|
103
|
-
- it supports Browser, Cloudflare Workers, and Deno runtimes
|
|
104
|
-
- it supports encrypted JWTs (i.e. in JWE format)
|
|
105
|
-
- supports secp256k1, Ed25519, Ed448, X25519, and X448
|
|
106
|
-
- it supports JWK Key Format for all four key types (oct, RSA, EC and OKP)
|
|
107
|
-
- it is exclusively using native platform Key object representations (CryptoKey and KeyObject)
|
|
108
|
-
- there is JSON Web Encryption support
|
|
109
|
-
- it supports the General and Flattened JSON Serialization Syntaxes
|
|
110
|
-
- it supports the "crit" member validations to make sure extensions are handled correctly
|
|
111
|
-
|
|
112
|
-
#### How is it different from [`node-jose`](https://github.com/cisco/node-jose)?
|
|
113
|
-
|
|
114
|
-
`node-jose` is built to work in any javascript runtime, to be able to do that it packs a lot of
|
|
115
|
-
polyfills and javascript implementation code in the form of
|
|
116
|
-
[`node-forge`](https://github.com/digitalbazaar/forge), this significantly increases the footprint
|
|
117
|
-
of the modules with dependencies that either aren't ever used or have native implementation available
|
|
118
|
-
in the runtime already, those are often times faster and more reliable.
|
|
119
|
-
|
|
120
|
-
- supports secp256k1, Ed25519, Ed448, X25519, and X448
|
|
121
|
-
|
|
122
99
|
#### Uint8Array?!
|
|
123
100
|
|
|
124
101
|
- Whenever `Uint8Array` is a valid input, so is [`Buffer`](https://nodejs.org/api/buffer.html#buffer_buffer) since buffers are instances of Uint8Array.
|
|
@@ -33,18 +33,12 @@ function parseElement(bytes) {
|
|
|
33
33
|
length = bytes[position];
|
|
34
34
|
position++;
|
|
35
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) {
|
|
36
|
+
else if (length === 0x80) {
|
|
46
37
|
length = 0;
|
|
47
38
|
while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) {
|
|
39
|
+
if (length > bytes.byteLength) {
|
|
40
|
+
throw new TypeError('invalid indefinite form length');
|
|
41
|
+
}
|
|
48
42
|
length++;
|
|
49
43
|
}
|
|
50
44
|
const byteLength = position + length + 2;
|
|
@@ -54,6 +48,15 @@ function parseElement(bytes) {
|
|
|
54
48
|
raw: bytes.subarray(0, byteLength),
|
|
55
49
|
};
|
|
56
50
|
}
|
|
51
|
+
else {
|
|
52
|
+
let numberOfDigits = bytes[position] & 0x7f;
|
|
53
|
+
position++;
|
|
54
|
+
length = 0;
|
|
55
|
+
for (let i = 0; i < numberOfDigits; i++) {
|
|
56
|
+
length = length * 256 + bytes[position];
|
|
57
|
+
position++;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
57
60
|
const byteLength = position + length;
|
|
58
61
|
return {
|
|
59
62
|
byteLength,
|
|
@@ -80,7 +83,13 @@ export async function importX509(x509, alg, options) {
|
|
|
80
83
|
if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {
|
|
81
84
|
throw new TypeError('"x509" must be X.509 formatted string');
|
|
82
85
|
}
|
|
83
|
-
|
|
86
|
+
let spki;
|
|
87
|
+
try {
|
|
88
|
+
spki = getSPKI(x509);
|
|
89
|
+
}
|
|
90
|
+
catch (cause) {
|
|
91
|
+
throw new TypeError('failed to parse the X.509 certificate', { cause });
|
|
92
|
+
}
|
|
84
93
|
return importPublic(spki, alg, options);
|
|
85
94
|
}
|
|
86
95
|
export async function importPKCS8(pkcs8, alg, options) {
|
|
@@ -76,6 +76,12 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
76
76
|
throw unusable('NODE-ED25519');
|
|
77
77
|
break;
|
|
78
78
|
}
|
|
79
|
+
case 'EdDSA': {
|
|
80
|
+
if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
|
|
81
|
+
throw unusable('Ed25519 or Ed448');
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
79
85
|
case 'ES256':
|
|
80
86
|
case 'ES384':
|
|
81
87
|
case 'ES512': {
|
|
@@ -116,10 +122,17 @@ export function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
116
122
|
throw unusable(expected, 'algorithm.length');
|
|
117
123
|
break;
|
|
118
124
|
}
|
|
119
|
-
case 'ECDH':
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
case 'ECDH': {
|
|
126
|
+
switch (key.algorithm.name) {
|
|
127
|
+
case 'ECDH':
|
|
128
|
+
case 'X25519':
|
|
129
|
+
case 'X448':
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
throw unusable('ECDH, X25519, or X448');
|
|
133
|
+
}
|
|
122
134
|
break;
|
|
135
|
+
}
|
|
123
136
|
case 'PBES2-HS256+A128KW':
|
|
124
137
|
case 'PBES2-HS384+A192KW':
|
|
125
138
|
case 'PBES2-HS512+A256KW':
|
|
@@ -44,8 +44,14 @@ const getNamedCurve = (keyData) => {
|
|
|
44
44
|
return 'P-384';
|
|
45
45
|
case findOid(keyData, [0x2b, 0x81, 0x04, 0x00, 0x23]):
|
|
46
46
|
return 'P-521';
|
|
47
|
-
case
|
|
47
|
+
case findOid(keyData, [0x2b, 0x65, 0x6e]):
|
|
48
|
+
return 'X25519';
|
|
49
|
+
case findOid(keyData, [0x2b, 0x65, 0x6f]):
|
|
50
|
+
return 'X448';
|
|
51
|
+
case findOid(keyData, [0x2b, 0x65, 0x70]):
|
|
48
52
|
return 'Ed25519';
|
|
53
|
+
case findOid(keyData, [0x2b, 0x65, 0x71]):
|
|
54
|
+
return 'Ed448';
|
|
49
55
|
default:
|
|
50
56
|
throw new JOSENotSupported('Invalid or unsupported EC Key Curve or OKP Key Sub Type');
|
|
51
57
|
}
|
|
@@ -96,15 +102,22 @@ const genericImport = async (replace, keyFormat, pem, alg, options) => {
|
|
|
96
102
|
case 'ECDH-ES':
|
|
97
103
|
case 'ECDH-ES+A128KW':
|
|
98
104
|
case 'ECDH-ES+A192KW':
|
|
99
|
-
case 'ECDH-ES+A256KW':
|
|
100
|
-
|
|
105
|
+
case 'ECDH-ES+A256KW': {
|
|
106
|
+
const namedCurve = getNamedCurve(keyData);
|
|
107
|
+
algorithm = namedCurve.startsWith('P-') ? { name: 'ECDH', namedCurve } : { name: namedCurve };
|
|
101
108
|
keyUsages = isPublic ? [] : ['deriveBits'];
|
|
102
109
|
break;
|
|
103
|
-
|
|
110
|
+
}
|
|
111
|
+
case isCloudflareWorkers() && 'EdDSA': {
|
|
104
112
|
const namedCurve = getNamedCurve(keyData).toUpperCase();
|
|
105
113
|
algorithm = { name: `NODE-${namedCurve}`, namedCurve: `NODE-${namedCurve}` };
|
|
106
114
|
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
107
115
|
break;
|
|
116
|
+
}
|
|
117
|
+
case 'EdDSA':
|
|
118
|
+
algorithm = { name: getNamedCurve(keyData) };
|
|
119
|
+
keyUsages = isPublic ? ['verify'] : ['sign'];
|
|
120
|
+
break;
|
|
108
121
|
default:
|
|
109
122
|
throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value');
|
|
110
123
|
}
|
|
@@ -13,10 +13,21 @@ export async function deriveKey(publicKey, privateKey, algorithm, keyLength, apu
|
|
|
13
13
|
}
|
|
14
14
|
checkEncCryptoKey(privateKey, 'ECDH', 'deriveBits');
|
|
15
15
|
const value = concat(lengthAndInput(encoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
|
|
16
|
+
let length;
|
|
17
|
+
if (publicKey.algorithm.name === 'X25519') {
|
|
18
|
+
length = 256;
|
|
19
|
+
}
|
|
20
|
+
else if (publicKey.algorithm.name === 'X448') {
|
|
21
|
+
length = 448;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
length =
|
|
25
|
+
Math.ceil(parseInt(publicKey.algorithm.namedCurve.substr(-3), 10) / 8) << 3;
|
|
26
|
+
}
|
|
16
27
|
const sharedSecret = new Uint8Array(await crypto.subtle.deriveBits({
|
|
17
|
-
name:
|
|
28
|
+
name: publicKey.algorithm.name,
|
|
18
29
|
public: publicKey,
|
|
19
|
-
}, privateKey,
|
|
30
|
+
}, privateKey, length));
|
|
20
31
|
return concatKdf(sharedSecret, keyLength, value);
|
|
21
32
|
}
|
|
22
33
|
export async function generateEpk(key) {
|
|
@@ -29,5 +40,7 @@ export function ecdhAllowed(key) {
|
|
|
29
40
|
if (!isCryptoKey(key)) {
|
|
30
41
|
throw new TypeError(invalidKeyInput(key, ...types));
|
|
31
42
|
}
|
|
32
|
-
return ['P-256', 'P-384', 'P-521'].includes(key.algorithm.namedCurve)
|
|
43
|
+
return (['P-256', 'P-384', 'P-521'].includes(key.algorithm.namedCurve) ||
|
|
44
|
+
key.algorithm.name === 'X25519' ||
|
|
45
|
+
key.algorithm.name === 'X448');
|
|
33
46
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export function isCloudflareWorkers() {
|
|
2
|
-
return typeof WebSocketPair
|
|
2
|
+
return (typeof WebSocketPair !== 'undefined' ||
|
|
3
|
+
(typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
|
|
4
|
+
(typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
|
|
3
5
|
}
|
|
@@ -51,7 +51,7 @@ function getModulusLengthOption(options) {
|
|
|
51
51
|
return modulusLength;
|
|
52
52
|
}
|
|
53
53
|
export async function generateKeyPair(alg, options) {
|
|
54
|
-
var _a, _b;
|
|
54
|
+
var _a, _b, _c;
|
|
55
55
|
let algorithm;
|
|
56
56
|
let keyUsages;
|
|
57
57
|
switch (alg) {
|
|
@@ -112,15 +112,42 @@ export async function generateKeyPair(alg, options) {
|
|
|
112
112
|
throw new JOSENotSupported('Invalid or unsupported crv option provided');
|
|
113
113
|
}
|
|
114
114
|
break;
|
|
115
|
+
case 'EdDSA':
|
|
116
|
+
keyUsages = ['sign', 'verify'];
|
|
117
|
+
const crv = (_a = options === null || options === void 0 ? void 0 : options.crv) !== null && _a !== void 0 ? _a : 'Ed25519';
|
|
118
|
+
switch (crv) {
|
|
119
|
+
case 'Ed25519':
|
|
120
|
+
case 'Ed448':
|
|
121
|
+
algorithm = { name: crv };
|
|
122
|
+
break;
|
|
123
|
+
default:
|
|
124
|
+
throw new JOSENotSupported('Invalid or unsupported crv option provided');
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
115
127
|
case 'ECDH-ES':
|
|
116
128
|
case 'ECDH-ES+A128KW':
|
|
117
129
|
case 'ECDH-ES+A192KW':
|
|
118
|
-
case 'ECDH-ES+A256KW':
|
|
119
|
-
algorithm = { name: 'ECDH', namedCurve: (_a = options === null || options === void 0 ? void 0 : options.crv) !== null && _a !== void 0 ? _a : 'P-256' };
|
|
130
|
+
case 'ECDH-ES+A256KW': {
|
|
120
131
|
keyUsages = ['deriveKey', 'deriveBits'];
|
|
132
|
+
const crv = (_b = options === null || options === void 0 ? void 0 : options.crv) !== null && _b !== void 0 ? _b : 'P-256';
|
|
133
|
+
switch (crv) {
|
|
134
|
+
case 'P-256':
|
|
135
|
+
case 'P-384':
|
|
136
|
+
case 'P-521': {
|
|
137
|
+
algorithm = { name: 'ECDH', namedCurve: crv };
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case 'X25519':
|
|
141
|
+
case 'X448':
|
|
142
|
+
algorithm = { name: crv };
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, X25519, and X448');
|
|
146
|
+
}
|
|
121
147
|
break;
|
|
148
|
+
}
|
|
122
149
|
default:
|
|
123
150
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
124
151
|
}
|
|
125
|
-
return (crypto.subtle.generateKey(algorithm, (
|
|
152
|
+
return (crypto.subtle.generateKey(algorithm, (_c = options === null || options === void 0 ? void 0 : options.extractable) !== null && _c !== void 0 ? _c : false, keyUsages));
|
|
126
153
|
}
|
|
@@ -109,9 +109,27 @@ function subtleMapping(jwk) {
|
|
|
109
109
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
110
110
|
break;
|
|
111
111
|
default:
|
|
112
|
-
throw new JOSENotSupported('Invalid or unsupported JWK "
|
|
112
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
113
113
|
}
|
|
114
114
|
break;
|
|
115
|
+
case 'OKP': {
|
|
116
|
+
switch (jwk.alg) {
|
|
117
|
+
case 'EdDSA':
|
|
118
|
+
algorithm = { name: jwk.crv };
|
|
119
|
+
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|
120
|
+
break;
|
|
121
|
+
case 'ECDH-ES':
|
|
122
|
+
case 'ECDH-ES+A128KW':
|
|
123
|
+
case 'ECDH-ES+A192KW':
|
|
124
|
+
case 'ECDH-ES+A256KW':
|
|
125
|
+
algorithm = { name: jwk.crv };
|
|
126
|
+
keyUsages = jwk.d ? ['deriveBits'] : [];
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
115
133
|
default:
|
|
116
134
|
throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
|
|
117
135
|
}
|
|
@@ -22,6 +22,8 @@ export default function subtleDsa(alg, algorithm) {
|
|
|
22
22
|
case isCloudflareWorkers() && 'EdDSA':
|
|
23
23
|
const { namedCurve } = algorithm;
|
|
24
24
|
return { name: namedCurve, namedCurve };
|
|
25
|
+
case 'EdDSA':
|
|
26
|
+
return { name: algorithm.name };
|
|
25
27
|
default:
|
|
26
28
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
27
29
|
}
|
|
@@ -36,18 +36,12 @@ function parseElement(bytes) {
|
|
|
36
36
|
length = bytes[position];
|
|
37
37
|
position++;
|
|
38
38
|
}
|
|
39
|
-
else {
|
|
40
|
-
let numberOfDigits = bytes[position] & 0x7f;
|
|
41
|
-
position++;
|
|
42
|
-
length = 0;
|
|
43
|
-
for (let i = 0; i < numberOfDigits; i++) {
|
|
44
|
-
length = length * 256 + bytes[position];
|
|
45
|
-
position++;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (length === 0x80) {
|
|
39
|
+
else if (length === 0x80) {
|
|
49
40
|
length = 0;
|
|
50
41
|
while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) {
|
|
42
|
+
if (length > bytes.byteLength) {
|
|
43
|
+
throw new TypeError('invalid indefinite form length');
|
|
44
|
+
}
|
|
51
45
|
length++;
|
|
52
46
|
}
|
|
53
47
|
const byteLength = position + length + 2;
|
|
@@ -57,6 +51,15 @@ function parseElement(bytes) {
|
|
|
57
51
|
raw: bytes.subarray(0, byteLength),
|
|
58
52
|
};
|
|
59
53
|
}
|
|
54
|
+
else {
|
|
55
|
+
let numberOfDigits = bytes[position] & 0x7f;
|
|
56
|
+
position++;
|
|
57
|
+
length = 0;
|
|
58
|
+
for (let i = 0; i < numberOfDigits; i++) {
|
|
59
|
+
length = length * 256 + bytes[position];
|
|
60
|
+
position++;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
60
63
|
const byteLength = position + length;
|
|
61
64
|
return {
|
|
62
65
|
byteLength,
|
|
@@ -84,7 +87,13 @@ async function importX509(x509, alg, options) {
|
|
|
84
87
|
if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {
|
|
85
88
|
throw new TypeError('"x509" must be X.509 formatted string');
|
|
86
89
|
}
|
|
87
|
-
|
|
90
|
+
let spki;
|
|
91
|
+
try {
|
|
92
|
+
spki = getSPKI(x509);
|
|
93
|
+
}
|
|
94
|
+
catch (cause) {
|
|
95
|
+
throw new TypeError('failed to parse the X.509 certificate', { cause });
|
|
96
|
+
}
|
|
88
97
|
return (0, asn1_js_1.fromSPKI)(spki, alg, options);
|
|
89
98
|
}
|
|
90
99
|
exports.importX509 = importX509;
|
|
@@ -79,6 +79,12 @@ function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
79
79
|
throw unusable('NODE-ED25519');
|
|
80
80
|
break;
|
|
81
81
|
}
|
|
82
|
+
case 'EdDSA': {
|
|
83
|
+
if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
|
|
84
|
+
throw unusable('Ed25519 or Ed448');
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
82
88
|
case 'ES256':
|
|
83
89
|
case 'ES384':
|
|
84
90
|
case 'ES512': {
|
|
@@ -120,10 +126,17 @@ function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
120
126
|
throw unusable(expected, 'algorithm.length');
|
|
121
127
|
break;
|
|
122
128
|
}
|
|
123
|
-
case 'ECDH':
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
case 'ECDH': {
|
|
130
|
+
switch (key.algorithm.name) {
|
|
131
|
+
case 'ECDH':
|
|
132
|
+
case 'X25519':
|
|
133
|
+
case 'X448':
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
throw unusable('ECDH, X25519, or X448');
|
|
137
|
+
}
|
|
126
138
|
break;
|
|
139
|
+
}
|
|
127
140
|
case 'PBES2-HS256+A128KW':
|
|
128
141
|
case 'PBES2-HS384+A192KW':
|
|
129
142
|
case 'PBES2-HS512+A256KW':
|
|
@@ -33,18 +33,12 @@ function parseElement(bytes) {
|
|
|
33
33
|
length = bytes[position];
|
|
34
34
|
position++;
|
|
35
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) {
|
|
36
|
+
else if (length === 0x80) {
|
|
46
37
|
length = 0;
|
|
47
38
|
while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) {
|
|
39
|
+
if (length > bytes.byteLength) {
|
|
40
|
+
throw new TypeError('invalid indefinite form length');
|
|
41
|
+
}
|
|
48
42
|
length++;
|
|
49
43
|
}
|
|
50
44
|
const byteLength = position + length + 2;
|
|
@@ -54,6 +48,15 @@ function parseElement(bytes) {
|
|
|
54
48
|
raw: bytes.subarray(0, byteLength),
|
|
55
49
|
};
|
|
56
50
|
}
|
|
51
|
+
else {
|
|
52
|
+
let numberOfDigits = bytes[position] & 0x7f;
|
|
53
|
+
position++;
|
|
54
|
+
length = 0;
|
|
55
|
+
for (let i = 0; i < numberOfDigits; i++) {
|
|
56
|
+
length = length * 256 + bytes[position];
|
|
57
|
+
position++;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
57
60
|
const byteLength = position + length;
|
|
58
61
|
return {
|
|
59
62
|
byteLength,
|
|
@@ -80,7 +83,13 @@ export async function importX509(x509, alg, options) {
|
|
|
80
83
|
if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {
|
|
81
84
|
throw new TypeError('"x509" must be X.509 formatted string');
|
|
82
85
|
}
|
|
83
|
-
|
|
86
|
+
let spki;
|
|
87
|
+
try {
|
|
88
|
+
spki = getSPKI(x509);
|
|
89
|
+
}
|
|
90
|
+
catch (cause) {
|
|
91
|
+
throw new TypeError('failed to parse the X.509 certificate', { cause });
|
|
92
|
+
}
|
|
84
93
|
return importPublic(spki, alg, options);
|
|
85
94
|
}
|
|
86
95
|
export async function importPKCS8(pkcs8, alg, options) {
|
|
@@ -76,6 +76,12 @@ export function checkSigCryptoKey(key, alg, ...usages) {
|
|
|
76
76
|
throw unusable('NODE-ED25519');
|
|
77
77
|
break;
|
|
78
78
|
}
|
|
79
|
+
case 'EdDSA': {
|
|
80
|
+
if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
|
|
81
|
+
throw unusable('Ed25519 or Ed448');
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
79
85
|
case 'ES256':
|
|
80
86
|
case 'ES384':
|
|
81
87
|
case 'ES512': {
|
|
@@ -116,10 +122,17 @@ export function checkEncCryptoKey(key, alg, ...usages) {
|
|
|
116
122
|
throw unusable(expected, 'algorithm.length');
|
|
117
123
|
break;
|
|
118
124
|
}
|
|
119
|
-
case 'ECDH':
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
case 'ECDH': {
|
|
126
|
+
switch (key.algorithm.name) {
|
|
127
|
+
case 'ECDH':
|
|
128
|
+
case 'X25519':
|
|
129
|
+
case 'X448':
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
throw unusable('ECDH, X25519, or X448');
|
|
133
|
+
}
|
|
122
134
|
break;
|
|
135
|
+
}
|
|
123
136
|
case 'PBES2-HS256+A128KW':
|
|
124
137
|
case 'PBES2-HS384+A192KW':
|
|
125
138
|
case 'PBES2-HS512+A256KW':
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { JWK } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Calculates a base64url-encoded JSON Web Key (JWK) Thumbprint
|
|
4
|
-
* [RFC7638](https://www.rfc-editor.org/rfc/rfc7638).
|
|
3
|
+
* Calculates a base64url-encoded JSON Web Key (JWK) Thumbprint
|
|
5
4
|
*
|
|
6
5
|
* @example Usage
|
|
7
6
|
*
|
|
@@ -18,11 +17,13 @@ import type { JWK } from '../types';
|
|
|
18
17
|
* ```
|
|
19
18
|
*
|
|
20
19
|
* @param jwk JSON Web Key.
|
|
21
|
-
* @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is
|
|
20
|
+
* @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is
|
|
21
|
+
* "sha256".
|
|
22
|
+
* @see [RFC7638](https://www.rfc-editor.org/rfc/rfc7638)
|
|
22
23
|
*/
|
|
23
24
|
export declare function calculateJwkThumbprint(jwk: JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise<string>;
|
|
24
25
|
/**
|
|
25
|
-
* Calculates a JSON Web Key (JWK) Thumbprint URI
|
|
26
|
+
* Calculates a JSON Web Key (JWK) Thumbprint URI
|
|
26
27
|
*
|
|
27
28
|
* @example Usage
|
|
28
29
|
*
|
|
@@ -39,6 +40,8 @@ export declare function calculateJwkThumbprint(jwk: JWK, digestAlgorithm?: 'sha2
|
|
|
39
40
|
* ```
|
|
40
41
|
*
|
|
41
42
|
* @param jwk JSON Web Key.
|
|
42
|
-
* @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is
|
|
43
|
+
* @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is
|
|
44
|
+
* "sha256".
|
|
45
|
+
* @see [RFC9278](https://www.rfc-editor.org/rfc/rfc9278)
|
|
43
46
|
*/
|
|
44
47
|
export declare function calculateJwkThumbprintUri(jwk: JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise<string>;
|
|
@@ -11,7 +11,10 @@ export interface RemoteJWKSetOptions {
|
|
|
11
11
|
* successful fetch. Default is 30000 (30 seconds).
|
|
12
12
|
*/
|
|
13
13
|
cooldownDuration?: number;
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Maximum time (in milliseconds) between successful HTTP requests. Default is 600000 (10
|
|
16
|
+
* minutes).
|
|
17
|
+
*/
|
|
15
18
|
cacheMaxAge?: number | typeof Infinity;
|
|
16
19
|
/**
|
|
17
20
|
* An instance of [http.Agent](https://nodejs.org/api/http.html#class-httpagent) or
|
|
@@ -25,14 +28,12 @@ export interface RemoteJWKSetOptions {
|
|
|
25
28
|
/** Optional headers to be sent with the HTTP request. */
|
|
26
29
|
headers?: Record<string, string>;
|
|
27
30
|
}
|
|
28
|
-
interface URL {
|
|
29
|
-
href: string;
|
|
30
|
-
}
|
|
31
31
|
/**
|
|
32
32
|
* Returns a function that resolves to a key object downloaded from a remote endpoint returning a
|
|
33
33
|
* JSON Web Key Set, that is, for example, an OAuth 2.0 or OIDC jwks_uri. Only a single public key
|
|
34
34
|
* must match the selection process. The JSON Web Key Set is fetched when no key matches the
|
|
35
|
-
* selection process but only as frequently as the `cooldownDuration` option allows, to prevent
|
|
35
|
+
* selection process but only as frequently as the `cooldownDuration` option allows, to prevent
|
|
36
|
+
* abuse.
|
|
36
37
|
*
|
|
37
38
|
* @example Usage
|
|
38
39
|
*
|
|
@@ -51,4 +52,3 @@ interface URL {
|
|
|
51
52
|
* @param options Options for the remote JSON Web Key Set.
|
|
52
53
|
*/
|
|
53
54
|
export declare function createRemoteJWKSet(url: URL, options?: RemoteJWKSetOptions): GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;
|
|
54
|
-
export {};
|
|
@@ -47,7 +47,8 @@ export declare class ProduceJWT {
|
|
|
47
47
|
/**
|
|
48
48
|
* Set "iat" (Issued At) Claim.
|
|
49
49
|
*
|
|
50
|
-
* @param input "iat" (Issued At) Claim value to set on the JWT Claims Set. Default is current
|
|
50
|
+
* @param input "iat" (Issued At) Claim value to set on the JWT Claims Set. Default is current
|
|
51
|
+
* timestamp.
|
|
51
52
|
*/
|
|
52
53
|
setIssuedAt(input?: number): this;
|
|
53
54
|
}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -368,7 +368,7 @@ export interface CritOption {
|
|
|
368
368
|
* for those is either `true` or `false`. `true` when the Header Parameter MUST be integrity
|
|
369
369
|
* protected, `false` when it's irrelevant.
|
|
370
370
|
*
|
|
371
|
-
* This makes the "Extension Header Parameter "
|
|
371
|
+
* This makes the "Extension Header Parameter "..." is not recognized" error go away.
|
|
372
372
|
*
|
|
373
373
|
* Use this when a given JWS/JWT/JWE profile requires the use of proprietary non-registered "crit"
|
|
374
374
|
* (Critical) Header Parameters. This will only make sure the Header Parameter is syntactically
|
|
@@ -378,7 +378,8 @@ export interface CritOption {
|
|
|
378
378
|
* the operation succeeds.
|
|
379
379
|
*
|
|
380
380
|
* The JWS extension Header Parameter `b64` is always recognized and processed properly. No other
|
|
381
|
-
* registered Header Parameters that need this kind of default built-in treatment are currently
|
|
381
|
+
* registered Header Parameters that need this kind of default built-in treatment are currently
|
|
382
|
+
* available.
|
|
382
383
|
*/
|
|
383
384
|
crit?: {
|
|
384
385
|
[propName: string]: boolean
|
|
@@ -460,7 +461,8 @@ export interface JWTClaimVerificationOptions {
|
|
|
460
461
|
export interface VerifyOptions extends CritOption {
|
|
461
462
|
/**
|
|
462
463
|
* A list of accepted JWS "alg" (Algorithm) Header Parameter values. By default all "alg"
|
|
463
|
-
* (Algorithm) values applicable for the used key/secret are allowed. Note: "none" is never
|
|
464
|
+
* (Algorithm) values applicable for the used key/secret are allowed. Note: "none" is never
|
|
465
|
+
* accepted.
|
|
464
466
|
*/
|
|
465
467
|
algorithms?: string[]
|
|
466
468
|
}
|
|
@@ -470,25 +472,49 @@ export interface SignOptions extends CritOption {}
|
|
|
470
472
|
|
|
471
473
|
/** Recognized JWT Claims Set members, any other members may also be present. */
|
|
472
474
|
export interface JWTPayload {
|
|
473
|
-
/**
|
|
475
|
+
/**
|
|
476
|
+
* JWT Issuer
|
|
477
|
+
*
|
|
478
|
+
* @see [RFC7519#section-4.1.1](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1)
|
|
479
|
+
*/
|
|
474
480
|
iss?: string
|
|
475
481
|
|
|
476
|
-
/**
|
|
482
|
+
/**
|
|
483
|
+
* JWT Subject
|
|
484
|
+
*
|
|
485
|
+
* @see [RFC7519#section-4.1.2](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2)
|
|
486
|
+
*/
|
|
477
487
|
sub?: string
|
|
478
488
|
|
|
479
489
|
/** JWT Audience [RFC7519#section-4.1.3](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3). */
|
|
480
490
|
aud?: string | string[]
|
|
481
491
|
|
|
482
|
-
/**
|
|
492
|
+
/**
|
|
493
|
+
* JWT ID
|
|
494
|
+
*
|
|
495
|
+
* @see [RFC7519#section-4.1.7](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7)
|
|
496
|
+
*/
|
|
483
497
|
jti?: string
|
|
484
498
|
|
|
485
|
-
/**
|
|
499
|
+
/**
|
|
500
|
+
* JWT Not Before
|
|
501
|
+
*
|
|
502
|
+
* @see [RFC7519#section-4.1.5](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5)
|
|
503
|
+
*/
|
|
486
504
|
nbf?: number
|
|
487
505
|
|
|
488
|
-
/**
|
|
506
|
+
/**
|
|
507
|
+
* JWT Expiration Time
|
|
508
|
+
*
|
|
509
|
+
* @see [RFC7519#section-4.1.4](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4)
|
|
510
|
+
*/
|
|
489
511
|
exp?: number
|
|
490
512
|
|
|
491
|
-
/**
|
|
513
|
+
/**
|
|
514
|
+
* JWT Issued At
|
|
515
|
+
*
|
|
516
|
+
* @see [RFC7519#section-4.1.6](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6)
|
|
517
|
+
*/
|
|
492
518
|
iat?: number
|
|
493
519
|
|
|
494
520
|
/** Any other JWT Claim Set member. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jose",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK, JWKS
|
|
3
|
+
"version": "4.10.1",
|
|
4
|
+
"description": "'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, and other Web-interoperable runtimes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"browser",
|
|
7
7
|
"cloudflare",
|