Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/crypto/crypto_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,23 @@ static std::vector<X509*>& GetSystemStoreCACertificates() {
return system_store_certs;
}

static void LoadSystemCACertificates(void* data) {
GetSystemStoreCACertificates();
}

static uv_thread_t system_ca_thread;
static bool system_ca_thread_started = false;
int LoadSystemCACertificatesOffThread() {
// This is only run once during the initialization of the process, so
// it is safe to use a static thread here.
int r =
uv_thread_create(&system_ca_thread, LoadSystemCACertificates, nullptr);
if (r == 0) {
system_ca_thread_started = true;
}
return r;
}

static std::vector<X509*> InitializeExtraCACertificates() {
std::vector<X509*> extra_certs;
unsigned long err = LoadCertsFromFile( // NOLINT(runtime/int)
Expand Down Expand Up @@ -925,6 +942,10 @@ void CleanupCachedRootCertificates() {
X509_free(cert);
}
}
if (system_ca_thread_started) {
uv_thread_join(&system_ca_thread);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why but if I don't do this, the process can crash from segfault - it's not always reproducible though

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a bit of debugging and looks like this must be done or otherwise if the process is started to run something very trivial and the main thread finishes too quickly, it will try to shut down and clean up resources that are not yet properly initialized by the certificate loading thread. So this is required.

system_ca_thread_started = false;
}
}

void GetBundledRootCertificates(const FunctionCallbackInfo<Value>& args) {
Expand Down
1 change: 1 addition & 0 deletions src/crypto/crypto_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void InitCryptoOnce();
void InitCrypto(v8::Local<v8::Object> target);

extern void UseExtraCaCerts(std::string_view file);
extern int LoadSystemCACertificatesOffThread();
void CleanupCachedRootCertificates();

int PasswordCallback(char* buf, int size, int rwflag, void* u);
Expand Down
14 changes: 14 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,20 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
return result;
}

if (per_process::cli_options->use_system_ca) {
// Load the system CA certificates eagerly off the main thread to avoid
// blocking the main thread when the first TLS connection is made. We
// don't need to wait for the thread to finish with code here, as
// GetSystemStoreCACertificates() has a function-local static and any
// actual user of it will wait for that to complete initialization.
int r = crypto::LoadSystemCACertificatesOffThread();
if (r != 0) {
FPrintF(
stderr,
"Warning: Failed to load system CA certificates off thread: %s\n",
uv_strerror(r));
}
}
// Ensure CSPRNG is properly seeded.
CHECK(ncrypto::CSPRNG(nullptr, 0));

Expand Down
Loading