mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
tls: implement tls.getCACertificates()
To accompany --use-system-ca, this adds a new API that allows querying various kinds of CA certificates. - If the first argument `type` is `"default"` or undefined, it returns the CA certificates that will be used by Node.js TLS clients by default, which includes the Mozilla CA if --use-bundled-ca is enabled or --use-openssl-ca is not enabled, and the system certificates if --use-system-ca is enabled, and the extra certificates if NODE_EXTRA_CA_CERTS is used. - If `type` is `"system"` this returns the system certificates, regardless of whether --use-system-ca is enabeld or not. - If `type` is `"bundled"` this is the same as `tls.rootCertificates` and returns the Mozilla CA certificates. - If `type` is `"extra"` this returns the certificates parsed from the path specified by NODE_EXTRA_CA_CERTS. Drive-by: remove the inaccurate description in `tls.rootCertificates` about including system certificates, since it in fact does not include them, and also it is contradicting the previous description about `tls.rootCertificates` always returning the Mozilla CA store and staying the same across platforms. PR-URL: https://github.com/nodejs/node/pull/57107 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
348393777e
commit
a7909014f7
|
|
@ -1985,9 +1985,13 @@ changes:
|
|||
* `allowPartialTrustChain` {boolean} Treat intermediate (non-self-signed)
|
||||
certificates in the trust CA certificate list as trusted.
|
||||
* `ca` {string|string\[]|Buffer|Buffer\[]} Optionally override the trusted CA
|
||||
certificates. Default is to trust the well-known CAs curated by Mozilla.
|
||||
Mozilla's CAs are completely replaced when CAs are explicitly specified
|
||||
using this option. The value can be a string or `Buffer`, or an `Array` of
|
||||
certificates. If not specified, the CA certificates trusted by default are
|
||||
the same as the ones returned by [`tls.getCACertificates()`][] using the
|
||||
`default` type. If specified, the default list would be completely replaced
|
||||
(instead of being concatenated) by the certificates in the `ca` option.
|
||||
Users need to concatenate manually if they wish to add additional certificates
|
||||
instead of completely overriding the default.
|
||||
The value can be a string or `Buffer`, or an `Array` of
|
||||
strings and/or `Buffer`s. Any string or `Buffer` can contain multiple PEM
|
||||
CAs concatenated together. The peer's certificate must be chainable to a CA
|
||||
trusted by the server for the connection to be authenticated. When using
|
||||
|
|
@ -2001,7 +2005,6 @@ changes:
|
|||
provided.
|
||||
For PEM encoded certificates, supported types are "TRUSTED CERTIFICATE",
|
||||
"X509 CERTIFICATE", and "CERTIFICATE".
|
||||
See also [`tls.rootCertificates`][].
|
||||
* `cert` {string|string\[]|Buffer|Buffer\[]} Cert chains in PEM format. One
|
||||
cert chain should be provided per private key. Each cert chain should
|
||||
consist of the PEM formatted certificate for a provided private `key`,
|
||||
|
|
@ -2364,6 +2367,39 @@ openssl pkcs12 -certpbe AES-256-CBC -export -out client-cert.pem \
|
|||
The server can be tested by connecting to it using the example client from
|
||||
[`tls.connect()`][].
|
||||
|
||||
## `tls.getCACertificates([type])`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* `type` {string|undefined} The type of CA certificates that will be returned. Valid values
|
||||
are `"default"`, `"system"`, `"bundled"` and `"extra"`.
|
||||
**Default:** `"default"`.
|
||||
* Returns: {string\[]} An array of PEM-encoded certificates. The array may contain duplicates
|
||||
if the same certificate is repeatedly stored in multiple sources.
|
||||
|
||||
Returns an array containing the CA certificates from various sources, depending on `type`:
|
||||
|
||||
* `"default"`: return the CA certificates that will be used by the Node.js TLS clients by default.
|
||||
* When [`--use-bundled-ca`][] is enabled (default), or [`--use-openssl-ca`][] is not enabled,
|
||||
this would include CA certificates from the bundled Mozilla CA store.
|
||||
* When [`--use-system-ca`][] is enabled, this would also include certificates from the system's
|
||||
trusted store.
|
||||
* When [`NODE_EXTRA_CA_CERTS`][] is used, this would also include certificates loaded from the specified
|
||||
file.
|
||||
* `"system"`: return the CA certificates that are loaded from the system's trusted store, according
|
||||
to rules set by [`--use-system-ca`][]. This can be used to get the certificates from the system
|
||||
when [`--use-system-ca`][] is not enabled.
|
||||
* `"bundled"`: return the CA certificates from the bundled Mozilla CA store. This would be the same
|
||||
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.
|
||||
|
||||
<!-- YAML
|
||||
added: v0.10.2
|
||||
-->
|
||||
|
||||
## `tls.getCiphers()`
|
||||
|
||||
<!-- YAML
|
||||
|
|
@ -2400,8 +2436,10 @@ from the bundled Mozilla CA store as supplied by the current Node.js version.
|
|||
The bundled CA store, as supplied by Node.js, is a snapshot of Mozilla CA store
|
||||
that is fixed at release time. It is identical on all supported platforms.
|
||||
|
||||
On macOS if `--use-system-ca` is passed then trusted certificates
|
||||
from the user and system keychains are also included.
|
||||
To get the actual CA certificates used by the current Node.js instance, which
|
||||
may include certificates loaded from the system store (if `--use-system-ca` is used)
|
||||
or loaded from a file indicated by `NODE_EXTRA_CA_CERTS`, use
|
||||
[`tls.getCACertificates()`][].
|
||||
|
||||
## `tls.DEFAULT_ECDH_CURVE`
|
||||
|
||||
|
|
@ -2487,7 +2525,11 @@ added:
|
|||
[`'secureConnection'`]: #event-secureconnection
|
||||
[`'session'`]: #event-session
|
||||
[`--tls-cipher-list`]: cli.md#--tls-cipher-listlist
|
||||
[`--use-bundled-ca`]: cli.md#--use-bundled-ca---use-openssl-ca
|
||||
[`--use-openssl-ca`]: cli.md#--use-bundled-ca---use-openssl-ca
|
||||
[`--use-system-ca`]: cli.md#--use-system-ca
|
||||
[`Duplex`]: stream.md#class-streamduplex
|
||||
[`NODE_EXTRA_CA_CERTS`]: cli.md#node_extra_ca_certsfile
|
||||
[`NODE_OPTIONS`]: cli.md#node_optionsoptions
|
||||
[`SSL_export_keying_material`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_export_keying_material.html
|
||||
[`SSL_get_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_version.html
|
||||
|
|
@ -2516,6 +2558,7 @@ added:
|
|||
[`tls.createSecureContext()`]: #tlscreatesecurecontextoptions
|
||||
[`tls.createSecurePair()`]: #tlscreatesecurepaircontext-isserver-requestcert-rejectunauthorized-options
|
||||
[`tls.createServer()`]: #tlscreateserveroptions-secureconnectionlistener
|
||||
[`tls.getCACertificates()`]: #tlsgetcacertificatestype
|
||||
[`tls.getCiphers()`]: #tlsgetciphers
|
||||
[`tls.rootCertificates`]: #tlsrootcertificates
|
||||
[`x509.checkHost()`]: crypto.md#x509checkhostname-options
|
||||
|
|
|
|||
88
lib/tls.js
88
lib/tls.js
|
|
@ -24,6 +24,8 @@
|
|||
const {
|
||||
Array,
|
||||
ArrayIsArray,
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
ArrayPrototypePush,
|
||||
JSONParse,
|
||||
ObjectDefineProperty,
|
||||
ObjectFreeze,
|
||||
|
|
@ -34,6 +36,7 @@ const {
|
|||
ERR_TLS_CERT_ALTNAME_FORMAT,
|
||||
ERR_TLS_CERT_ALTNAME_INVALID,
|
||||
ERR_OUT_OF_RANGE,
|
||||
ERR_INVALID_ARG_VALUE,
|
||||
} = require('internal/errors').codes;
|
||||
const internalUtil = require('internal/util');
|
||||
internalUtil.assertCrypto();
|
||||
|
|
@ -44,12 +47,18 @@ const {
|
|||
|
||||
const net = require('net');
|
||||
const { getOptionValue } = require('internal/options');
|
||||
const { getRootCertificates, getSSLCiphers } = internalBinding('crypto');
|
||||
const {
|
||||
getBundledRootCertificates,
|
||||
getExtraCACertificates,
|
||||
getSystemCACertificates,
|
||||
getSSLCiphers,
|
||||
} = internalBinding('crypto');
|
||||
const { Buffer } = require('buffer');
|
||||
const { canonicalizeIP } = internalBinding('cares_wrap');
|
||||
const _tls_common = require('_tls_common');
|
||||
const _tls_wrap = require('_tls_wrap');
|
||||
const { createSecurePair } = require('internal/tls/secure-pair');
|
||||
const { validateString } = require('internal/validators');
|
||||
|
||||
// Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations
|
||||
// every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more
|
||||
|
|
@ -85,23 +94,84 @@ exports.getCiphers = internalUtil.cachedResult(
|
|||
() => internalUtil.filterDuplicateStrings(getSSLCiphers(), true),
|
||||
);
|
||||
|
||||
let rootCertificates;
|
||||
let bundledRootCertificates;
|
||||
function cacheBundledRootCertificates() {
|
||||
bundledRootCertificates ||= ObjectFreeze(getBundledRootCertificates());
|
||||
|
||||
function cacheRootCertificates() {
|
||||
rootCertificates = ObjectFreeze(getRootCertificates());
|
||||
return bundledRootCertificates;
|
||||
}
|
||||
|
||||
ObjectDefineProperty(exports, 'rootCertificates', {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: () => {
|
||||
// Out-of-line caching to promote inlining the getter.
|
||||
if (!rootCertificates) cacheRootCertificates();
|
||||
return rootCertificates;
|
||||
},
|
||||
get: cacheBundledRootCertificates,
|
||||
});
|
||||
|
||||
let extraCACertificates;
|
||||
function cacheExtraCACertificates() {
|
||||
extraCACertificates ||= ObjectFreeze(getExtraCACertificates());
|
||||
|
||||
return extraCACertificates;
|
||||
}
|
||||
|
||||
let systemCACertificates;
|
||||
function cacheSystemCACertificates() {
|
||||
systemCACertificates ||= ObjectFreeze(getSystemCACertificates());
|
||||
|
||||
return systemCACertificates;
|
||||
}
|
||||
|
||||
let defaultCACertificates;
|
||||
function cacheDefaultCACertificates() {
|
||||
if (defaultCACertificates) { return defaultCACertificates; }
|
||||
defaultCACertificates = [];
|
||||
|
||||
if (!getOptionValue('--use-openssl-ca')) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_EXTRA_CA_CERTS) {
|
||||
const extra = cacheExtraCACertificates();
|
||||
for (let i = 0; i < extra.length; ++i) {
|
||||
|
||||
ArrayPrototypePush(defaultCACertificates, extra[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectFreeze(defaultCACertificates);
|
||||
return defaultCACertificates;
|
||||
}
|
||||
|
||||
// TODO(joyeecheung): support X509Certificate output?
|
||||
function getCACertificates(type = 'default') {
|
||||
validateString(type, 'type');
|
||||
|
||||
switch (type) {
|
||||
case 'default':
|
||||
return cacheDefaultCACertificates();
|
||||
case 'bundled':
|
||||
return cacheBundledRootCertificates();
|
||||
case 'system':
|
||||
return cacheSystemCACertificates();
|
||||
case 'extra':
|
||||
return cacheExtraCACertificates();
|
||||
default:
|
||||
throw new ERR_INVALID_ARG_VALUE('type', type);
|
||||
}
|
||||
}
|
||||
exports.getCACertificates = getCACertificates;
|
||||
|
||||
// Convert protocols array into valid OpenSSL protocols list
|
||||
// ("\x06spdy/2\x08http/1.1\x08http/1.0")
|
||||
function convertProtocols(protocols) {
|
||||
|
|
|
|||
|
|
@ -42,11 +42,13 @@ using ncrypto::MarkPopErrorOnReturn;
|
|||
using ncrypto::SSLPointer;
|
||||
using ncrypto::StackOfX509;
|
||||
using ncrypto::X509Pointer;
|
||||
using ncrypto::X509View;
|
||||
using v8::Array;
|
||||
using v8::ArrayBufferView;
|
||||
using v8::Boolean;
|
||||
using v8::Context;
|
||||
using v8::DontDelete;
|
||||
using v8::EscapableHandleScope;
|
||||
using v8::Exception;
|
||||
using v8::External;
|
||||
using v8::FunctionCallbackInfo;
|
||||
|
|
@ -57,7 +59,9 @@ using v8::Integer;
|
|||
using v8::Isolate;
|
||||
using v8::JustVoid;
|
||||
using v8::Local;
|
||||
using v8::LocalVector;
|
||||
using v8::Maybe;
|
||||
using v8::MaybeLocal;
|
||||
using v8::Nothing;
|
||||
using v8::Object;
|
||||
using v8::PropertyAttribute;
|
||||
|
|
@ -672,9 +676,6 @@ static void LoadCertsFromDir(std::vector<X509*>* certs,
|
|||
return;
|
||||
}
|
||||
|
||||
uv_fs_t stats_req;
|
||||
auto cleanup_stats =
|
||||
OnScopeLeave([&stats_req]() { uv_fs_req_cleanup(&stats_req); });
|
||||
for (;;) {
|
||||
uv_dirent_t ent;
|
||||
|
||||
|
|
@ -691,12 +692,14 @@ static void LoadCertsFromDir(std::vector<X509*>* certs,
|
|||
return;
|
||||
}
|
||||
|
||||
uv_fs_t stats_req;
|
||||
std::string file_path = std::string(cert_dir) + "/" + ent.name;
|
||||
int stats_r = uv_fs_stat(nullptr, &stats_req, file_path.c_str(), nullptr);
|
||||
if (stats_r == 0 &&
|
||||
(static_cast<uv_stat_t*>(stats_req.ptr)->st_mode & S_IFREG)) {
|
||||
LoadCertsFromFile(certs, file_path.c_str());
|
||||
}
|
||||
uv_fs_req_cleanup(&stats_req);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -775,7 +778,7 @@ static std::vector<X509*> InitializeSystemStoreCertificates() {
|
|||
return system_store_certs;
|
||||
}
|
||||
|
||||
static std::vector<X509*>& GetSystemStoreRootCertificates() {
|
||||
static std::vector<X509*>& GetSystemStoreCACertificates() {
|
||||
// Use function-local static to guarantee thread safety.
|
||||
static std::vector<X509*> system_store_certs =
|
||||
InitializeSystemStoreCertificates();
|
||||
|
|
@ -847,7 +850,7 @@ X509_STORE* NewRootCertStore() {
|
|||
CHECK_EQ(1, X509_STORE_add_cert(store, cert));
|
||||
}
|
||||
if (per_process::cli_options->use_system_ca) {
|
||||
for (X509* cert : GetSystemStoreRootCertificates()) {
|
||||
for (X509* cert : GetSystemStoreCACertificates()) {
|
||||
CHECK_EQ(1, X509_STORE_add_cert(store, cert));
|
||||
}
|
||||
}
|
||||
|
|
@ -869,7 +872,7 @@ void CleanupCachedRootCertificates() {
|
|||
}
|
||||
}
|
||||
if (has_cached_system_root_certs.load()) {
|
||||
for (X509* cert : GetSystemStoreRootCertificates()) {
|
||||
for (X509* cert : GetSystemStoreCACertificates()) {
|
||||
X509_free(cert);
|
||||
}
|
||||
}
|
||||
|
|
@ -881,7 +884,7 @@ void CleanupCachedRootCertificates() {
|
|||
}
|
||||
}
|
||||
|
||||
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
|
||||
void GetBundledRootCertificates(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Local<Value> result[arraysize(root_certs)];
|
||||
|
||||
|
|
@ -898,6 +901,58 @@ void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
|
|||
Array::New(env->isolate(), result, arraysize(root_certs)));
|
||||
}
|
||||
|
||||
MaybeLocal<Array> X509sToArrayOfStrings(Environment* env,
|
||||
const std::vector<X509*>& certs) {
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
EscapableHandleScope scope(env->isolate());
|
||||
|
||||
LocalVector<Value> result(env->isolate(), certs.size());
|
||||
for (size_t i = 0; i < certs.size(); ++i) {
|
||||
X509View view(certs[i]);
|
||||
auto pem_bio = view.toPEM();
|
||||
if (!pem_bio) {
|
||||
ThrowCryptoError(env, ERR_get_error(), "X509 to PEM conversion");
|
||||
return MaybeLocal<Array>();
|
||||
}
|
||||
|
||||
char* pem_data = nullptr;
|
||||
auto pem_size = BIO_get_mem_data(pem_bio.get(), &pem_data);
|
||||
if (pem_size <= 0 || !pem_data) {
|
||||
ThrowCryptoError(env, ERR_get_error(), "Reading PEM data");
|
||||
return MaybeLocal<Array>();
|
||||
}
|
||||
// PEM is base64-encoded, so it must be one-byte.
|
||||
if (!String::NewFromOneByte(env->isolate(),
|
||||
reinterpret_cast<uint8_t*>(pem_data),
|
||||
v8::NewStringType::kNormal,
|
||||
pem_size)
|
||||
.ToLocal(&result[i])) {
|
||||
return MaybeLocal<Array>();
|
||||
}
|
||||
}
|
||||
return scope.Escape(Array::New(env->isolate(), result.data(), result.size()));
|
||||
}
|
||||
|
||||
void GetSystemCACertificates(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Local<Array> results;
|
||||
if (X509sToArrayOfStrings(env, GetSystemStoreCACertificates())
|
||||
.ToLocal(&results)) {
|
||||
args.GetReturnValue().Set(results);
|
||||
}
|
||||
}
|
||||
|
||||
void GetExtraCACertificates(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
if (extra_root_certs_file.empty()) {
|
||||
return args.GetReturnValue().Set(Array::New(env->isolate()));
|
||||
}
|
||||
Local<Array> results;
|
||||
if (X509sToArrayOfStrings(env, GetExtraCACertificates()).ToLocal(&results)) {
|
||||
args.GetReturnValue().Set(results);
|
||||
}
|
||||
}
|
||||
|
||||
bool SecureContext::HasInstance(Environment* env, const Local<Value>& value) {
|
||||
return GetConstructorTemplate(env)->HasInstance(value);
|
||||
}
|
||||
|
|
@ -981,8 +1036,14 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
|
|||
GetConstructorTemplate(env),
|
||||
SetConstructorFunctionFlag::NONE);
|
||||
|
||||
SetMethodNoSideEffect(context,
|
||||
target,
|
||||
"getBundledRootCertificates",
|
||||
GetBundledRootCertificates);
|
||||
SetMethodNoSideEffect(
|
||||
context, target, "getRootCertificates", GetRootCertificates);
|
||||
context, target, "getSystemCACertificates", GetSystemCACertificates);
|
||||
SetMethodNoSideEffect(
|
||||
context, target, "getExtraCACertificates", GetExtraCACertificates);
|
||||
}
|
||||
|
||||
void SecureContext::RegisterExternalReferences(
|
||||
|
|
@ -1022,7 +1083,9 @@ void SecureContext::RegisterExternalReferences(
|
|||
|
||||
registry->Register(CtxGetter);
|
||||
|
||||
registry->Register(GetRootCertificates);
|
||||
registry->Register(GetBundledRootCertificates);
|
||||
registry->Register(GetSystemCACertificates);
|
||||
registry->Register(GetExtraCACertificates);
|
||||
}
|
||||
|
||||
SecureContext* SecureContext::Create(Environment* env) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
'use strict';
|
||||
const crypto = require('crypto');
|
||||
const net = require('net');
|
||||
const assert = require('assert');
|
||||
|
||||
exports.ccs = Buffer.from('140303000101', 'hex');
|
||||
|
||||
|
|
@ -173,4 +174,16 @@ function P_hash(algo, secret, seed, size) {
|
|||
return result;
|
||||
}
|
||||
|
||||
exports.assertIsCAArray = function assertIsCAArray(certs) {
|
||||
assert(Array.isArray(certs));
|
||||
assert(certs.length > 0);
|
||||
|
||||
// The certificates looks PEM-encoded.
|
||||
for (const cert of certs) {
|
||||
const trimmed = cert.trim();
|
||||
assert.match(trimmed, /^-----BEGIN CERTIFICATE-----/);
|
||||
assert.match(trimmed, /-----END CERTIFICATE-----$/);
|
||||
}
|
||||
};
|
||||
|
||||
exports.TestTLSSocket = TestTLSSocket;
|
||||
|
|
|
|||
17
test/fixtures/tls-check-extra-ca-certificates.js
vendored
Normal file
17
test/fixtures/tls-check-extra-ca-certificates.js
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
const tls = require('tls');
|
||||
const assert = require('assert');
|
||||
|
||||
const defaultSet = new Set(tls.getCACertificates('default'));
|
||||
const extraSet = new Set(tls.getCACertificates('extra'));
|
||||
console.log(defaultSet.size, 'default certificates');
|
||||
console.log(extraSet.size, 'extra certificates')
|
||||
|
||||
// Parent process is supposed to call this with
|
||||
// NODE_EXTRA_CA_CERTS set to test/fixtures/keys/ca1-cert.pem.
|
||||
assert.strictEqual(extraSet.size, 1);
|
||||
|
||||
// Check that default set is a super set of extra set.
|
||||
assert.deepStrictEqual(defaultSet.intersection(extraSet),
|
||||
extraSet);
|
||||
11
test/fixtures/tls-get-ca-certificates.js
vendored
Normal file
11
test/fixtures/tls-get-ca-certificates.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
// This fixture just writes tls.getCACertificates() outputs to process.env.CA_OUT
|
||||
const tls = require('tls');
|
||||
const fs = require('fs');
|
||||
const assert = require('assert');
|
||||
assert(process.env.CA_TYPE);
|
||||
assert(process.env.CA_OUT);
|
||||
|
||||
const certs = tls.getCACertificates(process.env.CA_TYPE);
|
||||
|
||||
fs.writeFileSync(process.env.CA_OUT, JSON.stringify(certs), 'utf8');
|
||||
17
test/parallel/test-tls-get-ca-certificates-bundled-subset.js
Normal file
17
test/parallel/test-tls-get-ca-certificates-bundled-subset.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
'use strict';
|
||||
// Flags: --no-use-openssl-ca
|
||||
// This tests that tls.getCACertificates() returns the bundled
|
||||
// certificates correctly.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
|
||||
const defaultSet = new Set(tls.getCACertificates('default'));
|
||||
const bundledSet = new Set(tls.getCACertificates('bundled'));
|
||||
|
||||
// When --use-openssl-ca is false (i.e. bundled CA is sued),
|
||||
// default is a superset of bundled certificates.
|
||||
assert.deepStrictEqual(defaultSet.intersection(bundledSet), bundledSet);
|
||||
20
test/parallel/test-tls-get-ca-certificates-bundled.js
Normal file
20
test/parallel/test-tls-get-ca-certificates-bundled.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
// This tests that tls.getCACertificates() returns the bundled
|
||||
// certificates correctly.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const { assertIsCAArray } = require('../common/tls');
|
||||
|
||||
const certs = tls.getCACertificates('bundled');
|
||||
assertIsCAArray(certs);
|
||||
|
||||
// It's the same as tls.rootCertificates - both are
|
||||
// Mozilla CA stores across platform.
|
||||
assert.strictEqual(certs, tls.rootCertificates);
|
||||
|
||||
// It's cached on subsequent accesses.
|
||||
assert.strictEqual(certs, tls.getCACertificates('bundled'));
|
||||
20
test/parallel/test-tls-get-ca-certificates-default.js
Normal file
20
test/parallel/test-tls-get-ca-certificates-default.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
// This tests that tls.getCACertificates() returns the default
|
||||
// certificates correctly.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const { assertIsCAArray } = require('../common/tls');
|
||||
|
||||
const certs = tls.getCACertificates();
|
||||
assertIsCAArray(certs);
|
||||
|
||||
const certs2 = tls.getCACertificates('default');
|
||||
assert.strictEqual(certs, certs2);
|
||||
|
||||
// It's cached on subsequent accesses.
|
||||
assert.strictEqual(certs, tls.getCACertificates('default'));
|
||||
20
test/parallel/test-tls-get-ca-certificates-error.js
Normal file
20
test/parallel/test-tls-get-ca-certificates-error.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
// This tests that tls.getCACertificates() throws error when being
|
||||
// passed an invalid argument.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
|
||||
for (const invalid of [1, null, () => {}, true]) {
|
||||
assert.throws(() => tls.getCACertificates(invalid), {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
}
|
||||
|
||||
assert.throws(() => tls.getCACertificates('test'), {
|
||||
code: 'ERR_INVALID_ARG_VALUE'
|
||||
});
|
||||
29
test/parallel/test-tls-get-ca-certificates-extra-empty.js
Normal file
29
test/parallel/test-tls-get-ca-certificates-extra-empty.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
// This tests that tls.getCACertificates('extra') returns an empty
|
||||
// array if NODE_EXTRA_CA_CERTS is empty.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const fs = require('fs');
|
||||
|
||||
const assert = require('assert');
|
||||
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
tmpdir.refresh();
|
||||
const certsJSON = tmpdir.resolve('certs.json');
|
||||
|
||||
// If NODE_EXTRA_CA_CERTS is not set, it should be an empty array.
|
||||
spawnSyncAndExitWithoutError(process.execPath, [fixtures.path('tls-get-ca-certificates.js')], {
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_EXTRA_CA_CERTS: undefined,
|
||||
CA_TYPE: 'extra',
|
||||
CA_OUT: certsJSON,
|
||||
}
|
||||
});
|
||||
|
||||
const parsed = JSON.parse(fs.readFileSync(certsJSON, 'utf-8'));
|
||||
assert.deepStrictEqual(parsed, []);
|
||||
16
test/parallel/test-tls-get-ca-certificates-extra-subset.js
Normal file
16
test/parallel/test-tls-get-ca-certificates-extra-subset.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
// This tests that tls.getCACertificates('defulat') returns a superset
|
||||
// of tls.getCACertificates('extra') when NODE_EXTRA_CA_CERTS is used.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
spawnSyncAndExitWithoutError(process.execPath, [fixtures.path('tls-check-extra-ca-certificates.js')], {
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_EXTRA_CA_CERTS: fixtures.path('keys', 'ca1-cert.pem'),
|
||||
}
|
||||
});
|
||||
29
test/parallel/test-tls-get-ca-certificates-extra.js
Normal file
29
test/parallel/test-tls-get-ca-certificates-extra.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
// This tests that tls.getCACertificates('extra') returns the extra
|
||||
// certificates from NODE_EXTRA_CA_CERTS correctly.
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const fs = require('fs');
|
||||
const assert = require('assert');
|
||||
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
tmpdir.refresh();
|
||||
const certsJSON = tmpdir.resolve('certs.json');
|
||||
|
||||
// If NODE_EXTRA_CA_CERTS is set, it should contain a list of certificates.
|
||||
spawnSyncAndExitWithoutError(process.execPath, [fixtures.path('tls-get-ca-certificates.js')], {
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_EXTRA_CA_CERTS: fixtures.path('keys', 'ca1-cert.pem'),
|
||||
CA_TYPE: 'extra',
|
||||
CA_OUT: certsJSON,
|
||||
}
|
||||
});
|
||||
|
||||
const parsed = JSON.parse(fs.readFileSync(certsJSON, 'utf-8'));
|
||||
assert.deepStrictEqual(parsed, [fixtures.readKey('ca1-cert.pem', 'utf8')]);
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
// This tests that tls.getCACertificates() returns the system
|
||||
// certificates correctly when --use-system-ca is disabled.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const fs = require('fs');
|
||||
|
||||
const assert = require('assert');
|
||||
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tls = require('tls');
|
||||
|
||||
const certs = tls.getCACertificates('system');
|
||||
if (certs.length === 0) {
|
||||
common.skip('No trusted system certificates installed. Skip.');
|
||||
}
|
||||
|
||||
tmpdir.refresh();
|
||||
const certsJSON = tmpdir.resolve('certs.json');
|
||||
spawnSyncAndExitWithoutError(process.execPath, [
|
||||
'--no-use-system-ca',
|
||||
fixtures.path('tls-get-ca-certificates.js'),
|
||||
], {
|
||||
env: {
|
||||
...process.env,
|
||||
CA_TYPE: 'system',
|
||||
CA_OUT: certsJSON,
|
||||
}
|
||||
});
|
||||
|
||||
const parsed = JSON.parse(fs.readFileSync(certsJSON, 'utf-8'));
|
||||
assert.deepStrictEqual(parsed, certs);
|
||||
32
test/parallel/test-tls-get-ca-certificates-system.js
Normal file
32
test/parallel/test-tls-get-ca-certificates-system.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
// Flags: --use-system-ca
|
||||
// This tests that tls.getCACertificates() returns the system
|
||||
// certificates correctly.
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const { assertIsCAArray } = require('../common/tls');
|
||||
|
||||
const systemCerts = tls.getCACertificates('system');
|
||||
// Usually Windows come with some certificates installed by default.
|
||||
// This can't be said about other systems, in that case check that
|
||||
// at least systemCerts is an array (which may be empty).
|
||||
if (common.isWindows) {
|
||||
assertIsCAArray(systemCerts);
|
||||
} else {
|
||||
assert(Array.isArray(systemCerts));
|
||||
}
|
||||
|
||||
// When --use-system-ca is true, default is a superset of system
|
||||
// certificates.
|
||||
const defaultCerts = tls.getCACertificates('default');
|
||||
assert(defaultCerts.length >= systemCerts.length);
|
||||
const defaultSet = new Set(defaultCerts);
|
||||
const systemSet = new Set(systemCerts);
|
||||
assert.deepStrictEqual(defaultSet.intersection(systemSet), systemSet);
|
||||
|
||||
// It's cached on subsequent accesses.
|
||||
assert.strictEqual(systemCerts, tls.getCACertificates('system'));
|
||||
|
|
@ -68,16 +68,22 @@ class SimpleTestCase(test.TestCase):
|
|||
# is currently when Node is configured --without-ssl and the tests should
|
||||
# still be runnable but skip any tests that require ssl (which includes the
|
||||
# inspector related tests). Also, if there is no ssl support the options
|
||||
# '--use-bundled-ca' and '--use-openssl-ca' will also cause a similar
|
||||
# failure so such tests are also skipped.
|
||||
# '--use-bundled-ca', '--use-system-ca' and '--use-openssl-ca' will also
|
||||
# cause a similar failure so such tests are also skipped.
|
||||
if (any(flag.startswith('--inspect') for flag in flags) and
|
||||
not self.context.v8_enable_inspector):
|
||||
print(': Skipping as node was compiled without inspector support')
|
||||
elif (('--use-bundled-ca' in flags or
|
||||
'--use-openssl-ca' in flags or
|
||||
'--use-system-ca' in flags or
|
||||
'--no-use-bundled-ca' in flags or
|
||||
'--no-use-openssl-ca' in flags or
|
||||
'--no-use-system-ca' in flags or
|
||||
'--tls-v1.0' in flags or
|
||||
'--tls-v1.1' in flags) and
|
||||
not self.context.node_has_crypto):
|
||||
# TODO(joyeecheung): add this to the status file variables so that we can
|
||||
# list the crypto dependency in the status files explicitly instead.
|
||||
print(': Skipping as node was compiled without crypto support')
|
||||
else:
|
||||
result += flags
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user