Skip to content

Commit 5b2f698

Browse files
ebickletargos
authored andcommittedApr 22, 2020
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 <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 8602392 commit 5b2f698

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
@@ -985,24 +985,6 @@ static X509_STORE* NewRootCertStore() {
985985
}
986986

987987

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

@@ -2645,6 +2627,21 @@ static inline Local<Value> BIOToStringOrBuffer(Environment* env,
26452627
}
26462628
}
26472629

2630+
static MaybeLocal<Value> X509ToPEM(Environment* env, X509* cert) {
2631+
BIOPointer bio(BIO_new(BIO_s_mem()));
2632+
if (!bio) {
2633+
ThrowCryptoError(env, ERR_get_error(), "BIO_new");
2634+
return MaybeLocal<Value>();
2635+
}
2636+
2637+
if (PEM_write_bio_X509(bio.get(), cert) == 0) {
2638+
ThrowCryptoError(env, ERR_get_error(), "PEM_write_bio_X509");
2639+
return MaybeLocal<Value>();
2640+
}
2641+
2642+
return BIOToStringOrBuffer(env, bio.get(), kKeyFormatPEM);
2643+
}
2644+
26482645
static bool WritePublicKeyInner(EVP_PKEY* pkey,
26492646
const BIOPointer& bio,
26502647
const PublicKeyEncodingConfig& config) {
@@ -6513,6 +6510,36 @@ void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
65136510
}
65146511

65156512

6513+
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
6514+
Environment* env = Environment::GetCurrent(args);
6515+
6516+
if (root_cert_store == nullptr)
6517+
root_cert_store = NewRootCertStore();
6518+
6519+
stack_st_X509_OBJECT* objs = X509_STORE_get0_objects(root_cert_store);
6520+
int num_objs = sk_X509_OBJECT_num(objs);
6521+
6522+
std::vector<Local<Value>> result;
6523+
result.reserve(num_objs);
6524+
6525+
for (int i = 0; i < num_objs; i++) {
6526+
X509_OBJECT* obj = sk_X509_OBJECT_value(objs, i);
6527+
if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
6528+
X509* cert = X509_OBJECT_get0_X509(obj);
6529+
6530+
Local<Value> value;
6531+
if (!X509ToPEM(env, cert).ToLocal(&value))
6532+
return;
6533+
6534+
result.push_back(value);
6535+
}
6536+
}
6537+
6538+
args.GetReturnValue().Set(
6539+
Array::New(env->isolate(), result.data(), result.size()));
6540+
}
6541+
6542+
65166543
// Convert the input public key to compressed, uncompressed, or hybrid formats.
65176544
void ConvertKey(const FunctionCallbackInfo<Value>& args) {
65186545
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)
Please sign in to comment.