diff --git a/README.md b/README.md index b0a1232944..ffddddcf4e 100644 --- a/README.md +++ b/README.md @@ -28,82 +28,6 @@ Available JWT validation profiles - OAuth 2.0 JWT Access Tokens (`at+JWT`) - [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] - OIDC Logout Token (`logout_token`) - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] -
- Detailed feature matrix (Click to expand)
- -Legend: -- **✓** Implemented -- **✕** Missing node crypto support / won't implement -- **◯** TBD - -| JWK Key Types | Supported | `kty` | -| -- | -- | -- | -| RSA | ✓ | RSA | -| Elliptic Curve | ✓ | EC (P-256, secp256k1, P-384, P-521) | -| Octet Key Pair | ✓ | OKP (Ed25519, Ed448, X25519, X448) | -| Octet sequence | ✓ | oct | - -| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt | -| -- | -- | -- | -- | -- | -| Compact | ✓ | ✓ | ✓ | ✓ | -| General JSON | ✓ | ✓ | ✓ | ✓ | -| Flattened JSON | ✓ | ✓ | ✓ | ✓ | - -| JWS Algorithms | Supported || -| -- | -- | -- | -| RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | -| RSASSA-PSS | ✓ | PS256, PS384, PS512 | -| ECDSA | ✓ | ES256, ES256K, ES384, ES512 | -| Edwards-curve DSA | ✓ | EdDSA | -| HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | - -| JWE Key Management Algorithms | Supported || -| -- | -- | -- | -| AES | ✓ | A128KW, A192KW, A256KW | -| AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW | -| Direct Key Agreement | ✓ | dir | -| RSAES OAEP | ✓ | RSA-OAEP, RSA-OAEP-256 | -| RSAES-PKCS1-v1_5 | ✓ | RSA1_5 | -| PBES2 | ✓ | PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW | -| ECDH-ES (for all EC keys) | ✓ | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW | -| ECDH-ES (for OKP X25519) | ✓ via [plugin][plugin-x25519] | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW | -| ECDH-ES (for OKP X448) | ✕ || -| (X)ChaCha | ✓ via [plugin][plugin-chacha] | C20PKW, X20CPKW, ECDH-ES+C20PKW, ECDH-ES+XC20PKW | - -| JWE Content Encryption Algorithms | Supported || -| -- | -- | -- | -| AES GCM | ✓ | A128GCM, A192GCM, A256GCM | -| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | -| (X)ChaCha | ✓ via [plugin][plugin-chacha] | C20P, X20CP | - -| JWT profile validation | Supported | profile option value | -| -- | -- | -- | -| ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] | ✓ | `id_token` | -| JWT Access Tokens [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] | ✓ | `at+JWT` | -| Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] | ✓ | `logout_token` | -| JARM - [JWT Secured Authorization Response Mode for OAuth 2.0][draft-jarm] | ◯ || - -Notes -- RSA-OAEP-256 JWE algorithm is only supported when Node.js >= 12.9.0 runtime is detected -- Importing X.509 certificates and handling `x5c` is only supported when Node.js >= 12.0.0 runtime is detected -- OKP keys are only supported when Node.js >= 12.0.0 runtime is detected -- See [#electron-support](#electron-support) for electron exceptions - ---- - -Pending Node.js Support 🤞: -- ECDH-ES with X25519 and X448 - see [nodejs/node#26626](https://github.com/nodejs/node/pull/26626) - -Won't implement: -- ✕ JWS embedded key / referenced verification - - one can decode the header and pass the (`x5c`, `jwk`) to `JWK.asKey` and validate with that - key, similarly the application can handle fetching and then instantiating the referenced `x5u` - or `jku` in its own code. This way you opt-in to these behaviours. -- ✕ "none" alg support - - no crypto, no use - -
-
Have a question about using `jose`? - [ask][ask]. @@ -128,15 +52,6 @@ If you or your business use `jose`, please consider becoming a [sponsor][support - [JWS (JSON Web Signature)][documentation-jws] - [JWE (JSON Web Encryption)][documentation-jwe] -## Plugins - -There are two plugin extensions with functionality which is either not available in Node.js `crypto` -module yet and therefore needs a crypto polyfill (libsodium), or are not IETF WG standards/drafts -"worthy" of landing in the core library. - -- [jose-chacha][plugin-chacha] adds aead_chacha20_poly1305 and aead_xchacha20_poly1305 based algorithms (individual draft) -- [jose-x25519-ecdh][plugin-x25519] adds OKP X25519 curve keys ECDH-ES support (missing Node.js `crypto` support) - ## Usage For the best performance Node.js version **>=12.0.0** is recommended, but **^10.13.0** lts/dubnium @@ -356,17 +271,66 @@ jose.JWE.decrypt( ) ``` -#### Electron Support +## Detailed Support Matrix + +| JWK Key Types | Supported | `kty` value | `crv` values | +| -- | -- | -- | -- | +| RSA | ✓ | RSA || +| Elliptic Curve | ✓ | EC | P-256, secp256k1[1], P-384, P-521 | +| Octet Key Pair | ✓ | OKP | Ed25519, Ed448[1], X25519[1], X448[1] | +| Octet sequence | ✓ | oct || + +| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt | +| -- | -- | -- | -- | -- | +| Compact | ✓ | ✓ | ✓ | ✓ | +| General JSON | ✓ | ✓ | ✓ | ✓ | +| Flattened JSON | ✓ | ✓ | ✓ | ✓ | + +| JWS Algorithms | Supported || +| -- | -- | -- | +| RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | +| RSASSA-PSS | ✓ | PS256, PS384, PS512 | +| ECDSA | ✓ | ES256, ES256K[1], ES384, ES512 | +| Edwards-curve DSA | ✓ | EdDSA | +| HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | +| Unsecured JWS | ✓ | none[2] | -Electron >=6.0.0 runtime is supported to the extent of the crypto engine BoringSSL feature parity -with standard Node.js OpenSSL. The following is disabled in Electron runtime because of its lack of -[support](https://github.com/panva/jose/blob/master/test/electron/electron.test.js). +| JWE Key Management Algorithms | Supported || +| -- | -- | -- | +| AES | ✓ | A128KW[1], A192KW[1], A256KW[1] | +| AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW | +| Direct Key Agreement | ✓ | dir | +| RSAES OAEP | ✓ | RSA-OAEP, RSA-OAEP-256[3] | +| RSAES-PKCS1-v1_5 | ✓ | RSA1_5 | +| PBES2 | ✓ | PBES2-HS256+A128KW[1], PBES2-HS384+A192KW[1], PBES2-HS512+A256KW[1] | +| ECDH-ES (for all EC keys) | ✓ | ECDH-ES, ECDH-ES+A128KW[1], ECDH-ES+A192KW[1], ECDH-ES+A256KW[1] | +| ECDH-ES (for OKP X25519) | ✓ via [plugin][plugin-x25519] | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW | +| ECDH-ES (for OKP X448) | ✕ || +| (X)ChaCha | ✓ via [plugin][plugin-chacha] | C20PKW, XC20PKW, ECDH-ES+C20PKW, ECDH-ES+XC20PKW | + +| JWE Content Encryption Algorithms | Supported || +| -- | -- | -- | +| AES GCM | ✓ | A128GCM, A192GCM, A256GCM | +| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | +| (X)ChaCha | ✓ via [plugin][plugin-chacha] | C20P, X20CP | + +| JWT profile validation | Supported | profile option value | +| -- | -- | -- | +| ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] | ✓ | `id_token` | +| JWT Access Tokens [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] | ✓ | `at+JWT` | +| Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] | ✓ | `logout_token` | +| JARM - [JWT Secured Authorization Response Mode for OAuth 2.0][draft-jarm] | ◯ || + +Legend: +- **✓** Implemented +- **✕** Missing node crypto support / won't implement +- **◯** TBD -- JWE `A128KW`, `A192KW` and `A256KW` algorithms are not available, this also means that other JWAs - depending on those are not working, those are `ECDH-ES+A128KW`, `ECDH-ES+A192KW`, - `ECDH-ES+A256KW`, `PBES2-HS256+A128KW`, `PBES2-HS384+A192KW`, `PBES2-HS512+A256KW`) -- OKP curves `Ed448`, `X25519` and `X448` are not supported -- EC curve `secp256k1` is not supported +1 Not supported in Electron due to Electron's use of BoringSSL +2 Unsecured JWS is [supported][documentation-none] for the JWS and JWT sign and verify +operations but it is an entirely opt-in behaviour, downgrade attacks are prevented by the required +use of a special `JWK.Key` instance that cannot be instantiated through the key import API. +3 RSA-OAEP-256 is only supported when Node.js >= 12.9.0 runtime is detected ## FAQ @@ -418,12 +382,13 @@ in terms of performance and API (not having well defined errors). [ask]: https://github.com/panva/jose/issues/new?labels=question&template=question.md&title=question%3A+ [bug]: https://github.com/panva/jose/issues/new?labels=bug&template=bug-report.md&title=bug%3A+ -[documentation-jwe]: https://github.com/panva/jose/blob/master/docs/README.md#jwe-json-web-encryption -[documentation-jwk]: https://github.com/panva/jose/blob/master/docs/README.md#jwk-json-web-key -[documentation-jwks]: https://github.com/panva/jose/blob/master/docs/README.md#jwks-json-web-key-set -[documentation-jws]: https://github.com/panva/jose/blob/master/docs/README.md#jws-json-web-signature -[documentation-jwt]: https://github.com/panva/jose/blob/master/docs/README.md#jwt-json-web-token -[documentation]: https://github.com/panva/jose/blob/master/docs/README.md +[documentation-jwe]: /docs/README.md#jwe-json-web-encryption +[documentation-jwk]: /docs/README.md#jwk-json-web-key +[documentation-jwks]: /docs/README.md#jwks-json-web-key-set +[documentation-jws]: /docs/README.md#jws-json-web-signature +[documentation-jwt]: /docs/README.md#jwt-json-web-token +[documentation-none]: /docs/README.md#jwknone +[documentation]: /docs/README.md [node-jose]: https://github.com/cisco/node-jose [security-vulnerability]: https://github.com/panva/jose/issues/new?template=security-vulnerability.md [spec-b64]: https://tools.ietf.org/html/rfc7797 diff --git a/docs/README.md b/docs/README.md index b16698c5ad..7838ecc72b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,6 +51,7 @@ If you or your business use `jose`, please consider becoming a [sponsor][support - [JWK.generate(kty[, crvOrSize[, options[, private]]]) generating new keys](#jwkgeneratekty-crvorsize-options-private-generating-new-keys) - [JWK.generateSync(kty[, crvOrSize[, options[, private]]])](#jwkgeneratesynckty-crvorsize-options-private) - [JWK.isKey(object)](#jwkiskeyobject) +- [JWK.None](#jwknone) All sign and encrypt operations require `` or `JWK.asKey()` compatible input. @@ -574,6 +575,54 @@ Returns 'true' if the value is an instance of ``. --- +#### `JWK.None` + +`JWK.None` is a special key object that can be used with JWS/JWT sign and verify whenever you want +to opt-in for the `none` Unsecured JWS algorithm. Using this key fulfills the requirements given by +the [specification](https://tools.ietf.org/html/rfc7518#section-3.6), namely: + +- Implementations MUST NOT accept Unsecured JWSs by default. +- Implementations that support Unsecured JWSs MUST NOT accept such objects as valid unless the +application specifies that it is acceptable for a specific object to not be integrity protected. + +```js +const { JWK: { None, generateSync }, JWT, JWS } = require('jose') +const anActualKey = generateSync('RSA') + +const signedJWT = JWT.sign({ sub: 'John Doe' }, anActualKey) +JWT.verify(signedJWT, None) +// Thrown: +// JWKKeySupport: the key does not support PS256 verify algorithm +// name: 'JWKKeySupport', +// code: 'ERR_JWK_KEY_SUPPORT' + +const unsecuredJWT = JWT.sign({ sub: 'John Doe' }, None) +// eyJhbGciOiJub25lIn0.eyJzdWIiOiJKb2huIERvZSIsImlhdCI6MTU3OTc5NDM2Mn0. + +JWT.verify(unsecuredJWT, anActualKey) +// Thrown: +// JWKKeySupport: the key does not support none verify algorithm +// name: 'JWKKeySupport', +// code: 'ERR_JWK_KEY_SUPPORT' + +JWT.verify(unsecuredJWT, None) +// { sub: 'John Doe', iat: 1579794362 } + +const unsecuredJWS = JWS.sign('foobar', None) +// eyJhbGciOiJub25lIn0.Zm9vYmFy. + +JWS.verify(unsecuredJWS, anActualKey) +// Thrown: +// JWKKeySupport: the key does not support none verify algorithm +// name: 'JWKKeySupport', +// code: 'ERR_JWK_KEY_SUPPORT' + +JWS.verify(unsecuredJWS, None) +// foobar +``` + +--- + ## JWKS (JSON Web Key Set) diff --git a/lib/jwa/index.js b/lib/jwa/index.js index 0505a0adee..4afd402ccd 100644 --- a/lib/jwa/index.js +++ b/lib/jwa/index.js @@ -9,6 +9,7 @@ require('./ecdsa')(JWA, JWK) require('./eddsa')(JWA, JWK) require('./rsassa_pss')(JWA, JWK) require('./rsassa')(JWA, JWK) +require('./none')(JWA) // encrypt, decrypt require('./aes_cbc_hmac_sha2')(JWA, JWK) diff --git a/lib/jwa/none.js b/lib/jwa/none.js new file mode 100644 index 0000000000..e9de26a837 --- /dev/null +++ b/lib/jwa/none.js @@ -0,0 +1,14 @@ +const { strict: assert } = require('assert') + +const sign = (key, payload) => Buffer.from('') +const verify = (key, payload, signature) => !signature.length + +module.exports = (JWA, JWK) => { + const jwaAlg = 'none' + + assert(!JWA.sign.has(jwaAlg), `sign alg ${jwaAlg} already registered`) + assert(!JWA.verify.has(jwaAlg), `verify alg ${jwaAlg} already registered`) + + JWA.sign.set(jwaAlg, sign) + JWA.verify.set(jwaAlg, verify) +} diff --git a/lib/jwk/index.js b/lib/jwk/index.js index 580908dc78..e42b738332 100644 --- a/lib/jwk/index.js +++ b/lib/jwk/index.js @@ -1,11 +1,14 @@ const Key = require('./key/base') +const None = require('./key/none') const importKey = require('./import') -const { generate, generateSync } = require('./generate') +const generate = require('./generate') -module.exports.asKey = importKey -module.exports.generate = generate -module.exports.generateSync = generateSync -module.exports.isKey = input => input instanceof Key +module.exports = { + ...generate, + asKey: importKey, + isKey: input => input instanceof Key, + None +} /* deprecated */ Object.defineProperty(module.exports, 'importKey', { diff --git a/lib/jwk/key/none.js b/lib/jwk/key/none.js new file mode 100644 index 0000000000..257b4e3c2f --- /dev/null +++ b/lib/jwk/key/none.js @@ -0,0 +1,33 @@ +const { inspect } = require('util') + +const Key = require('./base') + +class NoneKey extends Key { + constructor () { + super({ type: 'unsecured' }, { alg: 'none' }) + Object.defineProperties(this, { + kid: { value: undefined }, + thumbprint: { value: undefined }, + toJWK: { value: undefined }, + toPEM: { value: undefined } + }) + } + + /* c8 ignore next 3 */ + [inspect.custom] () { + return 'None {}' + } + + algorithms (operation) { + switch (operation) { + case 'sign': + case 'verify': + case undefined: + return new Set(['none']) + default: + return new Set() + } + } +} + +module.exports = new NoneKey({ type: 'unsecured' }, { alg: 'none' }) diff --git a/lib/jwks/keystore.js b/lib/jwks/keystore.js index 4ab1b5b6fe..39110a82ad 100644 --- a/lib/jwks/keystore.js +++ b/lib/jwks/keystore.js @@ -2,9 +2,8 @@ const { deprecate, inspect } = require('util') const isObject = require('../help/is_object') const { generate, generateSync } = require('../jwk/generate') -const Key = require('../jwk/key/base') -const importKey = require('../jwk/import') const { USES_MAPPING } = require('../help/consts') +const { None, isKey, asKey: importKey } = require('../jwk') const keyscore = (key, { alg, use, ops }) => { let score = 0 @@ -45,8 +44,8 @@ class KeyStore { return acc }, []) } - if (keys.some(k => !(k instanceof Key))) { - throw new TypeError('all keys must be an instances of a key instantiated by JWK.asKey') + if (keys.some(k => !isKey(k) || k === None)) { + throw new TypeError('all keys must be instances of a key instantiated by JWK.asKey') } i(this).keys = new Set(keys) @@ -113,7 +112,7 @@ class KeyStore { } add (key) { - if (!(key instanceof Key)) { + if (!isKey(key) || key === None) { throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } @@ -121,7 +120,7 @@ class KeyStore { } remove (key) { - if (!(key instanceof Key)) { + if (!isKey(key)) { throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } diff --git a/test/jwks/keystore.test.js b/test/jwks/keystore.test.js index 3654bc5ea0..888e62d89b 100644 --- a/test/jwks/keystore.test.js +++ b/test/jwks/keystore.test.js @@ -33,7 +33,7 @@ test('constructor', t => { test('constructor only accepts Key instances created through JWK.asKey', t => { t.throws(() => { new KeyStore({}) // eslint-disable-line no-new - }, { instanceOf: TypeError, message: 'all keys must be an instances of a key instantiated by JWK.asKey' }) + }, { instanceOf: TypeError, message: 'all keys must be instances of a key instantiated by JWK.asKey' }) }) test('.generate()', async t => { diff --git a/test/jws/unsecured.test.js b/test/jws/unsecured.test.js new file mode 100644 index 0000000000..5a18d1ee1b --- /dev/null +++ b/test/jws/unsecured.test.js @@ -0,0 +1,111 @@ +const test = require('ava') + +const { errors, JWK: { generateSync, None, isKey }, JWS } = require('../..') + +const properKey = generateSync('oct') + +test('JWS.None is an instance of a key but not really', t => { + t.true(isKey(None)) + t.is(None.alg, 'none') + t.is(None.type, 'unsecured') + t.true(None.algorithms() instanceof Set) + t.deepEqual([...None.algorithms()], ['none']) + t.deepEqual([...None.algorithms('sign')], ['none']) + t.deepEqual([...None.algorithms('verify')], ['none']) + t.deepEqual([...None.algorithms('encrypt')], []) + t.deepEqual([...None.algorithms('foobar')], []) + t.is(None.thumbprint, undefined) + t.is(None.kid, undefined) +}) + +test('JWS.None "signs"', t => { + const unsignedJWS = JWS.sign('foo', None) + t.deepEqual( + JWS.verify(unsignedJWS, None, { complete: true }), + { + key: None, + payload: 'foo', + protected: { + alg: 'none' + } + } + ) +}) + +test('JWS.None "signs" flattened', t => { + const unsignedJWS = JWS.sign.flattened('foo', None) + t.deepEqual( + unsignedJWS, + { + payload: 'Zm9v', + protected: 'eyJhbGciOiJub25lIn0', + signature: '' + } + ) + t.deepEqual( + JWS.verify(unsignedJWS, None, { complete: true }), + { + key: None, + payload: 'foo', + protected: { + alg: 'none' + } + } + ) +}) + +test('JWS.None "signs" general', t => { + const sign = new JWS.Sign('foo') + sign.recipient(None) + sign.recipient(None) + const unsignedJWS = sign.sign('general') + + t.deepEqual( + unsignedJWS, + { + payload: 'Zm9v', + signatures: [ + { + protected: 'eyJhbGciOiJub25lIn0', + signature: '' + }, + { + protected: 'eyJhbGciOiJub25lIn0', + signature: '' + } + ] + } + ) + t.deepEqual( + JWS.verify(unsignedJWS, None, { complete: true }), + { + key: None, + payload: 'foo', + protected: { + alg: 'none' + } + } + ) +}) + +test('JWS.None fails to verify real tokens', t => { + const signedToken = JWS.sign('foo', properKey) + t.throws(() => { + JWS.verify(signedToken, None) + }, { + instanceOf: errors.JWKKeySupport, + code: 'ERR_JWK_KEY_SUPPORT', + message: 'the key does not support HS256 verify algorithm' + }) +}) + +test('JWS.None fails to verify None signed tokens with a signature', t => { + const unsignedJWS = JWS.sign('foo', None) + t.throws(() => { + JWS.verify(`${unsignedJWS}fooba`, None) + }, { + instanceOf: errors.JWSVerificationFailed, + code: 'ERR_JWS_VERIFICATION_FAILED', + message: 'signature verification failed' + }) +}) diff --git a/test/jwt/unsecured.test.js b/test/jwt/unsecured.test.js new file mode 100644 index 0000000000..71d529ba1f --- /dev/null +++ b/test/jwt/unsecured.test.js @@ -0,0 +1,46 @@ +const test = require('ava') + +const { errors, JWK: { generateSync, None }, JWT } = require('../..') + +const properKey = generateSync('oct') + +const PAYLOAD = { sub: 'foobar', iat: 0 } + +test('JWS.None "signs" (JWT)', t => { + const unsignedJWS = JWT.sign(PAYLOAD, None, { iat: false }) + t.deepEqual( + JWT.verify(unsignedJWS, None, { complete: true }), + { + key: None, + payload: { + ...PAYLOAD + }, + header: { + alg: 'none' + }, + signature: '' + } + ) +}) + +test('JWS.None fails to verify real tokens (JWT)', t => { + const signedToken = JWT.sign(PAYLOAD, properKey) + t.throws(() => { + JWT.verify(signedToken, None) + }, { + instanceOf: errors.JWKKeySupport, + code: 'ERR_JWK_KEY_SUPPORT', + message: 'the key does not support HS256 verify algorithm' + }) +}) + +test('JWS.None fails to verify None signed tokens with a signature (JWT)', t => { + const unsignedJWS = JWT.sign(PAYLOAD, None) + t.throws(() => { + JWT.verify(`${unsignedJWS}fooba`, None) + }, { + instanceOf: errors.JWSVerificationFailed, + code: 'ERR_JWS_VERIFICATION_FAILED', + message: 'signature verification failed' + }) +}) diff --git a/types/index.d.ts b/types/index.d.ts index 0320335cab..df330cfe07 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -27,6 +27,9 @@ export type JWTProfiles = 'id_token' | 'at+JWT' | 'logout_token'; export type KeyInput = PrivateKeyInput | PublicKeyInput | string | Buffer; export type ProduceKeyInput = JWK.Key | KeyObject | KeyInput | JWKOctKey | JWKRSAKey | JWKECKey | JWKOKPKey; export type ConsumeKeyInput = ProduceKeyInput | JWKS.KeyStore; +export type NoneKey = JWK.NoneKey; +export type ProduceKeyInputWithNone = ProduceKeyInput | NoneKey; +export type ConsumeKeyInputWithNone = ConsumeKeyInput | NoneKey; export interface JWKOctKey extends BasicParameters { // no x5c kty: 'oct'; @@ -148,6 +151,14 @@ export namespace JWK { toJWK(private?: boolean): JWKOctKey; } + interface NoneKey { + type: 'unsecured'; + alg: 'none'; + algorithms(operation?: keyOperation): Set; + } + + const None: NoneKey; + function isKey(object: any): boolean; function asKey(key: KeyObject | KeyInput, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey; @@ -239,17 +250,17 @@ export namespace JWS { class Sign { constructor(payload: string | Buffer | object); - recipient(key: ProduceKeyInput, protected?: object, header?: object): void; + recipient(key: ProduceKeyInputWithNone, protected?: object, header?: object): void; sign(serialization: 'compact'): string; sign(serialization: 'flattened'): FlattenedJWS; sign(serialization: 'general'): GeneralJWS; } - function sign(payload: string | Buffer | object, key: ProduceKeyInput, protected?: object): string; + function sign(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object): string; namespace sign { - function flattened(payload: string | Buffer | object, key: ProduceKeyInput, protected?: object, header?: object): FlattenedJWS; - function general(payload: string | Buffer | object, key: ProduceKeyInput, protected?: object, header?: object): GeneralJWS; + function flattened(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object, header?: object): FlattenedJWS; + function general(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object, header?: object): GeneralJWS; } interface VerifyOptions { @@ -260,17 +271,19 @@ export namespace JWS { algorithms?: string[]; } - interface completeVerification { + interface completeVerification { payload: T; - key: JWK.Key; + key: T2; protected?: object; header?: object; } - function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput, options?: VerifyOptions): string | object; - function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput, options?: VerifyOptions): Buffer; - function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput, options?: VerifyOptions): completeVerification; - function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput, options?: VerifyOptions): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInputWithNone, options?: VerifyOptions): string | object; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInputWithNone, options?: VerifyOptions): Buffer; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput, options?: VerifyOptions): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput, options?: VerifyOptions): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: NoneKey, options?: VerifyOptions): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: NoneKey, options?: VerifyOptions): completeVerification; } export namespace JWE { @@ -364,8 +377,9 @@ export namespace JWT { profile?: JWTProfiles; } - function verify(jwt: string, key: ConsumeKeyInput, options?: VerifyOptions): object; + function verify(jwt: string, key: ConsumeKeyInputWithNone, options?: VerifyOptions): object; function verify(jwt: string, key: ConsumeKeyInput, options?: VerifyOptions): completeResult; + function verify(jwt: string, key: NoneKey, options?: VerifyOptions): completeResult; interface SignOptions { iat?: boolean; @@ -382,7 +396,7 @@ export namespace JWT { now?: Date; } - function sign(payload: object, key: ProduceKeyInput, options?: SignOptions): string; + function sign(payload: object, key: ProduceKeyInputWithNone, options?: SignOptions): string; interface VerifyProfileOptions { issuer: string; @@ -391,18 +405,21 @@ export namespace JWT { } namespace IdToken { - function verify(jwt: string, key: ConsumeKeyInput, options: VerifyOptions & VerifyProfileOptions<'id_token'>): object; + function verify(jwt: string, key: ConsumeKeyInputWithNone, options: VerifyOptions & VerifyProfileOptions<'id_token'>): object; function verify(jwt: string, key: ConsumeKeyInput, options: VerifyOptions & VerifyProfileOptions<'id_token'>): completeResult; + function verify(jwt: string, key: NoneKey, options: VerifyOptions & VerifyProfileOptions<'id_token'>): completeResult; } namespace LogoutToken { - function verify(jwt: string, key: ConsumeKeyInput, options: VerifyOptions & VerifyProfileOptions<'logout_token'>): object; + function verify(jwt: string, key: ConsumeKeyInputWithNone, options: VerifyOptions & VerifyProfileOptions<'logout_token'>): object; function verify(jwt: string, key: ConsumeKeyInput, options: VerifyOptions & VerifyProfileOptions<'logout_token'>): completeResult; + function verify(jwt: string, key: NoneKey, options: VerifyOptions & VerifyProfileOptions<'logout_token'>): completeResult; } namespace AccessToken { - function verify(jwt: string, key: ConsumeKeyInput, options: VerifyOptions & VerifyProfileOptions<'at+JWT'>): object; + function verify(jwt: string, key: ConsumeKeyInputWithNone, options: VerifyOptions & VerifyProfileOptions<'at+JWT'>): object; function verify(jwt: string, key: ConsumeKeyInput, options: VerifyOptions & VerifyProfileOptions<'at+JWT'>): completeResult; + function verify(jwt: string, key: NoneKey, options: VerifyOptions & VerifyProfileOptions<'at+JWT'>): completeResult; } }