tls: only do off-thread certificate loading on loading tls · nodejs/node@f5d3f91

@@ -814,23 +814,6 @@ static std::vector<X509*>& GetSystemStoreCACertificates() {

814814

return system_store_certs;

815815

}

816816817-

static void LoadSystemCACertificates(void* data) {

818-

GetSystemStoreCACertificates();

819-

}

820-821-

static uv_thread_t system_ca_thread;

822-

static bool system_ca_thread_started = false;

823-

int LoadSystemCACertificatesOffThread() {

824-

// This is only run once during the initialization of the process, so

825-

// it is safe to use a static thread here.

826-

int r =

827-

uv_thread_create(&system_ca_thread, LoadSystemCACertificates, nullptr);

828-

if (r == 0) {

829-

system_ca_thread_started = true;

830-

}

831-

return r;

832-

}

833-834817

static std::vector<X509*> InitializeExtraCACertificates() {

835818

std::vector<X509*> extra_certs;

836819

unsigned long err = LoadCertsFromFile( // NOLINT(runtime/int)

@@ -854,6 +837,53 @@ static std::vector<X509*>& GetExtraCACertificates() {

854837

return extra_certs;

855838

}

856839840+

static void LoadCACertificates(void* data) {

841+

per_process::Debug(DebugCategory::CRYPTO,

842+

"Started loading system root certificates off-thread\n");

843+

GetSystemStoreCACertificates();

844+

}

845+846+

static std::atomic<bool> tried_cert_loading_off_thread = false;

847+

static std::atomic<bool> cert_loading_thread_started = false;

848+

static Mutex start_cert_loading_thread_mutex;

849+

static uv_thread_t cert_loading_thread;

850+851+

void StartLoadingCertificatesOffThread(

852+

const FunctionCallbackInfo<Value>& args) {

853+

// Load the CA certificates eagerly off the main thread to avoid

854+

// blocking the main thread when the first TLS connection is made. We

855+

// don't need to wait for the thread to finish with code here, as

856+

// Get*CACertificates() functions has a function-local static and any

857+

// actual user of it will wait for that to complete initialization.

858+859+

{

860+

Mutex::ScopedLock cli_lock(node::per_process::cli_options_mutex);

861+

if (!per_process::cli_options->use_system_ca) {

862+

return;

863+

}

864+

}

865+866+

// Only try to start the thread once. If it ever fails, we won't try again.

867+

if (tried_cert_loading_off_thread.load()) {

868+

return;

869+

}

870+

{

871+

Mutex::ScopedLock lock(start_cert_loading_thread_mutex);

872+

// Re-check under the lock.

873+

if (tried_cert_loading_off_thread.load()) {

874+

return;

875+

}

876+

tried_cert_loading_off_thread.store(true);

877+

int r = uv_thread_create(&cert_loading_thread, LoadCACertificates, nullptr);

878+

cert_loading_thread_started.store(r == 0);

879+

if (r != 0) {

880+

FPrintF(stderr,

881+

"Warning: Failed to load CA certificates off thread: %s\n",

882+

uv_strerror(r));

883+

}

884+

}

885+

}

886+857887

// Due to historical reasons the various options of CA certificates

858888

// may invalid one another. The current rule is:

859889

// 1. If the configure-time option --openssl-use-def-ca-store is NOT used

@@ -942,9 +972,12 @@ void CleanupCachedRootCertificates() {

942972

X509_free(cert);

943973

}

944974

}

945-

if (system_ca_thread_started) {

946-

uv_thread_join(&system_ca_thread);

947-

system_ca_thread_started = false;

975+976+

// Serialize with starter to avoid the race window.

977+

Mutex::ScopedLock lock(start_cert_loading_thread_mutex);

978+

if (tried_cert_loading_off_thread.load() &&

979+

cert_loading_thread_started.load()) {

980+

uv_thread_join(&cert_loading_thread);

948981

}

949982

}

950983

@@ -1233,6 +1266,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {

12331266

SetMethod(context, target, "resetRootCertStore", ResetRootCertStore);

12341267

SetMethodNoSideEffect(

12351268

context, target, "getUserRootCertificates", GetUserRootCertificates);

1269+

SetMethod(context,

1270+

target,

1271+

"startLoadingCertificatesOffThread",

1272+

StartLoadingCertificatesOffThread);

12361273

}

1237127412381275

void SecureContext::RegisterExternalReferences(

@@ -1277,6 +1314,7 @@ void SecureContext::RegisterExternalReferences(

12771314

registry->Register(GetExtraCACertificates);

12781315

registry->Register(ResetRootCertStore);

12791316

registry->Register(GetUserRootCertificates);

1317+

registry->Register(StartLoadingCertificatesOffThread);

12801318

}

1281131912821320

SecureContext* SecureContext::Create(Environment* env) {