8
8
#include " node.h"
9
9
#include " node_buffer.h"
10
10
#include " node_options.h"
11
+ #include " node_process-inl.h"
11
12
#include " util.h"
12
13
#include " v8.h"
13
14
@@ -49,7 +50,7 @@ static const char system_cert_path[] = NODE_OPENSSL_SYSTEM_CERT_PATH;
49
50
50
51
static X509_STORE* root_cert_store;
51
52
52
- static bool extra_root_certs_loaded = false ;
53
+ static std::string extra_root_certs_file; // NOLINT(runtime/string)
53
54
54
55
// Takes a string or buffer and loads it into a BIO.
55
56
// Caller responsible for BIO_free_all-ing the returned object.
@@ -188,28 +189,69 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
188
189
issuer);
189
190
}
190
191
192
+ unsigned long LoadCertsFromFile ( // NOLINT(runtime/int)
193
+ std::vector<X509*>* certs,
194
+ const char * file) {
195
+ ClearErrorOnReturn clear_error_on_return;
196
+
197
+ BIOPointer bio (BIO_new_file (file, " r" ));
198
+ if (!bio)
199
+ return ERR_get_error ();
200
+
201
+ while (X509* x509 =
202
+ PEM_read_bio_X509 (bio.get (), nullptr , NoPasswordCallback, nullptr )) {
203
+ certs->push_back (x509);
204
+ }
205
+
206
+ unsigned long err = ERR_peek_error (); // NOLINT(runtime/int)
207
+ // Ignore error if its EOF/no start line found.
208
+ if (ERR_GET_LIB (err) == ERR_LIB_PEM &&
209
+ ERR_GET_REASON (err) == PEM_R_NO_START_LINE) {
210
+ return 0 ;
211
+ }
212
+
213
+ return err;
214
+ }
215
+
191
216
} // namespace
192
217
193
- X509_STORE* NewRootCertStore () {
218
+ X509_STORE* NewRootCertStore (Environment* env ) {
194
219
static std::vector<X509*> root_certs_vector;
195
- static Mutex root_certs_vector_mutex;
220
+ static bool root_certs_vector_loaded = false ;
221
+ static Mutex root_certs_vector_mutex;
196
222
Mutex::ScopedLock lock (root_certs_vector_mutex);
197
223
198
- if (root_certs_vector. empty () &&
199
- per_process::cli_options->ssl_openssl_cert_store == false ) {
200
- for (size_t i = 0 ; i < arraysize (root_certs); i++) {
201
- X509* x509 =
202
- PEM_read_bio_X509 (NodeBIO::NewFixed (root_certs[i],
203
- strlen (root_certs[i])).get (),
204
- nullptr , // no re-use of X509 structure
205
- NoPasswordCallback,
206
- nullptr ); // no callback data
224
+ if (!root_certs_vector_loaded) {
225
+ if ( per_process::cli_options->ssl_openssl_cert_store == false ) {
226
+ for (size_t i = 0 ; i < arraysize (root_certs); i++) {
227
+ X509* x509 =
228
+ PEM_read_bio_X509 (NodeBIO::NewFixed (root_certs[i],
229
+ strlen (root_certs[i])).get (),
230
+ nullptr , // no re-use of X509 structure
231
+ NoPasswordCallback,
232
+ nullptr ); // no callback data
207
233
208
- // Parse errors from the built-in roots are fatal.
209
- CHECK_NOT_NULL (x509);
234
+ // Parse errors from the built-in roots are fatal.
235
+ CHECK_NOT_NULL (x509);
210
236
211
- root_certs_vector.push_back (x509);
237
+ root_certs_vector.push_back (x509);
238
+ }
212
239
}
240
+
241
+ if (!extra_root_certs_file.empty ()) {
242
+ unsigned long err = LoadCertsFromFile ( // NOLINT(runtime/int)
243
+ &root_certs_vector,
244
+ extra_root_certs_file.c_str ());
245
+ if (err) {
246
+ ProcessEmitWarning (
247
+ env,
248
+ " Ignoring extra certs from `%s`, load failed: %s\n " ,
249
+ extra_root_certs_file.c_str (),
250
+ ERR_error_string (err, nullptr ));
251
+ }
252
+ }
253
+
254
+ root_certs_vector_loaded = true ;
213
255
}
214
256
215
257
X509_STORE* store = X509_STORE_new ();
@@ -222,11 +264,10 @@ X509_STORE* NewRootCertStore() {
222
264
Mutex::ScopedLock cli_lock (node::per_process::cli_options_mutex);
223
265
if (per_process::cli_options->ssl_openssl_cert_store ) {
224
266
X509_STORE_set_default_paths (store);
225
- } else {
226
- for (X509* cert : root_certs_vector) {
227
- X509_up_ref (cert);
228
- X509_STORE_add_cert (store, cert);
229
- }
267
+ }
268
+
269
+ for (X509* cert : root_certs_vector) {
270
+ X509_STORE_add_cert (store, cert);
230
271
}
231
272
232
273
return store;
@@ -333,11 +374,6 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
333
374
334
375
SetMethodNoSideEffect (
335
376
context, target, " getRootCertificates" , GetRootCertificates);
336
- // Exposed for testing purposes only.
337
- SetMethodNoSideEffect (context,
338
- target,
339
- " isExtraRootCertsFileLoaded" ,
340
- IsExtraRootCertsFileLoaded);
341
377
}
342
378
343
379
void SecureContext::RegisterExternalReferences (
@@ -377,7 +413,6 @@ void SecureContext::RegisterExternalReferences(
377
413
registry->Register (CtxGetter);
378
414
379
415
registry->Register (GetRootCertificates);
380
- registry->Register (IsExtraRootCertsFileLoaded);
381
416
}
382
417
383
418
SecureContext* SecureContext::Create (Environment* env) {
@@ -702,7 +737,7 @@ void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
702
737
while (X509* x509 = PEM_read_bio_X509_AUX (
703
738
bio.get (), nullptr , NoPasswordCallback, nullptr )) {
704
739
if (cert_store == root_cert_store) {
705
- cert_store = NewRootCertStore ();
740
+ cert_store = NewRootCertStore (env );
706
741
SSL_CTX_set_cert_store (sc->ctx_ .get (), cert_store);
707
742
}
708
743
X509_STORE_add_cert (cert_store, x509);
@@ -733,7 +768,7 @@ void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) {
733
768
734
769
X509_STORE* cert_store = SSL_CTX_get_cert_store (sc->ctx_ .get ());
735
770
if (cert_store == root_cert_store) {
736
- cert_store = NewRootCertStore ();
771
+ cert_store = NewRootCertStore (env );
737
772
SSL_CTX_set_cert_store (sc->ctx_ .get (), cert_store);
738
773
}
739
774
@@ -748,7 +783,8 @@ void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) {
748
783
ClearErrorOnReturn clear_error_on_return;
749
784
750
785
if (root_cert_store == nullptr ) {
751
- root_cert_store = NewRootCertStore ();
786
+ Environment* env = Environment::GetCurrent (args);
787
+ root_cert_store = NewRootCertStore (env);
752
788
}
753
789
754
790
// Increment reference count so global store is not deleted along with CTX.
@@ -1027,7 +1063,7 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
1027
1063
X509* ca = sk_X509_value (extra_certs.get (), i);
1028
1064
1029
1065
if (cert_store == root_cert_store) {
1030
- cert_store = NewRootCertStore ();
1066
+ cert_store = NewRootCertStore (env );
1031
1067
SSL_CTX_set_cert_store (sc->ctx_ .get (), cert_store);
1032
1068
}
1033
1069
X509_STORE_add_cert (cert_store, ca);
@@ -1297,61 +1333,9 @@ void SecureContext::GetCertificate(const FunctionCallbackInfo<Value>& args) {
1297
1333
args.GetReturnValue ().Set (buff);
1298
1334
}
1299
1335
1300
- namespace {
1301
- unsigned long AddCertsFromFile ( // NOLINT(runtime/int)
1302
- X509_STORE* store,
1303
- const char * file) {
1304
- ERR_clear_error ();
1305
- MarkPopErrorOnReturn mark_pop_error_on_return;
1306
-
1307
- BIOPointer bio (BIO_new_file (file, " r" ));
1308
- if (!bio)
1309
- return ERR_get_error ();
1310
-
1311
- while (X509* x509 =
1312
- PEM_read_bio_X509 (bio.get (), nullptr , NoPasswordCallback, nullptr )) {
1313
- X509_STORE_add_cert (store, x509);
1314
- X509_free (x509);
1315
- }
1316
-
1317
- unsigned long err = ERR_peek_error (); // NOLINT(runtime/int)
1318
- // Ignore error if its EOF/no start line found.
1319
- if (ERR_GET_LIB (err) == ERR_LIB_PEM &&
1320
- ERR_GET_REASON (err) == PEM_R_NO_START_LINE) {
1321
- return 0 ;
1322
- }
1323
-
1324
- return err;
1325
- }
1326
- } // namespace
1327
-
1328
1336
// UseExtraCaCerts is called only once at the start of the Node.js process.
1329
1337
void UseExtraCaCerts (const std::string& file) {
1330
- ClearErrorOnReturn clear_error_on_return;
1331
-
1332
- if (root_cert_store == nullptr ) {
1333
- root_cert_store = NewRootCertStore ();
1334
-
1335
- if (!file.empty ()) {
1336
- unsigned long err = AddCertsFromFile ( // NOLINT(runtime/int)
1337
- root_cert_store,
1338
- file.c_str ());
1339
- if (err) {
1340
- fprintf (stderr,
1341
- " Warning: Ignoring extra certs from `%s`, load failed: %s\n " ,
1342
- file.c_str (),
1343
- ERR_error_string (err, nullptr ));
1344
- } else {
1345
- extra_root_certs_loaded = true ;
1346
- }
1347
- }
1348
- }
1349
- }
1350
-
1351
- // Exposed to JavaScript strictly for testing purposes.
1352
- void IsExtraRootCertsFileLoaded (
1353
- const FunctionCallbackInfo<Value>& args) {
1354
- return args.GetReturnValue ().Set (extra_root_certs_loaded);
1338
+ extra_root_certs_file = file;
1355
1339
}
1356
1340
1357
1341
} // namespace crypto
0 commit comments