Skip to content

Commit 95a3625

Browse files
committed
[v16.x backport] src,deps,build,test: add OpenSSL config appname
This commit adds the setting of an appname (configuration section name), 'nodejs_conf', to be used when reading OpenSSL configuration files. The motivation for this is that currently the default OpenSSL configuration, 'openssl_conf', element will be used which may be undesirable as it might configure OpenSSL in unwanted ways. With this commit it is still possible to use a default openssl.cnf file but the only section that Node.js will read from is a section named 'nodejs_conf'. PR-URL: nodejs#43124 Refs: nodejs#40366 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]> Reviewed-By: Beth Griggs <[email protected]>
1 parent 0284901 commit 95a3625

File tree

6 files changed

+83
-34
lines changed

6 files changed

+83
-34
lines changed

BUILDING.md

+14
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ file a new issue.
5252
* [Build with a specific ICU](#build-with-a-specific-icu)
5353
* [Unix/macOS](#unixmacos-3)
5454
* [Windows](#windows-4)
55+
* [Configuring OpenSSL config appname](#configure-openssl-appname)
5556
* [Building Node.js with FIPS-compliant OpenSSL](#building-nodejs-with-fips-compliant-openssl)
5657
* [Building Node.js with external core modules](#building-nodejs-with-external-core-modules)
5758
* [Unix/macOS](#unixmacos-4)
@@ -779,6 +780,19 @@ as `deps/icu` (You'll have: `deps/icu/source/...`)
779780
> .\vcbuild full-icu
780781
```
781782

783+
### Configure OpenSSL appname
784+
785+
Node.js can use an OpenSSL configuration file by specifying the environment
786+
variable `OPENSSL_CONF`, or using the command line option `--openssl-conf`, and
787+
if none of those are specified will default to reading the default OpenSSL
788+
configuration file `openssl.cnf`. Node.js will only read a section that is by
789+
default named `nodejs_conf`, but this name can be overridden using the following
790+
configure option:
791+
792+
```console
793+
$ ./configure --openssl-conf-name=<some_conf_name>
794+
```
795+
782796
## Building Node.js with FIPS-compliant OpenSSL
783797

784798
The current version of Node.js supports FIPS when statically and

configure.py

+8
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@
181181
"e.g. /root/x/y.js will be referenced via require('root/x/y'). "
182182
"Can be used multiple times")
183183

184+
parser.add_argument("--openssl-conf-name",
185+
action="store",
186+
dest="openssl_conf_name",
187+
default='nodejs_conf',
188+
help="The OpenSSL config appname (config section name) used by Node.js")
189+
184190
parser.add_argument('--openssl-default-cipher-list',
185191
action='store',
186192
dest='openssl_default_cipher_list',
@@ -1461,6 +1467,8 @@ def configure_openssl(o):
14611467
if options.openssl_no_asm:
14621468
variables['openssl_no_asm'] = 1
14631469

1470+
o['defines'] += ['NODE_OPENSSL_CONF_NAME=' + options.openssl_conf_name]
1471+
14641472
if options.without_ssl:
14651473
def without_ssl_error(option):
14661474
error('--without-ssl is incompatible with %s' % option)

src/node.cc

+58-31
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#if HAVE_OPENSSL
4545
#include "allocated_buffer-inl.h" // Inlined functions needed by node_crypto.h
4646
#include "node_crypto.h"
47+
#include <openssl/conf.h>
4748
#endif
4849

4950
#if defined(NODE_HAVE_I18N_SUPPORT)
@@ -162,6 +163,11 @@ PVOID old_vectored_exception_handler;
162163
struct V8Platform v8_platform;
163164
} // namespace per_process
164165

166+
// The section in the OpenSSL configuration file to be loaded.
167+
const char* conf_section_name = STRINGIFY(NODE_OPENSSL_CONF_NAME);
168+
169+
const char* fips_error_msg = "OpenSSL error when trying to enable FIPS:\n";
170+
165171
#ifdef __POSIX__
166172
void SignalExit(int signo, siginfo_t* info, void* ucontext) {
167173
ResetStdio();
@@ -975,6 +981,16 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
975981
return InitializeOncePerProcess(argc, argv, kDefaultInitialization);
976982
}
977983

984+
InitializationResult handle_openssl_error(int exit_code,
985+
const char* msg,
986+
InitializationResult* result) {
987+
result->exit_code = exit_code;
988+
result->early_return = true;
989+
fprintf(stderr, "%s", msg);
990+
ERR_print_errors_fp(stderr);
991+
return *result;
992+
}
993+
978994
InitializationResult InitializeOncePerProcess(
979995
int argc,
980996
char** argv,
@@ -1054,7 +1070,6 @@ InitializationResult InitializeOncePerProcess(
10541070
}
10551071
// In the case of FIPS builds we should make sure
10561072
// the random source is properly initialized first.
1057-
#if OPENSSL_VERSION_MAJOR >= 3
10581073
// Call OPENSSL_init_crypto to initialize OPENSSL_INIT_LOAD_CONFIG to
10591074
// avoid the default behavior where errors raised during the parsing of the
10601075
// OpenSSL configuration file are not propagated and cannot be detected.
@@ -1069,46 +1084,58 @@ InitializationResult InitializeOncePerProcess(
10691084
// CheckEntropy. CheckEntropy will call RAND_status which will now always
10701085
// return 0, leading to an endless loop and the node process will appear to
10711086
// hang/freeze.
1087+
1088+
// Passing NULL as the config file will allow the default openssl.cnf file
1089+
// to be loaded, but the default section in that file will not be used,
1090+
// instead only the section that matches the value of conf_section_name
1091+
// will be read from the default configuration file.
1092+
const char* conf_file = nullptr;
1093+
// Use OPENSSL_CONF environment variable is set.
10721094
std::string env_openssl_conf;
10731095
credentials::SafeGetenv("OPENSSL_CONF", &env_openssl_conf);
1096+
if (!env_openssl_conf.empty()) {
1097+
conf_file = env_openssl_conf.c_str();
1098+
}
1099+
// Use --openssl-conf command line option if specified.
1100+
if (!per_process::cli_options->openssl_config.empty()) {
1101+
conf_file = per_process::cli_options->openssl_config.c_str();
1102+
}
10741103

1075-
bool has_cli_conf = !per_process::cli_options->openssl_config.empty();
1076-
if (has_cli_conf || !env_openssl_conf.empty()) {
1077-
OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
1078-
OPENSSL_INIT_set_config_file_flags(settings, CONF_MFLAGS_DEFAULT_SECTION);
1079-
if (has_cli_conf) {
1080-
const char* conf = per_process::cli_options->openssl_config.c_str();
1081-
OPENSSL_INIT_set_config_filename(settings, conf);
1082-
}
1083-
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
1084-
OPENSSL_INIT_free(settings);
1085-
1086-
if (ERR_peek_error() != 0) {
1087-
result.exit_code = ERR_GET_REASON(ERR_peek_error());
1088-
result.early_return = true;
1089-
fprintf(stderr, "OpenSSL configuration error:\n");
1090-
ERR_print_errors_fp(stderr);
1091-
return result;
1104+
OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
1105+
OPENSSL_INIT_set_config_filename(settings, conf_file);
1106+
OPENSSL_INIT_set_config_appname(settings, conf_section_name);
1107+
OPENSSL_INIT_set_config_file_flags(settings,
1108+
CONF_MFLAGS_IGNORE_MISSING_FILE);
1109+
1110+
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
1111+
OPENSSL_INIT_free(settings);
1112+
1113+
if (ERR_peek_error() != 0) {
1114+
int ossl_error_code = ERR_GET_REASON(ERR_peek_error());
1115+
if (ossl_error_code == EVP_R_FIPS_MODE_NOT_SUPPORTED) {
1116+
if (!crypto::ProcessFipsOptions()) {
1117+
return handle_openssl_error(ossl_error_code, fips_error_msg, &result);
1118+
}
1119+
} else {
1120+
return handle_openssl_error(ossl_error_code,
1121+
"OpenSSL configuration error:\n",
1122+
&result);
10921123
}
10931124
}
1094-
#else // OPENSSL_VERSION_MAJOR < 3
10951125
if (FIPS_mode()) {
10961126
OPENSSL_init();
10971127
}
1098-
#endif
1099-
if (!crypto::ProcessFipsOptions()) {
1100-
result.exit_code = ERR_GET_REASON(ERR_peek_error());
1101-
result.early_return = true;
1102-
fprintf(stderr, "OpenSSL error when trying to enable FIPS:\n");
1103-
ERR_print_errors_fp(stderr);
1104-
return result;
1105-
}
11061128

1107-
// V8 on Windows doesn't have a good source of entropy. Seed it from
1108-
// OpenSSL's pool.
1109-
V8::SetEntropySource(crypto::EntropySource);
1129+
// V8 on Windows doesn't have a good source of entropy. Seed it from
1130+
// OpenSSL's pool.
1131+
V8::SetEntropySource(crypto::EntropySource);
1132+
if (!crypto::ProcessFipsOptions()) {
1133+
return handle_openssl_error(ERR_GET_REASON(ERR_peek_error()),
1134+
fips_error_msg,
1135+
&result);
1136+
}
11101137
#endif // HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
1111-
}
1138+
}
11121139
per_process::v8_platform.Initialize(
11131140
static_cast<int>(per_process::cli_options->v8_thread_pool_size));
11141141
if (init_flags & kInitializeV8) {

test/fixtures/openssl_fips_disabled.cnf

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Skeleton openssl.cnf for testing with FIPS
22

3-
openssl_conf = openssl_conf_section
3+
nodejs_conf = openssl_conf_section
44
authorityKeyIdentifier=keyid:always,issuer:always
55

66
[openssl_conf_section]

test/fixtures/openssl_fips_enabled.cnf

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Skeleton openssl.cnf for testing with FIPS
22

3-
openssl_conf = openssl_conf_section
3+
nodejs_conf = openssl_conf_section
44
authorityKeyIdentifier=keyid:always,issuer:always
55

66
[openssl_conf_section]

test/parallel/test-crypto-fips.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ testHelper(
8383
[],
8484
FIPS_DISABLED,
8585
'require("crypto").getFips()',
86-
{ ...process.env, 'OPENSSL_CONF': '' });
86+
{ ...process.env, 'OPENSSL_CONF': ' ' });
8787

8888
// This should succeed for both FIPS and non-FIPS builds in combination with
8989
// OpenSSL 1.1.1 or OpenSSL 3.0

0 commit comments

Comments
 (0)