diff --git a/BUILDING.md b/BUILDING.md index 5d2459eb76548f..0ae3c09d99fb0b 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -52,6 +52,7 @@ file a new issue. * [Build with a specific ICU](#build-with-a-specific-icu) * [Unix/macOS](#unixmacos-3) * [Windows](#windows-4) +* [Configuring OpenSSL config appname](#configure-openssl-appname) * [Building Node.js with FIPS-compliant OpenSSL](#building-nodejs-with-fips-compliant-openssl) * [Building Node.js with external core modules](#building-nodejs-with-external-core-modules) * [Unix/macOS](#unixmacos-4) @@ -766,6 +767,19 @@ as `deps/icu` (You'll have: `deps/icu/source/...`) > .\vcbuild full-icu ``` +### Configure OpenSSL appname + +Node.js can use an OpenSSL configuration file by specifying the environment +variable `OPENSSL_CONF`, or using the command line option `--openssl-conf`, and +if none of those are specified will default to reading the default OpenSSL +configuration file `openssl.cnf`. Node.js will only read a section that is by +default named `nodejs_conf`, but this name can be overridden using the following +configure option: + +```console +$ ./configure --openssl-conf-name= +``` + ## Building Node.js with FIPS-compliant OpenSSL The current version of Node.js does not support FIPS. diff --git a/configure.py b/configure.py index 2ea4eb69f5d0eb..892e1d420221cb 100755 --- a/configure.py +++ b/configure.py @@ -176,6 +176,12 @@ "e.g. /root/x/y.js will be referenced via require('root/x/y'). " "Can be used multiple times") +parser.add_option("--openssl-conf-name", + action="store", + dest="openssl_conf_name", + default='nodejs_conf', + help="The OpenSSL config appname (config section name) used by Node.js") + parser.add_option('--openssl-default-cipher-list', action='store', dest='openssl_default_cipher_list', @@ -1337,6 +1343,8 @@ def configure_openssl(o): if options.openssl_no_asm: variables['openssl_no_asm'] = 1 + o['defines'] += ['NODE_OPENSSL_CONF_NAME=' + options.openssl_conf_name] + if options.without_ssl: def without_ssl_error(option): error('--without-ssl is incompatible with %s' % option) diff --git a/src/node.cc b/src/node.cc index 683e36c1a5bc3f..d3b884aa66c5a3 100644 --- a/src/node.cc +++ b/src/node.cc @@ -44,6 +44,7 @@ #if HAVE_OPENSSL #include "allocated_buffer-inl.h" // Inlined functions needed by node_crypto.h #include "node_crypto.h" +#include #endif #if defined(NODE_HAVE_I18N_SUPPORT) @@ -154,6 +155,9 @@ uint64_t node_start_time; struct V8Platform v8_platform; } // namespace per_process +// The section in the OpenSSL configuration file to be loaded. +const char* conf_section_name = STRINGIFY(NODE_OPENSSL_CONF_NAME); + #ifdef __POSIX__ void SignalExit(int signo, siginfo_t* info, void* ucontext) { ResetStdio(); @@ -975,6 +979,7 @@ void Init(int* argc, argv[i] = strdup(argv_[i].c_str()); } + InitializationResult InitializeOncePerProcess(int argc, char** argv) { // Initialized the enabled list for Debug() calls with system // environment variables. @@ -1040,6 +1045,44 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) { if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs)) crypto::UseExtraCaCerts(extra_ca_certs); } + + // Passing NULL as the config file will allow the default openssl.cnf file + // to be loaded, but the default section in that file will not be used, + // instead only the section that matches the value of conf_section_name + // will be read from the default configuration file. + const char* conf_file = nullptr; + // Use OPENSSL_CONF environment variable is set. + std::string env_openssl_conf; + credentials::SafeGetenv("OPENSSL_CONF", &env_openssl_conf); + if (!env_openssl_conf.empty()) { + conf_file = env_openssl_conf.c_str(); + } + // Use --openssl-conf command line option if specified. + if (!per_process::cli_options->openssl_config.empty()) { + conf_file = per_process::cli_options->openssl_config.c_str(); + } + + OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new(); + OPENSSL_INIT_set_config_filename(settings, conf_file); + OPENSSL_INIT_set_config_appname(settings, conf_section_name); + OPENSSL_INIT_set_config_file_flags(settings, + CONF_MFLAGS_IGNORE_MISSING_FILE); + + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings); + OPENSSL_INIT_free(settings); + + if (ERR_peek_error() != 0) { + int ossl_error_code = ERR_GET_REASON(ERR_peek_error()); + if (ossl_error_code != EVP_R_FIPS_MODE_NOT_SUPPORTED) { + result.exit_code = ossl_error_code; + result.early_return = true; + fprintf(stderr, "%s", "OpenSSL configuration error:\n"); + ERR_print_errors_fp(stderr); + return result; + } + } + + // In the case of FIPS builds we should make sure // the random source is properly initialized first. if (FIPS_mode()) { diff --git a/test/fixtures/openssl_fips_disabled.cnf b/test/fixtures/openssl_fips_disabled.cnf index 8668370fac52f7..253c6906e3f3a3 100644 --- a/test/fixtures/openssl_fips_disabled.cnf +++ b/test/fixtures/openssl_fips_disabled.cnf @@ -1,6 +1,6 @@ # Skeleton openssl.cnf for testing with FIPS -openssl_conf = openssl_conf_section +nodejs_conf = openssl_conf_section authorityKeyIdentifier=keyid:always,issuer:always [openssl_conf_section] diff --git a/test/fixtures/openssl_fips_enabled.cnf b/test/fixtures/openssl_fips_enabled.cnf index 9c1a90f5087727..79733c657a96d0 100644 --- a/test/fixtures/openssl_fips_enabled.cnf +++ b/test/fixtures/openssl_fips_enabled.cnf @@ -1,6 +1,6 @@ # Skeleton openssl.cnf for testing with FIPS -openssl_conf = openssl_conf_section +nodejs_conf = openssl_conf_section authorityKeyIdentifier=keyid:always,issuer:always [openssl_conf_section] diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index a1ed6451842c54..bf8b3c157d1763 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -64,7 +64,7 @@ testHelper( [], FIPS_DISABLED, 'require("crypto").getFips()', - { ...process.env, 'OPENSSL_CONF': '' }); + { ...process.env, 'OPENSSL_CONF': ' ' }); // --enable-fips should turn FIPS mode on testHelper(