tls: expose built-in root certificates
Fixes: https://github.com/nodejs/node/issues/25824 PR-URL: https://github.com/nodejs/node/pull/26415 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com>
This commit is contained in:
parent
cc7e15f850
commit
f1a3968a01
@ -1384,6 +1384,7 @@ 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`, followed by the
|
||||
@ -1599,6 +1600,17 @@ TLSv1.2 and below.
|
||||
console.log(tls.getCiphers()); // ['aes128-gcm-sha256', 'aes128-sha', ...]
|
||||
```
|
||||
|
||||
## tls.rootCertificates
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* {string[]}
|
||||
|
||||
An immutable array of strings representing the root certificates (in PEM format)
|
||||
used for verifying peer certificates. This is the default value of the `ca`
|
||||
option to [`tls.createSecureContext()`].
|
||||
|
||||
## tls.DEFAULT_ECDH_CURVE
|
||||
<!-- YAML
|
||||
added: v0.11.13
|
||||
@ -1784,6 +1796,7 @@ where `secureSocket` has the same API as `pair.cleartext`.
|
||||
[`tls.createSecurePair()`]: #tls_tls_createsecurepair_context_isserver_requestcert_rejectunauthorized_options
|
||||
[`tls.createServer()`]: #tls_tls_createserver_options_secureconnectionlistener
|
||||
[`tls.getCiphers()`]: #tls_tls_getciphers
|
||||
[`tls.rootCertificates`]: #tls_tls_rootcertificates
|
||||
[Chrome's 'modern cryptography' setting]: https://www.chromium.org/Home/chromium-security/education/tls#TOC-Cipher-Suites
|
||||
[DHE]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
|
||||
[ECDHE]: https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman
|
||||
|
22
lib/tls.js
22
lib/tls.js
@ -21,6 +21,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Object } = primordials;
|
||||
|
||||
const {
|
||||
ERR_TLS_CERT_ALTNAME_INVALID,
|
||||
ERR_OUT_OF_RANGE
|
||||
@ -33,7 +35,7 @@ const { isArrayBufferView } = require('internal/util/types');
|
||||
const net = require('net');
|
||||
const { getOptionValue } = require('internal/options');
|
||||
const url = require('url');
|
||||
const binding = internalBinding('crypto');
|
||||
const { getRootCertificates, getSSLCiphers } = internalBinding('crypto');
|
||||
const { Buffer } = require('buffer');
|
||||
const EventEmitter = require('events');
|
||||
const { URL } = require('internal/url');
|
||||
@ -76,9 +78,25 @@ else
|
||||
|
||||
|
||||
exports.getCiphers = internalUtil.cachedResult(
|
||||
() => internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true)
|
||||
() => internalUtil.filterDuplicateStrings(getSSLCiphers(), true)
|
||||
);
|
||||
|
||||
let rootCertificates;
|
||||
|
||||
function cacheRootCertificates() {
|
||||
rootCertificates = Object.freeze(getRootCertificates());
|
||||
}
|
||||
|
||||
Object.defineProperty(exports, 'rootCertificates', {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: () => {
|
||||
// Out-of-line caching to promote inlining the getter.
|
||||
if (!rootCertificates) cacheRootCertificates();
|
||||
return rootCertificates;
|
||||
},
|
||||
});
|
||||
|
||||
// Convert protocols array into valid OpenSSL protocols list
|
||||
// ("\x06spdy/2\x08http/1.1\x08http/1.0")
|
||||
function convertProtocols(protocols) {
|
||||
|
@ -944,6 +944,24 @@ static X509_STORE* NewRootCertStore() {
|
||||
}
|
||||
|
||||
|
||||
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Local<Array> result = Array::New(env->isolate(), arraysize(root_certs));
|
||||
|
||||
for (size_t i = 0; i < arraysize(root_certs); i++) {
|
||||
Local<Value> value;
|
||||
if (!String::NewFromOneByte(env->isolate(),
|
||||
reinterpret_cast<const uint8_t*>(root_certs[i]),
|
||||
NewStringType::kNormal).ToLocal(&value) ||
|
||||
!result->Set(env->context(), i, value).FromMaybe(false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(result);
|
||||
}
|
||||
|
||||
|
||||
void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
@ -6870,6 +6888,8 @@ void Initialize(Local<Object> target,
|
||||
env->SetMethodNoSideEffect(target, "certVerifySpkac", VerifySpkac);
|
||||
env->SetMethodNoSideEffect(target, "certExportPublicKey", ExportPublicKey);
|
||||
env->SetMethodNoSideEffect(target, "certExportChallenge", ExportChallenge);
|
||||
env->SetMethodNoSideEffect(target, "getRootCertificates",
|
||||
GetRootCertificates);
|
||||
// Exposed for testing purposes only.
|
||||
env->SetMethodNoSideEffect(target, "isExtraRootCertsFileLoaded",
|
||||
IsExtraRootCertsFileLoaded);
|
||||
|
File diff suppressed because it is too large
Load Diff
31
test/parallel/test-tls-root-certificates.js
Normal file
31
test/parallel/test-tls-root-certificates.js
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto) common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
|
||||
assert(Array.isArray(tls.rootCertificates));
|
||||
assert(tls.rootCertificates.length > 0);
|
||||
|
||||
// Getter should return the same object.
|
||||
assert.strictEqual(tls.rootCertificates, tls.rootCertificates);
|
||||
|
||||
// Array is immutable...
|
||||
assert.throws(() => tls.rootCertificates[0] = 0, /TypeError/);
|
||||
assert.throws(() => tls.rootCertificates.sort(), /TypeError/);
|
||||
|
||||
// ...and so is the property.
|
||||
assert.throws(() => tls.rootCertificates = 0, /TypeError/);
|
||||
|
||||
// Does not contain duplicates.
|
||||
assert.strictEqual(tls.rootCertificates.length,
|
||||
new Set(tls.rootCertificates).size);
|
||||
|
||||
assert(tls.rootCertificates.every((s) => {
|
||||
return s.startsWith('-----BEGIN CERTIFICATE-----\n');
|
||||
}));
|
||||
|
||||
assert(tls.rootCertificates.every((s) => {
|
||||
return s.endsWith('\n-----END CERTIFICATE-----');
|
||||
}));
|
@ -265,7 +265,7 @@ while (<TXT>) {
|
||||
$encoded =~ s/(.{1,${opt_w}})/"$1\\n"\n/g;
|
||||
my $pem = "\"-----BEGIN CERTIFICATE-----\\n\"\n"
|
||||
. $encoded
|
||||
. "\"-----END CERTIFICATE-----\\n\",\n";
|
||||
. "\"-----END CERTIFICATE-----\",\n";
|
||||
print CRT "\n/* $caname */\n";
|
||||
|
||||
my $maxStringLength = length($caname);
|
||||
|
Loading…
x
Reference in New Issue
Block a user