mirror of
https://github.com/nodejs/node.git
synced 2024-11-30 15:30:56 +01:00
c6f968de71
This commit moves the _impl function call out of the handleError function, which now only takes in an object as its parameter. PR-URL: https://github.com/nodejs/node/pull/28318 Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: James M Snell <jasnell@gmail.com>
266 lines
8.1 KiB
JavaScript
266 lines
8.1 KiB
JavaScript
'use strict';
|
|
|
|
const { Object } = primordials;
|
|
|
|
const { AsyncWrap, Providers } = internalBinding('async_wrap');
|
|
const {
|
|
generateKeyPairRSA,
|
|
generateKeyPairRSAPSS,
|
|
generateKeyPairDSA,
|
|
generateKeyPairEC,
|
|
generateKeyPairNid,
|
|
EVP_PKEY_ED25519,
|
|
EVP_PKEY_ED448,
|
|
EVP_PKEY_X25519,
|
|
EVP_PKEY_X448,
|
|
OPENSSL_EC_NAMED_CURVE,
|
|
OPENSSL_EC_EXPLICIT_CURVE
|
|
} = internalBinding('crypto');
|
|
const {
|
|
parsePublicKeyEncoding,
|
|
parsePrivateKeyEncoding,
|
|
|
|
PublicKeyObject,
|
|
PrivateKeyObject
|
|
} = require('internal/crypto/keys');
|
|
const { customPromisifyArgs } = require('internal/util');
|
|
const { isUint32, validateString } = require('internal/validators');
|
|
const {
|
|
ERR_INVALID_ARG_TYPE,
|
|
ERR_INVALID_ARG_VALUE,
|
|
ERR_INVALID_CALLBACK,
|
|
ERR_INVALID_OPT_VALUE
|
|
} = require('internal/errors').codes;
|
|
|
|
const { isArrayBufferView } = require('internal/util/types');
|
|
|
|
function wrapKey(key, ctor) {
|
|
if (typeof key === 'string' || isArrayBufferView(key))
|
|
return key;
|
|
return new ctor(key);
|
|
}
|
|
|
|
function generateKeyPair(type, options, callback) {
|
|
if (typeof options === 'function') {
|
|
callback = options;
|
|
options = undefined;
|
|
}
|
|
|
|
const impl = check(type, options);
|
|
|
|
if (typeof callback !== 'function')
|
|
throw new ERR_INVALID_CALLBACK(callback);
|
|
|
|
const wrap = new AsyncWrap(Providers.KEYPAIRGENREQUEST);
|
|
wrap.ondone = (ex, pubkey, privkey) => {
|
|
if (ex) return callback.call(wrap, ex);
|
|
// If no encoding was chosen, return key objects instead.
|
|
pubkey = wrapKey(pubkey, PublicKeyObject);
|
|
privkey = wrapKey(privkey, PrivateKeyObject);
|
|
callback.call(wrap, null, pubkey, privkey);
|
|
};
|
|
|
|
handleError(impl(wrap));
|
|
}
|
|
|
|
Object.defineProperty(generateKeyPair, customPromisifyArgs, {
|
|
value: ['publicKey', 'privateKey'],
|
|
enumerable: false
|
|
});
|
|
|
|
function generateKeyPairSync(type, options) {
|
|
const impl = check(type, options);
|
|
return handleError(impl());
|
|
}
|
|
|
|
function handleError(ret) {
|
|
if (ret === undefined)
|
|
return; // async
|
|
|
|
const [err, publicKey, privateKey] = ret;
|
|
if (err !== undefined)
|
|
throw err;
|
|
|
|
// If no encoding was chosen, return key objects instead.
|
|
return {
|
|
publicKey: wrapKey(publicKey, PublicKeyObject),
|
|
privateKey: wrapKey(privateKey, PrivateKeyObject)
|
|
};
|
|
}
|
|
|
|
function parseKeyEncoding(keyType, options) {
|
|
const { publicKeyEncoding, privateKeyEncoding } = options;
|
|
|
|
let publicFormat, publicType;
|
|
if (publicKeyEncoding == null) {
|
|
publicFormat = publicType = undefined;
|
|
} else if (typeof publicKeyEncoding === 'object') {
|
|
({
|
|
format: publicFormat,
|
|
type: publicType
|
|
} = parsePublicKeyEncoding(publicKeyEncoding, keyType,
|
|
'publicKeyEncoding'));
|
|
} else {
|
|
throw new ERR_INVALID_OPT_VALUE('publicKeyEncoding', publicKeyEncoding);
|
|
}
|
|
|
|
let privateFormat, privateType, cipher, passphrase;
|
|
if (privateKeyEncoding == null) {
|
|
privateFormat = privateType = undefined;
|
|
} else if (typeof privateKeyEncoding === 'object') {
|
|
({
|
|
format: privateFormat,
|
|
type: privateType,
|
|
cipher,
|
|
passphrase
|
|
} = parsePrivateKeyEncoding(privateKeyEncoding, keyType,
|
|
'privateKeyEncoding'));
|
|
} else {
|
|
throw new ERR_INVALID_OPT_VALUE('privateKeyEncoding', privateKeyEncoding);
|
|
}
|
|
|
|
return {
|
|
cipher, passphrase, publicType, publicFormat, privateType, privateFormat
|
|
};
|
|
}
|
|
|
|
function check(type, options, callback) {
|
|
validateString(type, 'type');
|
|
|
|
// These will be set after parsing the type and type-specific options to make
|
|
// the order a bit more intuitive.
|
|
let cipher, passphrase, publicType, publicFormat, privateType, privateFormat;
|
|
|
|
if (options !== undefined && typeof options !== 'object')
|
|
throw new ERR_INVALID_ARG_TYPE('options', 'object', options);
|
|
|
|
function needOptions() {
|
|
if (options == null)
|
|
throw new ERR_INVALID_ARG_TYPE('options', 'object', options);
|
|
return options;
|
|
}
|
|
|
|
let impl;
|
|
switch (type) {
|
|
case 'rsa':
|
|
case 'rsa-pss':
|
|
{
|
|
const { modulusLength } = needOptions();
|
|
if (!isUint32(modulusLength))
|
|
throw new ERR_INVALID_OPT_VALUE('modulusLength', modulusLength);
|
|
|
|
let { publicExponent } = options;
|
|
if (publicExponent == null) {
|
|
publicExponent = 0x10001;
|
|
} else if (!isUint32(publicExponent)) {
|
|
throw new ERR_INVALID_OPT_VALUE('publicExponent', publicExponent);
|
|
}
|
|
|
|
if (type === 'rsa') {
|
|
impl = (wrap) => generateKeyPairRSA(modulusLength, publicExponent,
|
|
publicFormat, publicType,
|
|
privateFormat, privateType,
|
|
cipher, passphrase, wrap);
|
|
break;
|
|
}
|
|
|
|
const { hash, mgf1Hash, saltLength } = options;
|
|
if (hash !== undefined && typeof hash !== 'string')
|
|
throw new ERR_INVALID_OPT_VALUE('hash', hash);
|
|
if (mgf1Hash !== undefined && typeof mgf1Hash !== 'string')
|
|
throw new ERR_INVALID_OPT_VALUE('mgf1Hash', mgf1Hash);
|
|
if (saltLength !== undefined && !isUint32(saltLength))
|
|
throw new ERR_INVALID_OPT_VALUE('saltLength', saltLength);
|
|
|
|
impl = (wrap) => generateKeyPairRSAPSS(modulusLength, publicExponent,
|
|
hash, mgf1Hash, saltLength,
|
|
publicFormat, publicType,
|
|
privateFormat, privateType,
|
|
cipher, passphrase, wrap);
|
|
}
|
|
break;
|
|
case 'dsa':
|
|
{
|
|
const { modulusLength } = needOptions();
|
|
if (!isUint32(modulusLength))
|
|
throw new ERR_INVALID_OPT_VALUE('modulusLength', modulusLength);
|
|
|
|
let { divisorLength } = options;
|
|
if (divisorLength == null) {
|
|
divisorLength = -1;
|
|
} else if (!isUint32(divisorLength)) {
|
|
throw new ERR_INVALID_OPT_VALUE('divisorLength', divisorLength);
|
|
}
|
|
|
|
impl = (wrap) => generateKeyPairDSA(modulusLength, divisorLength,
|
|
publicFormat, publicType,
|
|
privateFormat, privateType,
|
|
cipher, passphrase, wrap);
|
|
}
|
|
break;
|
|
case 'ec':
|
|
{
|
|
const { namedCurve } = needOptions();
|
|
if (typeof namedCurve !== 'string')
|
|
throw new ERR_INVALID_OPT_VALUE('namedCurve', namedCurve);
|
|
let { paramEncoding } = options;
|
|
if (paramEncoding == null || paramEncoding === 'named')
|
|
paramEncoding = OPENSSL_EC_NAMED_CURVE;
|
|
else if (paramEncoding === 'explicit')
|
|
paramEncoding = OPENSSL_EC_EXPLICIT_CURVE;
|
|
else
|
|
throw new ERR_INVALID_OPT_VALUE('paramEncoding', paramEncoding);
|
|
|
|
impl = (wrap) => generateKeyPairEC(namedCurve, paramEncoding,
|
|
publicFormat, publicType,
|
|
privateFormat, privateType,
|
|
cipher, passphrase, wrap);
|
|
}
|
|
break;
|
|
case 'ed25519':
|
|
case 'ed448':
|
|
case 'x25519':
|
|
case 'x448':
|
|
{
|
|
let id;
|
|
switch (type) {
|
|
case 'ed25519':
|
|
id = EVP_PKEY_ED25519;
|
|
break;
|
|
case 'ed448':
|
|
id = EVP_PKEY_ED448;
|
|
break;
|
|
case 'x25519':
|
|
id = EVP_PKEY_X25519;
|
|
break;
|
|
case 'x448':
|
|
id = EVP_PKEY_X448;
|
|
break;
|
|
}
|
|
impl = (wrap) => generateKeyPairNid(id,
|
|
publicFormat, publicType,
|
|
privateFormat, privateType,
|
|
cipher, passphrase, wrap);
|
|
}
|
|
break;
|
|
default:
|
|
throw new ERR_INVALID_ARG_VALUE('type', type,
|
|
'must be a supported key type');
|
|
}
|
|
|
|
if (options) {
|
|
({
|
|
cipher,
|
|
passphrase,
|
|
publicType,
|
|
publicFormat,
|
|
privateType,
|
|
privateFormat
|
|
} = parseKeyEncoding(type, options));
|
|
}
|
|
|
|
return impl;
|
|
}
|
|
|
|
module.exports = { generateKeyPair, generateKeyPairSync };
|