| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 2870a73 commit 095e7a8
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -39,30 +39,46 @@ const { | |||
| 39 | 39 | ERR_INVALID_ARG_VALUE, | |
| 40 | 40 | ERR_INVALID_ARG_TYPE, | |
| 41 | 41 | } = require('internal/errors').codes; | |
| 42 | - const internalUtil = require('internal/util'); | ||
| 43 | - internalUtil.assertCrypto(); | ||
| 44 | - const { | ||
| 45 | - isArrayBufferView, | ||
| 46 | - isUint8Array, | ||
| 47 | - } = require('internal/util/types'); | ||
| 48 | 42 | ||
| 49 | - const net = require('net'); | ||
| 50 | - const { getOptionValue } = require('internal/options'); | ||
| 51 | 43 | const { | |
| 52 | 44 | getBundledRootCertificates, | |
| 53 | 45 | getExtraCACertificates, | |
| 54 | 46 | getSystemCACertificates, | |
| 55 | 47 | resetRootCertStore, | |
| 56 | 48 | getUserRootCertificates, | |
| 57 | 49 | getSSLCiphers, | |
| 50 | + startLoadingCertificatesOffThread, | ||
| 58 | 51 | } = internalBinding('crypto'); | |
| 52 | + | ||
| 53 | + // Start loading root certificates in a separate thread as early as possible | ||
| 54 | + // once the tls module is loaded, so that by the time an actual TLS connection is | ||
| 55 | + // made, the loading is done. | ||
| 56 | + startLoadingCertificatesOffThread(); | ||
| 57 | + | ||
| 58 | + const internalUtil = require('internal/util'); | ||
| 59 | + internalUtil.assertCrypto(); | ||
| 60 | + const { | ||
| 61 | + isArrayBufferView, | ||
| 62 | + isUint8Array, | ||
| 63 | + } = require('internal/util/types'); | ||
| 64 | + | ||
| 65 | + const net = require('net'); | ||
| 66 | + const { getOptionValue } = require('internal/options'); | ||
| 59 | 67 | const { Buffer } = require('buffer'); | |
| 60 | 68 | const { canonicalizeIP } = internalBinding('cares_wrap'); | |
| 61 | 69 | const _tls_common = require('_tls_common'); | |
| 62 | 70 | const _tls_wrap = require('_tls_wrap'); | |
| 63 | 71 | const { createSecurePair } = require('internal/tls/secure-pair'); | |
| 64 | 72 | const { validateString } = require('internal/validators'); | |
| 65 | 73 | ||
| 74 | + const { | ||
| 75 | + namespace: { | ||
| 76 | + addDeserializeCallback, | ||
| 77 | + addSerializeCallback, | ||
| 78 | + isBuildingSnapshot, | ||
| 79 | + }, | ||
| 80 | + } = require('internal/v8/startup_snapshot'); | ||
| 81 | + | ||
| 66 | 82 | // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations | |
| 67 | 83 | // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more | |
| 68 | 84 | // renegotiations are seen. The settings are applied to all remote client | |
@@ -204,6 +220,28 @@ function setDefaultCACertificates(certs) { | |||
| 204 | 220 | ||
| 205 | 221 | exports.setDefaultCACertificates = setDefaultCACertificates; | |
| 206 | 222 | ||
| 223 | + if (isBuildingSnapshot()) { | ||
| 224 | + addSerializeCallback(() => { | ||
| 225 | + // Clear the cached certs so that they are reloaded at runtime. | ||
| 226 | + // Bundled certificates are immutable so they are spared. | ||
| 227 | + extraCACertificates = undefined; | ||
| 228 | + systemCACertificates = undefined; | ||
| 229 | + if (hasResetDefaultCACertificates) { | ||
| 230 | + defaultCACertificates = undefined; | ||
| 231 | + } | ||
| 232 | + }); | ||
| 233 | + addDeserializeCallback(() => { | ||
| 234 | + // If the tls module is loaded during snapshotting, load the certificates from | ||
| 235 | + // various sources again at runtime so that by the time an actual TLS connection is | ||
| 236 | + // made, the loading is done. If the default CA certificates have been overridden, then | ||
| 237 | + // the serialized overriding certificates are likely to be used and pre-loading | ||
| 238 | + // from the sources would probably not yield any benefit, so skip it. | ||
| 239 | + if (!hasResetDefaultCACertificates) { | ||
| 240 | + startLoadingCertificatesOffThread(); | ||
| 241 | + } | ||
| 242 | + }); | ||
| 243 | + } | ||
| 244 | + | ||
| 207 | 245 | // Convert protocols array into valid OpenSSL protocols list | |
| 208 | 246 | // ("\x06spdy/2\x08http/1.1\x08http/1.0") | |
| 209 | 247 | function convertProtocols(protocols) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -812,23 +812,6 @@ static std::vector<X509*>& GetSystemStoreCACertificates() { | |||
| 812 | 812 | return system_store_certs; | |
| 813 | 813 | } | |
| 814 | 814 | ||
| 815 | - static void LoadSystemCACertificates(void* data) { | ||
| 816 | - GetSystemStoreCACertificates(); | ||
| 817 | - } | ||
| 818 | - | ||
| 819 | - static uv_thread_t system_ca_thread; | ||
| 820 | - static bool system_ca_thread_started = false; | ||
| 821 | - int LoadSystemCACertificatesOffThread() { | ||
| 822 | - // This is only run once during the initialization of the process, so | ||
| 823 | - // it is safe to use a static thread here. | ||
| 824 | - int r = | ||
| 825 | - uv_thread_create(&system_ca_thread, LoadSystemCACertificates, nullptr); | ||
| 826 | - if (r == 0) { | ||
| 827 | - system_ca_thread_started = true; | ||
| 828 | - } | ||
| 829 | - return r; | ||
| 830 | - } | ||
| 831 | - | ||
| 832 | 815 | static std::vector<X509*> InitializeExtraCACertificates() { | |
| 833 | 816 | std::vector<X509*> extra_certs; | |
| 834 | 817 | unsigned long err = LoadCertsFromFile( // NOLINT(runtime/int) | |
@@ -852,6 +835,53 @@ static std::vector<X509*>& GetExtraCACertificates() { | |||
| 852 | 835 | return extra_certs; | |
| 853 | 836 | } | |
| 854 | 837 | ||
| 838 | + static void LoadCACertificates(void* data) { | ||
| 839 | + per_process::Debug(DebugCategory::CRYPTO, | ||
| 840 | + "Started loading system root certificates off-thread\n"); | ||
| 841 | + GetSystemStoreCACertificates(); | ||
| 842 | + } | ||
| 843 | + | ||
| 844 | + static std::atomic<bool> tried_cert_loading_off_thread = false; | ||
| 845 | + static std::atomic<bool> cert_loading_thread_started = false; | ||
| 846 | + static Mutex start_cert_loading_thread_mutex; | ||
| 847 | + static uv_thread_t cert_loading_thread; | ||
| 848 | + | ||
| 849 | + void StartLoadingCertificatesOffThread( | ||
| 850 | + const FunctionCallbackInfo<Value>& args) { | ||
| 851 | + // Load the CA certificates eagerly off the main thread to avoid | ||
| 852 | + // blocking the main thread when the first TLS connection is made. We | ||
| 853 | + // don't need to wait for the thread to finish with code here, as | ||
| 854 | + // Get*CACertificates() functions has a function-local static and any | ||
| 855 | + // actual user of it will wait for that to complete initialization. | ||
| 856 | + | ||
| 857 | + { | ||
| 858 | + Mutex::ScopedLock cli_lock(node::per_process::cli_options_mutex); | ||
| 859 | + if (!per_process::cli_options->use_system_ca) { | ||
| 860 | + return; | ||
| 861 | + } | ||
| 862 | + } | ||
| 863 | + | ||
| 864 | + // Only try to start the thread once. If it ever fails, we won't try again. | ||
| 865 | + if (tried_cert_loading_off_thread.load()) { | ||
| 866 | + return; | ||
| 867 | + } | ||
| 868 | + { | ||
| 869 | + Mutex::ScopedLock lock(start_cert_loading_thread_mutex); | ||
| 870 | + // Re-check under the lock. | ||
| 871 | + if (tried_cert_loading_off_thread.load()) { | ||
| 872 | + return; | ||
| 873 | + } | ||
| 874 | + tried_cert_loading_off_thread.store(true); | ||
| 875 | + int r = uv_thread_create(&cert_loading_thread, LoadCACertificates, nullptr); | ||
| 876 | + cert_loading_thread_started.store(r == 0); | ||
| 877 | + if (r != 0) { | ||
| 878 | + FPrintF(stderr, | ||
| 879 | + "Warning: Failed to load CA certificates off thread: %s\n", | ||
| 880 | + uv_strerror(r)); | ||
| 881 | + } | ||
| 882 | + } | ||
| 883 | + } | ||
| 884 | + | ||
| 855 | 885 | // Due to historical reasons the various options of CA certificates | |
| 856 | 886 | // may invalid one another. The current rule is: | |
| 857 | 887 | // 1. If the configure-time option --openssl-use-def-ca-store is NOT used | |
@@ -940,9 +970,12 @@ void CleanupCachedRootCertificates() { | |||
| 940 | 970 | X509_free(cert); | |
| 941 | 971 | } | |
| 942 | 972 | } | |
| 943 | - if (system_ca_thread_started) { | ||
| 944 | - uv_thread_join(&system_ca_thread); | ||
| 945 | - system_ca_thread_started = false; | ||
| 973 | + | ||
| 974 | + // Serialize with starter to avoid the race window. | ||
| 975 | + Mutex::ScopedLock lock(start_cert_loading_thread_mutex); | ||
| 976 | + if (tried_cert_loading_off_thread.load() && | ||
| 977 | + cert_loading_thread_started.load()) { | ||
| 978 | + uv_thread_join(&cert_loading_thread); | ||
| 946 | 979 | } | |
| 947 | 980 | } | |
| 948 | 981 | ||
@@ -1231,6 +1264,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) { | |||
| 1231 | 1264 | SetMethod(context, target, "resetRootCertStore", ResetRootCertStore); | |
| 1232 | 1265 | SetMethodNoSideEffect( | |
| 1233 | 1266 | context, target, "getUserRootCertificates", GetUserRootCertificates); | |
| 1267 | + SetMethod(context, | ||
| 1268 | + target, | ||
| 1269 | + "startLoadingCertificatesOffThread", | ||
| 1270 | + StartLoadingCertificatesOffThread); | ||
| 1234 | 1271 | } | |
| 1235 | 1272 | ||
| 1236 | 1273 | void SecureContext::RegisterExternalReferences( | |
@@ -1275,6 +1312,7 @@ void SecureContext::RegisterExternalReferences( | |||
| 1275 | 1312 | registry->Register(GetExtraCACertificates); | |
| 1276 | 1313 | registry->Register(ResetRootCertStore); | |
| 1277 | 1314 | registry->Register(GetUserRootCertificates); | |
| 1315 | + registry->Register(StartLoadingCertificatesOffThread); | ||
| 1278 | 1316 | } | |
| 1279 | 1317 | ||
| 1280 | 1318 | SecureContext* SecureContext::Create(Environment* env) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -62,7 +62,6 @@ void InitCryptoOnce(); | |||
| 62 | 62 | void InitCrypto(v8::Local<v8::Object> target); | |
| 63 | 63 | ||
| 64 | 64 | extern void UseExtraCaCerts(const std::string& file); | |
| 65 | - extern int LoadSystemCACertificatesOffThread(); | ||
| 66 | 65 | void CleanupCachedRootCertificates(); | |
| 67 | 66 | ||
| 68 | 67 | int PasswordCallback(char* buf, int size, int rwflag, void* u); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,6 +42,7 @@ void NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str); | |||
| 42 | 42 | // from a provider type to a debug category. | |
| 43 | 43 | #define DEBUG_CATEGORY_NAMES(V) \ | |
| 44 | 44 | NODE_ASYNC_PROVIDER_TYPES(V) \ | |
| 45 | + V(CRYPTO) \ | ||
| 45 | 46 | V(COMPILE_CACHE) \ | |
| 46 | 47 | V(DIAGNOSTICS) \ | |
| 47 | 48 | V(HUGEPAGES) \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1255,20 +1255,6 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args, | |||
| 1255 | 1255 | return result; | |
| 1256 | 1256 | } | |
| 1257 | 1257 | ||
| 1258 | - if (per_process::cli_options->use_system_ca) { | ||
| 1259 | - // Load the system CA certificates eagerly off the main thread to avoid | ||
| 1260 | - // blocking the main thread when the first TLS connection is made. We | ||
| 1261 | - // don't need to wait for the thread to finish with code here, as | ||
| 1262 | - // GetSystemStoreCACertificates() has a function-local static and any | ||
| 1263 | - // actual user of it will wait for that to complete initialization. | ||
| 1264 | - int r = crypto::LoadSystemCACertificatesOffThread(); | ||
| 1265 | - if (r != 0) { | ||
| 1266 | - FPrintF( | ||
| 1267 | - stderr, | ||
| 1268 | - "Warning: Failed to load system CA certificates off thread: %s\n", | ||
| 1269 | - uv_strerror(r)); | ||
| 1270 | - } | ||
| 1271 | - } | ||
| 1272 | 1258 | // Ensure CSPRNG is properly seeded. | |
| 1273 | 1259 | CHECK(ncrypto::CSPRNG(nullptr, 0)); | |
| 1274 | 1260 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments