mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
0646eda4fc
Store all primordials as properties of the primordials object. Static functions are prefixed by the constructor's name and prototype methods are prefixed by the constructor's name followed by "Prototype". For example: primordials.Object.keys becomes primordials.ObjectKeys. PR-URL: https://github.com/nodejs/node/pull/30610 Refs: https://github.com/nodejs/node/issues/29766 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
268 lines
8.1 KiB
JavaScript
268 lines
8.1 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ObjectDefineProperty,
|
|
} = 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));
|
|
}
|
|
|
|
ObjectDefineProperty(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 };
|