Skip to content

Commit 3bea054

Browse files
committed
tls: support code compatibility using OpenSSL default CAfile
1 parent b962d64 commit 3bea054

4 files changed

Lines changed: 70 additions & 5 deletions

File tree

lib/tls.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const {
4545
getBundledRootCertificates,
4646
getExtraCACertificates,
4747
// getOpenSSLCACertificates,
48+
getOpenSSLDefaultCACertificates,
4849
lookupOpenSSLCACertificates,
4950
getSystemCACertificates,
5051
resetRootCertStore,
@@ -158,6 +159,14 @@ function cacheSystemCACertificates() {
158159
// return opensslCACertificates;
159160
// }
160161

162+
let opensslDefaultCACertificates;
163+
function cacheOpenSSLDefaultCACertificates() {
164+
opensslDefaultCACertificates ||= ObjectFreeze(
165+
getOpenSSLDefaultCACertificates());
166+
167+
return opensslDefaultCACertificates;
168+
}
169+
161170
let opensslCACertificateLookup;
162171
function cacheOpenSSLCertificateLookup(subjectNameOrCert) {
163172
opensslCACertificateLookup ??= new SafeMap();
@@ -191,15 +200,19 @@ function cacheDefaultCACertificates() {
191200

192201
defaultCACertificates = [];
193202

194-
if (!getOptionValue('--use-openssl-ca')) {
203+
if (getOptionValue('--use-openssl-ca')) {
204+
const openssl = cacheOpenSSLDefaultCACertificates();
205+
for (let i = 0; i < openssl.length; ++i) {
206+
ArrayPrototypePush(defaultCACertificates, openssl[i]);
207+
}
208+
} else {
195209
const bundled = cacheBundledRootCertificates();
196210
for (let i = 0; i < bundled.length; ++i) {
197211
ArrayPrototypePush(defaultCACertificates, bundled[i]);
198212
}
199213
if (getOptionValue('--use-system-ca')) {
200214
const system = cacheSystemCACertificates();
201215
for (let i = 0; i < system.length; ++i) {
202-
203216
ArrayPrototypePush(defaultCACertificates, system[i]);
204217
}
205218
}
@@ -208,7 +221,6 @@ function cacheDefaultCACertificates() {
208221
if (process.env.NODE_EXTRA_CA_CERTS) {
209222
const extra = cacheExtraCACertificates();
210223
for (let i = 0; i < extra.length; ++i) {
211-
212224
ArrayPrototypePush(defaultCACertificates, extra[i]);
213225
}
214226
}
@@ -284,6 +296,7 @@ if (isBuildingSnapshot()) {
284296
extraCACertificates = undefined;
285297
systemCACertificates = undefined;
286298
// opensslCACertificates = undefined;
299+
opensslDefaultCACertificates = undefined;
287300
opensslCACertificateLookup = undefined;
288301
if (hasResetDefaultCACertificates) {
289302
defaultCACertificates = undefined;

src/crypto/crypto_context.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,31 @@ void GetOpenSSLCACertificates(const FunctionCallbackInfo<Value>& args) {
14461446
}
14471447
*/
14481448

1449+
void GetOpenSSLDefaultCACertificates(const FunctionCallbackInfo<Value>& args) {
1450+
Environment* env = Environment::GetCurrent(args);
1451+
std::vector<X509*> certs;
1452+
std::string cert_file;
1453+
// SSL_CERT_DIR uses subject-hash lookups, so there is no exact list without
1454+
// a lookup key. Only the default CA file can be enumerated here.
1455+
if (!credentials::SafeGetenv(X509_get_default_cert_file_env(), &cert_file)) {
1456+
cert_file = X509_get_default_cert_file();
1457+
}
1458+
if (!cert_file.empty()) {
1459+
LoadCertsFromFile(&certs, cert_file.c_str());
1460+
}
1461+
auto cleanup = OnScopeLeave([&certs]() {
1462+
for (X509* cert : certs) {
1463+
X509_free(cert);
1464+
}
1465+
});
1466+
1467+
Local<Array> results;
1468+
if (X509sToArrayOfStrings(env, certs.begin(), certs.end(), certs.size())
1469+
.ToLocal(&results)) {
1470+
args.GetReturnValue().Set(results);
1471+
}
1472+
}
1473+
14491474
static X509StorePointer NewOpenSSLDefaultCertificateStore(Environment* env) {
14501475
X509StorePointer store(X509_STORE_new(), X509_STORE_free);
14511476
if (!store) {
@@ -1671,6 +1696,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
16711696
context, target, "getSystemCACertificates", GetSystemCACertificates);
16721697
// SetMethodNoSideEffect(
16731698
// context, target, "getOpenSSLCACertificates", GetOpenSSLCACertificates);
1699+
SetMethodNoSideEffect(context,
1700+
target,
1701+
"getOpenSSLDefaultCACertificates",
1702+
GetOpenSSLDefaultCACertificates);
16741703
SetMethodNoSideEffect(context,
16751704
target,
16761705
"lookupOpenSSLCACertificates",
@@ -1731,6 +1760,7 @@ void SecureContext::RegisterExternalReferences(
17311760
registry->Register(GetBundledRootCertificates);
17321761
registry->Register(GetSystemCACertificates);
17331762
// registry->Register(GetOpenSSLCACertificates);
1763+
registry->Register(GetOpenSSLDefaultCACertificates);
17341764
registry->Register(LookupOpenSSLCACertificates);
17351765
registry->Register(GetExtraCACertificates);
17361766
registry->Register(ResetRootCertStore);

test/fixtures/tls-check-openssl-ca-certificates.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,24 @@ const { includesCert } = require('../common/tls');
88

99
const expectedCertFiles = process.env.EXPECTED_CERT_FILES ?
1010
JSON.parse(process.env.EXPECTED_CERT_FILES) : [process.env.SSL_CERT_FILE];
11+
const expectedDefaultCertFiles = process.env.EXPECTED_DEFAULT_CERT_FILES ?
12+
JSON.parse(process.env.EXPECTED_DEFAULT_CERT_FILES) : [];
13+
const unexpectedDefaultCertFiles = process.env.UNEXPECTED_DEFAULT_CERT_FILES ?
14+
JSON.parse(process.env.UNEXPECTED_DEFAULT_CERT_FILES) : [];
1115
const defaultCerts = tls.getCACertificates('default');
12-
assert.deepStrictEqual(defaultCerts, []);
1316
assert.strictEqual(defaultCerts, tls.getCACertificates());
1417
assert.strictEqual(defaultCerts, tls.getCACertificates('default'));
18+
assert.strictEqual(defaultCerts.length, expectedDefaultCertFiles.length);
19+
20+
for (const certFile of expectedDefaultCertFiles) {
21+
const cert = fs.readFileSync(certFile, 'utf8');
22+
assert(includesCert(defaultCerts, cert));
23+
}
24+
25+
for (const certFile of unexpectedDefaultCertFiles) {
26+
const cert = fs.readFileSync(certFile, 'utf8');
27+
assert(!includesCert(defaultCerts, cert));
28+
}
1529

1630
const expectedCerts = expectedCertFiles.map((certFile) => {
1731
const cert = fs.readFileSync(certFile, 'utf8');

test/parallel/test-tls-get-ca-certificates-openssl.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
'use strict';
22

33
// This tests that tls.getCACertificates('openssl', subjectNameOrCert) looks up
4-
// certificates from OpenSSL's default certificate file and hashed directories.
4+
// certificates from OpenSSL's default certificate file and hashed directories,
5+
// while tls.getCACertificates('default') only enumerates the default certificate
6+
// file without scanning hashed directories.
57

68
const common = require('../common');
79
if (!common.hasCrypto) common.skip('missing crypto');
@@ -56,6 +58,12 @@ spawnSyncAndExitWithoutError(
5658
env: {
5759
...process.env,
5860
EXPECTED_CERT_FILES: JSON.stringify(expectedCertFiles),
61+
EXPECTED_DEFAULT_CERT_FILES: JSON.stringify([expectedCertFiles[0]]),
62+
UNEXPECTED_DEFAULT_CERT_FILES: JSON.stringify([
63+
expectedCertFiles[1],
64+
expectedCertFiles[2],
65+
unexpectedCertFile,
66+
]),
5967
UNEXPECTED_CERT_FILE: unexpectedCertFile,
6068
NODE_EXTRA_CA_CERTS: undefined,
6169
SSL_CERT_FILE: expectedCertFiles[0],

0 commit comments

Comments
 (0)