UNPKG

@guarani/jose

Version:

Implementation of the RFCs of the JOSE Working Group.

133 lines (132 loc) 6.15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RsaKey = void 0; const crypto_1 = require("crypto"); const util_1 = require("util"); const invalid_json_web_key_exception_1 = require("../../../exceptions/invalid-json-web-key.exception"); const unsupported_algorithm_exception_1 = require("../../../exceptions/unsupported-algorithm.exception"); const jsonwebkey_1 = require("../../jsonwebkey"); const generateKeyPairAsync = (0, util_1.promisify)(crypto_1.generateKeyPair); /** * Implementation of {@link https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3 RFC 7518 Section 6.3}. */ class RsaKey extends jsonwebkey_1.JsonWebKey { /** * Instantiates an RSA JSON Web Key based on the provided Parameters. * * @param key Parameters of the RSA JSON Web Key. * @param options Optional JSON Web Key Parameters. */ constructor(key, options = {}) { if (key instanceof RsaKey) { return key; } const params = { ...key, ...options }; if (typeof params.kty !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid parameter "kty".'); } if (params.kty !== 'RSA') { throw new unsupported_algorithm_exception_1.UnsupportedAlgorithmException(`Invalid JSON Web Key Type. Expected "RSA", got "${params.kty}".`); } if (typeof params.n !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "n".'); } if (Buffer.from(params.n, 'base64url').length < 256) { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('The modulus MUST have AT LEAST 2048 bits.'); } if (typeof params.e !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "e".'); } // TODO: Validate the following values based on the previous ones. if (['d', 'p', 'q', 'dp', 'dq', 'qi'].some((param) => params[param] !== undefined)) { if (typeof params.d !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "d".'); } if (typeof params.p !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "p".'); } if (typeof params.q !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "q".'); } if (typeof params.dp !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "dp".'); } if (typeof params.dq !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "dq".'); } if (typeof params.qi !== 'string') { throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "qi".'); } } super(params); } /** * Generates a new RSA JSON Web Key. * * @param options Options for the generation of the RSA JSON Web Key. * @param params Optional JSON Web Key Parameters. * @returns Generated RSA JSON Web Key. */ static async generate(options, params = {}) { const { modulus, publicExponent } = options; if (!Number.isInteger(modulus)) { throw new TypeError('Invalid parameter "modulus".'); } if (modulus < 2048) { throw new Error('The modulus must be at least 2048 bits.'); } if (publicExponent !== undefined && !Number.isInteger(publicExponent)) { throw new TypeError('Invalid parameter "publicExponent".'); } const { privateKey } = await generateKeyPairAsync('rsa', { modulusLength: modulus, publicExponent }); return new RsaKey(privateKey.export({ format: 'jwk' }), params); } /** * Loads the provided JSON Web Key into a NodeJS Crypto Key. * * @param params Parameters of the JSON Web Key. * @returns NodeJS Crypto Key. */ loadCryptoKey(params) { const input = { format: 'jwk', key: params }; return params.d === undefined ? (0, crypto_1.createPublicKey)(input) : (0, crypto_1.createPrivateKey)(input); } /** * Exports the data of the RSA JSON Web Key. * * @param options Options for exporting the data of the RSA JSON Web Key. * @returns Encoded data of the RSA JSON Web Key. */ export(options) { const { encoding, format, type } = options; if (encoding !== 'der' && encoding !== 'pem') { throw new TypeError('Invalid option "encoding".'); } if (format !== 'pkcs1' && format !== 'pkcs8' && format !== 'spki') { throw new TypeError('Invalid option "format".'); } if (type !== 'private' && type !== 'public') { throw new TypeError('Invalid option "type".'); } if (type === 'private' && format !== 'pkcs1' && format !== 'pkcs8') { throw new TypeError(`Unsupported format "${format}" for type "${type}".`); } if (type === 'public' && format !== 'pkcs1' && format !== 'spki') { throw new TypeError(`Unsupported format "${format}" for type "${type}".`); } if (this.cryptoKey.type === 'public' && type === 'private') { throw new TypeError('Cannot export private data from a public key.'); } let { cryptoKey } = this; const input = { format: encoding, type: format }; if (this.cryptoKey.type === 'private' && type === 'public') { cryptoKey = (0, crypto_1.createPublicKey)(cryptoKey); } let exported = cryptoKey.export(input); if (encoding === 'pem') { exported = exported.slice(0, -1); } return exported; } } exports.RsaKey = RsaKey;