Skip to content

Commit d0cd0d0

Browse files
committed
tls: simplify getCACertificates() API
1 parent 105f2b5 commit d0cd0d0

File tree

6 files changed

+46
-87
lines changed

6 files changed

+46
-87
lines changed

doc/api/tls.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,12 +2327,10 @@ changes:
23272327
* `type` {string} The type of CA certificates to return. One of `"default"`, `"system"`, `"bundled"`, or `"extra"`.
23282328
**Default:** `"default"`.
23292329
* `format` {string} The format of returned certificates. One of `"string"`, `"buffer"`, or `"x509"`.
2330-
**Default**: `"string"`.
2331-
* `"string"`: Returns PEM-encoded strings by default. See `encoding` for DER.
2332-
* `"buffer"`: Returns an array of certificate data as `Buffer` objects.
2330+
**Default:** `"string"`.
2331+
* `"string"`: Returns an array of PEM-encoded certificate strings.
2332+
* `"buffer"`: Returns an array of certificate data as `Buffer` objects in DER format.
23332333
* `"x509"`: Returns an array of [`X509Certificate`][x509certificate] instances.
2334-
* `encoding` {string} When `format` is `"string"`, the encoding of the returned strings.
2335-
One of `"pem"` (PEM-encoded) or `"der"` (base64 DER). **Default:** `"pem"`.
23362334

23372335
* Returns: {Array}
23382336
An array of certificate data in the specified format (Buffer or X509Certificate).

lib/tls.js

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,10 @@ function getCACertificates(options = {}) {
178178
const {
179179
type = 'default',
180180
format = 'string',
181-
encoding = 'pem',
182181
} = options;
183182

184183
validateString(type, 'type');
185184
validateOneOf(format, 'format', ['string', 'buffer', 'x509']);
186-
if (format === 'string') {
187-
validateOneOf(encoding, 'encoding', ['pem', 'der']);
188-
}
189185

190186
let certs;
191187
switch (type) {
@@ -196,37 +192,33 @@ function getCACertificates(options = {}) {
196192
default: throw new ERR_INVALID_ARG_VALUE('type', type);
197193
}
198194

199-
if (format === 'string' && encoding === 'pem') {
200-
return certs;
201-
}
202-
203-
if (format === 'buffer' || format === 'x509') {
204-
const buffers = certs.map((cert) => {
205-
if (Buffer.isBuffer(cert)) return cert;
206-
if (typeof cert === 'string') {
207-
const base64 = cert
208-
.replace(/-----BEGIN CERTIFICATE-----/g, '')
209-
.replace(/-----END CERTIFICATE-----/g, '')
210-
.replace(/\s+/g, '');
211-
return Buffer.from(base64, 'base64');
212-
}
195+
if (format === 'string') {
196+
// Return PEM strings directly
197+
return certs.map((cert) => {
198+
if (typeof cert === 'string') return cert;
199+
if (Buffer.isBuffer(cert)) return cert.toString('ascii');
213200
throw new ERR_INVALID_ARG_VALUE('cert', cert);
214201
});
215-
return (format === 'buffer') ? buffers : buffers.map((buf) => new X509Certificate(buf));
216202
}
217203

218-
return certs.map((cert) => {
204+
const buffers = certs.map((cert) => {
205+
if (Buffer.isBuffer(cert)) return cert;
219206
if (typeof cert === 'string') {
220207
const base64 = cert
221208
.replace(/-----BEGIN CERTIFICATE-----/g, '')
222209
.replace(/-----END CERTIFICATE-----/g, '')
223210
.replace(/\s+/g, '');
224-
return Buffer.from(base64, 'base64').toString('base64');
211+
return Buffer.from(base64, 'base64');
225212
}
226-
return encoding === 'pem' ? cert.toString('utf8') : cert.toString('base64');
213+
throw new ERR_INVALID_ARG_VALUE('cert', cert);
227214
});
228-
}
229215

216+
if (format === 'buffer') {
217+
return buffers;
218+
}
219+
220+
return buffers.map((buf) => new X509Certificate(buf));
221+
}
230222

231223
exports.getCACertificates = getCACertificates;
232224

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
2-
// This tests that tls.getCACertificates() returns the bundled
3-
// certificates correctly.
2+
// Test that tls.getCACertificates() returns the bundled certificates correctly.
43

54
const common = require('../common');
65
if (!common.hasCrypto) common.skip('missing crypto');
@@ -9,12 +8,9 @@ const assert = require('assert');
98
const tls = require('tls');
109
const { assertIsCAArray } = require('../common/tls');
1110

12-
const certs = tls.getCACertificates('bundled');
11+
const certs = tls.getCACertificates({ type: 'bundled', format: 'string' });
1312
assertIsCAArray(certs);
1413

15-
// It's the same as tls.rootCertificates - both are
16-
// Mozilla CA stores across platform.
17-
assert.strictEqual(certs, tls.rootCertificates);
14+
assert.deepStrictEqual(certs, tls.rootCertificates);
1815

19-
// It's cached on subsequent accesses.
20-
assert.strictEqual(certs, tls.getCACertificates('bundled'));
16+
assert.deepStrictEqual(certs, tls.getCACertificates({ type: 'bundled', format: 'string' }));
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
'use strict';
2-
3-
// This tests that tls.getCACertificates() returns the default
4-
// certificates correctly.
2+
// Test that tls.getCACertificates() returns the default certificates correctly.
53

64
const common = require('../common');
75
if (!common.hasCrypto) common.skip('missing crypto');
@@ -10,11 +8,10 @@ const assert = require('assert');
108
const tls = require('tls');
119
const { assertIsCAArray } = require('../common/tls');
1210

13-
const certs = tls.getCACertificates();
11+
const certs = tls.getCACertificates({ format: 'string' });
1412
assertIsCAArray(certs);
1513

16-
const certs2 = tls.getCACertificates('default');
17-
assert.strictEqual(certs, certs2);
14+
const certs2 = tls.getCACertificates({ type: 'default', format: 'string' });
15+
assert.deepStrictEqual(certs, certs2);
1816

19-
// It's cached on subsequent accesses.
20-
assert.strictEqual(certs, tls.getCACertificates('default'));
17+
assert.deepStrictEqual(certs, tls.getCACertificates({ type: 'default', format: 'string' }));
Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22
// Flags: --use-system-ca
3-
// This tests that tls.getCACertificates() returns the system
4-
// certificates correctly.
3+
// Test that tls.getCACertificates() returns system certificates correctly.
54

65
const common = require('../common');
76
if (!common.hasCrypto) common.skip('missing crypto');
@@ -10,23 +9,20 @@ const assert = require('assert');
109
const tls = require('tls');
1110
const { assertIsCAArray } = require('../common/tls');
1211

13-
const systemCerts = tls.getCACertificates('system');
14-
// Usually Windows come with some certificates installed by default.
15-
// This can't be said about other systems, in that case check that
16-
// at least systemCerts is an array (which may be empty).
12+
const systemCerts = tls.getCACertificates({ type: 'system', format: 'string' });
13+
1714
if (common.isWindows) {
1815
assertIsCAArray(systemCerts);
1916
} else {
2017
assert(Array.isArray(systemCerts));
2118
}
2219

23-
// When --use-system-ca is true, default is a superset of system
24-
// certificates.
25-
const defaultCerts = tls.getCACertificates('default');
20+
const defaultCerts = tls.getCACertificates({ format: 'string' });
2621
assert(defaultCerts.length >= systemCerts.length);
2722
const defaultSet = new Set(defaultCerts);
2823
const systemSet = new Set(systemCerts);
29-
assert.deepStrictEqual(defaultSet.intersection(systemSet), systemSet);
24+
for (const cert of systemSet) {
25+
assert(defaultSet.has(cert));
26+
}
3027

31-
// It's cached on subsequent accesses.
32-
assert.strictEqual(systemCerts, tls.getCACertificates('system'));
28+
assert.deepStrictEqual(systemCerts, tls.getCACertificates({ type: 'system', format: 'string' }));

test/parallel/test-tls-get-ca-certificates-x509-option.js

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,29 @@ const { X509Certificate } = require('crypto');
1010

1111
{
1212
const certs = tls.getCACertificates({ type: 'default', format: 'x509' });
13-
14-
assert.ok(Array.isArray(certs), 'should return an array');
15-
assert.ok(certs.length > 0, 'should return non-empty array');
16-
17-
for (let i = 0; i < certs.length; i++) {
18-
assert.ok(certs[i] instanceof X509Certificate,
19-
`cert at index ${i} should be instance of X509Certificate`);
13+
assert.ok(Array.isArray(certs));
14+
assert.ok(certs.length > 0);
15+
for (const cert of certs) {
16+
assert.ok(cert instanceof X509Certificate);
2017
}
21-
22-
assert.match(certs[0].serialNumber, /^[0-9A-F]+$/i,
23-
'serialNumber should be hex string');
2418
}
2519

2620
{
2721
const certs = tls.getCACertificates({ type: 'default', format: 'buffer' });
2822
assert.ok(Array.isArray(certs));
2923
assert.ok(certs.length > 0);
30-
31-
for (let i = 0; i < certs.length; i++) {
32-
assert.ok(Buffer.isBuffer(certs[i]),
33-
`cert at index ${i} should be a Buffer`);
24+
for (const cert of certs) {
25+
assert.ok(Buffer.isBuffer(cert));
3426
}
3527
}
3628

3729
{
3830
const certs = tls.getCACertificates({ type: 'default' });
3931
assert.ok(Array.isArray(certs));
4032
assert.ok(certs.length > 0);
41-
for (let i = 0; i < certs.length; i++) {
42-
assert.strictEqual(typeof certs[i], 'string');
43-
assert.ok(certs[i].includes('-----BEGIN CERTIFICATE-----'));
33+
for (const cert of certs) {
34+
assert.strictEqual(typeof cert, 'string');
35+
assert.ok(cert.includes('-----BEGIN CERTIFICATE-----'));
4436
}
4537
}
4638

@@ -58,10 +50,8 @@ const { X509Certificate } = require('crypto');
5850
const certs = tls.getCACertificates({ format: 'buffer' });
5951
assert.ok(Array.isArray(certs));
6052
assert.ok(certs.length > 0);
61-
62-
for (let i = 0; i < certs.length; i++) {
63-
assert.ok(Buffer.isBuffer(certs[i]),
64-
`cert at index ${i} should be a Buffer`);
53+
for (const cert of certs) {
54+
assert.ok(Buffer.isBuffer(cert));
6555
}
6656
}
6757

@@ -74,13 +64,3 @@ const { X509Certificate } = require('crypto');
7464
message: "The argument 'type' is invalid. Received 'invalid'"
7565
});
7666
}
77-
78-
{
79-
const certs = tls.getCACertificates({ format: 'string', encoding: 'der' });
80-
assert.ok(Array.isArray(certs));
81-
assert.ok(certs.length > 0);
82-
for (let i = 0; i < certs.length; i++) {
83-
assert.strictEqual(typeof certs[i], 'string');
84-
assert.ok(/^[A-Za-z0-9+/]+=*$/.test(certs[i]), 'should be base64 string');
85-
}
86-
}

0 commit comments

Comments
 (0)