Skip to content

Commit 1fc7c04

Browse files
ebickleMylesBorins
authored andcommitted
src: fix missing extra ca in tls.rootCertificates
Fixes tls.rootCertificates missing certificates loaded from NODE_EXTRA_CA_CERTS. Fixes: #32074 PR-URL: #32075 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 3119bbe commit 1fc7c04

File tree

2 files changed

+89
-43
lines changed

2 files changed

+89
-43
lines changed

src/node_crypto.cc

+45-18
Original file line numberDiff line numberDiff line change
@@ -986,24 +986,6 @@ static X509_STORE* NewRootCertStore() {
986986
}
987987

988988

989-
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
990-
Environment* env = Environment::GetCurrent(args);
991-
Local<Value> result[arraysize(root_certs)];
992-
993-
for (size_t i = 0; i < arraysize(root_certs); i++) {
994-
if (!String::NewFromOneByte(
995-
env->isolate(),
996-
reinterpret_cast<const uint8_t*>(root_certs[i]),
997-
NewStringType::kNormal).ToLocal(&result[i])) {
998-
return;
999-
}
1000-
}
1001-
1002-
args.GetReturnValue().Set(
1003-
Array::New(env->isolate(), result, arraysize(root_certs)));
1004-
}
1005-
1006-
1007989
void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
1008990
Environment* env = Environment::GetCurrent(args);
1009991

@@ -2680,6 +2662,21 @@ static inline Local<Value> BIOToStringOrBuffer(Environment* env,
26802662
}
26812663
}
26822664

2665+
static MaybeLocal<Value> X509ToPEM(Environment* env, X509* cert) {
2666+
BIOPointer bio(BIO_new(BIO_s_mem()));
2667+
if (!bio) {
2668+
ThrowCryptoError(env, ERR_get_error(), "BIO_new");
2669+
return MaybeLocal<Value>();
2670+
}
2671+
2672+
if (PEM_write_bio_X509(bio.get(), cert) == 0) {
2673+
ThrowCryptoError(env, ERR_get_error(), "PEM_write_bio_X509");
2674+
return MaybeLocal<Value>();
2675+
}
2676+
2677+
return BIOToStringOrBuffer(env, bio.get(), kKeyFormatPEM);
2678+
}
2679+
26832680
static bool WritePublicKeyInner(EVP_PKEY* pkey,
26842681
const BIOPointer& bio,
26852682
const PublicKeyEncodingConfig& config) {
@@ -6660,6 +6657,36 @@ void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
66606657
}
66616658

66626659

6660+
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
6661+
Environment* env = Environment::GetCurrent(args);
6662+
6663+
if (root_cert_store == nullptr)
6664+
root_cert_store = NewRootCertStore();
6665+
6666+
stack_st_X509_OBJECT* objs = X509_STORE_get0_objects(root_cert_store);
6667+
int num_objs = sk_X509_OBJECT_num(objs);
6668+
6669+
std::vector<Local<Value>> result;
6670+
result.reserve(num_objs);
6671+
6672+
for (int i = 0; i < num_objs; i++) {
6673+
X509_OBJECT* obj = sk_X509_OBJECT_value(objs, i);
6674+
if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
6675+
X509* cert = X509_OBJECT_get0_X509(obj);
6676+
6677+
Local<Value> value;
6678+
if (!X509ToPEM(env, cert).ToLocal(&value))
6679+
return;
6680+
6681+
result.push_back(value);
6682+
}
6683+
}
6684+
6685+
args.GetReturnValue().Set(
6686+
Array::New(env->isolate(), result.data(), result.size()));
6687+
}
6688+
6689+
66636690
// Convert the input public key to compressed, uncompressed, or hybrid formats.
66646691
void ConvertKey(const FunctionCallbackInfo<Value>& args) {
66656692
MarkPopErrorOnReturn mark_pop_error_on_return;

test/parallel/test-tls-root-certificates.js

+44-25
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,49 @@
22
const common = require('../common');
33
if (!common.hasCrypto) common.skip('missing crypto');
44

5+
const fixtures = require('../common/fixtures');
56
const assert = require('assert');
67
const tls = require('tls');
7-
8-
assert(Array.isArray(tls.rootCertificates));
9-
assert(tls.rootCertificates.length > 0);
10-
11-
// Getter should return the same object.
12-
assert.strictEqual(tls.rootCertificates, tls.rootCertificates);
13-
14-
// Array is immutable...
15-
assert.throws(() => tls.rootCertificates[0] = 0, /TypeError/);
16-
assert.throws(() => tls.rootCertificates.sort(), /TypeError/);
17-
18-
// ...and so is the property.
19-
assert.throws(() => tls.rootCertificates = 0, /TypeError/);
20-
21-
// Does not contain duplicates.
22-
assert.strictEqual(tls.rootCertificates.length,
23-
new Set(tls.rootCertificates).size);
24-
25-
assert(tls.rootCertificates.every((s) => {
26-
return s.startsWith('-----BEGIN CERTIFICATE-----\n');
27-
}));
28-
29-
assert(tls.rootCertificates.every((s) => {
30-
return s.endsWith('\n-----END CERTIFICATE-----');
31-
}));
8+
const { fork } = require('child_process');
9+
10+
if (process.argv[2] !== 'child') {
11+
// Parent
12+
const NODE_EXTRA_CA_CERTS = fixtures.path('keys', 'ca1-cert.pem');
13+
14+
fork(
15+
__filename,
16+
['child'],
17+
{ env: { ...process.env, NODE_EXTRA_CA_CERTS } }
18+
).on('exit', common.mustCall(function(status) {
19+
assert.strictEqual(status, 0);
20+
}));
21+
} else {
22+
// Child
23+
assert(Array.isArray(tls.rootCertificates));
24+
assert(tls.rootCertificates.length > 0);
25+
26+
// Getter should return the same object.
27+
assert.strictEqual(tls.rootCertificates, tls.rootCertificates);
28+
29+
// Array is immutable...
30+
assert.throws(() => tls.rootCertificates[0] = 0, /TypeError/);
31+
assert.throws(() => tls.rootCertificates.sort(), /TypeError/);
32+
33+
// ...and so is the property.
34+
assert.throws(() => tls.rootCertificates = 0, /TypeError/);
35+
36+
// Does not contain duplicates.
37+
assert.strictEqual(tls.rootCertificates.length,
38+
new Set(tls.rootCertificates).size);
39+
40+
assert(tls.rootCertificates.every((s) => {
41+
return s.startsWith('-----BEGIN CERTIFICATE-----\n');
42+
}));
43+
44+
assert(tls.rootCertificates.every((s) => {
45+
return s.endsWith('\n-----END CERTIFICATE-----\n');
46+
}));
47+
48+
const extraCert = fixtures.readKey('ca1-cert.pem', 'utf8');
49+
assert(tls.rootCertificates.includes(extraCert));
50+
}

0 commit comments

Comments
 (0)