@guarani/jose
Version:
Implementation of the RFCs of the JOSE Working Group.
121 lines (120 loc) • 5.65 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EcKey = 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 unsupported_elliptic_curve_exception_1 = require("../../../exceptions/unsupported-elliptic-curve.exception");
const jsonwebkey_1 = require("../../jsonwebkey");
const elliptic_curves_registry_1 = require("./elliptic-curves-registry");
const generateKeyPairAsync = (0, util_1.promisify)(crypto_1.generateKeyPair);
/**
* Implementation of {@link https://www.rfc-editor.org/rfc/rfc7518.html#section-6.2 RFC 7518 Section 6.2}.
*/
class EcKey extends jsonwebkey_1.JsonWebKey {
/**
* Instantiates an Elliptic Curve JSON Web Key based on the provided Parameters.
*
* @param key Parameters of the Elliptic Curve JSON Web Key.
* @param options Optional JSON Web Key Parameters.
*/
constructor(key, options = {}) {
if (key instanceof EcKey) {
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 !== 'EC') {
throw new unsupported_algorithm_exception_1.UnsupportedAlgorithmException(`Invalid JSON Web Key Type. Expected "EC", got "${params.kty}".`);
}
if (typeof params.crv !== 'string') {
throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid parameter "crv".');
}
const curve = elliptic_curves_registry_1.ELLIPTIC_CURVES_REGISTRY.find((ellipticCurve) => ellipticCurve.id === params.crv);
if (curve === undefined) {
throw new unsupported_elliptic_curve_exception_1.UnsupportedEllipticCurveException(`Unsupported Elliptic Curve "${params.crv}".`);
}
if (typeof params.x !== 'string') {
throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "x".');
}
if (typeof params.y !== 'string') {
throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "y".');
}
if (params.d !== undefined) {
if (typeof params.d !== 'string') {
throw new invalid_json_web_key_exception_1.InvalidJsonWebKeyException('Invalid key parameter "d".');
}
}
super(params);
}
/**
* Generates a new Elliptic Curve JSON Web Key.
*
* @param options Options for the generation of the Elliptic Curve JSON Web Key.
* @param params Optional JSON Web Key Parameters.
* @returns Generated Elliptic Curve JSON Web Key.
*/
static async generate(options, params = {}) {
const { curve } = options;
if (typeof curve !== 'string') {
throw new TypeError('Invalid option "curve".');
}
const curveMeta = elliptic_curves_registry_1.ELLIPTIC_CURVES_REGISTRY.find((ellipticCurve) => ellipticCurve.id === curve);
if (curveMeta === undefined) {
throw new unsupported_elliptic_curve_exception_1.UnsupportedEllipticCurveException(`Unsupported Elliptic Curve "${curve}".`);
}
const { privateKey } = await generateKeyPairAsync('ec', { namedCurve: curveMeta.name });
return new EcKey(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 Elliptic Curve JSON Web Key.
*
* @param options Options for exporting the data of the Elliptic Curve JSON Web Key.
* @returns Encoded data of the Elliptic Curve JSON Web Key.
*/
export(options) {
const { encoding, format, type } = options;
if (encoding !== 'der' && encoding !== 'pem') {
throw new TypeError('Invalid option "encoding".');
}
if (format !== 'sec1' && 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 !== 'sec1' && format !== 'pkcs8') {
throw new TypeError(`Unsupported format "${format}" for type "${type}".`);
}
if (type === 'public' && 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.EcKey = EcKey;