| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a1e60bc commit d52f515
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -52,7 +52,7 @@ static const char* const root_certs[] = { | |||
| 52 | 52 | ||
| 53 | 53 | static const char system_cert_path[] = NODE_OPENSSL_SYSTEM_CERT_PATH; | |
| 54 | 54 | ||
| 55 | - static bool extra_root_certs_loaded = false; | ||
| 55 | + static std::string extra_root_certs_file; // NOLINT(runtime/string) | ||
| 56 | 56 | ||
| 57 | 57 | X509_STORE* GetOrCreateRootCertStore() { | |
| 58 | 58 | // Guaranteed thread-safe by standard, just don't use -fno-threadsafe-statics. | |
@@ -197,26 +197,66 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, | |||
| 197 | 197 | issuer); | |
| 198 | 198 | } | |
| 199 | 199 | ||
| 200 | + unsigned long LoadCertsFromFile( // NOLINT(runtime/int) | ||
| 201 | + std::vector<X509*>* certs, | ||
| 202 | + const char* file) { | ||
| 203 | + MarkPopErrorOnReturn mark_pop_error_on_return; | ||
| 204 | + | ||
| 205 | + BIOPointer bio(BIO_new_file(file, "r")); | ||
| 206 | + if (!bio) return ERR_get_error(); | ||
| 207 | + | ||
| 208 | + while (X509* x509 = PEM_read_bio_X509( | ||
| 209 | + bio.get(), nullptr, NoPasswordCallback, nullptr)) { | ||
| 210 | + certs->push_back(x509); | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + unsigned long err = ERR_peek_last_error(); // NOLINT(runtime/int) | ||
| 214 | + // Ignore error if its EOF/no start line found. | ||
| 215 | + if (ERR_GET_LIB(err) == ERR_LIB_PEM && | ||
| 216 | + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { | ||
| 217 | + return 0; | ||
| 218 | + } else { | ||
| 219 | + return err; | ||
| 220 | + } | ||
| 221 | + } | ||
| 222 | + | ||
| 200 | 223 | X509_STORE* NewRootCertStore() { | |
| 201 | 224 | static std::vector<X509*> root_certs_vector; | |
| 225 | + static bool root_certs_vector_loaded = false; | ||
| 202 | 226 | static Mutex root_certs_vector_mutex; | |
| 203 | 227 | Mutex::ScopedLock lock(root_certs_vector_mutex); | |
| 204 | 228 | ||
| 205 | - if (root_certs_vector.empty() && | ||
| 206 | - per_process::cli_options->ssl_openssl_cert_store == false) { | ||
| 207 | - for (size_t i = 0; i < arraysize(root_certs); i++) { | ||
| 208 | - X509* x509 = | ||
| 209 | - PEM_read_bio_X509(NodeBIO::NewFixed(root_certs[i], | ||
| 210 | - strlen(root_certs[i])).get(), | ||
| 211 | - nullptr, // no re-use of X509 structure | ||
| 212 | - NoPasswordCallback, | ||
| 213 | - nullptr); // no callback data | ||
| 229 | + if (!root_certs_vector_loaded) { | ||
| 230 | + if (per_process::cli_options->ssl_openssl_cert_store == false) { | ||
| 231 | + for (size_t i = 0; i < arraysize(root_certs); i++) { | ||
| 232 | + X509* x509 = PEM_read_bio_X509( | ||
| 233 | + NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])).get(), | ||
| 234 | + nullptr, // no re-use of X509 structure | ||
| 235 | + NoPasswordCallback, | ||
| 236 | + nullptr); // no callback data | ||
| 237 | + | ||
| 238 | + // Parse errors from the built-in roots are fatal. | ||
| 239 | + CHECK_NOT_NULL(x509); | ||
| 214 | 240 | ||
| 215 | - // Parse errors from the built-in roots are fatal. | ||
| 216 | - CHECK_NOT_NULL(x509); | ||
| 241 | + root_certs_vector.push_back(x509); | ||
| 242 | + } | ||
| 243 | + } | ||
| 217 | 244 | ||
| 218 | - root_certs_vector.push_back(x509); | ||
| 245 | + if (!extra_root_certs_file.empty()) { | ||
| 246 | + unsigned long err = LoadCertsFromFile( // NOLINT(runtime/int) | ||
| 247 | + &root_certs_vector, | ||
| 248 | + extra_root_certs_file.c_str()); | ||
| 249 | + if (err) { | ||
| 250 | + char buf[256]; | ||
| 251 | + ERR_error_string_n(err, buf, sizeof(buf)); | ||
| 252 | + fprintf(stderr, | ||
| 253 | + "Warning: Ignoring extra certs from `%s`, load failed: %s\n", | ||
| 254 | + extra_root_certs_file.c_str(), | ||
| 255 | + buf); | ||
| 256 | + } | ||
| 219 | 257 | } | |
| 258 | + | ||
| 259 | + root_certs_vector_loaded = true; | ||
| 220 | 260 | } | |
| 221 | 261 | ||
| 222 | 262 | X509_STORE* store = X509_STORE_new(); | |
@@ -228,12 +268,11 @@ X509_STORE* NewRootCertStore() { | |||
| 228 | 268 | ||
| 229 | 269 | Mutex::ScopedLock cli_lock(node::per_process::cli_options_mutex); | |
| 230 | 270 | if (per_process::cli_options->ssl_openssl_cert_store) { | |
| 231 | - X509_STORE_set_default_paths(store); | ||
| 232 | - } else { | ||
| 233 | - for (X509* cert : root_certs_vector) { | ||
| 234 | - X509_up_ref(cert); | ||
| 235 | - X509_STORE_add_cert(store, cert); | ||
| 236 | - } | ||
| 271 | + CHECK_EQ(1, X509_STORE_set_default_paths(store)); | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + for (X509* cert : root_certs_vector) { | ||
| 275 | + CHECK_EQ(1, X509_STORE_add_cert(store, cert)); | ||
| 237 | 276 | } | |
| 238 | 277 | ||
| 239 | 278 | return store; | |
@@ -339,11 +378,6 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) { | |||
| 339 | 378 | ||
| 340 | 379 | SetMethodNoSideEffect( | |
| 341 | 380 | context, target, "getRootCertificates", GetRootCertificates); | |
| 342 | - // Exposed for testing purposes only. | ||
| 343 | - SetMethodNoSideEffect(context, | ||
| 344 | - target, | ||
| 345 | - "isExtraRootCertsFileLoaded", | ||
| 346 | - IsExtraRootCertsFileLoaded); | ||
| 347 | 381 | } | |
| 348 | 382 | ||
| 349 | 383 | void SecureContext::RegisterExternalReferences( | |
@@ -383,7 +417,6 @@ void SecureContext::RegisterExternalReferences( | |||
| 383 | 417 | registry->Register(CtxGetter); | |
| 384 | 418 | ||
| 385 | 419 | registry->Register(GetRootCertificates); | |
| 386 | - registry->Register(IsExtraRootCertsFileLoaded); | ||
| 387 | 420 | } | |
| 388 | 421 | ||
| 389 | 422 | SecureContext* SecureContext::Create(Environment* env) { | |
@@ -1383,54 +1416,9 @@ void SecureContext::GetCertificate(const FunctionCallbackInfo<Value>& args) { | |||
| 1383 | 1416 | args.GetReturnValue().Set(buff); | |
| 1384 | 1417 | } | |
| 1385 | 1418 | ||
| 1386 | - namespace { | ||
| 1387 | - unsigned long AddCertsFromFile( // NOLINT(runtime/int) | ||
| 1388 | - X509_STORE* store, | ||
| 1389 | - const char* file) { | ||
| 1390 | - ERR_clear_error(); | ||
| 1391 | - MarkPopErrorOnReturn mark_pop_error_on_return; | ||
| 1392 | - | ||
| 1393 | - BIOPointer bio(BIO_new_file(file, "r")); | ||
| 1394 | - if (!bio) | ||
| 1395 | - return ERR_get_error(); | ||
| 1396 | - | ||
| 1397 | - while (X509Pointer x509 = X509Pointer(PEM_read_bio_X509( | ||
| 1398 | - bio.get(), nullptr, NoPasswordCallback, nullptr))) { | ||
| 1399 | - X509_STORE_add_cert(store, x509.get()); | ||
| 1400 | - } | ||
| 1401 | - | ||
| 1402 | - unsigned long err = ERR_peek_error(); // NOLINT(runtime/int) | ||
| 1403 | - // Ignore error if its EOF/no start line found. | ||
| 1404 | - if (ERR_GET_LIB(err) == ERR_LIB_PEM && | ||
| 1405 | - ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { | ||
| 1406 | - return 0; | ||
| 1407 | - } | ||
| 1408 | - | ||
| 1409 | - return err; | ||
| 1410 | - } | ||
| 1411 | - } // namespace | ||
| 1412 | - | ||
| 1413 | 1419 | // UseExtraCaCerts is called only once at the start of the Node.js process. | |
| 1414 | 1420 | void UseExtraCaCerts(const std::string& file) { | |
| 1415 | - if (file.empty()) return; | ||
| 1416 | - ClearErrorOnReturn clear_error_on_return; | ||
| 1417 | - X509_STORE* store = GetOrCreateRootCertStore(); | ||
| 1418 | - if (auto err = AddCertsFromFile(store, file.c_str())) { | ||
| 1419 | - char buf[256]; | ||
| 1420 | - ERR_error_string_n(err, buf, sizeof(buf)); | ||
| 1421 | - fprintf(stderr, | ||
| 1422 | - "Warning: Ignoring extra certs from `%s`, load failed: %s\n", | ||
| 1423 | - file.c_str(), | ||
| 1424 | - buf); | ||
| 1425 | - } else { | ||
| 1426 | - extra_root_certs_loaded = true; | ||
| 1427 | - } | ||
| 1428 | - } | ||
| 1429 | - | ||
| 1430 | - // Exposed to JavaScript strictly for testing purposes. | ||
| 1431 | - void IsExtraRootCertsFileLoaded( | ||
| 1432 | - const FunctionCallbackInfo<Value>& args) { | ||
| 1433 | - return args.GetReturnValue().Set(extra_root_certs_loaded); | ||
| 1421 | + extra_root_certs_file = file; | ||
| 1434 | 1422 | } | |
| 1435 | 1423 | ||
| 1436 | 1424 | } // namespace crypto | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,9 +19,6 @@ constexpr int kMaxSupportedVersion = TLS1_3_VERSION; | |||
| 19 | 19 | void GetRootCertificates( | |
| 20 | 20 | const v8::FunctionCallbackInfo<v8::Value>& args); | |
| 21 | 21 | ||
| 22 | - void IsExtraRootCertsFileLoaded( | ||
| 23 | - const v8::FunctionCallbackInfo<v8::Value>& args); | ||
| 24 | - | ||
| 25 | 22 | X509_STORE* NewRootCertStore(); | |
| 26 | 23 | ||
| 27 | 24 | X509_STORE* GetOrCreateRootCertStore(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,82 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + | ||
| 5 | + if (!common.hasCrypto) | ||
| 6 | + common.skip('missing crypto'); | ||
| 7 | + | ||
| 8 | + const assert = require('node:assert'); | ||
| 9 | + const tls = require('node:tls'); | ||
| 10 | + const { fork } = require('node:child_process'); | ||
| 11 | + const fixtures = require('../common/fixtures'); | ||
| 12 | + | ||
| 13 | + const tests = [ | ||
| 14 | + { | ||
| 15 | + get clientOptions() { | ||
| 16 | + const secureContext = tls.createSecureContext(); | ||
| 17 | + secureContext.context.addCACert( | ||
| 18 | + fixtures.readKey('ca1-cert.pem') | ||
| 19 | + ); | ||
| 20 | + | ||
| 21 | + return { | ||
| 22 | + secureContext | ||
| 23 | + }; | ||
| 24 | + } | ||
| 25 | + }, | ||
| 26 | + { | ||
| 27 | + clientOptions: { | ||
| 28 | + crl: fixtures.readKey('ca2-crl.pem') | ||
| 29 | + } | ||
| 30 | + }, | ||
| 31 | + { | ||
| 32 | + clientOptions: { | ||
| 33 | + pfx: fixtures.readKey('agent1.pfx'), | ||
| 34 | + passphrase: 'sample' | ||
| 35 | + } | ||
| 36 | + }, | ||
| 37 | + ]; | ||
| 38 | + | ||
| 39 | + if (process.argv[2]) { | ||
| 40 | + const testNumber = parseInt(process.argv[2], 10); | ||
| 41 | + assert(testNumber >= 0 && testNumber < tests.length); | ||
| 42 | + | ||
| 43 | + const test = tests[testNumber]; | ||
| 44 | + | ||
| 45 | + const clientOptions = { | ||
| 46 | + ...test.clientOptions, | ||
| 47 | + port: process.argv[3], | ||
| 48 | + checkServerIdentity: common.mustCall() | ||
| 49 | + }; | ||
| 50 | + | ||
| 51 | + const client = tls.connect(clientOptions, common.mustCall(() => { | ||
| 52 | + client.end('hi'); | ||
| 53 | + })); | ||
| 54 | + } else { | ||
| 55 | + const serverOptions = { | ||
| 56 | + key: fixtures.readKey('agent3-key.pem'), | ||
| 57 | + cert: fixtures.readKey('agent3-cert.pem') | ||
| 58 | + }; | ||
| 59 | + | ||
| 60 | + for (const testNumber in tests) { | ||
| 61 | + const server = tls.createServer(serverOptions, common.mustCall((socket) => { | ||
| 62 | + socket.end('bye'); | ||
| 63 | + server.close(); | ||
| 64 | + })); | ||
| 65 | + | ||
| 66 | + server.listen(0, common.mustCall(() => { | ||
| 67 | + const env = { | ||
| 68 | + ...process.env, | ||
| 69 | + NODE_EXTRA_CA_CERTS: fixtures.path('keys', 'ca2-cert.pem') | ||
| 70 | + }; | ||
| 71 | + | ||
| 72 | + const args = [ | ||
| 73 | + testNumber, | ||
| 74 | + server.address().port, | ||
| 75 | + ]; | ||
| 76 | + | ||
| 77 | + fork(__filename, args, { env }).on('exit', common.mustCall((status) => { | ||
| 78 | + assert.strictEqual(status, 0); | ||
| 79 | + })); | ||
| 80 | + })); | ||
| 81 | + } | ||
| 82 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments