From 916b26ebe82d455f6901da4cdce7b73b3893c6cb Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 4 Mar 2022 02:18:56 +0800 Subject: [PATCH] src: include crypto in the bootstrap snapshot To lazy load the run time options, the following properties are updated from value properties to accessor properties whose getter would turn them back to a value properties upon the initial access. - crypto.constants.defaultCipherList - crypto.pseudoRandomBytes - crypto.prng - crypto.rng PR-URL: https://github.com/nodejs/node/pull/42203 Refs: https://github.com/nodejs/node/issues/37476 Reviewed-By: Anna Henningsen Reviewed-By: Bradley Farias Reviewed-By: Colin Ihrig Reviewed-By: Darshan Sen Reviewed-By: James M Snell Reviewed-By: Antoine du Hamel --- lib/crypto.js | 114 ++++++++++++++++-------- lib/internal/bootstrap/node.js | 3 + lib/internal/crypto/keygen.js | 4 +- src/node_crypto.cc | 2 - src/node_main_instance.cc | 7 ++ test/parallel/test-bootstrap-modules.js | 20 +++++ test/parallel/test-crypto-random.js | 1 - 7 files changed, 110 insertions(+), 41 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index a839f5fe27b029..77de7cda9d08a2 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -40,8 +40,6 @@ const { } = require('internal/errors').codes; const constants = internalBinding('constants').crypto; const { getOptionValue } = require('internal/options'); -const pendingDeprecation = getOptionValue('--pending-deprecation'); -const fipsForced = getOptionValue('--force-fips'); const { getFipsCrypto, setFipsCrypto, @@ -221,8 +219,8 @@ module.exports = { sign: signOneShot, setEngine, timingSafeEqual, - getFips: fipsForced ? getFipsForced : getFipsCrypto, - setFips: fipsForced ? setFipsForced : setFipsCrypto, + getFips, + setFips, verify: verifyOneShot, // Classes @@ -243,13 +241,17 @@ module.exports = { secureHeapUsed, }; -function setFipsForced(val) { - if (val) return; - throw new ERR_CRYPTO_FIPS_FORCED(); +function getFips() { + return getOptionValue('--force-fips') ? 1 : getFipsCrypto(); } -function getFipsForced() { - return 1; +function setFips(val) { + if (getOptionValue('--force-fips')) { + if (val) return; + throw new ERR_CRYPTO_FIPS_FORCED(); + } else { + setFipsCrypto(val); + } } function getRandomValues(array) { @@ -257,9 +259,69 @@ function getRandomValues(array) { } ObjectDefineProperty(constants, 'defaultCipherList', { - value: getOptionValue('--tls-cipher-list') + get() { + const value = getOptionValue('--tls-cipher-list'); + ObjectDefineProperty(this, 'defaultCipherList', { + writable: true, + configurable: true, + enumerable: true, + value + }); + return value; + }, + set(val) { + ObjectDefineProperty(this, 'defaultCipherList', { + writable: true, + configurable: true, + enumerable: true, + value: val + }); + }, + configurable: true, + enumerable: true, }); +function getRandomBytesAlias(key) { + return { + enumerable: false, + configurable: true, + get() { + let value; + if (getOptionValue('--pending-deprecation')) { + value = deprecate( + randomBytes, + `crypto.${key} is deprecated.`, + 'DEP0115'); + } else { + value = randomBytes; + } + ObjectDefineProperty( + this, + key, + { + enumerable: false, + configurable: true, + writable: true, + value: value + } + ); + return value; + }, + set(value) { + ObjectDefineProperty( + this, + key, + { + enumerable: true, + configurable: true, + writable: true, + value + } + ); + } + }; +} + ObjectDefineProperties(module.exports, { createCipher: { enumerable: false, @@ -273,8 +335,8 @@ ObjectDefineProperties(module.exports, { }, // crypto.fips is deprecated. DEP0093. Use crypto.getFips()/crypto.setFips() fips: { - get: fipsForced ? getFipsForced : getFipsCrypto, - set: fipsForced ? setFipsForced : setFipsCrypto + get: getFips, + set: setFips, }, DEFAULT_ENCODING: { enumerable: false, @@ -313,29 +375,7 @@ ObjectDefineProperties(module.exports, { // Aliases for randomBytes are deprecated. // The ecosystem needs those to exist for backwards compatibility. - prng: { - enumerable: false, - configurable: true, - writable: true, - value: pendingDeprecation ? - deprecate(randomBytes, 'crypto.prng is deprecated.', 'DEP0115') : - randomBytes - }, - pseudoRandomBytes: { - enumerable: false, - configurable: true, - writable: true, - value: pendingDeprecation ? - deprecate(randomBytes, - 'crypto.pseudoRandomBytes is deprecated.', 'DEP0115') : - randomBytes - }, - rng: { - enumerable: false, - configurable: true, - writable: true, - value: pendingDeprecation ? - deprecate(randomBytes, 'crypto.rng is deprecated.', 'DEP0115') : - randomBytes - } + prng: getRandomBytesAlias('prng'), + pseudoRandomBytes: getRandomBytesAlias('pseudoRandomBytes'), + rng: getRandomBytesAlias('rng') }); diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 5c7f67d7541032..1fc59fdeffd510 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -339,6 +339,9 @@ require('v8'); require('vm'); require('url'); require('internal/options'); +if (config.hasOpenSSL) { + require('crypto'); +} function setupPrepareStackTrace() { const { diff --git a/lib/internal/crypto/keygen.js b/lib/internal/crypto/keygen.js index bbbe72475bd870..a043a17f48deec 100644 --- a/lib/internal/crypto/keygen.js +++ b/lib/internal/crypto/keygen.js @@ -61,7 +61,6 @@ const { const { isArrayBufferView } = require('internal/util/types'); const { getOptionValue } = require('internal/options'); -const pendingDeprecation = getOptionValue('--pending-deprecation'); function wrapKey(key, ctor) { if (typeof key === 'string' || @@ -199,6 +198,9 @@ function createJob(mode, type, options) { const { hash, mgf1Hash, hashAlgorithm, mgf1HashAlgorithm, saltLength } = options; + + const pendingDeprecation = getOptionValue('--pending-deprecation'); + if (saltLength !== undefined && (!isInt32(saltLength) || saltLength < 0)) throw new ERR_INVALID_ARG_VALUE('options.saltLength', saltLength); if (hashAlgorithm !== undefined && typeof hashAlgorithm !== 'string') diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 267705b7cbd4c3..c3f400f1ae5cd4 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -75,8 +75,6 @@ void Initialize(Local target, void* priv) { Environment* env = Environment::GetCurrent(context); - // TODO(joyeecheung): this needs to be called again if the instance is - // deserialized from a snapshot with the crypto bindings. if (!InitCryptoOnce(env->isolate())) { return; } diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index ce319cca3edca3..fdda0253932b11 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -1,5 +1,8 @@ #include "node_main_instance.h" #include +#if HAVE_OPENSSL +#include "crypto/crypto_util.h" +#endif // HAVE_OPENSSL #include "debug_utils-inl.h" #include "node_external_reference.h" #include "node_internals.h" @@ -205,6 +208,10 @@ NodeMainInstance::CreateMainEnvironment(int* exit_code, env->InitializeInspector({}); #endif env->DoneBootstrapping(); + +#if HAVE_OPENSSL + crypto::InitCryptoOnce(isolate_); +#endif // HAVE_OPENSSL } else { context = NewContext(isolate_); CHECK(!context.IsEmpty()); diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index d29e2de66bdf4d..04883cdf4cfbe0 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -206,6 +206,26 @@ if (process.env.NODE_V8_COVERAGE) { expectedModules.add('Internal Binding profiler'); } +if (common.hasCrypto) { + expectedModules.add('Internal Binding crypto'); + expectedModules.add('NativeModule crypto'); + expectedModules.add('NativeModule internal/crypto/certificate'); + expectedModules.add('NativeModule internal/crypto/cipher'); + expectedModules.add('NativeModule internal/crypto/diffiehellman'); + expectedModules.add('NativeModule internal/crypto/hash'); + expectedModules.add('NativeModule internal/crypto/hashnames'); + expectedModules.add('NativeModule internal/crypto/hkdf'); + expectedModules.add('NativeModule internal/crypto/keygen'); + expectedModules.add('NativeModule internal/crypto/keys'); + expectedModules.add('NativeModule internal/crypto/pbkdf2'); + expectedModules.add('NativeModule internal/crypto/random'); + expectedModules.add('NativeModule internal/crypto/scrypt'); + expectedModules.add('NativeModule internal/crypto/sig'); + expectedModules.add('NativeModule internal/crypto/util'); + expectedModules.add('NativeModule internal/crypto/x509'); + expectedModules.add('NativeModule internal/streams/lazy_transform'); +} + const { internalBinding } = require('internal/test/binding'); if (internalBinding('config').hasDtrace) { expectedModules.add('Internal Binding dtrace'); diff --git a/test/parallel/test-crypto-random.js b/test/parallel/test-crypto-random.js index afe2edfc4fb4b3..7b8c2c2b7a59ea 100644 --- a/test/parallel/test-crypto-random.js +++ b/test/parallel/test-crypto-random.js @@ -338,7 +338,6 @@ assert.throws( const desc = Object.getOwnPropertyDescriptor(crypto, f); assert.ok(desc); assert.strictEqual(desc.configurable, true); - assert.strictEqual(desc.writable, true); assert.strictEqual(desc.enumerable, false); });