cli: add NODE_USE_SYSTEM_CA=1

Similar to how NODE_USE_ENV_PROXY complements --use-env-proxy, this
complements --use-system-ca. This will allow the setting to be
applied to workers individually in the future.

PR-URL: https://github.com/nodejs/node/pull/59276
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
Joyee Cheung 2025-08-10 16:20:58 +02:00 committed by GitHub
parent 013190dd9c
commit ca76b39356
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 113 additions and 0 deletions

View file

@ -3696,6 +3696,18 @@ specified proxy.
This can also be enabled using the [`--use-env-proxy`][] command-line flag. This can also be enabled using the [`--use-env-proxy`][] command-line flag.
When both are set, `--use-env-proxy` takes precedence. When both are set, `--use-env-proxy` takes precedence.
### `NODE_USE_SYSTEM_CA=1`
<!-- YAML
added: REPLACEME
-->
Node.js uses the trusted CA certificates present in the system store along with
the `--use-bundled-ca` option and the `NODE_EXTRA_CA_CERTS` environment variable.
This can also be enabled using the [`--use-system-ca`][] command-line flag.
When both are set, `--use-system-ca` takes precedence.
### `NODE_V8_COVERAGE=dir` ### `NODE_V8_COVERAGE=dir`
When set, Node.js will begin outputting [V8 JavaScript code coverage][] and When set, Node.js will begin outputting [V8 JavaScript code coverage][] and
@ -4025,6 +4037,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
[`--redirect-warnings`]: #--redirect-warningsfile [`--redirect-warnings`]: #--redirect-warningsfile
[`--require`]: #-r---require-module [`--require`]: #-r---require-module
[`--use-env-proxy`]: #--use-env-proxy [`--use-env-proxy`]: #--use-env-proxy
[`--use-system-ca`]: #--use-system-ca
[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage [`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
[`Buffer`]: buffer.md#class-buffer [`Buffer`]: buffer.md#class-buffer
[`CRYPTO_secure_malloc_init`]: https://www.openssl.org/docs/man3.0/man3/CRYPTO_secure_malloc_init.html [`CRYPTO_secure_malloc_init`]: https://www.openssl.org/docs/man3.0/man3/CRYPTO_secure_malloc_init.html

View file

@ -844,6 +844,12 @@ This currently only affects requests sent over
.Ar fetch() . .Ar fetch() .
Support for other built-in http and https methods is under way. Support for other built-in http and https methods is under way.
. .
.It Ev NODE_USE_SYSTEM_CA
Similar to
.Fl -use-system-ca .
Use the trusted CA certificates present in the system store, in addition to the certificates in the
bundled Mozilla CA store and certificates from `NODE_EXTRA_CA_CERTS`.
.
.It Ev NODE_V8_COVERAGE Ar dir .It Ev NODE_V8_COVERAGE Ar dir
When set, Node.js writes JavaScript code coverage information to When set, Node.js writes JavaScript code coverage information to
.Ar dir . .Ar dir .

View file

@ -868,6 +868,15 @@ static ExitCode InitializeNodeWithArgsInternal(
// default value. // default value.
V8::SetFlagsFromString("--rehash-snapshot"); V8::SetFlagsFromString("--rehash-snapshot");
#if HAVE_OPENSSL
// TODO(joyeecheung): make this a per-env option and move the normalization
// into HandleEnvOptions.
std::string use_system_ca;
if (credentials::SafeGetenv("NODE_USE_SYSTEM_CA", &use_system_ca) &&
use_system_ca == "1") {
per_process::cli_options->use_system_ca = true;
}
#endif // HAVE_OPENSSL
HandleEnvOptions(per_process::cli_options->per_isolate->per_env); HandleEnvOptions(per_process::cli_options->per_isolate->per_env);
std::string node_options; std::string node_options;

View file

@ -0,0 +1,29 @@
'use strict';
// This tests that NODE_USE_SYSTEM_CA environment variable works the same
// as --use-system-ca flag by comparing certificate counts.
const common = require('../common');
if (!common.hasCrypto) common.skip('missing crypto');
const tls = require('tls');
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
const systemCerts = tls.getCACertificates('system');
if (systemCerts.length === 0) {
common.skip('no system certificates available');
}
const { child: { stdout: expectedLength } } = spawnSyncAndExitWithoutError(process.execPath, [
'--use-system-ca',
'-p',
`tls.getCACertificates('default').length`,
], {
env: { ...process.env, NODE_USE_SYSTEM_CA: '0' },
});
spawnSyncAndExitWithoutError(process.execPath, [
'-p',
`assert.strictEqual(tls.getCACertificates('default').length, ${expectedLength.toString()})`,
], {
env: { ...process.env, NODE_USE_SYSTEM_CA: '1' },
});

View file

@ -0,0 +1,56 @@
// Env: NODE_USE_SYSTEM_CA=1
// Same as test-native-root-certs.mjs, just testing the environment variable instead of the flag.
import * as common from '../common/index.mjs';
import assert from 'node:assert/strict';
import https from 'node:https';
import fixtures from '../common/fixtures.js';
import { it, beforeEach, afterEach, describe } from 'node:test';
import { once } from 'events';
if (!common.hasCrypto) {
common.skip('requires crypto');
}
// To run this test, the system needs to be configured to trust
// the CA certificate first (which needs an interactive GUI approval, e.g. TouchID):
// see the README.md in this folder for instructions on how to do this.
const handleRequest = (req, res) => {
const path = req.url;
switch (path) {
case '/hello-world':
res.writeHead(200);
res.end('hello world\n');
break;
default:
assert(false, `Unexpected path: ${path}`);
}
};
describe('use-system-ca', function() {
async function setupServer(key, cert) {
const theServer = https.createServer({
key: fixtures.readKey(key),
cert: fixtures.readKey(cert),
}, handleRequest);
theServer.listen(0);
await once(theServer, 'listening');
return theServer;
}
let server;
beforeEach(async function() {
server = await setupServer('agent8-key.pem', 'agent8-cert.pem');
});
it('trusts a valid root certificate', async function() {
await fetch(`https://localhost:${server.address().port}/hello-world`);
});
afterEach(async function() {
server?.close();
});
});