Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
fc66355135 Fix tls.getCACertificates('system') returning empty array
Previously, tls.getCACertificates('system') would return an empty array
because us_get_root_system_cert_instances() only loaded system certificates
when the --use-system-ca flag was set or NODE_USE_SYSTEM_CA=1.

This was incorrect behavior. The function should always load and return
system certificates when explicitly requested. The flag should only control
whether system certificates are automatically included in the "default" set.

Changes:
- Modified us_get_root_system_cert_instances() to always load system certs
- Added thread-safe lazy initialization for system certificates
- System certs are now loaded independently of the --use-system-ca flag
- The flag still controls inclusion in the default certificate set

Fixes #24339

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 07:52:32 +00:00
2 changed files with 78 additions and 5 deletions

View File

@@ -203,11 +203,34 @@ STACK_OF(X509) *us_get_root_extra_cert_instances() {
}
STACK_OF(X509) *us_get_root_system_cert_instances() {
if (!us_should_use_system_ca())
return NULL;
// Ensure single-path initialization via us_internal_init_root_certs
auto certs = us_get_default_ca_certificates();
return certs->root_system_cert_instances;
// Always load system certificates when explicitly requested
// The us_should_use_system_ca() check only controls whether they're
// included in the default set, not whether they can be retrieved
static STACK_OF(X509) *system_certs = NULL;
static std::atomic_bool system_certs_initialized = false;
static std::atomic_flag system_certs_lock = ATOMIC_FLAG_INIT;
if (std::atomic_load(&system_certs_initialized) == 1)
return system_certs;
while (atomic_flag_test_and_set_explicit(&system_certs_lock,
std::memory_order_acquire))
;
if (!atomic_exchange(&system_certs_initialized, 1)) {
#ifdef __APPLE__
us_load_system_certificates_macos(&system_certs);
#elif defined(_WIN32)
us_load_system_certificates_windows(&system_certs);
#else
us_load_system_certificates_linux(&system_certs);
#endif
}
atomic_flag_clear_explicit(&system_certs_lock,
std::memory_order_release);
return system_certs;
}
extern "C" X509_STORE *us_get_default_ca_store() {

View File

@@ -0,0 +1,50 @@
// https://github.com/oven-sh/bun/issues/24339
import { expect, test } from "bun:test";
import tls from "node:tls";
test("tls.getCACertificates('system') should return system certificates", () => {
const systemCerts = tls.getCACertificates("system");
// System certificates should not be empty
expect(systemCerts.length).toBeGreaterThan(0);
// Each certificate should be a string in PEM format
expect(systemCerts[0]).toBeString();
expect(systemCerts[0]).toContain("-----BEGIN CERTIFICATE-----");
expect(systemCerts[0]).toContain("-----END CERTIFICATE-----");
});
test("tls.getCACertificates('bundled') should return bundled certificates", () => {
const bundledCerts = tls.getCACertificates("bundled");
// Bundled certificates should not be empty
expect(bundledCerts.length).toBeGreaterThan(0);
// Each certificate should be a string in PEM format
expect(bundledCerts[0]).toBeString();
expect(bundledCerts[0]).toContain("-----BEGIN CERTIFICATE-----");
expect(bundledCerts[0]).toContain("-----END CERTIFICATE-----");
});
test("tls.getCACertificates('default') should only include bundled certs by default", () => {
const defaultCerts = tls.getCACertificates("default");
const bundledCerts = tls.getCACertificates("bundled");
// Without --use-system-ca, default should equal bundled
expect(defaultCerts.length).toBe(bundledCerts.length);
});
test("tls.getCACertificates() should default to 'default' type", () => {
const defaultCerts = tls.getCACertificates();
const explicitDefaultCerts = tls.getCACertificates("default");
expect(defaultCerts.length).toBe(explicitDefaultCerts.length);
});
test("system and bundled certificates should be different", () => {
const systemCerts = tls.getCACertificates("system");
const bundledCerts = tls.getCACertificates("bundled");
// System and bundled should be different (system is from OS, bundled is from Node.js)
expect(systemCerts.length).not.toBe(bundledCerts.length);
});