Skip to content

Commit 148a60b

Browse files
authored
fix: add OpenSSL init code/use modern Node.js init API (#30)
Copy OpenSSL initialization code from Node.js, and add code to use the initialization API being worked out in the referenced Node.js pull request to avoid having to adjust this kind of code in the future. Fixes: https://jira.mongodb.org/browse/MONGOSH-1258
1 parent 6326e32 commit 148a60b

File tree

3 files changed

+102
-10
lines changed

3 files changed

+102
-10
lines changed

resources/entry-point-trampoline.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ module.exports = (() => {
6969
Object.defineProperties(require, Object.getOwnPropertyDescriptors(innerRequire));
7070
Object.setPrototypeOf(require, Object.getPrototypeOf(innerRequire));
7171

72-
process.argv[1] = __filename;
72+
process.argv.unshift(__filename);
7373

7474
const module = {
7575
exports,

resources/main-template.cc

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,31 @@
66
#include "node.h"
77
#include "node_api.h"
88
#include "uv.h"
9+
#if HAVE_OPENSSL
10+
#include <openssl/err.h>
11+
#include <openssl/ssl.h>
12+
#include <openssl/bn.h>
13+
#include <openssl/dh.h>
14+
#include <openssl/ec.h>
15+
#include <openssl/rsa.h>
16+
#include <openssl/rand.h>
17+
#endif
918

1019
using namespace node;
1120
using namespace v8;
1221

22+
// This version can potentially be lowered if/when
23+
// https://github.com/nodejs/node/pull/44121 is backported.
24+
#if !NODE_VERSION_AT_LEAST(19, 0, 0)
25+
#define USE_OWN_LEGACY_PROCESS_INITIALIZATION 1
26+
#endif
27+
28+
#ifdef USE_OWN_LEGACY_PROCESS_INITIALIZATION
1329
namespace boxednode {
1430
void InitializeOncePerProcess();
1531
void TearDownOncePerProcess();
1632
}
33+
#endif
1734

1835
extern "C" {
1936
typedef void (*register_boxednode_linked_module)(const void**, const void**);
@@ -170,20 +187,38 @@ static int RunNodeInstance(MultiIsolatePlatform* platform,
170187
}
171188

172189
static int BoxednodeMain(std::vector<std::string> args) {
173-
boxednode::InitializeOncePerProcess();
174190
std::vector<std::string> exec_args;
175191
std::vector<std::string> errors;
176192

177-
args.insert(args.begin(), "--");
193+
if (args.size() > 0)
194+
args.insert(args.begin() + 1, "--");
178195

179196
// Parse Node.js CLI options, and print any errors that have occurred while
180197
// trying to parse them.
198+
#ifdef USE_OWN_LEGACY_PROCESS_INITIALIZATION
199+
boxednode::InitializeOncePerProcess();
181200
int exit_code = node::InitializeNodeWithArgs(&args, &exec_args, &errors);
182201
for (const std::string& error : errors)
183202
fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str());
184203
if (exit_code != 0) {
185204
return exit_code;
186205
}
206+
#else
207+
if (args.size() > 1)
208+
args.insert(args.begin() + 1, "--openssl-shared-config");
209+
auto result = node::InitializeOncePerProcess(args, {
210+
node::ProcessInitializationFlags::kNoInitializeV8,
211+
node::ProcessInitializationFlags::kNoInitializeNodeV8Platform,
212+
node::ProcessInitializationFlags::kNoPrintHelpOrVersionOutput
213+
});
214+
for (const std::string& error : result->errors())
215+
fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str());
216+
if (result->exit_code() != 0) {
217+
return result->exit_code();
218+
}
219+
args = result->args();
220+
exec_args = result->exec_args();
221+
#endif
187222

188223
// Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way
189224
// to create a v8::Platform instance that Node.js can use when creating
@@ -198,8 +233,13 @@ static int BoxednodeMain(std::vector<std::string> args) {
198233
int ret = RunNodeInstance(platform.get(), args, exec_args);
199234

200235
V8::Dispose();
236+
#ifdef USE_OWN_LEGACY_PROCESS_INITIALIZATION
201237
V8::ShutdownPlatform();
202238
boxednode::TearDownOncePerProcess();
239+
#else
240+
V8::DisposePlatform();
241+
node::TearDownOncePerProcess();
242+
#endif
203243
return ret;
204244
}
205245

@@ -242,7 +282,7 @@ int main(int argc, char** argv) {
242282
#endif
243283

244284
// The code below is mostly lifted directly from node.cc
245-
// TODO(addaleax): Expose these APIs on the Node.js side.
285+
#ifdef USE_OWN_LEGACY_PROCESS_INITIALIZATION
246286

247287
#if defined(__APPLE__) || defined(__linux__) || defined(_WIN32)
248288
#define NODE_USE_V8_WASM_TRAP_HANDLER 1
@@ -279,6 +319,30 @@ static PVOID old_vectored_exception_handler;
279319

280320
namespace boxednode {
281321

322+
#if HAVE_OPENSSL
323+
static void CheckEntropy() {
324+
for (;;) {
325+
int status = RAND_status();
326+
assert(status >= 0); // Cannot fail.
327+
if (status != 0)
328+
break;
329+
330+
// Give up, RAND_poll() not supported.
331+
if (RAND_poll() == 0)
332+
break;
333+
}
334+
}
335+
336+
static bool EntropySource(unsigned char* buffer, size_t length) {
337+
// Ensure that OpenSSL's PRNG is properly seeded.
338+
CheckEntropy();
339+
// RAND_bytes() can return 0 to indicate that the entropy data is not truly
340+
// random. That's okay, it's still better than V8's stock source of entropy,
341+
// which is /dev/urandom on UNIX platforms and the current time on Windows.
342+
return RAND_bytes(buffer, length) != -1;
343+
}
344+
#endif
345+
282346
void ResetStdio();
283347

284348
#ifdef __POSIX__
@@ -550,9 +614,41 @@ void ResetStdio() {
550614
#endif // __POSIX__
551615
}
552616

617+
static void InitializeOpenSSL() {
618+
#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
619+
// In the case of FIPS builds we should make sure
620+
// the random source is properly initialized first.
621+
#if OPENSSL_VERSION_MAJOR >= 3
622+
// Use OPENSSL_CONF environment variable is set.
623+
const char* conf_file = getenv("OPENSSL_CONF");
624+
625+
OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
626+
OPENSSL_INIT_set_config_filename(settings, conf_file);
627+
OPENSSL_INIT_set_config_appname(settings, "openssl_conf");
628+
OPENSSL_INIT_set_config_file_flags(settings,
629+
CONF_MFLAGS_IGNORE_MISSING_FILE);
630+
631+
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
632+
OPENSSL_INIT_free(settings);
633+
634+
if (ERR_peek_error() != 0) {
635+
fprintf(stderr, "OpenSSL configuration error:\n");
636+
ERR_print_errors_fp(stderr);
637+
exit(1);
638+
}
639+
#else // OPENSSL_VERSION_MAJOR < 3
640+
if (FIPS_mode()) {
641+
OPENSSL_init();
642+
}
643+
#endif
644+
V8::SetEntropySource(boxednode::EntropySource);
645+
#endif
646+
}
647+
553648
void InitializeOncePerProcess() {
554649
atexit(ResetStdio);
555650
PlatformInit();
651+
InitializeOpenSSL();
556652
}
557653

558654
void TearDownOncePerProcess() {
@@ -562,3 +658,5 @@ void TearDownOncePerProcess() {
562658
}
563659

564660
} // namespace boxednode
661+
662+
#endif // USE_OWN_LEGACY_PROCESS_INITIALIZATION

resources/third_party_main.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1 @@
1-
'use strict'
2-
const path = require('path')
3-
// Since this behaves like a Node.js binary, it would not usually count itself
4-
// as the script that is being run. Fix that by making process.argv[0] and
5-
// process.argv[1] the same.
6-
process.argv.unshift(process.execPath)
71
require(REPLACE_WITH_ENTRY_POINT)

0 commit comments

Comments
 (0)