From faa45bc03b30a62deeb14b94a074e419ebeb8dac Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sun, 20 Jan 2019 19:37:27 +0100 Subject: [PATCH] refactor: remove generic errors --- lib/errors.js | 3 + lib/help/ecdsa_signatures.js | 4 +- lib/jwa/index.js | 10 +-- lib/jwe/generate_cek.js | 22 ++++++ lib/jwk/generate.js | 20 ++++++ lib/jwk/import.js | 3 +- lib/jwk/index.js | 1 + lib/jwk/key/base.js | 3 +- lib/jwk/key/ec.js | 83 +++++++++++++--------- lib/jwk/key/oct.js | 99 +++++++++++++++++++++++--- lib/jwk/key/rsa.js | 83 +++++++++++++--------- lib/jws/serializers.js | 4 +- lib/jws/sign.js | 6 +- lib/jwt/decode.js | 9 +-- lib/jwt/sign.js | 12 +--- lib/jwt/verify.js | 12 +--- test/help/ecdsa_signatures.test.js | 36 +++++----- test/jwk/ec.test.js | 108 ++++++++++++++++++++++++++--- test/jwk/oct.test.js | 4 ++ test/jwk/rsa.test.js | 108 ++++++++++++++++++++++++++--- test/jwt/sign.test.js | 12 ++-- test/jwt/verify.test.js | 16 ++--- 22 files changed, 493 insertions(+), 165 deletions(-) create mode 100644 lib/jwe/generate_cek.js create mode 100644 lib/jwk/generate.js diff --git a/lib/errors.js b/lib/errors.js index 58709dcd..c0cbacd9 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -1,4 +1,5 @@ const CODES = { + TODO: 'ERR_TODO', JWSInvalidHeader: 'ERR_JWS_INVALID_HEADER', JWSMissingAlg: 'ERR_JWS_ALG_MISSING', JWSNoRecipients: 'ERR_JWS_NO_RECIPIENTS', @@ -30,3 +31,5 @@ module.exports.JWTIssuerMismatch = class JWTIssuerMismatch extends JoseError {} module.exports.JWTNonceMismatch = class JWTNonceMismatch extends JoseError {} module.exports.JWTSubjectMismatch = class JWTSubjectMismatch extends JoseError {} module.exports.JWTTokenIdMismatch = class JWTTokenIdMismatch extends JoseError {} + +module.exports.TODO = class TODO extends JoseError {} diff --git a/lib/help/ecdsa_signatures.js b/lib/help/ecdsa_signatures.js index be92f0ac..0b656b50 100644 --- a/lib/help/ecdsa_signatures.js +++ b/lib/help/ecdsa_signatures.js @@ -126,14 +126,14 @@ module.exports.joseToDer = (signature, alg) => { } if (!paramBytesForAlg[alg]) { - throw new Error(`Unknown algorithm "${alg}"`) + throw new TypeError(`Unknown algorithm "${alg}"`) } const paramBytes = paramBytesForAlg[alg] const signatureBytes = signature.length if (signatureBytes !== paramBytes * 2) { - throw new TypeError(`"${alg}" signatures must be "${paramBytes * 2}" bytes, saw "${signatureBytes}"`) + throw new Error(`"${alg}" signatures must be "${paramBytes * 2}" bytes, saw "${signatureBytes}"`) } const rPadding = countPadding(signature, 0, paramBytes) diff --git a/lib/jwa/index.js b/lib/jwa/index.js index d463cdee..d568d989 100644 --- a/lib/jwa/index.js +++ b/lib/jwa/index.js @@ -1,3 +1,5 @@ +const { TODO } = require('../errors') + const JWA = { sign: new Map(), verify: new Map() @@ -11,20 +13,20 @@ require('./rsassa_pkcs1')(JWA) module.exports = { sign: (alg, key, payload) => { if (!JWA.sign.has(alg)) { - throw new Error(`sign alg ${alg} not implemented`) + throw new TODO(`sign alg ${alg} not implemented`) } if (!key.algorithms('sign').has(alg)) { - throw new Error(`the key does not support ${alg} sign algorithm`) + throw new TODO(`the key does not support ${alg} sign algorithm`) } return JWA.sign.get(alg)(key, payload) }, verify: (alg, key, payload, signature) => { if (!JWA.verify.has(alg)) { - throw new Error(`verify alg ${alg} not implemented`) + throw new TODO(`verify alg ${alg} not implemented`) } if (!key.algorithms('verify').has(alg)) { - throw new Error(`the key does not support ${alg} verify algorithm`) + throw new TODO(`the key does not support ${alg} verify algorithm`) } return JWA.verify.get(alg)(key, payload, signature) diff --git a/lib/jwe/generate_cek.js b/lib/jwe/generate_cek.js new file mode 100644 index 00000000..636f8a1e --- /dev/null +++ b/lib/jwe/generate_cek.js @@ -0,0 +1,22 @@ +const { randomBytes, createSecretKey } = require('crypto') + +const OctKey = require('../jwk/key/oct') + +const KEYLENGTHS = { + 'A128CBC-HS256': 256 / 8, + 'A192CBC-HS384': 384 / 8, + 'A256CBC-HS512': 512 / 8, + 'A128GCM': 128 / 8, + 'A192GCM': 192 / 8, + 'A256GCM': 256 / 8 +} + +module.exports = (alg) => { + const byteLength = KEYLENGTHS[alg] + + if (byteLength === undefined) { + throw new TypeError('unsupported intended content encryption key alg') + } + + return new OctKey(createSecretKey(randomBytes(byteLength))) +} diff --git a/lib/jwk/generate.js b/lib/jwk/generate.js new file mode 100644 index 00000000..c11810b6 --- /dev/null +++ b/lib/jwk/generate.js @@ -0,0 +1,20 @@ +const RSAKey = require('./key/rsa') +const ECKey = require('./key/ec') +const OctKey = require('./key/oct') + +function generate (kty, ...args) { + switch (kty) { + case 'rsa': + case 'RSA': + return RSAKey.generate(...args) + case 'ec': + case 'EC': + return ECKey.generate(...args) + case 'oct': + return OctKey.generate(...args) + default: + throw new TypeError('invalid key type') + } +} + +module.exports = generate diff --git a/lib/jwk/import.js b/lib/jwk/import.js index bcd61cdc..277266b0 100644 --- a/lib/jwk/import.js +++ b/lib/jwk/import.js @@ -5,6 +5,7 @@ const RSAKey = require('./key/rsa') const ECKey = require('./key/ec') const OctKey = require('./key/oct') const base64url = require('../help/base64url') +const { TODO } = require('../errors') const { PrivateKeyObject, PublicKeyObject, SecretKeyObject } = require('../help/key_objects') const { jwkToPem } = require('../help/key_utils') @@ -51,7 +52,7 @@ function importKey (key, opts) { } if (!privateKey && !publicKey && !secret) { - throw new Error('import failed') + throw new TODO('import failed') } const keyObject = privateKey || publicKey || secret diff --git a/lib/jwk/index.js b/lib/jwk/index.js index 44aa90de..14d82ce4 100644 --- a/lib/jwk/index.js +++ b/lib/jwk/index.js @@ -1 +1,2 @@ module.exports.importKey = require('./import') +module.exports.generate = require('./generate') diff --git a/lib/jwk/key/base.js b/lib/jwk/key/base.js index ccd74253..c7c12eda 100644 --- a/lib/jwk/key/base.js +++ b/lib/jwk/key/base.js @@ -1,5 +1,6 @@ const { pemToJwk } = require('../../help/key_utils') const thumbprint = require('../thumbprint') +const { TODO } = require('../../errors') const RSA_PUBLIC = ['e', 'n'] const RSA_PRIVATE = [...RSA_PUBLIC, 'd', 'p', 'q', 'dp', 'dq', 'qi'] @@ -88,7 +89,7 @@ class Key { } thumbprintMaterial () { - throw new Error('not implemented') + throw new TODO('not implemented') } } diff --git a/lib/jwk/key/ec.js b/lib/jwk/key/ec.js index 16cc1dbc..e52c16f6 100644 --- a/lib/jwk/key/ec.js +++ b/lib/jwk/key/ec.js @@ -1,3 +1,6 @@ +const { promisify } = require('util') +const generateKeyPair = promisify(require('crypto').generateKeyPair) + const Key = require('./base') const SIG_ALGS = new Set([ @@ -6,12 +9,12 @@ const SIG_ALGS = new Set([ 'ES512' ]) -// const WRAP_ALGS = new Set([ -// 'ECDH-ES', -// 'ECDH-ES+A128KW', -// 'ECDH-ES+A192KW', -// 'ECDH-ES+A256KW' -// ]) +const WRAP_ALGS = new Set([ + 'ECDH-ES', + 'ECDH-ES+A128KW', + 'ECDH-ES+A192KW', + 'ECDH-ES+A256KW' +]) class ECKey extends Key { constructor (...args) { @@ -36,53 +39,67 @@ class ECKey extends Key { } algorithms (operation) { - // TODO: operation empty, return all supported or throw - switch (operation) { + case 'encrypt': + case 'decrypt': + return new Set() case 'sign': if (this.public || this.use === 'enc') { - return new Set([]) + return new Set() } if (this.alg) { - return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : []) + return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : undefined) } return new Set([`ES${this.length === 521 ? 512 : this.length}`]) case 'verify': if (this.use === 'enc') { - return new Set([]) + return new Set() } if (this.alg) { - return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : []) + return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : undefined) } return new Set([`ES${this.length === 521 ? 512 : this.length}`]) - // case 'unwrapKey': - // if (this.public || this.use === 'sig') { - // return new Set([]) - // } - // - // if (this.alg) { - // return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : []) - // } - // - // return new Set(WRAP_ALGS) - // case 'wrapKey': - // if (this.use === 'sig') { - // return new Set([]) - // } - // - // if (this.alg) { - // return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : []) - // } - // - // return new Set(WRAP_ALGS) + case 'wrapKey': + if (this.use === 'sig') { + return new Set() + } + + if (this.alg) { + return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : undefined) + } + + return new Set(WRAP_ALGS) + case 'unwrapKey': + if (this.public || this.use === 'sig') { + return new Set() + } + + if (this.alg) { + return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : undefined) + } + + return new Set(WRAP_ALGS) + case undefined: + return new Set([ + ...this.algorithms('sign'), + ...this.algorithms('verify'), + ...this.algorithms('wrapKey'), + ...this.algorithms('unwrapKey') + ]) default: - return new Set([]) + throw new TypeError('invalid key operation') } } + + static async generate (crv = 'P-256', opts, privat = true) { + const { privateKey, publicKey } = await generateKeyPair('ec', { namedCurve: crv }) + + return new ECKey(privat ? privateKey : publicKey, opts) + } } module.exports = ECKey diff --git a/lib/jwk/key/oct.js b/lib/jwk/key/oct.js index 73962b99..8b162fae 100644 --- a/lib/jwk/key/oct.js +++ b/lib/jwk/key/oct.js @@ -1,3 +1,5 @@ +const { randomBytes, createSecretKey } = require('crypto') + const Key = require('./base') const base64url = require('../../help/base64url') @@ -7,6 +9,42 @@ const SIG_ALGS = new Set([ 'HS512' ]) +const ENC_LEN = new Set([ + 128, + 192, + 256, + 384, + 512 +]) + +const ENC_ALGS = new Set([ + 'A128GCM', + 'A192GCM', + 'A256GCM', + 'A128CBC-HS256', + 'A192CBC-HS384', + 'A256CBC-HS512' +]) + +const WRAP_LEN = new Set([ + 128, + 192, + 256 +]) + +const WRAP_ALGS = new Set([ + 'A128KW', + 'A192KW', + 'A256KW', + 'A128GCMKW', + 'A192GCMKW', + 'A256GCMKW', + 'PBES2-HS256+A128KW', + 'PBES2-HS384+A192KW', + 'PBES2-HS512+A256KW', + 'dir' +]) + class OctKey extends Key { constructor (...args) { super(...args) @@ -15,8 +53,16 @@ class OctKey extends Key { value: this.keyObject.symmetricKeySize * 8 }, k: { - value: base64url.encode(this.keyObject.export()), - enumerable: true + enumerable: true, + get () { + Object.defineProperty(this, 'k', { + value: base64url.encode(this.keyObject.export()), + configurable: false + }) + + return this.k + }, + configurable: true } }) } @@ -26,22 +72,22 @@ class OctKey extends Key { } algorithms (operation) { - // TODO: operation empty, return all supported or throw - switch (operation) { - case 'sign': - if (this.use === 'enc') { - return new Set([]) + case 'encrypt': + case 'decrypt': + if (this.use === 'sig' || !ENC_LEN.has(this.length)) { + return new Set() } if (this.alg) { - return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : []) + return new Set(ENC_ALGS.has(this.alg) ? [this.alg] : []) } - return new Set(SIG_ALGS) + return new Set([`A${this.length / 2}CBC-HS${this.length}`, `A${this.length}GCM`].filter(a => ENC_ALGS.has(a))) + case 'sign': case 'verify': if (this.use === 'enc') { - return new Set([]) + return new Set() } if (this.alg) { @@ -49,10 +95,41 @@ class OctKey extends Key { } return new Set(SIG_ALGS) + case 'wrapKey': + case 'unwrapKey': + if (this.use === 'sig') { + return new Set() + } + + if (this.alg) { + return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : []) + } + + const algs = new Set(['dir', 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW']) + + if (WRAP_LEN.has(this.length)) { + algs.add(`A${this.length}KW`) + algs.add(`A${this.length}GCMKW`) + } + + return algs + case undefined: + return new Set([ + ...this.algorithms('encrypt'), + ...this.algorithms('sign'), + ...this.algorithms('wrapKey') + ]) default: - return new Set([]) + throw new TypeError('invalid key operation') } } + + static async generate (len = 256, opts) { + if (!Number.isSafeInteger(len) || !len || len % 8 !== 0) { + throw new TypeError('invalid bit length') + } + return new OctKey(createSecretKey(randomBytes(len / 8)), opts) + } } module.exports = OctKey diff --git a/lib/jwk/key/rsa.js b/lib/jwk/key/rsa.js index 45b53354..85569e91 100644 --- a/lib/jwk/key/rsa.js +++ b/lib/jwk/key/rsa.js @@ -1,3 +1,6 @@ +const { promisify } = require('util') +const generateKeyPair = promisify(require('crypto').generateKeyPair) + const Key = require('./base') const SIG_ALGS = new Set([ @@ -9,10 +12,10 @@ const SIG_ALGS = new Set([ 'PS512' ]) -// const WRAP_ALGS = new Set([ -// 'RSA-OAEP', -// 'RSA1_5' -// ]) +const WRAP_ALGS = new Set([ + 'RSA-OAEP', + 'RSA1_5' +]) class RSAKey extends Key { constructor (...args) { @@ -37,53 +40,71 @@ class RSAKey extends Key { } algorithms (operation) { - // TODO: operation empty, return all supported or throw - switch (operation) { + case 'encrypt': + case 'decrypt': + return new Set() case 'sign': if (this.public || this.use === 'enc') { - return new Set([]) + return new Set() } if (this.alg) { - return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : []) + return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : undefined) } return new Set(SIG_ALGS) case 'verify': if (this.use === 'enc') { - return new Set([]) + return new Set() } if (this.alg) { - return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : []) + return new Set(SIG_ALGS.has(this.alg) ? [this.alg] : undefined) } return new Set(SIG_ALGS) - // case 'unwrapKey': - // if (this.public || this.use === 'sig') { - // return new Set([]) - // } - // - // if (this.alg) { - // return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : []) - // } - // - // return new Set(WRAP_ALGS) - // case 'wrapKey': - // if (this.use === 'sig') { - // return new Set([]) - // } - // - // if (this.alg) { - // return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : []) - // } - // - // return new Set(WRAP_ALGS) + case 'wrapKey': + if (this.use === 'sig') { + return new Set() + } + + if (this.alg) { + return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : undefined) + } + + return new Set(WRAP_ALGS) + case 'unwrapKey': + if (this.public || this.use === 'sig') { + return new Set() + } + + if (this.alg) { + return new Set(WRAP_ALGS.has(this.alg) ? [this.alg] : undefined) + } + + return new Set(WRAP_ALGS) + case undefined: + return new Set([ + ...this.algorithms('sign'), + ...this.algorithms('verify'), + ...this.algorithms('wrapKey'), + ...this.algorithms('unwrapKey') + ]) default: - return new Set([]) + throw new TypeError('invalid key operation') } } + + static async generate (len = 2048, opts, privat = true) { + if (!Number.isSafeInteger(len) || len < 512 || len % 8 !== 0) { + throw new TypeError('invalid bit length') + } + + const { privateKey, publicKey } = await generateKeyPair('rsa', { modulusLength: len }) + + return new RSAKey(privat ? privateKey : publicKey, opts) + } } module.exports = RSAKey diff --git a/lib/jws/serializers.js b/lib/jws/serializers.js index 40fa1624..2492fedc 100644 --- a/lib/jws/serializers.js +++ b/lib/jws/serializers.js @@ -1,3 +1,5 @@ +const { TODO } = require('../errors') + function compactSerializer (payload, [{ signature, protected: prot }]) { return `${prot}.${payload}.${signature}` } @@ -50,7 +52,7 @@ function detect (input) { } } - throw new Error('invalid serialization') + throw new TODO('invalid serialization') } module.exports = { diff --git a/lib/jws/sign.js b/lib/jws/sign.js index bc06d34f..086e053a 100644 --- a/lib/jws/sign.js +++ b/lib/jws/sign.js @@ -2,7 +2,7 @@ const base64url = require('../help/base64url') const serializers = require('./serializers') const Key = require('../jwk/key/base') -const { JWSInvalidHeader, JWSMissingAlg } = require('../errors') +const { JWSInvalidHeader, JWSMissingAlg, TODO } = require('../errors') const { sign } = require('../jwa') function process ({ payload, sharedProtectedHeader, sharedUnprotectedHeader }, recipient) { @@ -64,12 +64,12 @@ class Sign { */ sign (serialization = 'compact') { if (!this.recipients.length) { - throw new Error('missing recipients') + throw new TODO('missing recipients') } const serializer = serializers[serialization] if (!serializer) { - throw new TypeError('invalid serialization') + throw new TODO('invalid serialization') } serializer.validate(this, this.recipients) diff --git a/lib/jwt/decode.js b/lib/jwt/decode.js index 46ecae47..2d73aa1c 100644 --- a/lib/jwt/decode.js +++ b/lib/jwt/decode.js @@ -1,18 +1,19 @@ const base64url = require('../help/base64url') +const { TODO } = require('../errors') module.exports = (jwt, { complete = false } = {}) => { if (typeof jwt !== 'string') { - throw TypeError('jwt must be a string') + throw new TypeError('jwt must be a string') } const parts = jwt.split('.') if (parts.length === 5) { - throw new Error('jwt appears to be encrypted') + throw new TODO('jwt appears to be encrypted') } if (parts.length !== 3) { - throw new Error('jwt malformed') + throw new TODO('jwt malformed') } let [header, payload] = parts @@ -21,7 +22,7 @@ module.exports = (jwt, { complete = false } = {}) => { header = base64url.JSON.decode(header) payload = base64url.JSON.decode(payload) } catch (err) { - throw new Error('jwt malformed') + throw new TODO('jwt malformed') } return complete ? { header, payload, signature: parts[2] } : payload diff --git a/lib/jwt/sign.js b/lib/jwt/sign.js index 30d02d84..c9b0d617 100644 --- a/lib/jwt/sign.js +++ b/lib/jwt/sign.js @@ -3,10 +3,6 @@ const ms = require('ms') const Key = require('../jwk/key/base') const { sign } = require('../jws') const epoch = require('../help/epoch') -const importKey = require('../jwk/import') - -let lastInput -let lastKey module.exports = ( payload = {}, @@ -29,13 +25,7 @@ module.exports = ( } = {} ) => { if (!(key instanceof Key)) { - if (key === lastInput) { - key = lastKey - } else { - const imported = importKey(key) - lastInput = key - key = lastKey = imported - } + throw new TypeError('key must be an instance of a key instantiated by JWK.importKey') } // TODO: full options assert diff --git a/lib/jwt/verify.js b/lib/jwt/verify.js index 6a9cc210..d58e0bcd 100644 --- a/lib/jwt/verify.js +++ b/lib/jwt/verify.js @@ -3,14 +3,10 @@ const ms = require('ms') const Key = require('../jwk/key/base') const { verify } = require('../jws') const epoch = require('../help/epoch') -const importKey = require('../jwk/import') const errors = require('../errors') const decode = require('./decode') -let lastInput -let lastKey - module.exports = ( jwt, key, @@ -31,13 +27,7 @@ module.exports = ( } = {} ) => { if (!(key instanceof Key)) { - if (key === lastInput) { - key = lastKey - } else { - const imported = importKey(key) - lastInput = key - key = lastKey = imported - } + throw new TypeError('key must be an instance of a key instantiated by JWK.importKey') } const { header, payload, signature } = decode(jwt, { complete: true }) diff --git a/test/help/ecdsa_signatures.test.js b/test/help/ecdsa_signatures.test.js index b023b5c8..a8168975 100644 --- a/test/help/ecdsa_signatures.test.js +++ b/test/help/ecdsa_signatures.test.js @@ -15,7 +15,7 @@ test('.derToJose no signature', t => { return derToJose() } - t.throws(fn, TypeError) + t.throws(fn, { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) }) test('.derToJose non buffer or base64 signature', t => { @@ -23,7 +23,7 @@ test('.derToJose non buffer or base64 signature', t => { return derToJose(123) } - t.throws(fn, TypeError) + t.throws(fn, { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) }) test('.derToJose unknown algorithm', t => { @@ -31,7 +31,7 @@ test('.derToJose unknown algorithm', t => { return derToJose(decodeToBuffer('Zm9vLmJhci5iYXo'), 'foobar') } - t.throws(fn, /"foobar"/) + t.throws(fn, { instanceOf: Error, message: 'Unknown algorithm "foobar"' }) }) Object.entries({ @@ -47,7 +47,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /expected "seq"/) + t.throws(fn, { instanceOf: Error, message: /expected "seq"/ }) }) test(`.derToJose seq length exceeding input (${alg})`, t => { @@ -59,7 +59,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /length/) + t.throws(fn, { instanceOf: Error, message: /length/ }) }) test(`.derToJose r is not marked as int (${alg})`, t => { @@ -72,7 +72,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /expected "int".+"r"/) + t.throws(fn, { instanceOf: Error, message: /expected "int".+"r"/ }) }) test(`.derToJose r length exceeds available input (${alg})`, t => { @@ -86,7 +86,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /"r".+length/) + t.throws(fn, { instanceOf: Error, message: /"r".+length/ }) }) test(`.derToJose r length exceeds sensical param length (${alg})`, t => { @@ -100,7 +100,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /"r".+length.+acceptable/) + t.throws(fn, { instanceOf: Error, message: /"r".+length.+acceptable/ }) }) test(`.derToJose s is not marked as int (${alg})`, t => { @@ -117,7 +117,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /expected "int".+"s"/) + t.throws(fn, { instanceOf: Error, message: /expected "int".+"s"/ }) }) test(`.derToJose s length exceeds available input (${alg})`, t => { @@ -135,7 +135,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /"s".+length/) + t.throws(fn, { instanceOf: Error, message: /"s".+length/ }) }) test(`.derToJose s length does not consume available input (${alg})`, t => { @@ -153,7 +153,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /"s".+length/) + t.throws(fn, { instanceOf: Error, message: /"s".+length/ }) }) test(`.derToJose s length exceeds sensical param length (${alg})`, t => { @@ -171,7 +171,7 @@ Object.entries({ derToJose(input, alg) } - t.throws(fn, Error, /"s".+length.+acceptable/) + t.throws(fn, { instanceOf: Error, message: /"s".+length.+acceptable/ }) }) }) @@ -180,7 +180,7 @@ test('.joseToDer no signature', t => { return joseToDer() } - t.throws(fn, TypeError) + t.throws(fn, { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) }) test('.joseToDer non buffer or base64 signature', t => { @@ -188,7 +188,7 @@ test('.joseToDer non buffer or base64 signature', t => { return joseToDer(123) } - t.throws(fn, TypeError) + t.throws(fn, { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) }) test('.joseToDer unknown algorithm', t => { @@ -196,7 +196,7 @@ test('.joseToDer unknown algorithm', t => { return joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo='), 'foobar') } - t.throws(fn, /"foobar"/) + t.throws(fn, { instanceOf: Error, message: /"foobar"/ }) }) test('.joseToDer incorrect signature length (ES256)', t => { @@ -204,7 +204,7 @@ test('.joseToDer incorrect signature length (ES256)', t => { return joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'ES256') } - t.throws(fn, /"64"/) + t.throws(fn, { instanceOf: Error, message: /"64"/ }) }) test('.joseToDer incorrect signature length (ES384)', t => { @@ -212,7 +212,7 @@ test('.joseToDer incorrect signature length (ES384)', t => { return joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'ES384') } - t.throws(fn, /"96"/) + t.throws(fn, { instanceOf: Error, message: /"96"/ }) }) test('.joseToDer incorrect signature length (ES512)', t => { @@ -220,7 +220,7 @@ test('.joseToDer incorrect signature length (ES512)', t => { return joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'ES512') } - t.throws(fn, /"132"/) + t.throws(fn, { instanceOf: Error, message: '"ES512" signatures must be "132" bytes, saw "11"' }) }) test('ES256 should jose -> der -> jose', t => { diff --git a/test/jwk/ec.test.js b/test/jwk/ec.test.js index 5f3d8b24..427cffd6 100644 --- a/test/jwk/ec.test.js +++ b/test/jwk/ec.test.js @@ -5,6 +5,11 @@ const fixtures = require('../fixtures') const ECKey = require('../../lib/jwk/key/ec') +test(`EC key .algorithms invalid operation`, t => { + const key = new ECKey(createPrivateKey(fixtures.PEM['P-256'].private)) + t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) +}) + Object.entries({ 'P-256': [256, 'rDd6H6t9-nJUoz72nTpz8tInvypVWhE2iQoPznj8ZY8'], 'P-384': [384, '5gebayAhpztJCs4Pxo-z1hhsN0upoyG2NAoKpiiH2b0'], @@ -32,6 +37,19 @@ Object.entries({ test(`${crv} EC Private key`, hasProperty, key, 'public', false) test(`${crv} EC Private key`, hasProperty, key, 'use', undefined) + test(`${crv} EC Private key algorithms (no operation)`, t => { + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], [alg, 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) + }) + + test(`${crv} EC Private key algorithms (no operation, w/ alg)`, t => { + const key = new ECKey(keyObject, { alg }) + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], [alg]) + }) + test(`${crv} EC Private key supports sign alg (no use)`, t => { const result = key.algorithms('sign') t.is(result.constructor, Set) @@ -86,11 +104,43 @@ Object.entries({ t.deepEqual([...result], []) }) - test.todo(`${crv} EC Private key .algorithms() no arg`) - test.todo(`${crv} EC Private key .algorithms("encrypt")`) - test.todo(`${crv} EC Private key .algorithms("decrypt")`) - test.todo(`${crv} EC Private key .algorithms("wrapKey")`) - test.todo(`${crv} EC Private key .algorithms("unwrapKey")`) + test(`${crv} EC Private key .algorithms("encrypt")`, t => { + const result = key.algorithms('encrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test(`${crv} EC Private key .algorithms("decrypt")`, t => { + const result = key.algorithms('decrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test(`${crv} EC Private key .algorithms("wrapKey")`, t => { + const result = key.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) + }) + + test(`${crv} EC Private key .algorithms("wrapKey") when use is sig`, t => { + const sigKey = new ECKey(keyObject, { use: 'sig' }) + const result = sigKey.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test(`${crv} EC Private key .algorithms("unwrapKey")`, t => { + const result = key.algorithms('unwrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) + }) + + test(`${crv} EC Private key .algorithms("unwrapKey") when use is sig`, t => { + const sigKey = new ECKey(keyObject, { use: 'sig' }) + const result = sigKey.algorithms('unwrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) })() // public @@ -113,6 +163,19 @@ Object.entries({ test(`${crv} EC Public key`, hasProperty, key, 'public', true) test(`${crv} EC Public key`, hasProperty, key, 'use', undefined) + test(`${crv} EC Public key algorithms (no operation)`, t => { + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], [alg, 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) + }) + + test(`${crv} EC Public key algorithms (no operation, w/ alg)`, t => { + const key = new ECKey(keyObject, { alg }) + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], [alg]) + }) + test(`${crv} EC Public key cannot sign`, t => { const result = key.algorithms('sign') t.is(result.constructor, Set) @@ -167,10 +230,35 @@ Object.entries({ t.deepEqual([...result], []) }) - test.todo(`${crv} EC Public key .algorithms() no arg`) - test.todo(`${crv} EC Public key .algorithms("encrypt")`) - test.todo(`${crv} EC Public key .algorithms("decrypt")`) - test.todo(`${crv} EC Public key .algorithms("wrapKey")`) - test.todo(`${crv} EC Public key .algorithms("unwrapKey")`) + test(`${crv} EC Public key .algorithms("encrypt")`, t => { + const result = key.algorithms('encrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test(`${crv} EC Public key .algorithms("decrypt")`, t => { + const result = key.algorithms('decrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test(`${crv} EC Public key .algorithms("wrapKey")`, t => { + const result = key.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) + }) + + test(`${crv} EC Public key .algorithms("wrapKey") when use is sig`, t => { + const sigKey = new ECKey(keyObject, { use: 'sig' }) + const result = sigKey.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test(`${crv} EC Public key .algorithms("unwrapKey")`, t => { + const result = key.algorithms('unwrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) })() }) diff --git a/test/jwk/oct.test.js b/test/jwk/oct.test.js index 88a46130..52c7b3c5 100644 --- a/test/jwk/oct.test.js +++ b/test/jwk/oct.test.js @@ -7,6 +7,10 @@ const OctKey = require('../../lib/jwk/key/oct') const keyObject = createSecretKey(Buffer.from('secret')) const key = new OctKey(keyObject) +test(`RSA key .algorithms invalid operation`, t => { + t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) +}) + test('oct key .thumbprintMaterial()', hasProperties, key.thumbprintMaterial(), 'k', 'kty') test('oct key (with alg)', hasProperty, new OctKey(keyObject, { alg: 'HS256' }), 'alg', 'HS256') test('oct key (with kid)', hasProperty, new OctKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') diff --git a/test/jwk/rsa.test.js b/test/jwk/rsa.test.js index 77d1e70b..dca282ad 100644 --- a/test/jwk/rsa.test.js +++ b/test/jwk/rsa.test.js @@ -5,6 +5,11 @@ const fixtures = require('../fixtures') const RSAKey = require('../../lib/jwk/key/rsa') +test(`RSA key .algorithms invalid operation`, t => { + const key = new RSAKey(createPrivateKey(fixtures.PEM.RSA.private)) + t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) +}) + // private ;(() => { const keyObject = createPrivateKey(fixtures.PEM.RSA.private) @@ -25,6 +30,19 @@ const RSAKey = require('../../lib/jwk/key/rsa') test(`RSA Private key`, hasProperty, key, 'public', false) test(`RSA Private key`, hasProperty, key, 'use', undefined) + test('RSA Private key algorithms (no operation)', t => { + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], ['RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512', 'RSA-OAEP', 'RSA1_5']) + }) + + test('RSA Private key algorithms (no operation, w/ alg)', t => { + const key = new RSAKey(keyObject, { alg: 'RS256' }) + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], ['RS256']) + }) + test(`RSA Private key supports sign alg (no use)`, t => { const result = key.algorithms('sign') t.is(result.constructor, Set) @@ -79,11 +97,43 @@ const RSAKey = require('../../lib/jwk/key/rsa') t.deepEqual([...result], []) }) - test.todo(`RSA Private key .algorithms() no arg`) - test.todo(`RSA Private key .algorithms("encrypt")`) - test.todo(`RSA Private key .algorithms("decrypt")`) - test.todo(`RSA Private key .algorithms("wrapKey")`) - test.todo(`RSA Private key .algorithms("unwrapKey")`) + test('RSA Private key .algorithms("encrypt")', t => { + const result = key.algorithms('encrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test('RSA Private key .algorithms("decrypt")', t => { + const result = key.algorithms('decrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test('RSA Private key .algorithms("wrapKey")', t => { + const result = key.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], ['RSA-OAEP', 'RSA1_5']) + }) + + test('RSA Private key .algorithms("wrapKey") when use is sig', t => { + const sigKey = new RSAKey(keyObject, { use: 'sig' }) + const result = sigKey.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test('RSA Private key .algorithms("unwrapKey")', t => { + const result = key.algorithms('unwrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], ['RSA-OAEP', 'RSA1_5']) + }) + + test('RSA Private key .algorithms("unwrapKey") when use is sig', t => { + const sigKey = new RSAKey(keyObject, { use: 'sig' }) + const result = sigKey.algorithms('unwrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) })() // public @@ -106,6 +156,19 @@ const RSAKey = require('../../lib/jwk/key/rsa') test(`RSA Public key`, hasProperty, key, 'public', true) test(`RSA Public key`, hasProperty, key, 'use', undefined) + test('RSA EC Public key algorithms (no operation)', t => { + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], ['RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512', 'RSA-OAEP', 'RSA1_5']) + }) + + test('RSA EC Public key algorithms (no operation, w/ alg)', t => { + const key = new RSAKey(keyObject, { alg: 'RS256' }) + const result = key.algorithms() + t.is(result.constructor, Set) + t.deepEqual([...result], ['RS256']) + }) + test(`RSA Public key cannot sign`, t => { const result = key.algorithms('sign') t.is(result.constructor, Set) @@ -160,9 +223,34 @@ const RSAKey = require('../../lib/jwk/key/rsa') t.deepEqual([...result], []) }) - test.todo(`RSA Public key .algorithms() no arg`) - test.todo(`RSA Public key .algorithms("encrypt")`) - test.todo(`RSA Public key .algorithms("decrypt")`) - test.todo(`RSA Public key .algorithms("wrapKey")`) - test.todo(`RSA Public key .algorithms("unwrapKey")`) + test('RSA Public key .algorithms("encrypt")', t => { + const result = key.algorithms('encrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test('RSA Public key .algorithms("decrypt")', t => { + const result = key.algorithms('decrypt') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test('RSA Public key .algorithms("wrapKey")', t => { + const result = key.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], ['RSA-OAEP', 'RSA1_5']) + }) + + test('RSA Public key .algorithms("wrapKey") when use is sig', t => { + const sigKey = new RSAKey(keyObject, { use: 'sig' }) + const result = sigKey.algorithms('wrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) + + test('RSA Public key .algorithms("unwrapKey")', t => { + const result = key.algorithms('unwrapKey') + t.is(result.constructor, Set) + t.deepEqual([...result], []) + }) })() diff --git a/test/jwt/sign.test.js b/test/jwt/sign.test.js index 5fb85025..5e85475d 100644 --- a/test/jwt/sign.test.js +++ b/test/jwt/sign.test.js @@ -1,17 +1,17 @@ const test = require('ava') -const { sign } = require('../../lib/jwt') +const { JWT: { sign }, JWK: { importKey } } = require('../..') const { compactJwt } = require('../macros') const fixtures = require('../fixtures') -const oct = Buffer.from('foo') +const oct = importKey(Buffer.from('foo')) test('uses HS256 for oct keys', compactJwt, () => sign({}, oct, { noTimestamp: true }), { alg: 'HS256' }, {}) -test('uses RS256 for RSA keys', compactJwt, () => sign({}, fixtures.PEM.RSA.private, { noTimestamp: true }), { alg: 'RS256' }, {}) -test('uses ES256 for P-256 keys', compactJwt, () => sign({}, fixtures.PEM['P-256'].private, { noTimestamp: true }), { alg: 'ES256' }, {}) -test('uses ES384 for P-384 keys', compactJwt, () => sign({}, fixtures.PEM['P-384'].private, { noTimestamp: true }), { alg: 'ES384' }, {}) -test('uses ES512 for P-521 keys', compactJwt, () => sign({}, fixtures.PEM['P-521'].private, { noTimestamp: true }), { alg: 'ES512' }, {}) +test('uses RS256 for RSA keys', compactJwt, () => sign({}, importKey(fixtures.PEM.RSA.private), { noTimestamp: true }), { alg: 'RS256' }, {}) +test('uses ES256 for P-256 keys', compactJwt, () => sign({}, importKey(fixtures.PEM['P-256'].private), { noTimestamp: true }), { alg: 'ES256' }, {}) +test('uses ES384 for P-384 keys', compactJwt, () => sign({}, importKey(fixtures.PEM['P-384'].private), { noTimestamp: true }), { alg: 'ES384' }, {}) +test('uses ES512 for P-521 keys', compactJwt, () => sign({}, importKey(fixtures.PEM['P-521'].private), { noTimestamp: true }), { alg: 'ES512' }, {}) ;(() => { // header alg diff --git a/test/jwt/verify.test.js b/test/jwt/verify.test.js index bc394660..cb5b34df 100644 --- a/test/jwt/verify.test.js +++ b/test/jwt/verify.test.js @@ -1,21 +1,21 @@ const test = require('ava') -const { verify } = require('../../lib/jwt') +const { JWT: { verify }, JWK: { importKey } } = require('../..') const fixtures = require('../fixtures') -const oct = Buffer.from('foo') +const oct = importKey(Buffer.from('foo')) const empties = { HS256: [oct, 'eyJhbGciOiJIUzI1NiJ9.e30.wFzc1AaKc-h2sBmMo-q5Btx4pthqj4E1uI9iieszJB4'], HS384: [oct, 'eyJhbGciOiJIUzM4NCJ9.e30.hoxjcQRPLn3wGXBykB2WQFbRiwSM6DQEQaRF1HK8IkBMagxlsXl9tig9jeRmxyr0'], HS512: [oct, 'eyJhbGciOiJIUzUxMiJ9.e30.TbtVTdmZC0L9tIR2MrFUQVD1WEdTUIYZRHv6hV14WvbPB7xhxQq0Obf-XcUTlMLEadnc8dsbLkWO4oRAsn3Fgg'], - RS256: [fixtures.PEM.RSA.private, 'eyJhbGciOiJSUzI1NiJ9.e30.UJ3uM7z7mtwef9cru3MqO-G-8jLFLm4_vvW8kbPwIlLK4-J037vKE0oKHCu6kzFxlV8TwmYG8Otv4MtM3DlnbJED76E0OG0akkjXcAVQmjEVDq1maLePgZwCiwjhiAYOISXJCe__l0-NXkgHSma49uMqF2DDMK46XveOLWveKyj008SPCtGJNMal2mcCWceta1ay6IQ8_bsVnRCziWsN-2x4AM4BjF0hbE0Qv0regEPpPCVERKuFfQg_wT2CpJQFjf0qqgfYwZk-F-hE3AvBpkTnU-zd-5rxh_8ZuPpbj1xnRPVIni9FUkjkcDTtU1ZqY6d1T-WdfISGwRIx-mI9Rw'], - RS384: [fixtures.PEM.RSA.private, 'eyJhbGciOiJSUzM4NCJ9.e30.dJ78iwcXqKu5x4UqdJjt8Gk88e8XaAm1j4VurNRlWjR7pDQDtJv9a9yMgBpndc1LHgiDUDEPyDEf-PkKFL9LCmsc3QuJCJleJiLpwJAFiSLh4O9M0oCXWA-rNt3zuSAT7TZJOfOWcYoN8JrhJtUMeJbmssRa6q85Umt9-x3GPFq5B5N4N14_hXeoOyq-BfkW7hRfn3s4WaDS1wnRioU_i8FZDhgaYjuToD3qpbh1NODPu4eAGSBiGnFS2B7vL3igSx6o6tufXAMKe3uEeV6A_vLw8CS5PcRBI0SJb1ZoE6PpuG3a_QAhWOrwlEqI7kdrGsBI_6dn6fua37mYz5NDfA'], - RS512: [fixtures.PEM.RSA.private, 'eyJhbGciOiJSUzUxMiJ9.e30.TjpvzV_wg9tZcCTHoC0WfGocXlx7uHru1JDciJuCH9K2UxR-zKw4oYOeVWAWXfCjdksfq6dFHMcP1XOljjrwZndcd0DxngTePeI7KhNBUuoBRMW6UZgAVUxu6fGGKKIw2_iH-fhnYNcS2uAdJawmtSwrIOIYziSHHY4vPZR2cFQpZDRY_kLLzWVvjVRbYdQgGrAlpV9iwKvdfL24TRPNhDx4_PK8fdr92KFUv7RQEHB5B13n26jEM6hzAaGH9EBdZOj7qdQhDrheedytrkVrQrqsEZnpTY_NaGP9pWYJO0JOSWQFXGEuFwJbuD4pjYcyeyNNNO2LcaVBdlgETaQHmQ'], - ES256: [fixtures.PEM['P-256'].private, 'eyJhbGciOiJFUzI1NiJ9.e30.oFrJJCBiFG9VKFoB0SUWOE9nc4LP5ftKPupczd23stw8rAG-acek8mSvPtQwteq4C7Ztl4kAvedIwya0nyNdsQ'], - ES384: [fixtures.PEM['P-384'].private, 'eyJhbGciOiJFUzM4NCJ9.e30.Rl7rliQOo8L8kA83-lkDPiK6kwi_NPanU9tdpYB94Bja3W_fnqQbpkiKgjij9BB1Aaj5mlKcovSzRJFTKLaI0CUAsxETrg6FscHtKC2nog0bXHFRKBtuRjO7vFCg381S'], - ES512: [fixtures.PEM['P-521'].private, 'eyJhbGciOiJFUzUxMiJ9.e30.AcE4SOw8dm6gXAthcm1eY4m1cVZk844Xnt26X8bsahyc7xcb-zIJpwzqsKRX-H_rYaPM1RUkTgFJbLEnCuYvv8qSAV1mJUvjJqVlWfkQE2NByiLf1eFDR2YA8T5i9dAM6NLobl5B0koUd8m9YHj4tfgRWNdorQs3WZ7tkxfq-jXu1OeP'] + RS256: [importKey(fixtures.PEM.RSA.private), 'eyJhbGciOiJSUzI1NiJ9.e30.UJ3uM7z7mtwef9cru3MqO-G-8jLFLm4_vvW8kbPwIlLK4-J037vKE0oKHCu6kzFxlV8TwmYG8Otv4MtM3DlnbJED76E0OG0akkjXcAVQmjEVDq1maLePgZwCiwjhiAYOISXJCe__l0-NXkgHSma49uMqF2DDMK46XveOLWveKyj008SPCtGJNMal2mcCWceta1ay6IQ8_bsVnRCziWsN-2x4AM4BjF0hbE0Qv0regEPpPCVERKuFfQg_wT2CpJQFjf0qqgfYwZk-F-hE3AvBpkTnU-zd-5rxh_8ZuPpbj1xnRPVIni9FUkjkcDTtU1ZqY6d1T-WdfISGwRIx-mI9Rw'], + RS384: [importKey(fixtures.PEM.RSA.private), 'eyJhbGciOiJSUzM4NCJ9.e30.dJ78iwcXqKu5x4UqdJjt8Gk88e8XaAm1j4VurNRlWjR7pDQDtJv9a9yMgBpndc1LHgiDUDEPyDEf-PkKFL9LCmsc3QuJCJleJiLpwJAFiSLh4O9M0oCXWA-rNt3zuSAT7TZJOfOWcYoN8JrhJtUMeJbmssRa6q85Umt9-x3GPFq5B5N4N14_hXeoOyq-BfkW7hRfn3s4WaDS1wnRioU_i8FZDhgaYjuToD3qpbh1NODPu4eAGSBiGnFS2B7vL3igSx6o6tufXAMKe3uEeV6A_vLw8CS5PcRBI0SJb1ZoE6PpuG3a_QAhWOrwlEqI7kdrGsBI_6dn6fua37mYz5NDfA'], + RS512: [importKey(fixtures.PEM.RSA.private), 'eyJhbGciOiJSUzUxMiJ9.e30.TjpvzV_wg9tZcCTHoC0WfGocXlx7uHru1JDciJuCH9K2UxR-zKw4oYOeVWAWXfCjdksfq6dFHMcP1XOljjrwZndcd0DxngTePeI7KhNBUuoBRMW6UZgAVUxu6fGGKKIw2_iH-fhnYNcS2uAdJawmtSwrIOIYziSHHY4vPZR2cFQpZDRY_kLLzWVvjVRbYdQgGrAlpV9iwKvdfL24TRPNhDx4_PK8fdr92KFUv7RQEHB5B13n26jEM6hzAaGH9EBdZOj7qdQhDrheedytrkVrQrqsEZnpTY_NaGP9pWYJO0JOSWQFXGEuFwJbuD4pjYcyeyNNNO2LcaVBdlgETaQHmQ'], + ES256: [importKey(fixtures.PEM['P-256'].private), 'eyJhbGciOiJFUzI1NiJ9.e30.oFrJJCBiFG9VKFoB0SUWOE9nc4LP5ftKPupczd23stw8rAG-acek8mSvPtQwteq4C7Ztl4kAvedIwya0nyNdsQ'], + ES384: [importKey(fixtures.PEM['P-384'].private), 'eyJhbGciOiJFUzM4NCJ9.e30.Rl7rliQOo8L8kA83-lkDPiK6kwi_NPanU9tdpYB94Bja3W_fnqQbpkiKgjij9BB1Aaj5mlKcovSzRJFTKLaI0CUAsxETrg6FscHtKC2nog0bXHFRKBtuRjO7vFCg381S'], + ES512: [importKey(fixtures.PEM['P-521'].private), 'eyJhbGciOiJFUzUxMiJ9.e30.AcE4SOw8dm6gXAthcm1eY4m1cVZk844Xnt26X8bsahyc7xcb-zIJpwzqsKRX-H_rYaPM1RUkTgFJbLEnCuYvv8qSAV1mJUvjJqVlWfkQE2NByiLf1eFDR2YA8T5i9dAM6NLobl5B0koUd8m9YHj4tfgRWNdorQs3WZ7tkxfq-jXu1OeP'] } const jwtverify = (t, jwt, key, ePayload, options) => {