From 6b0c111fe1779a991557356c8539112a51989142 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 4 Mar 2022 02:01:07 +0800 Subject: [PATCH 1/6] src: include internal/options in the snapshot This patch enables internal/options to be included in the snapshot, so that when lazy loading the run time options, the modules only need to make sure that the options are queried lazily and do not have to lazy load the internal/options module together. We can still guarantee that no run time options are serialized into the state-independent bootstrap snapshot with the assertion inside GetCLIOptions(). --- lib/internal/bootstrap/node.js | 1 + src/node_external_reference.h | 1 + src/node_options.cc | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 239f5258620c04..5c7f67d7541032 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -338,6 +338,7 @@ require('fs'); require('v8'); require('vm'); require('url'); +require('internal/options'); function setupPrepareStackTrace() { const { diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 347945a7496d5f..c57a01ff39c20e 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -67,6 +67,7 @@ class ExternalReferenceRegistry { V(heap_utils) \ V(messaging) \ V(native_module) \ + V(options) \ V(os) \ V(performance) \ V(process_methods) \ diff --git a/src/node_options.cc b/src/node_options.cc index b8b6d85f39e4ed..35ee54d223176a 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -3,6 +3,7 @@ #include "env-inl.h" #include "node_binding.h" +#include "node_external_reference.h" #include "node_internals.h" #if HAVE_OPENSSL #include "openssl/opensslv.h" @@ -1133,6 +1134,10 @@ void Initialize(Local target, .Check(); } +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(GetCLIOptions); + registry->Register(GetEmbedderOptions); +} } // namespace options_parser void HandleEnvOptions(std::shared_ptr env_options) { @@ -1199,3 +1204,5 @@ std::vector ParseNodeOptionsEnvVar( } // namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(options, node::options_parser::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(options, + node::options_parser::RegisterExternalReferences) From b70ed6d603618789e12a7108e63280f02d052f1d Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 4 Mar 2022 02:18:56 +0800 Subject: [PATCH 2/6] 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 --- lib/crypto.js | 114 ++++++++++++++++-------- lib/internal/bootstrap/node.js | 1 + lib/internal/crypto/keygen.js | 4 +- src/node_crypto.cc | 2 - src/node_main_instance.cc | 2 + test/parallel/test-bootstrap-modules.js | 17 ++++ test/parallel/test-crypto-random.js | 1 - 7 files changed, 100 insertions(+), 41 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index a839f5fe27b029..daf31196c48d44 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..7d8d43867ee86a 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -339,6 +339,7 @@ require('v8'); require('vm'); require('url'); require('internal/options'); +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..093cbd37692639 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -1,5 +1,6 @@ #include "node_main_instance.h" #include +#include "crypto/crypto_util.h" #include "debug_utils-inl.h" #include "node_external_reference.h" #include "node_internals.h" @@ -205,6 +206,7 @@ NodeMainInstance::CreateMainEnvironment(int* exit_code, env->InitializeInspector({}); #endif env->DoneBootstrapping(); + crypto::InitCryptoOnce(isolate_); } 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..0e7549e86eb2e6 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -16,6 +16,7 @@ const expectedModules = new Set([ 'Internal Binding constants', 'Internal Binding contextify', 'Internal Binding credentials', + 'Internal Binding crypto', 'Internal Binding errors', 'Internal Binding fs_dir', 'Internal Binding fs_event_wrap', @@ -44,6 +45,22 @@ const expectedModules = new Set([ 'Internal Binding v8', 'Internal Binding worker', 'NativeModule buffer', + 'NativeModule crypto', + 'NativeModule internal/crypto/certificate', + 'NativeModule internal/crypto/cipher', + 'NativeModule internal/crypto/diffiehellman', + 'NativeModule internal/crypto/hash', + 'NativeModule internal/crypto/hashnames', + 'NativeModule internal/crypto/hkdf', + 'NativeModule internal/crypto/keygen', + 'NativeModule internal/crypto/keys', + 'NativeModule internal/crypto/pbkdf2', + 'NativeModule internal/crypto/random', + 'NativeModule internal/crypto/scrypt', + 'NativeModule internal/crypto/sig', + 'NativeModule internal/crypto/util', + 'NativeModule internal/crypto/x509', + 'NativeModule internal/streams/lazy_transform', 'NativeModule events', 'NativeModule fs', 'NativeModule internal/abort_controller', 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); }); From 9be337e4ed9ccd9e1101acb8f920f64e10820562 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 4 Mar 2022 02:33:51 +0800 Subject: [PATCH 3/6] fixup! src: include crypto in the bootstrap snapshot --- lib/crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/crypto.js b/lib/crypto.js index daf31196c48d44..77de7cda9d08a2 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -265,7 +265,7 @@ ObjectDefineProperty(constants, 'defaultCipherList', { writable: true, configurable: true, enumerable: true, - value + value }); return value; }, From fd0403b7b26dbc1989c5b959b329e3ae128d2572 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 4 Mar 2022 22:29:14 +0800 Subject: [PATCH 4/6] fixup! src: include crypto in the bootstrap snapshot --- src/node_main_instance.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 093cbd37692639..fdda0253932b11 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -1,6 +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" @@ -206,7 +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()); From 099876e857f0f43b54833abc50c6cc3cb3b383d9 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 11 Mar 2022 19:08:05 +0800 Subject: [PATCH 5/6] fixup! src: include crypto in the bootstrap snapshot --- lib/internal/bootstrap/node.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 7d8d43867ee86a..1fc59fdeffd510 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -339,7 +339,9 @@ require('v8'); require('vm'); require('url'); require('internal/options'); -require('crypto'); +if (config.hasOpenSSL) { + require('crypto'); +} function setupPrepareStackTrace() { const { From 22b7b8c2b36a467210a9933da61b19d933389df0 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 11 Mar 2022 19:50:22 +0800 Subject: [PATCH 6/6] fixup! src: include crypto in the bootstrap snapshot --- test/parallel/test-bootstrap-modules.js | 37 +++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 0e7549e86eb2e6..04883cdf4cfbe0 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -16,7 +16,6 @@ const expectedModules = new Set([ 'Internal Binding constants', 'Internal Binding contextify', 'Internal Binding credentials', - 'Internal Binding crypto', 'Internal Binding errors', 'Internal Binding fs_dir', 'Internal Binding fs_event_wrap', @@ -45,22 +44,6 @@ const expectedModules = new Set([ 'Internal Binding v8', 'Internal Binding worker', 'NativeModule buffer', - 'NativeModule crypto', - 'NativeModule internal/crypto/certificate', - 'NativeModule internal/crypto/cipher', - 'NativeModule internal/crypto/diffiehellman', - 'NativeModule internal/crypto/hash', - 'NativeModule internal/crypto/hashnames', - 'NativeModule internal/crypto/hkdf', - 'NativeModule internal/crypto/keygen', - 'NativeModule internal/crypto/keys', - 'NativeModule internal/crypto/pbkdf2', - 'NativeModule internal/crypto/random', - 'NativeModule internal/crypto/scrypt', - 'NativeModule internal/crypto/sig', - 'NativeModule internal/crypto/util', - 'NativeModule internal/crypto/x509', - 'NativeModule internal/streams/lazy_transform', 'NativeModule events', 'NativeModule fs', 'NativeModule internal/abort_controller', @@ -223,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');