Skip to content

Commit dccd16f

Browse files
orgadsclaude
andcommitted
src: don't fail startup on unreadable OpenSSL config
OpenSSL is initialized with CONF_MFLAGS_IGNORE_MISSING_FILE so that a missing configuration file does not prevent Node.js from starting, but that flag does not cover a file that exists and cannot be opened. Running in a container where /etc/ssl is not accessible to the current user therefore aborts startup with: OpenSSL configuration error: ...:BIO_new_file:Permission denied:...fopen(/etc/ssl/openssl.cnf, rb) Ignore the error when the unreadable file is the default configuration file, that is, one that was not requested via OPENSSL_CONF or --openssl-config. Errors from an explicitly requested file, and from the files it includes, stay fatal. Fixes: #62230 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Orgad Shaneh <orgad.shaneh@audiocodes.com>
1 parent bb76938 commit dccd16f

1 file changed

Lines changed: 22 additions & 0 deletions

File tree

‎src/node.cc‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "node_version.h"
4949

5050
#if HAVE_OPENSSL
51+
#include <openssl/conf.h>
5152
#include "ncrypto.h"
5253
#include "node_crypto.h"
5354
#if OPENSSL_VERSION_MAJOR >= 3 && !defined(CONF_MFLAGS_IGNORE_MISSING_FILE)
@@ -135,6 +136,7 @@
135136
#include <cstdlib>
136137
#include <cstring>
137138

139+
#include <fstream>
138140
#include <string>
139141
#include <tuple>
140142
#include <vector>
@@ -1099,6 +1101,17 @@ bool CanEnableWebAssemblyTrapHandler() {
10991101
}
11001102
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
11011103

1104+
#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL) && OPENSSL_VERSION_MAJOR >= 3
1105+
// Whether the configuration file that OpenSSL uses when none was requested
1106+
// explicitly can be opened for reading.
1107+
static bool DefaultOpenSSLConfIsReadable() {
1108+
char* path = CONF_get1_default_config_file();
1109+
if (path == nullptr) return false;
1110+
auto free_path = OnScopeLeave([&]() { OPENSSL_free(path); });
1111+
return std::ifstream(path).is_open();
1112+
}
1113+
#endif
1114+
11021115
static std::shared_ptr<InitializationResultImpl>
11031116
InitializeOncePerProcessInternal(const std::vector<std::string>& args,
11041117
ProcessInitializationFlags::Flags flags =
@@ -1229,6 +1242,15 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
12291242
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
12301243
OPENSSL_INIT_free(settings);
12311244

1245+
// CONF_MFLAGS_IGNORE_MISSING_FILE only covers a missing file, not a default
1246+
// configuration file that exists but cannot be opened, e.g. when /etc/ssl
1247+
// is not readable by the current user. Loading it was not something the
1248+
// user asked for, so ignore that failure as well instead of refusing to
1249+
// start. Refs: https://github.com/nodejs/node/issues/62230
1250+
if (conf_file == nullptr && !DefaultOpenSSLConfIsReadable()) {
1251+
ERR_clear_error();
1252+
}
1253+
12321254
if (ERR_peek_error() != 0) {
12331255
// XXX: ERR_GET_REASON does not return something that is
12341256
// useful as an exit code at all.

0 commit comments

Comments
 (0)