Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions doc/api/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -2353,7 +2353,7 @@ const additionalCerts = ['-----BEGIN CERTIFICATE-----\n...'];
tls.setDefaultCACertificates([...currentCerts, ...additionalCerts]);
```

## `tls.getCACertificates([type])`
## `tls.getCACertificates([type[, subjectNameOrCert]])`

<!-- YAML
added:
Expand All @@ -2362,8 +2362,11 @@ added:
-->

* `type` {string|undefined} The type of CA certificates that will be returned. Valid values
are `"default"`, `"system"`, `"bundled"` and `"extra"`.
are `"default"`, `"system"`, `"bundled"`, `"extra"` and `"openssl"`.
**Default:** `"default"`.
* `subjectNameOrCert` {string|ArrayBufferView|X509Certificate|undefined}
The subject name or certificate used to filter OpenSSL CA certificates.
Required when `type` is `"openssl"`.
* Returns: {string\[]} An array of PEM-encoded certificates. The array may contain duplicates
if the same certificate is repeatedly stored in multiple sources.

Expand All @@ -2383,6 +2386,11 @@ Returns an array containing the CA certificates from various sources, depending
as [`tls.rootCertificates`][].
* `"extra"`: return the CA certificates loaded from [`NODE_EXTRA_CA_CERTS`][]. It's an empty array if
[`NODE_EXTRA_CA_CERTS`][] is not set.
* `"openssl"`: return CA certificates looked up from OpenSSL's default CA
store using `subjectNameOrCert`. If `subjectNameOrCert` is a certificate,
its issuer name is used for the lookup. If it is a subject name string, the
subject name is used directly. This follows OpenSSL's hashed-directory lookup
behavior for certificates loaded from the default certificate directory.

## `tls.getCiphers()`

Expand Down
75 changes: 71 additions & 4 deletions lib/tls.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
JSONParse,
ObjectDefineProperty,
ObjectFreeze,
SafeMap,
StringFromCharCode,
} = primordials;

Expand All @@ -43,6 +44,9 @@
const {
getBundledRootCertificates,
getExtraCACertificates,
// getOpenSSLCACertificates,
getOpenSSLDefaultCACertificates,
lookupOpenSSLCACertificates,
getSystemCACertificates,
resetRootCertStore,
getUserRootCertificates,
Expand Down Expand Up @@ -71,6 +75,8 @@
const tlsWrap = require('internal/tls/wrap');
const { domainToASCII } = require('internal/url');
const { validateString } = require('internal/validators');
const { isX509Certificate } = require('internal/crypto/x509');
const { kHandle } = require('internal/crypto/util');

const {
namespace: {
Expand Down Expand Up @@ -146,6 +152,40 @@
return systemCACertificates;
}

// let opensslCACertificates;

Check failure on line 155 in lib/tls.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Comments should not begin with a lowercase character
// function cacheOpenSSLCACertificates() {
// opensslCACertificates ||= ObjectFreeze(getOpenSSLCACertificates());

// return opensslCACertificates;
// }

let opensslDefaultCACertificates;
function cacheOpenSSLDefaultCACertificates() {
opensslDefaultCACertificates ||= ObjectFreeze(
getOpenSSLDefaultCACertificates());

return opensslDefaultCACertificates;
}

let opensslCACertificateLookup;
function cacheOpenSSLCertificateLookup(subjectNameOrCert) {
opensslCACertificateLookup ??= new SafeMap();

const key = isArrayBufferView(subjectNameOrCert) ?
`buffer:${Buffer.from(
subjectNameOrCert.buffer,
subjectNameOrCert.byteOffset,
subjectNameOrCert.byteLength).toString('base64')}` :
`subject:${subjectNameOrCert}`;

const cached = opensslCACertificateLookup.get(key);
if (cached !== undefined) return cached;

const result = ObjectFreeze(lookupOpenSSLCACertificates(subjectNameOrCert));
opensslCACertificateLookup.set(key, result);
return result;
}

let defaultCACertificates;
let hasResetDefaultCACertificates = false;

Expand All @@ -160,15 +200,19 @@

defaultCACertificates = [];

if (!getOptionValue('--use-openssl-ca')) {
if (getOptionValue('--use-openssl-ca')) {
const openssl = cacheOpenSSLDefaultCACertificates();
for (let i = 0; i < openssl.length; ++i) {
ArrayPrototypePush(defaultCACertificates, openssl[i]);
}
} else {
const bundled = cacheBundledRootCertificates();
for (let i = 0; i < bundled.length; ++i) {
ArrayPrototypePush(defaultCACertificates, bundled[i]);
}
if (getOptionValue('--use-system-ca')) {
const system = cacheSystemCACertificates();
for (let i = 0; i < system.length; ++i) {

ArrayPrototypePush(defaultCACertificates, system[i]);
}
}
Expand All @@ -177,7 +221,6 @@
if (process.env.NODE_EXTRA_CA_CERTS) {
const extra = cacheExtraCACertificates();
for (let i = 0; i < extra.length; ++i) {

ArrayPrototypePush(defaultCACertificates, extra[i]);
}
}
Expand All @@ -186,8 +229,25 @@
return defaultCACertificates;
}

function validateOpenSSLCACertificateFilter(subjectNameOrCert) {
if (subjectNameOrCert !== null &&
(typeof subjectNameOrCert === 'object' ||
typeof subjectNameOrCert === 'function') &&
isX509Certificate(subjectNameOrCert)) {
return subjectNameOrCert[kHandle].pem();
}
if (typeof subjectNameOrCert !== 'string' &&
!isArrayBufferView(subjectNameOrCert)) {
throw new ERR_INVALID_ARG_TYPE(
'subjectNameOrCert',
['string', 'ArrayBufferView', 'X509Certificate'],
subjectNameOrCert);
}
return subjectNameOrCert;
}

// TODO(joyeecheung): support X509Certificate output?
function getCACertificates(type = 'default') {
function getCACertificates(type = 'default', subjectNameOrCert) {
validateString(type, 'type');

switch (type) {
Expand All @@ -199,6 +259,10 @@
return cacheSystemCACertificates();
case 'extra':
return cacheExtraCACertificates();
case 'openssl':
subjectNameOrCert =
validateOpenSSLCACertificateFilter(subjectNameOrCert);
return cacheOpenSSLCertificateLookup(subjectNameOrCert);
default:
throw new ERR_INVALID_ARG_VALUE('type', type);
}
Expand Down Expand Up @@ -231,6 +295,9 @@
// Bundled certificates are immutable so they are spared.
extraCACertificates = undefined;
systemCACertificates = undefined;
// opensslCACertificates = undefined;
opensslDefaultCACertificates = undefined;
opensslCACertificateLookup = undefined;
if (hasResetDefaultCACertificates) {
defaultCACertificates = undefined;
}
Expand Down
Loading
Loading