diff --git a/CHANGELOG.md b/CHANGELOG.md index 46328875f5..6d8a1a6d77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -# [1.2.0](https://github.com/panva/jose/compare/v1.1.0...v1.2.0) (2019-05-25) +# YANKED [1.2.0](https://github.com/panva/jose/compare/v1.1.0...v1.2.0) (2019-05-25) ### Features @@ -12,7 +12,7 @@ All notable changes to this project will be documented in this file. See [standa -# [1.1.0](https://github.com/panva/jose/compare/v1.0.2...v1.1.0) (2019-05-23) +# YANKED [1.1.0](https://github.com/panva/jose/compare/v1.0.2...v1.1.0) (2019-05-23) ### Bug Fixes diff --git a/README.md b/README.md index 60283f4fca..e2e51e0739 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Pending Node.js Support 🤞: Won't implement: - ✕ JWS embedded key / referenced verification - - one can decode the header and pass the (`x5c`, `jwk`) to `JWK.importKey` and validate with that + - 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. - ✕ JWS detached content @@ -137,14 +137,14 @@ const { Prepare your Keys and KeyStores. See the [documentation][documentation-jwk] for more. ```js -const key = jose.JWK.importKey(fs.readFileSync('path/to/key/file')) +const key = jose.JWK.asKey(fs.readFileSync('path/to/key/file')) const jwk = { kty: 'EC', kid: 'dl4M_fcI7XoFCsQ22PYrQBkuxZ2pDcbDimcdFmmXM98', crv: 'P-256', x: 'v37avifcL-xgh8cy6IFzcINqqmFLc2JF20XUpn4Y2uQ', y: 'QTwy27XgP7ZMOdGOSopAHB-FU1JMQn3J9GEWGtUXreQ' } -const anotherKey = jose.JWK.importKey(jwk) +const anotherKey = jose.JWK.asKey(jwk) const keystore = new jose.JWK.KeyStore(key, key2) ``` diff --git a/docs/README.md b/docs/README.md index f6239ba769..e3420fc72f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -45,10 +45,10 @@ I can continue maintaining it and adding new features carefree. You may also don - [key.algorithms([operation])](#keyalgorithmsoperation) - [key.toJWK([private])](#keytojwkprivate) - [key.toPEM([private[, encoding]])](#keytopemprivate-encoding) -- JWK.importKey - - [JWK.importKey(key[, options]) asymmetric key import](#jwkimportkeykey-options-asymmetric-key-import) - - [JWK.importKey(secret[, options]) secret key import](#jwkimportkeysecret-options-secret-key-import) - - [JWK.importKey(jwk) JWK-formatted key import](#jwkimportkeyjwk-jwk-formatted-key-import) +- JWK.asKey + - [JWK.asKey(key[, options]) asymmetric key import](#jwkaskeykey-options-asymmetric-key-import) + - [JWK.asKey(secret[, options]) secret key import](#jwkaskeysecret-options-secret-key-import) + - [JWK.asKey(jwk[, options]) JWK-formatted key import](#jwkaskeyjwk-options-jwk-formatted-key-import) - [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) @@ -60,7 +60,7 @@ how to get a `` instances generated or instantiated from existing key m ```js const { JWK } = require('@panva/jose') -// { importKey: [Function: importKey], +// { asKey: [Function: asKey], // generate: [AsyncFunction: generate], // generateSync: [Function: generateSync] } ``` @@ -70,7 +70,7 @@ const { JWK } = require('@panva/jose') #### Class: `` and `` | `` | `` | `` ``, ``, `` and `` represent a key usable for JWS and JWE operations. -The `JWK.importKey()` method is used to retrieve a key representation of an existing key or secret. +The `JWK.asKey()` method is used to retrieve a key representation of an existing key or secret. `JWK.generate()` method is used to generate a new random key. ``, ``, `` and `` inherit methods from `` and in addition @@ -330,7 +330,7 @@ key.toPEM(true, { passphrase: 'super-strong', cipher: 'aes-256-cbc' }) --- -#### `JWK.importKey(key[, options])` asymmetric key import +#### `JWK.asKey(key[, options])` asymmetric key import Imports an asymmetric private or public key. Supports importing JWK formatted keys (private, public, secrets), `pem` and `der` formatted private and public keys, `pem` formatted X.509 certificates. @@ -362,9 +362,9 @@ formats ```js const { readFileSync } = require('fs') -const { JWK: { importKey } } = require('@panva/jose') +const { JWK: { asKey } } = require('@panva/jose') -const key = importKey(readFileSync('path/to/key/file')) +const key = asKey(readFileSync('path/to/key/file')) // ECKey { // kty: 'EC', // public: true, @@ -377,7 +377,7 @@ const key = importKey(readFileSync('path/to/key/file')) --- -#### `JWK.importKey(secret[, options])` secret key import +#### `JWK.asKey(secret[, options])` secret key import Imports a symmetric key. @@ -394,9 +394,9 @@ Imports a symmetric key. Example (Click to expand) ```js -const { JWK: { importKey } } = require('@panva/jose') +const { JWK: { asKey } } = require('@panva/jose') -const key = importKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ')) +const key = asKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ')) // OctKey { // kty: 'oct', // kid: [Getter], @@ -406,7 +406,7 @@ const key = importKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ')) --- -#### `JWK.importKey(jwk)` JWK-formatted key import +#### `JWK.asKey(jwk[, options])` JWK-formatted key import Imports a JWK formatted key. This supports JWK formatted RSA, EC, OKP and oct keys. Asymmetrical keys may be both private and public. @@ -420,18 +420,28 @@ keys may be both private and public. [RFC7638][spec-thumbprint] - `e`, `n` properties as `` for RSA public keys - `e`, `n`, `d`, `p`, `q`, `dp`, `dq`, `qi` properties as `` for RSA private keys + - `e`, `n`, `d` properties as `` for RSA private keys without optimization parametes (only + with `calculateMissingRSAPrimes` option, see below) - `crv`, `x`, `y` properties as `` for EC public keys - `crv`, `x`, `y`, `d` properties as `` for EC private keys - `crv`, `x`, properties as `` for OKP public keys - `crv`, `x`, `d` properties as `` for OKP private keys - `k` properties as `` for secret oct keys +- `options`: `` + - `calculateMissingRSAPrimes`: `` **Default** 'false'. This option is really only in + effect when importing private RSA JWK keys, by default, keys without the optimization private + key parameters (p, q, dp, dq, qi) won't imported because their calculation is heavy and prone + to blocking the process. Setting this option to true will enable these keys to be imported, + albeit at your own risk. Depending on the key size the calculation takes long and it should + only be used for JWK keys from trusted sources. - Returns: `` | `` | `` | `` +
Example (Click to expand) ```js -const { JWK: { importKey } } = require('@panva/jose') +const { JWK: { asKey } } = require('@panva/jose') const jwk = { kty: 'RSA', kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc', @@ -440,7 +450,7 @@ const jwk = { n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ' } -const key = importKey(jwk) +const key = asKey(jwk) // RSAKey { // kty: 'RSA', // public: true, @@ -563,7 +573,7 @@ Returns 'true' if the value is an instance of ``. - [keystore.generate(...)](#keystoregenerate) - [keystore.generateSync(...)](#keystoregeneratesync) - [keystore.toJWKS([private])](#keystoretojwksprivate) - - [JWKS.KeyStore.fromJWKS(jwks)](#jwkskeystorefromjwksjwks) + - [JWKS.asKeyStore(jwks[, options])](#jwksaskeystorejwks-options) ```js @@ -584,7 +594,7 @@ an existing store. Creates a new KeyStore, either empty or populated. -- `keys`: `` Array of key keys instantiated by `JWK.importKey()` +- `keys`: `` Array of key keys instantiated by `JWK.asKey()` - Returns: `` --- @@ -671,29 +681,41 @@ Exports the keystore to a JSON Web Key Set formatted object. --- -#### `JWKS.KeyStore.fromJWKS(jwks)` +#### `JWKS.asKeyStore(jwks[, options])` Creates a new KeyStore from a JSON Web Key Set. - `jwks`: `` JWKS formatted object (`{ keys: [{ kty: '...', ... }, ...] }`) +- `options`: `` + - `calculateMissingRSAPrimes`: `` **Default** 'false'. This option is really only in + effect when the JWKS contains private RSA JWK keys, by default, keys without the optimization + private key parameters (p, q, dp, dq, qi) won't imported because their calculation is heavy and + prone to blocking the process. Setting this option to true will enable these keys to be + imported, albeit at your own risk. Depending on the key size the calculation takes long and it + should only be used for JWKS from trusted sources. - Returns: ``
Example (Click to expand) ```js -const { JWKS: { KeyStore } } = require('@panva/jose') -const jwks = { keys: - [ { kty: 'RSA', - kid: 'gqUcZ2TjhmNrVOd1d27tedkabhOTs9WghMHIyjIBn7Y', - e: 'AQAB', - n: - 'vi1Aui6R0rUL_7pdcFKKMhBF25h4x8WiTZ4w66eNZhwIp48lz-vBuyUUrSR-RwcuvnxlXdjBdSaN-PZkNRDv2bXE3mVtjZgoYyzQlGLJ1wduQaBXIkrQWxc7yzL91MvtP1kWwFHHrQHZRlpiFQQm9gNCy2wXCTbWGT9kjrR1W1bkwhmOKK4rF-hMgaCNDrtEQ6xWknxV8aXW4itouJ0pJv8xplc6J14f_SNq6arVUcAZ26EzJYC2fcvqwsrnKzvW7QxQGQzh-u9Tn82Tl14Omh1KDV8C7Vb_m8XClv_9zOrKBGdaTl1zgINyMEaa_IMophnBgK_kAXvtVvEThQ93GQ', - use: 'enc' } ] } -const ks = KeyStore.fromJWKS(jwks) +const { JWKS: { KeyStore, asKeyStore } } = require('@panva/jose') +const jwks = { + keys: [ + { kty: 'RSA', + kid: 'gqUcZ2TjhmNrVOd1d27tedkabhOTs9WghMHIyjIBn7Y', + e: 'AQAB', + n: + 'vi1Aui6R0rUL_7pdcFKKMhBF25h4x8WiTZ4w66eNZhwIp48lz-vBuyUUrSR-RwcuvnxlXdjBdSaN-PZkNRDv2bXE3mVtjZgoYyzQlGLJ1wduQaBXIkrQWxc7yzL91MvtP1kWwFHHrQHZRlpiFQQm9gNCy2wXCTbWGT9kjrR1W1bkwhmOKK4rF-hMgaCNDrtEQ6xWknxV8aXW4itouJ0pJv8xplc6J14f_SNq6arVUcAZ26EzJYC2fcvqwsrnKzvW7QxQGQzh-u9Tn82Tl14Omh1KDV8C7Vb_m8XClv_9zOrKBGdaTl1zgINyMEaa_IMophnBgK_kAXvtVvEThQ93GQ', + use: 'enc' } + ] +} +const ks = asKeyStore(jwks) // KeyStore {} ks.size // 1 +ks instanceof KeyStore +// true ```
@@ -750,7 +772,7 @@ that will be used to sign with is either provided as part of the 'options.algori ```js const { JWT, JWK } = require('@panva/jose') -const key = JWK.importKey({ +const key = JWK.asKey({ kty: 'oct', k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' }) @@ -820,7 +842,7 @@ Verifies the claims and signature of a JSON Web Token. ```js const { JWK, JWT } = require('@panva/jose') -const key = JWK.importKey({ +const key = JWK.asKey({ kty: 'oct', k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' }) @@ -914,11 +936,11 @@ signatures of the same payload) using the General JWS JSON Serialization Syntax. ```js const { JWK, JWS } = require('@panva/jose') -const key = JWK.importKey({ +const key = JWK.asKey({ kty: 'oct', k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' }) -const key2 = JWK.importKey({ +const key2 = JWK.asKey({ kty: 'oct', k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8' }) @@ -997,7 +1019,7 @@ provided `` instance. ```js const { JWK, JWS } = require('@panva/jose') -const key = JWK.importKey({ +const key = JWK.asKey({ kty: 'oct', k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' }) @@ -1031,7 +1053,7 @@ inferred from the provided `` instance. ```js const { JWK, JWS } = require('@panva/jose') -const key = JWK.importKey({ +const key = JWK.asKey({ kty: 'oct', k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' }) @@ -1073,11 +1095,11 @@ Verifies the provided JWS in either serialization with a given `` or `< ```js const { JWK, JWS, JWKS } = require('@panva/jose') -const key = JWK.importKey({ +const key = JWK.asKey({ kty: 'oct', k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' }) -const key2 = JWK.importKey({ +const key2 = JWK.asKey({ kty: 'oct', k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8' }) diff --git a/lib/help/base64url.js b/lib/help/base64url.js index df95d14be7..83b07bb801 100644 --- a/lib/help/base64url.js +++ b/lib/help/base64url.js @@ -1,3 +1,5 @@ +const b64uRegExp = /^[a-zA-Z0-9_-]*$/ + const fromBase64 = (base64) => { return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') } @@ -14,11 +16,17 @@ const encodeBuffer = (buf) => { return fromBase64(buf.toString('base64')) } -const decode = (input, encoding = 'utf8') => { - return Buffer.from(toBase64(input), 'base64').toString(encoding) +const decode = (input) => { + if (!b64uRegExp.test(input)) { + throw new TypeError('input is not a valid base64url encoded string') + } + return Buffer.from(toBase64(input), 'base64').toString('utf8') } const decodeToBuffer = (input) => { + if (!b64uRegExp.test(input)) { + throw new TypeError('input is not a valid base64url encoded string') + } return Buffer.from(toBase64(input), 'base64') } diff --git a/lib/help/key_utils.js b/lib/help/key_utils.js index 3654a64f7b..3814849a10 100644 --- a/lib/help/key_utils.js +++ b/lib/help/key_utils.js @@ -188,7 +188,7 @@ const concatEcPublicKey = (x, y) => ({ const jwkToPem = { RSA: { - private (jwk) { + private (jwk, { calculateMissingRSAPrimes }) { const RSAPrivateKey = asn1.get('RSAPrivateKey') if ('oth' in jwk) { @@ -197,10 +197,12 @@ const jwkToPem = { if (jwk.p || jwk.q || jwk.dp || jwk.dq || jwk.qi) { if (!(jwk.p && jwk.q && jwk.dp && jwk.dq && jwk.qi)) { - throw new errors.JWKImportFailed('all other private key parameters must be present when any one of them is present') + throw new errors.JWKInvalid('all other private key parameters must be present when any one of them is present') } - } else { + } else if (calculateMissingRSAPrimes) { jwk = computePrimes(jwk) + } else if (!calculateMissingRSAPrimes) { + throw new errors.JOSENotSupported('importing private RSA keys without all other private key parameters is not enabled, see documentation and its advisory on how and when its ok to enable it') } return RSAPrivateKey.encode({ @@ -293,7 +295,7 @@ const okpCrvToOid = (crv) => { } } -module.exports.jwkToPem = (jwk) => { +module.exports.jwkToPem = (jwk, { calculateMissingRSAPrimes = false } = {}) => { switch (jwk.kty) { case 'EC': if (!EC_CURVES.has(jwk.crv)) { @@ -312,7 +314,7 @@ module.exports.jwkToPem = (jwk) => { } if (jwk.d) { - return jwkToPem[jwk.kty].private(jwk) + return jwkToPem[jwk.kty].private(jwk, { calculateMissingRSAPrimes }) } return jwkToPem[jwk.kty].public(jwk) diff --git a/lib/help/rsa_primes.js b/lib/help/rsa_primes.js index 539640371b..5d77ec069a 100644 --- a/lib/help/rsa_primes.js +++ b/lib/help/rsa_primes.js @@ -3,6 +3,7 @@ const { randomBytes } = require('crypto') const base64url = require('./base64url') +const errors = require('../errors') const ZERO = BigInt(0) const ONE = BigInt(1) @@ -106,14 +107,29 @@ const odd = (n) => { return r } +// not sold on these values +const maxCountWhileNoY = 30 +const maxCountWhileInot0 = 22 + const getPrimeFactors = (e, d, n) => { const r = odd(e * d - ONE) + let countWhileNoY = 0 let y do { + countWhileNoY++ + if (countWhileNoY === maxCountWhileNoY) { + throw new errors.JWKImportFailed('failed to calculate missing primes') + } + + let countWhileInot0 = 0 let i = modPow(randBetween(TWO, n), r, n) let o = ZERO while (i !== ONE) { + countWhileInot0++ + if (countWhileInot0 === maxCountWhileInot0) { + throw new errors.JWKImportFailed('failed to calculate missing primes') + } o = i i = (i * i) % n } @@ -133,6 +149,10 @@ module.exports = (jwk) => { const d = fromBuffer(base64url.decodeToBuffer(jwk.d)) const n = fromBuffer(base64url.decodeToBuffer(jwk.n)) + if (d >= n) { + throw new errors.JWKInvalid('invalid RSA private exponent') + } + const { p, q } = getPrimeFactors(e, d, n) const dp = d % (p - ONE) const dq = d % (q - ONE) diff --git a/lib/index.d.ts b/lib/index.d.ts index fc4e75fbe6..8d112ae843 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -59,6 +59,10 @@ interface JSONWebKeySet { keys: JSONWebKey[] } +interface ImportOptions { + calculateMissingRSAPrimes?: boolean +} + export namespace JWK { interface pemEncodingOptions { @@ -139,6 +143,17 @@ export namespace JWK { export function isKey(object: any): boolean + export function asKey(keyObject: KeyObject, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey + export function asKey(key: PrivateKeyInput | PublicKeyInput | string | Buffer, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey + export function asKey(jwk: JWKOctKey): OctKey + export function asKey(jwk: JWKRSAKey, options?: ImportOptions): RSAKey + export function asKey(jwk: JWKECKey): ECKey + export function asKey(jwk: JWKOKPKey): OKPKey + + + /* + * @deprecated in favor of asKey + */ export function importKey(keyObject: KeyObject, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey export function importKey(key: PrivateKeyInput | PublicKeyInput | string | Buffer, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey export function importKey(jwk: JWKOctKey): OctKey @@ -185,7 +200,14 @@ export namespace JWKS { generateSync(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): void generateSync(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): void generateSync(kty: 'oct', bitlength?: number, parameters?: BasicParameters): void + + /* + * @deprecated in favor of JWKS.asKeyStore + */ + static fromJWKS(jwks: JSONWebKeySet): KeyStore } + + export function asKeyStore(jwks: JSONWebKeySet, options?: ImportOptions): KeyStore } export namespace JWS { diff --git a/lib/jwe/decrypt.js b/lib/jwe/decrypt.js index f01f6ac400..8490d3236c 100644 --- a/lib/jwe/decrypt.js +++ b/lib/jwe/decrypt.js @@ -2,7 +2,7 @@ const { createSecretKey } = require('crypto') const { inflateRawSync } = require('zlib') const base64url = require('../help/base64url') -const KeyStore = require('../jwks/keystore') +const { KeyStore } = require('../jwks') const Key = require('../jwk/key/base') const errors = require('../errors') const { check, decrypt, keyManagementDecrypt } = require('../jwa') @@ -42,7 +42,7 @@ const combineHeader = (prot = {}, unprotected = {}, header = {}) => { */ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], complete = false, algorithms } = {}) => { if (!(key instanceof Key) && !(key instanceof KeyStore)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.importKey or a JWKS.KeyStore') + throw new TypeError('key must be an instance of a key instantiated by JWK.asKey or a JWKS.KeyStore') } if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { @@ -130,13 +130,13 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c try { if (alg === 'dir') { - cek = JWK.importKey(key, { alg: enc, use: 'enc' }) + cek = JWK.asKey(key, { alg: enc, use: 'enc' }) } else if (alg === 'ECDH-ES') { const unwrapped = keyManagementDecrypt(alg, key, undefined, opts) - cek = JWK.importKey(createSecretKey(unwrapped), { alg: enc, use: 'enc' }) + cek = JWK.asKey(createSecretKey(unwrapped), { alg: enc, use: 'enc' }) } else { const unwrapped = keyManagementDecrypt(alg, key, base64url.decodeToBuffer(encryptedKey), opts) - cek = JWK.importKey(createSecretKey(unwrapped), { alg: enc, use: 'enc' }) + cek = JWK.asKey(createSecretKey(unwrapped), { alg: enc, use: 'enc' }) } } catch (err) { // To mitigate the attacks described in RFC 3218, the diff --git a/lib/jwe/encrypt.js b/lib/jwe/encrypt.js index 0c9dec7278..b3fa074a0f 100644 --- a/lib/jwe/encrypt.js +++ b/lib/jwe/encrypt.js @@ -56,7 +56,7 @@ class Encrypt { */ recipient (key, header) { if (!(key instanceof Key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.importKey') + throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } if (header !== undefined && !isObject(header)) { diff --git a/lib/jwk/import.js b/lib/jwk/import.js index 61646f8975..6bf31393e8 100644 --- a/lib/jwk/import.js +++ b/lib/jwk/import.js @@ -1,4 +1,5 @@ const { createPublicKey, createPrivateKey, createSecretKey, KeyObject } = require('crypto') +const { deprecate } = require('util') const base64url = require('../help/base64url') const isObject = require('../help/is_object') @@ -24,7 +25,7 @@ const mergedParameters = (target = {}, source = {}) => { }, target) } -const importKey = (key, parameters) => { +const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { let privateKey, publicKey, secret if (!importable.has(typeof key)) { @@ -57,9 +58,10 @@ const importKey = (key, parameters) => { } parameters = mergedParameters(parameters, key) } else if (typeof key === 'object' && 'kty' in key) { // assume JWK formatted asymmetric key + ({ calculateMissingRSAPrimes = false } = parameters || { calculateMissingRSAPrimes }) let pem try { - pem = jwkToPem(key) + pem = jwkToPem(key, { calculateMissingRSAPrimes }) } catch (err) { if (err instanceof errors.JOSEError) { throw err @@ -70,7 +72,7 @@ const importKey = (key, parameters) => { } else if (pem) { publicKey = createPublicKey(pem) } - parameters = mergedParameters(parameters, key) + parameters = mergedParameters({}, key) } else { // | | passed to crypto.createPrivateKey or crypto.createPublicKey or passed to crypto.createSecretKey try { privateKey = createPrivateKey(key) @@ -110,4 +112,8 @@ const importKey = (key, parameters) => { throw new errors.JWKImportFailed('import failed') } -module.exports = importKey +module.exports = asKey +Object.defineProperty(asKey, 'deprecated', { + value: deprecate((key, parameters) => { return asKey(key, parameters, { calculateMissingRSAPrimes: true }) }, 'JWK.importKey() is deprecated, use JWK.asKey() instead'), + enumerable: false +}) diff --git a/lib/jwk/index.js b/lib/jwk/index.js index e6c57248ad..580908dc78 100644 --- a/lib/jwk/index.js +++ b/lib/jwk/index.js @@ -2,7 +2,13 @@ const Key = require('./key/base') const importKey = require('./import') const { generate, generateSync } = require('./generate') -module.exports.importKey = importKey +module.exports.asKey = importKey module.exports.generate = generate module.exports.generateSync = generateSync module.exports.isKey = input => input instanceof Key + +/* deprecated */ +Object.defineProperty(module.exports, 'importKey', { + value: importKey.deprecated, + enumerable: false +}) diff --git a/lib/jwks/index.js b/lib/jwks/index.js index 5b56614630..285a2798d4 100644 --- a/lib/jwks/index.js +++ b/lib/jwks/index.js @@ -1,3 +1,3 @@ const KeyStore = require('./keystore') -module.exports = { KeyStore } +module.exports = KeyStore diff --git a/lib/jwks/keystore.js b/lib/jwks/keystore.js index 8abb875135..1eb425f533 100644 --- a/lib/jwks/keystore.js +++ b/lib/jwks/keystore.js @@ -1,4 +1,4 @@ -const { inspect } = require('util') +const { deprecate, inspect } = require('util') const isObject = require('../help/is_object') const { generate, generateSync } = require('../jwk/generate') @@ -44,22 +44,12 @@ class KeyStore { keys = keys.flat() } if (keys.some(k => !(k instanceof Key))) { - throw new TypeError('all keys must be an instances of a key instantiated by JWK.importKey') + throw new TypeError('all keys must be an instances of a key instantiated by JWK.asKey') } this.#keys = new Set(keys) } - static fromJWKS (jwks) { - if (!isObject(jwks) || !Array.isArray(jwks.keys) || jwks.keys.some(k => !isObject(k) || !('kty' in k))) { - throw new TypeError('jwks must be a JSON Web Key Set formatted object') - } - - const keys = jwks.keys.map((jwk) => importKey(jwk)) - - return new KeyStore(...keys) - } - all ({ alg, kid, use, kty, key_ops: ops, x5t, 'x5t#S256': x5t256 } = {}) { if (ops !== undefined && (!Array.isArray(ops) || !ops.length || ops.some(x => typeof x !== 'string'))) { throw new TypeError('`key_ops` must be a non-empty array of strings') @@ -117,7 +107,7 @@ class KeyStore { add (key) { if (!(key instanceof Key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.importKey') + throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } this.#keys.add(key) @@ -125,7 +115,7 @@ class KeyStore { remove (key) { if (!(key instanceof Key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.importKey') + throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } this.#keys.delete(key) @@ -164,4 +154,19 @@ class KeyStore { } } -module.exports = KeyStore +function asKeyStore (jwks, { calculateMissingRSAPrimes = false } = {}) { + if (!isObject(jwks) || !Array.isArray(jwks.keys) || jwks.keys.some(k => !isObject(k) || !('kty' in k))) { + throw new TypeError('jwks must be a JSON Web Key Set formatted object') + } + + const keys = jwks.keys.map((jwk) => importKey(jwk, { calculateMissingRSAPrimes })) + + return new KeyStore(...keys) +} + +Object.defineProperty(KeyStore, 'fromJWKS', { + value: deprecate(jwks => asKeyStore(jwks, { calculateMissingRSAPrimes: true }), 'JWKS.KeyStore.fromJWKS() is deprecated, use JWKS.asKeyStore() instead'), + enumerable: false +}) + +module.exports = { KeyStore, asKeyStore } diff --git a/lib/jws/sign.js b/lib/jws/sign.js index 06fa97f6ff..e75f86c29c 100644 --- a/lib/jws/sign.js +++ b/lib/jws/sign.js @@ -35,7 +35,7 @@ class Sign { */ recipient (key, protectedHeader, unprotectedHeader) { if (!(key instanceof Key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.importKey') + throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } if (protectedHeader !== undefined && !isObject(protectedHeader)) { diff --git a/lib/jws/verify.js b/lib/jws/verify.js index 16910f8a52..904fc7d5d3 100644 --- a/lib/jws/verify.js +++ b/lib/jws/verify.js @@ -1,7 +1,7 @@ const base64url = require('../help/base64url') const isDisjoint = require('../help/is_disjoint') let validateCrit = require('../help/validate_crit') -const KeyStore = require('../jwks/keystore') +const { KeyStore } = require('../jwks') const Key = require('../jwk/key/base') const errors = require('../errors') const { check, verify } = require('../jwa') @@ -16,7 +16,7 @@ const SINGLE_RECIPIENT = new Set(['compact', 'flattened']) */ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], complete = false, algorithms } = {}) => { if (!(key instanceof Key) && !(key instanceof KeyStore)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.importKey or a JWKS.KeyStore') + throw new TypeError('key must be an instance of a key instantiated by JWK.asKey or a JWKS.KeyStore') } if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { diff --git a/lib/jwt/verify.js b/lib/jwt/verify.js index 8c61afe9c8..977c05315d 100644 --- a/lib/jwt/verify.js +++ b/lib/jwt/verify.js @@ -2,7 +2,7 @@ const isObject = require('../help/is_object') const epoch = require('../help/epoch') const secs = require('../help/secs') const JWS = require('../jws') -const KeyStore = require('../jwks/keystore') +const { KeyStore } = require('../jwks') const { JWTClaimInvalid } = require('../errors') const { isStringOptional, isNotString } = require('./shared_validations') diff --git a/test/cookbook/4_1.rsa_v15_signature.test.js b/test/cookbook/4_1.rsa_v15_signature.test.js index 1cdcd60b95..a16a041b12 100644 --- a/test/cookbook/4_1.rsa_v15_signature.test.js +++ b/test/cookbook/4_1.rsa_v15_signature.test.js @@ -2,15 +2,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.1') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact sign`, t => { diff --git a/test/cookbook/4_2.rsa-pss_signature.test.js b/test/cookbook/4_2.rsa-pss_signature.test.js index 83630c6aa0..7ee91fb54c 100644 --- a/test/cookbook/4_2.rsa-pss_signature.test.js +++ b/test/cookbook/4_2.rsa-pss_signature.test.js @@ -3,15 +3,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.2') const { sig: verifiers } = require('./verifiers') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact sign (random)`, t => { diff --git a/test/cookbook/4_3.ecdsa_signature.test.js b/test/cookbook/4_3.ecdsa_signature.test.js index e09155082a..85c14b0510 100644 --- a/test/cookbook/4_3.ecdsa_signature.test.js +++ b/test/cookbook/4_3.ecdsa_signature.test.js @@ -3,15 +3,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.3') const { sig: verifiers } = require('./verifiers') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact sign (random)`, t => { diff --git a/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js b/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js index 841c8e1259..6decf67eab 100644 --- a/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js +++ b/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js @@ -2,15 +2,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.4') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact sign`, t => { diff --git a/test/cookbook/4_6.protecting_specific_header_fields.test.js b/test/cookbook/4_6.protecting_specific_header_fields.test.js index 9061ae03a6..7ca420fb10 100644 --- a/test/cookbook/4_6.protecting_specific_header_fields.test.js +++ b/test/cookbook/4_6.protecting_specific_header_fields.test.js @@ -2,15 +2,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.6') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: protec, unprotected } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - flattened sign`, t => { diff --git a/test/cookbook/4_7.protecting_content_only.test.js b/test/cookbook/4_7.protecting_content_only.test.js index 8d216d669c..34e46a48c4 100644 --- a/test/cookbook/4_7.protecting_content_only.test.js +++ b/test/cookbook/4_7.protecting_content_only.test.js @@ -2,15 +2,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.7') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { unprotected } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - flattened sign`, t => { diff --git a/test/cookbook/4_8.multiple_signatures.test.js b/test/cookbook/4_8.multiple_signatures.test.js index 4a1c46129f..cb0cb5a82f 100644 --- a/test/cookbook/4_8.multiple_signatures.test.js +++ b/test/cookbook/4_8.multiple_signatures.test.js @@ -2,11 +2,11 @@ const test = require('ava') const recipe = require('./recipes').get('4.8') -const { JWS, JWK: { importKey }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwks }, signing: recipients } = recipe -const keys = jwks.map((jwk) => importKey(jwk)) +const keys = jwks.map((jwk) => asKey(jwk)) const keystoreEmpty = new KeyStore() const keystore = new KeyStore(...keys) diff --git a/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js b/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js index a5f3a02037..b8de073e32 100644 --- a/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js +++ b/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.1') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_10.including_additional_authentication_data.test.js b/test/cookbook/5_10.including_additional_authentication_data.test.js index 651b43d56d..f566492052 100644 --- a/test/cookbook/5_10.including_additional_authentication_data.test.js +++ b/test/cookbook/5_10.including_additional_authentication_data.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.10') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk, aad }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - flattened encrypt`, t => { diff --git a/test/cookbook/5_11.protecting_specific_header_fields.test.js b/test/cookbook/5_11.protecting_specific_header_fields.test.js index 3f2e44f615..32ddb81e0d 100644 --- a/test/cookbook/5_11.protecting_specific_header_fields.test.js +++ b/test/cookbook/5_11.protecting_specific_header_fields.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.11') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot, unprotected } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - flattened encrypt`, t => { diff --git a/test/cookbook/5_12.protecting_content_only.test.js b/test/cookbook/5_12.protecting_content_only.test.js index 874665d076..95410df8f1 100644 --- a/test/cookbook/5_12.protecting_content_only.test.js +++ b/test/cookbook/5_12.protecting_content_only.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.12') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { unprotected } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - flattened encrypt`, t => { diff --git a/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js b/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js index 6ed304f688..72bb225a8b 100644 --- a/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js +++ b/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js @@ -3,7 +3,7 @@ const test = require('ava') const recipe = require('./recipes').get('5.13') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwks }, @@ -11,7 +11,7 @@ const { encrypting_key: recipients } = recipe -const keys = jwks.map((jwk) => importKey(jwk)) +const keys = jwks.map((jwk) => asKey(jwk)) const keystoreEmpty = new KeyStore() const keystore = new KeyStore(...keys) diff --git a/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js b/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js index 3e28e0b753..7ba5171e6e 100644 --- a/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js +++ b/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.2') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js b/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js index fd8b217623..e5603fc20d 100644 --- a/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js +++ b/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.3') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, pwd }, encrypting_content: { protected: prot } } = recipe -const key = importKey(Buffer.from(pwd)) +const key = asKey(Buffer.from(pwd)) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync('EC'), generateSync('RSA')) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js b/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js index 68349e436f..3c929c8c2d 100644 --- a/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js +++ b/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.4') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js b/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js index f69d5f92ca..f3900f0421 100644 --- a/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js +++ b/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.5') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js b/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js index c59bd5e120..96d674f780 100644 --- a/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js +++ b/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.6') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js b/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js index e7edee31fd..03d031807e 100644 --- a/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js +++ b/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.7') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js b/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js index decbf5631b..dfb5ff50ad 100644 --- a/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js +++ b/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.8') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/5_9.compressed_content.test.js b/test/cookbook/5_9.compressed_content.test.js index 2629d52ac3..ed685ad97d 100644 --- a/test/cookbook/5_9.compressed_content.test.js +++ b/test/cookbook/5_9.compressed_content.test.js @@ -3,18 +3,18 @@ const test = require('ava') const recipe = require('./recipes').get('5.9') const { enc: verifiers } = require('./verifiers') -const { JWE, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { plaintext, key: jwk }, encrypting_content: { protected: prot } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - compact encrypt`, t => { diff --git a/test/cookbook/jwk.test.js b/test/cookbook/jwk.test.js index 23aac3c72b..0f4000e33a 100644 --- a/test/cookbook/jwk.test.js +++ b/test/cookbook/jwk.test.js @@ -2,11 +2,11 @@ const test = require('ava') const recipes = require('./recipes') -const { JWK: { importKey }, JWKS: { KeyStore } } = require('../..') +const { JWK: { asKey }, JWKS: { KeyStore } } = require('../..') test('public EC', t => { const jwk = recipes.get('3.1') - const key = importKey(jwk) + const key = asKey(jwk) t.true(key.toPEM().includes('BEGIN PUBLIC KEY')) t.deepEqual(key.toJWK(), jwk) t.deepEqual(key.toJWK(false), jwk) @@ -26,7 +26,7 @@ test('public EC', t => { test('private EC', t => { const jwk = recipes.get('3.2') - const key = importKey(jwk) + const key = asKey(jwk) t.true(key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN ENCRYPTED PRIVATE KEY')) t.true(key.toPEM(true, { type: 'sec1' }).includes('BEGIN EC PRIVATE KEY')) t.true(key.toPEM(true, { type: 'sec1', cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('ENCRYPTED')) @@ -46,7 +46,7 @@ test('private EC', t => { test('public RSA', t => { const jwk = recipes.get('3.3') - const key = importKey(jwk) + const key = asKey(jwk) t.true(key.toPEM().includes('BEGIN PUBLIC KEY')) t.deepEqual(key.toJWK(), jwk) t.deepEqual(key.toJWK(false), jwk) @@ -60,7 +60,7 @@ test('public RSA', t => { test('private RSA', t => { const jwk = recipes.get('3.4') - const key = importKey(jwk) + const key = asKey(jwk) t.true(key.toPEM(true, { type: 'pkcs1' }).includes('BEGIN RSA PRIVATE KEY')) t.true(key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret', type: 'pkcs1' }).includes('ENCRYPTED')) t.true(key.toPEM(true, { type: 'pkcs1', cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN RSA PRIVATE KEY')) @@ -75,7 +75,7 @@ test('private RSA', t => { test('oct (1/2)', t => { const jwk = recipes.get('3.5') - const key = importKey(jwk) + const key = asKey(jwk) t.throws(() => { key.toPEM() }, { instanceOf: TypeError, message: 'symmetric keys cannot be exported as PEM' }) @@ -87,7 +87,7 @@ test('oct (1/2)', t => { test('oct (2/2)', t => { const jwk = recipes.get('3.6') - const key = importKey(jwk) + const key = asKey(jwk) t.deepEqual(key.toJWK(true), jwk) const { k, ...pub } = jwk t.deepEqual(key.toJWK(), pub) @@ -101,11 +101,11 @@ test('keystore .toJWKS()', t => { const { d, dp, dq, p, q, qi, ...pubRsa } = rsa const oct = recipes.get('3.5') const { k, ...pubOct } = oct - const ks = new KeyStore(importKey(ec), importKey(rsa), importKey(oct)) + const ks = new KeyStore(asKey(ec), asKey(rsa), asKey(oct)) t.deepEqual(ks.toJWKS(true), { keys: [ec, rsa, oct] }) t.deepEqual(ks.toJWKS(), { keys: [pubEc, pubRsa, pubOct] }) t.deepEqual(ks.toJWKS(false), { keys: [pubEc, pubRsa, pubOct] }) - ks.add(importKey(pubRsa)) + ks.add(asKey(pubRsa)) t.throws(() => { ks.toJWKS(true) }, { instanceOf: TypeError, message: 'public key cannot be exported as private' }) diff --git a/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js b/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js index f6c9e72acb..455e132cdb 100644 --- a/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js +++ b/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js @@ -2,15 +2,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.1 rfc7797') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync('EC'), generateSync('RSA')) test(`${recipe.title} - compact sign`, t => { diff --git a/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.js b/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.js index 560a067418..ae6ca3f072 100644 --- a/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.js +++ b/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.js @@ -2,15 +2,15 @@ const test = require('ava') const recipe = require('./recipes').get('4.2 rfc7797') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) test(`${recipe.title} - flattened sign`, t => { diff --git a/test/cookbook/rfc8037.a4.ed25519.test.js b/test/cookbook/rfc8037.a4.ed25519.test.js index 821a0f3ccf..667d7ebaec 100644 --- a/test/cookbook/rfc8037.a4.ed25519.test.js +++ b/test/cookbook/rfc8037.a4.ed25519.test.js @@ -2,11 +2,11 @@ const test = require('ava') const recipe = require('./recipes').get('A.4 rfc8037') -const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') +const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = importKey(jwk) +const key = asKey(jwk) test('OKP JWK Thumbprint Canonicalization', t => { t.is(key.kid, 'kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k') @@ -14,7 +14,7 @@ test('OKP JWK Thumbprint Canonicalization', t => { const keystoreEmpty = new KeyStore() const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) const keystoreMatchNone = new KeyStore(generateSync('EC'), generateSync('RSA')) test(`${recipe.title} - compact sign`, t => { diff --git a/test/help/base64url.test.js b/test/help/base64url.test.js index e51c6fc6c2..9a561f0597 100644 --- a/test/help/base64url.test.js +++ b/test/help/base64url.test.js @@ -21,10 +21,6 @@ test('.decode with default encoding', t => { t.is(base64url.decode('Zm9v'), 'foo') }) -test('.decode with non-default encoding', t => { - t.is(base64url.decode('Zm9v', 'hex'), '666f6f') -}) - test('.decodeToBuffer', t => { t.deepEqual(base64url.decodeToBuffer('fmkIOj-kafqtjMl-iC32a-9YGz0cKj_JT9Jt31uXR1la7FSXkjoBzg_F-huYm0udbM5z5qGlmPBNZASsixJLcA'), testBuf) }) diff --git a/test/help/ecdsa_signatures.test.js b/test/help/ecdsa_signatures.test.js index bfb2f7bda0..65c2ecedc2 100644 --- a/test/help/ecdsa_signatures.test.js +++ b/test/help/ecdsa_signatures.test.js @@ -152,7 +152,7 @@ test('.joseToDer non buffer or base64 signature', t => { }) test('.joseToDer unknown algorithm', t => { - t.throws(() => joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo='), 'foobar'), { instanceOf: Error, message: /"foobar"/ }) + t.throws(() => joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'foobar'), { instanceOf: Error, message: /"foobar"/ }) }) test('.joseToDer incorrect signature length (ES256)', t => { @@ -176,7 +176,7 @@ test('ES256 should jose -> der -> jose', t => { }) test('ES256 should der -> jose -> der', t => { - const expected = decodeToBuffer('MEUCIQD0nDQE4uBS6JuklnyACfPQRB/LMEh5Stq6sAfp38k6ewIgHvhX59iuruBiFpVkg3dQKJ3+Wk29lJmXfxp6ciRdj+Q=') + const expected = decodeToBuffer('MEUCIQD0nDQE4uBS6JuklnyACfPQRB_LMEh5Stq6sAfp38k6ewIgHvhX59iuruBiFpVkg3dQKJ3-Wk29lJmXfxp6ciRdj-Q') const jose = derToJose(expected, 'ES256') const actual = joseToDer(jose, 'ES256') @@ -192,7 +192,7 @@ test('ES384 should jose -> der -> jose', t => { }) test('ES384 should der -> jose -> der', t => { - const expected = decodeToBuffer('MGUCMADcY5icKo+sLF0YCh5eVzju55Elt3Dfu4geMMDnUlLNaEO8NiCFzCHeqMx7mW5GMwIxAI6sp8ihHjRJ0sn/WV6mZCxN6/5lEg1QZJ5eiUHYv2kBgmiJ/Yv1pnqqFY3gVDBp/g==') + const expected = decodeToBuffer('MGUCMADcY5icKo-sLF0YCh5eVzju55Elt3Dfu4geMMDnUlLNaEO8NiCFzCHeqMx7mW5GMwIxAI6sp8ihHjRJ0sn_WV6mZCxN6_5lEg1QZJ5eiUHYv2kBgmiJ_Yv1pnqqFY3gVDBp_g') const jose = derToJose(expected, 'ES384') const actual = joseToDer(jose, 'ES384') @@ -208,7 +208,7 @@ test('ES512 should jose -> der -> jose', t => { }) test('ES512 should der -> jose -> der', t => { - const expected = decodeToBuffer('MIGHAkFgiYpVsYxx6XiQp2OXscRW/PrbEcoime/FftP+B7x4QVa+M3KZzXlfP66zKqjo7O3nwK2s8GbTftW8H4HwojzimwJCAYQNsozTpCo5nwIkBgelcfIQ0y/U/60TbNH1+rlKpFDCFs6Q1ro7R1tjtXoAUb9aPIOVyXGiSQX/+fcmmWs1rkJU') + const expected = decodeToBuffer('MIGHAkFgiYpVsYxx6XiQp2OXscRW_PrbEcoime_FftP-B7x4QVa-M3KZzXlfP66zKqjo7O3nwK2s8GbTftW8H4HwojzimwJCAYQNsozTpCo5nwIkBgelcfIQ0y_U_60TbNH1-rlKpFDCFs6Q1ro7R1tjtXoAUb9aPIOVyXGiSQX_-fcmmWs1rkJU') const jose = derToJose(expected, 'ES512') const actual = joseToDer(jose, 'ES512') diff --git a/test/jwe/sanity.test.js b/test/jwe/sanity.test.js index c66c4c3691..5584840c3d 100644 --- a/test/jwe/sanity.test.js +++ b/test/jwe/sanity.test.js @@ -38,7 +38,7 @@ test('verify key or store argument', t => { ;[{}, new Object(), false, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object t.throws(() => { JWE.decrypt('....', val) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.importKey or a JWKS.KeyStore' }) + }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey or a JWKS.KeyStore' }) }) }) @@ -288,7 +288,7 @@ test('JWE encrypt rejects non keys', t => { ;[[], false, true, undefined, null, Infinity, 0].forEach((val) => { t.throws(() => { JWE.encrypt('foo', val) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.importKey' }) + }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey' }) }) }) diff --git a/test/jwe/smoke.test.js b/test/jwe/smoke.test.js index 852b919e6b..b63c14a83e 100644 --- a/test/jwe/smoke.test.js +++ b/test/jwe/smoke.test.js @@ -3,7 +3,7 @@ const test = require('ava') const { randomBytes } = require('crypto') const { encrypt, decrypt } = require('../../lib/jwe') -const { JWK: { importKey, generateSync }, errors } = require('../..') +const { JWK: { asKey, generateSync }, errors } = require('../..') const PAYLOAD = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' const ENCS = [ @@ -98,8 +98,8 @@ const failure = (t, eKey, dKey, alg, enc) => { } Object.entries(fixtures.PEM).forEach(([type, { private: key, public: pub }]) => { - const eKey = importKey(pub) - const dKey = importKey(key) + const eKey = asKey(pub) + const dKey = asKey(key) ;[...eKey.algorithms('wrapKey'), ...eKey.algorithms('deriveKey')].forEach((alg) => { ENCS.forEach((enc) => { @@ -111,7 +111,7 @@ Object.entries(fixtures.PEM).forEach(([type, { private: key, public: pub }]) => }) ;[16, 24, 32, 48, 64].forEach((len) => { - const sym = importKey(randomBytes(len)) + const sym = asKey(randomBytes(len)) ;[...sym.algorithms('wrapKey'), ...sym.algorithms('deriveKey')].forEach((alg) => { sym.algorithms('encrypt').forEach((enc) => { test(`key ${sym.kty} > alg ${alg} > ${enc}`, success, sym, sym, alg, enc) @@ -122,8 +122,8 @@ Object.entries(fixtures.PEM).forEach(([type, { private: key, public: pub }]) => { const rsa = generateSync('RSA') - const dKey = importKey({ kty: 'RSA', e: rsa.e, n: rsa.n, d: rsa.d }) - const eKey = importKey({ kty: 'RSA', e: rsa.e, n: rsa.n }) + const dKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n, d: rsa.d }, { calculateMissingRSAPrimes: true }) + const eKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n }) eKey.algorithms('wrapKey').forEach((alg) => { ENCS.forEach((enc) => { if (alg === 'ECDH-ES' && ['A192CBC-HS384', 'A256CBC-HS512'].includes(enc)) return diff --git a/test/jwk/general.test.js b/test/jwk/general.test.js index e3f3c0eca2..a3c75041d0 100644 --- a/test/jwk/general.test.js +++ b/test/jwk/general.test.js @@ -1,6 +1,6 @@ const test = require('ava') -const { JWK: { generateSync, isKey, importKey } } = require('../..') +const { JWK: { generateSync, isKey, asKey } } = require('../..') test('.isKey() only key objects return true', t => { ;[[], false, true, null, Infinity, 0].forEach((val) => { @@ -40,7 +40,7 @@ test('"kid" must be a non-empty string', t => { test('"kid" from JWK is used when available and its different from thumbprint', t => { const { kid: generatedThumbprint, ...jwk } = generateSync('oct').toJWK(true) - const key = importKey({ ...jwk, kid: 'foo' }) + const key = asKey({ ...jwk, kid: 'foo' }) t.is(key.kid, 'foo') t.is(key.thumbprint, generatedThumbprint) }) diff --git a/test/jwk/import.test.js b/test/jwk/import.test.js index ff79d69f3a..d0a8adbf74 100644 --- a/test/jwk/import.test.js +++ b/test/jwk/import.test.js @@ -1,29 +1,29 @@ const test = require('ava') const crypto = require('crypto') -const { JWS, JWE, JWK: { importKey, generate }, errors } = require('../..') +const { JWS, JWE, JWK: { asKey, importKey, generate }, errors } = require('../..') const fixtures = require('../fixtures') test('imports PrivateKeyObject and then its Key instance', t => { - const k = importKey(crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }).privateKey) - t.deepEqual(importKey(k).toJWK(), k.toJWK()) + const k = asKey(crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }).privateKey) + t.deepEqual(asKey(k).toJWK(), k.toJWK()) }) test('imports PublicKeyObject and then its Key instance', t => { - const k = importKey(crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }).publicKey) - t.deepEqual(importKey(k).toJWK(), k.toJWK()) + const k = asKey(crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }).publicKey) + t.deepEqual(asKey(k).toJWK(), k.toJWK()) }) test('imports SecretKeyObject and then its Key instance', t => { - const k = importKey(crypto.createSecretKey(Buffer.from('foo'))) - t.deepEqual(importKey(k).toJWK(), k.toJWK()) + const k = asKey(crypto.createSecretKey(Buffer.from('foo'))) + t.deepEqual(asKey(k).toJWK(), k.toJWK()) }) test('only imports string, object or buffer', t => { ;[Buffer, () => {}, async () => {}, true, Infinity, 1].forEach((val) => { t.throws(() => { - importKey(val) + asKey(val) }, { instanceOf: TypeError, message: 'key argument must be a string, buffer or an object' }) }) }) @@ -31,7 +31,7 @@ test('only imports string, object or buffer', t => { test('parameters must be a plain object', t => { ;[Buffer, () => {}, async () => {}, true, Infinity, 1, [], Buffer.from('foo')].forEach((val) => { t.throws(() => { - importKey('foo', val) + asKey('foo', val) }, { instanceOf: TypeError, message: 'parameters argument must be a plain object when provided' }) }) }) @@ -39,35 +39,35 @@ test('parameters must be a plain object', t => { Object.entries(fixtures.PEM).forEach(([type, { private: priv, public: pub }]) => { test(`fails to import ${type} as invalid string`, t => { t.throws(() => { - importKey(priv.toString('ascii').replace(/\n/g, '')) + asKey(priv.toString('ascii').replace(/\n/g, '')) }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED' }) }) test(`fails to import ${type} as invalid buffer`, t => { t.throws(() => { - importKey(Buffer.from(priv.toString('ascii').replace(/\n/g, ''))) + asKey(Buffer.from(priv.toString('ascii').replace(/\n/g, ''))) }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED' }) }) test(`${type} private can be imported as a string`, t => { - const k = importKey(priv.toString('ascii')) + const k = asKey(priv.toString('ascii')) t.true(k.private) }) test(`${type} public can be imported as a string`, t => { - const k = importKey(pub.toString('ascii')) + const k = asKey(pub.toString('ascii')) t.true(k.public) }) test(`${type} private can be imported as a buffer`, t => { - const k = importKey(priv) + const k = asKey(priv) t.true(k.private) }) test(`${type} public can be imported as a buffer`, t => { - const k = importKey(pub) + const k = asKey(pub) t.true(k.public) }) }) test('failed to import throws an error', t => { t.throws(() => { - importKey({ + asKey({ key: fixtures.PEM.RSA.public, format: 'der' }) @@ -81,7 +81,7 @@ test('failed to import throws an error', t => { ].forEach((unsupported, i) => { test(`fails to import unsupported PEM ${i + 1}/4`, t => { t.throws(() => { - importKey(unsupported) + asKey(unsupported) }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'only RSA, EC and OKP asymmetric keys are supported' }) }) }) @@ -89,7 +89,8 @@ test('failed to import throws an error', t => { test('minimal RSA test', async t => { const key = await generate('RSA') const { d, e, n } = key.toJWK(true) - const minKey = importKey({ kty: 'RSA', d, e, n }) + const minKey = asKey({ kty: 'RSA', d, e, n }, { calculateMissingRSAPrimes: true }) + importKey({ kty: 'RSA', d, e, n }) // deprecated key.algorithms('sign').forEach((alg) => { JWS.verify(JWS.sign({}, key), minKey, { alg }) JWS.verify(JWS.sign({}, minKey), key, { alg }) @@ -98,7 +99,15 @@ test('minimal RSA test', async t => { JWE.decrypt(JWE.encrypt('foo', key), minKey, { alg }) JWE.decrypt(JWE.encrypt('foo', minKey), key, { alg }) }) - t.pass() + t.throws(() => { + asKey({ kty: 'RSA', d: d.substr(1), e, n }, { calculateMissingRSAPrimes: true }) + }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'failed to calculate missing primes' }) + t.throws(() => { + asKey({ kty: 'RSA', d, e, n }) + }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'importing private RSA keys without all other private key parameters is not enabled, see documentation and its advisory on how and when its ok to enable it' }) + t.throws(() => { + asKey({ kty: 'RSA', d: `${d}F`, e, n }, { calculateMissingRSAPrimes: true }) + }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'invalid RSA private exponent' }) }) test('fails to import RSA without all optimization parameters', async t => { @@ -106,15 +115,15 @@ test('fails to import RSA without all optimization parameters', async t => { for (const param of ['p', 'q', 'dp', 'dq', 'qi']) { const { [param]: omit, ...jwk } = full t.throws(() => { - importKey(jwk) - }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'all other private key parameters must be present when any one of them is present' }) + asKey(jwk) + }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'all other private key parameters must be present when any one of them is present' }) } }) test('fails to import JWK RSA with oth', async t => { const jwk = (await generate('RSA')).toJWK(true) t.throws(() => { - importKey({ + asKey({ ...jwk, oth: [] }) diff --git a/test/jwk/key_ops.test.js b/test/jwk/key_ops.test.js index 94be1ca5aa..5c15935e83 100644 --- a/test/jwk/key_ops.test.js +++ b/test/jwk/key_ops.test.js @@ -2,77 +2,77 @@ const test = require('ava') const crypto = require('crypto') const errors = require('../../lib/errors') -const importKey = require('../../lib/jwk/import') +const asKey = require('../../lib/jwk/import') const { generateSync } = require('../../lib/jwk/generate') -const jwk = importKey('foo').toJWK(true) +const jwk = asKey('foo').toJWK(true) test('key_ops ignores unrecognized values', t => { - importKey({ ...jwk, key_ops: ['sign', 'verify', 'foo'] }) + asKey({ ...jwk, key_ops: ['sign', 'verify', 'foo'] }) t.pass() }) test('key_ops ignores duplicate values', t => { - const k = importKey({ ...jwk, key_ops: ['sign', 'verify', 'sign'] }) + const k = asKey({ ...jwk, key_ops: ['sign', 'verify', 'sign'] }) t.deepEqual(k.key_ops, ['sign', 'verify']) }) test('key_ops can be combined with use if consistent', t => { - importKey({ ...jwk, key_ops: ['sign', 'verify'], use: 'sig' }) + asKey({ ...jwk, key_ops: ['sign', 'verify'], use: 'sig' }) t.pass() }) test('key_ops are part of toJWK', t => { - const k = importKey({ ...jwk, key_ops: ['sign', 'verify'], use: 'sig' }) + const k = asKey({ ...jwk, key_ops: ['sign', 'verify'], use: 'sig' }) t.deepEqual(k.toJWK().key_ops, ['sign', 'verify']) t.deepEqual(k.toJWK(true).key_ops, ['sign', 'verify']) }) test('key_ops must be an array', t => { t.throws(() => { - importKey({ ...jwk, key_ops: 'wrapKey' }) + asKey({ ...jwk, key_ops: 'wrapKey' }) }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings when provided' }) }) test('key_ops must not be empty', t => { t.throws(() => { - importKey({ ...jwk, key_ops: [] }) + asKey({ ...jwk, key_ops: [] }) }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings when provided' }) }) test('key_ops must only contain strings', t => { t.throws(() => { - importKey({ ...jwk, key_ops: ['wrapKey', true] }) + asKey({ ...jwk, key_ops: ['wrapKey', true] }) }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings when provided' }) }) -test('JWK importKey with invalid use / key_ops throws', t => { +test('JWK asKey with invalid use / key_ops throws', t => { t.throws(() => { - importKey({ ...jwk, use: 'sig', key_ops: ['wrapKey'] }) + asKey({ ...jwk, use: 'sig', key_ops: ['wrapKey'] }) }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) }) -test('keyObject importKey with invalid use / key_ops throws 1/2', t => { +test('keyObject asKey with invalid use / key_ops throws 1/2', t => { const { publicKey } = crypto.generateKeyPairSync('ed25519') t.throws(() => { - importKey(publicKey, { use: 'sig', key_ops: ['wrapKey'] }) + asKey(publicKey, { use: 'sig', key_ops: ['wrapKey'] }) }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) }) -test('keyObject importKey with invalid use / key_ops throws 2/2', t => { +test('keyObject asKey with invalid use / key_ops throws 2/2', t => { const { publicKey } = crypto.generateKeyPairSync('ed25519') t.throws(() => { - importKey(publicKey, { use: 'enc', key_ops: ['sign'] }) + asKey(publicKey, { use: 'enc', key_ops: ['sign'] }) }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) }) -test('PEM importKey with invalid use / key_ops throws', t => { +test('PEM asKey with invalid use / key_ops throws', t => { const { publicKey } = crypto.generateKeyPairSync('ed25519') t.throws(() => { - importKey(publicKey.export({ type: 'spki', format: 'pem' }), { use: 'sig', key_ops: ['wrapKey'] }) + asKey(publicKey.export({ type: 'spki', format: 'pem' }), { use: 'sig', key_ops: ['wrapKey'] }) }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) }) diff --git a/test/jwk/oct.test.js b/test/jwk/oct.test.js index 01244fbe0e..430849349f 100644 --- a/test/jwk/oct.test.js +++ b/test/jwk/oct.test.js @@ -4,7 +4,7 @@ const { hasProperty, hasNoProperties } = require('../macros') const errors = require('../../lib/errors') const OctKey = require('../../lib/jwk/key/oct') -const { JWK: { importKey } } = require('../..') +const { JWK: { asKey } } = require('../..') const { generateSync } = require('../../lib/jwk/generate') const keyObject = createSecretKey(Buffer.from('secret')) @@ -113,7 +113,7 @@ test('oct keys may not be generated as public', t => { }) test('they may be imported from', t => { - const key = importKey({ + const key = asKey({ kty: 'oct', kid: '4p9o4_DcKoT6Qg2BI_mSgMP_MsXwFqogKuI26CunKAM' }) @@ -126,7 +126,7 @@ test('they may be imported from', t => { }) test('they may be imported from (no kid)', t => { - const key = importKey({ + const key = asKey({ kty: 'oct' }) @@ -141,7 +141,7 @@ test('they may be imported from (no kid)', t => { test('they may be imported so long as there was no k', t => { t.throws(() => { - importKey({ + asKey({ kty: 'oct', kid: '4p9o4_DcKoT6Qg2BI_mSgMP_MsXwFqogKuI26CunKAM', k: undefined diff --git a/test/jwk/x5c_thumbprints.test.js b/test/jwk/x5c_thumbprints.test.js index 0abc6fe4a8..dd58bb0371 100644 --- a/test/jwk/x5c_thumbprints.test.js +++ b/test/jwk/x5c_thumbprints.test.js @@ -2,7 +2,7 @@ const test = require('ava') const errors = require('../../lib/errors') -const { JWK: { importKey } } = require('../..') +const { JWK: { asKey } } = require('../..') const jwk = { kty: 'RSA', @@ -17,7 +17,7 @@ const jwk = { test('x5c can be imported and have their X.509 cert thumbprints calculated', t => { let key - t.notThrows(() => { key = importKey(jwk) }) + t.notThrows(() => { key = asKey(jwk) }) t.deepEqual(key.x5c, jwk.x5c) const asJWK = key.toJWK() t.deepEqual(asJWK.x5c, jwk.x5c) @@ -30,13 +30,13 @@ test('x5c can be imported and have their X.509 cert thumbprints calculated', t = test('checks that x5c is an array of valid PKIX certificates', t => { ;[[], {}, false, 1].forEach((value) => { t.throws(() => { - importKey({ + asKey({ ...jwk, x5c: value }) }, { instanceOf: TypeError, message: '`x5c` must be an array of one or more PKIX certificates when provided' }) t.throws(() => { - importKey({ + asKey({ ...jwk, x5c: [value] }) @@ -46,7 +46,7 @@ test('checks that x5c is an array of valid PKIX certificates', t => { test('checks that first x5c member must represent the key', t => { t.throws(() => { - importKey({ + asKey({ ...jwk, x5c: [ 'MIIC/zCCAeegAwIBAgIJYdZUZz2rikftMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMTEnBhbnZhLmV1LmF1dGgwLmNvbTAeFw0xNzEwMTgxNTExMjBaFw0zMTA2MjcxNTExMjBaMB0xGzAZBgNVBAMTEnBhbnZhLmV1LmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKROvB+A+ZlFV1AXl75tVegjaCuBE7CiXHNstVZ/F6fKl6OvIRhAW3YKnJEglzVvHw0q46Nw48yBdbbKjdwGo1jbrI15D2+MYPy8xlMfDzEqNWBjOsgnA1nhFFDXD7wITwFRMtlRKVvKMa19QCmMFrpQ2qcloMne/DzSvxlEnVA6DG1SYqHR/gdK5hoRATJkwHXQ5F/nUxD3BOAyyjsU5RsGJAeVVS4Yf532xmziIbda3iV4LMUiHUb1v8Oy2sDncYF+imq/sbHGgE7dyv5R5AsYHGANgvIPMHJ1QTFSQVU0lxPy+EWnLk9abVOZYzD6O5YRdJ29UWVtQ1q5UcyrF18CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSUcoPFHi/vm7dw1rt/IRmxvLMyowDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBcBXXBcbqliVOHkTgxocSYNUajcgIKjgeqG9RKFkbHfPuK/Hn80vQhd6mBKJTIyM7fY7DPh1/PjRsAyDQEwouHWItcM6iJBSdAkPq2DPfCkpUOi7MHrhXSouU1X4IOBvAl94k9Z8oj5k12KWVH8jZn5G03lwkWUgSfkLJ0Dh86+4sF2W4Dz2qZUXZuQbUL5eJcWRpfEZowff+T8xsiRjcIEpgfLz4nWonijtvEWESEa3bYpI9pI5OXLImgVJLGxVaUktsGIexQ6eM1AoxBYE7E+nbN/rwo30XWGbTkYecisySSYuzVn2c0xnC/8ZvW+gJ4SkzRDjlOAbm3R0r5j7b1' @@ -54,7 +54,7 @@ test('checks that first x5c member must represent the key', t => { }) }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'The key in the first `x5c` certificate MUST match the public key represented by the JWK' }) t.throws(() => { - importKey({ + asKey({ ...jwk, x5c: [ jwk.x5c[0], diff --git a/test/jwks/keystore.test.js b/test/jwks/keystore.test.js index 88cd22c480..c16e8e1eed 100644 --- a/test/jwks/keystore.test.js +++ b/test/jwks/keystore.test.js @@ -1,7 +1,8 @@ const test = require('ava') -const KeyStore = require('../../lib/jwks/keystore') -const { importKey, generateSync } = require('../../lib/jwk') +const { KeyStore, asKeyStore } = require('../../lib/jwks') +const { asKey, generateSync } = require('../../lib/jwk') +const errors = require('../../lib/errors') const withX5C = { kty: 'RSA', @@ -30,10 +31,10 @@ test('constructor', t => { }) }) -test('constructor only accepts Key instances created through JWK.importKey', 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.importKey' }) + }, { instanceOf: TypeError, message: 'all keys must be an instances of a key instantiated by JWK.asKey' }) }) test('.generate()', async t => { @@ -56,7 +57,7 @@ test('.add()', t => { t.is(ks.size, 1) t.throws(() => { ks.add({}) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.importKey' }) + }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey' }) }) test('.remove()', t => { @@ -67,7 +68,7 @@ test('.remove()', t => { ks.remove(k) t.throws(() => { ks.remove({}) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.importKey' }) + }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey' }) }) test('.all() key_ops must be an array', t => { @@ -158,25 +159,25 @@ test('.all() and .get() kid filter', t => { }) test('.all() and .get() x5t filter and sort', t => { - const k = importKey(withX5C) + const k = asKey(withX5C) const ks = new KeyStore(k) t.deepEqual(ks.all({ x5t: 'baz' }), []) t.deepEqual(ks.all({ x5t: '4pNenEBLv0JpLIdugWxQkOsZcK0' }), [k]) t.is(ks.get({ x5t: 'baz' }), undefined) t.is(ks.get({ x5t: '4pNenEBLv0JpLIdugWxQkOsZcK0' }), k) - const k2 = importKey({ ...withX5C, alg: 'RS256' }) + const k2 = asKey({ ...withX5C, alg: 'RS256' }) ks.add(k2) t.is(ks.get({ x5t: '4pNenEBLv0JpLIdugWxQkOsZcK0', alg: 'RS256' }), k2) }) test('.all() and .get() x5t#S256 filter and sort', t => { - const k = importKey(withX5C) + const k = asKey(withX5C) const ks = new KeyStore(k) t.deepEqual(ks.all({ 'x5t#S256': 'baz' }), []) t.deepEqual(ks.all({ 'x5t#S256': 'pJm2BBpkB8y7tCqrWM0X37WOmQTO8zQw-VpxVgBb21I' }), [k]) t.is(ks.get({ 'x5t#S256': 'baz' }), undefined) t.is(ks.get({ 'x5t#S256': 'pJm2BBpkB8y7tCqrWM0X37WOmQTO8zQw-VpxVgBb21I' }), k) - const k2 = importKey({ ...withX5C, alg: 'RS256' }) + const k2 = asKey({ ...withX5C, alg: 'RS256' }) ks.add(k2) t.is(ks.get({ 'x5t#S256': 'pJm2BBpkB8y7tCqrWM0X37WOmQTO8zQw-VpxVgBb21I', alg: 'RS256' }), k2) }) @@ -210,25 +211,26 @@ test('.all() and .get() alg sort', t => { t.is(ks.get({ alg: 'RS256' }), k2) }) -test('.fromJWKS()', t => { +test('.asKeyStore()', t => { const ks = new KeyStore() ks.generateSync('EC') ks.generateSync('RSA') - const ks2 = KeyStore.fromJWKS(ks.toJWKS()) + const ks2 = asKeyStore(ks.toJWKS()) + t.true(ks2 instanceof KeyStore) t.is(ks2.size, 2) }) -test('.fromJWKS() input validation', t => { +test('.asKeyStore() input validation', t => { [Buffer, 1, false, '', 'foo', {}, { foo: 'bar' }].forEach((val) => { t.throws(() => { - KeyStore.fromJWKS(val) + asKeyStore(val) }, { instanceOf: TypeError, message: 'jwks must be a JSON Web Key Set formatted object' }) t.throws(() => { - KeyStore.fromJWKS({ keys: val }) + asKeyStore({ keys: val }) }, { instanceOf: TypeError, message: 'jwks must be a JSON Web Key Set formatted object' }) t.throws(() => { - KeyStore.fromJWKS({ keys: [val] }) + asKeyStore({ keys: [val] }) }, { instanceOf: TypeError, message: 'jwks must be a JSON Web Key Set formatted object' }) }) }) @@ -242,3 +244,19 @@ test('keystore instance is an iterator', t => { } t.pass() }) + +test('minimal RSA test', async t => { + const key = generateSync('RSA') + const { d, e, n } = key.toJWK(true) + asKeyStore({ keys: [{ kty: 'RSA', d, e, n }] }, { calculateMissingRSAPrimes: true }) + KeyStore.fromJWKS({ keys: [{ kty: 'RSA', d, e, n }] }) // deprecated + t.throws(() => { + asKeyStore({ keys: [{ kty: 'RSA', d: d.substr(1), e, n }] }, { calculateMissingRSAPrimes: true }) + }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'failed to calculate missing primes' }) + t.throws(() => { + asKeyStore({ keys: [{ kty: 'RSA', d, e, n }] }) + }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'importing private RSA keys without all other private key parameters is not enabled, see documentation and its advisory on how and when its ok to enable it' }) + t.throws(() => { + asKeyStore({ keys: [{ kty: 'RSA', d: `${d}F`, e, n }] }, { calculateMissingRSAPrimes: true }) + }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'invalid RSA private exponent' }) +}) diff --git a/test/jws/b64.test.js b/test/jws/b64.test.js index 10a1c4375c..d66d024f7b 100644 --- a/test/jws/b64.test.js +++ b/test/jws/b64.test.js @@ -2,7 +2,7 @@ const test = require('ava') const { JWK, JWS, errors } = require('../..') -const k = JWK.importKey({ +const k = JWK.asKey({ kty: 'oct', k: 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow' }) diff --git a/test/jws/sanity.test.js b/test/jws/sanity.test.js index fd74c66631..cdb1e8dc23 100644 --- a/test/jws/sanity.test.js +++ b/test/jws/sanity.test.js @@ -38,7 +38,7 @@ test('verify key or store argument', t => { ;[{}, new Object(), false, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object t.throws(() => { JWS.verify('..', val) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.importKey or a JWKS.KeyStore' }) + }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey or a JWKS.KeyStore' }) }) }) @@ -73,7 +73,7 @@ test('JWS sign rejects non keys', t => { ;[[], false, true, undefined, null, Infinity, 0].forEach((val) => { t.throws(() => { JWS.sign('foo', val) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.importKey' }) + }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey' }) }) }) diff --git a/test/jws/smoke.test.js b/test/jws/smoke.test.js index c3d2d28280..17e014f5c0 100644 --- a/test/jws/smoke.test.js +++ b/test/jws/smoke.test.js @@ -1,7 +1,7 @@ const test = require('ava') const { sign, verify } = require('../../lib/jws') -const { JWK: { importKey, generateSync }, errors } = require('../..') +const { JWK: { asKey, generateSync }, errors } = require('../..') const PAYLOAD = {} @@ -61,8 +61,8 @@ const failure = (t, sKey, vKey, alg) => { } Object.entries(fixtures.PEM).forEach(([type, { private: key, public: pub }]) => { - const sKey = importKey(key) - const vKey = importKey(pub) + const sKey = asKey(key) + const vKey = asKey(pub) sKey.algorithms('sign').forEach((alg) => { test(`key ${type} > alg ${alg}`, success, sKey, vKey, alg) @@ -78,8 +78,8 @@ sym.algorithms('sign').forEach((alg) => { { const rsa = generateSync('RSA') - const sKey = importKey({ kty: 'RSA', e: rsa.e, n: rsa.n, d: rsa.d }) - const vKey = importKey({ kty: 'RSA', e: rsa.e, n: rsa.n }) + const sKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n, d: rsa.d }, { calculateMissingRSAPrimes: true }) + const vKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n }) sKey.algorithms('sign').forEach((alg) => { test(`key RSA (min) > alg ${alg}`, success, sKey, vKey, alg) test(`key RSA (min) > alg ${alg} (negative cases)`, failure, sKey, vKey, alg)