tls: disable TLS v1.0 and v1.1 by default

Refs: https://blog.mozilla.org/security/2018/10/15/removing-old-versions-of-tls/

PR-URL: https://github.com/nodejs/node/pull/23814
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Ben Noordhuis 2018-10-22 11:40:28 +02:00 committed by Anna Henningsen
parent fcd7a72428
commit 60eca6a5d4
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
11 changed files with 57 additions and 5 deletions

View File

@ -342,6 +342,22 @@ added: v4.0.0
Specify an alternative default TLS cipher list. Requires Node.js to be built Specify an alternative default TLS cipher list. Requires Node.js to be built
with crypto support (default). with crypto support (default).
### `--tls-v1.0`
<!-- YAML
added: REPLACEME
-->
Enable TLSv1.0. This should only be used for compatibility with old TLS
clients or servers.
### `--tls-v1.1`
<!-- YAML
added: REPLACEME
-->
Enable TLSv1.1. This should only be used for compatibility with old TLS
clients or servers.
### `--trace-deprecation` ### `--trace-deprecation`
<!-- YAML <!-- YAML
added: v0.8.0 added: v0.8.0

View File

@ -1102,7 +1102,8 @@ changes:
[OpenSSL Options][]. [OpenSSL Options][].
* `secureProtocol` {string} SSL method to use. The possible values are listed * `secureProtocol` {string} SSL method to use. The possible values are listed
as [SSL_METHODS][], use the function names as strings. For example, as [SSL_METHODS][], use the function names as strings. For example,
`'TLSv1_2_method'` to force TLS version 1.2. **Default:** `'TLS_method'`. `'TLSv1_2_method'` to force TLS version 1.2.
**Default:** `'TLSv1_2_method'`.
* `sessionIdContext` {string} Opaque identifier used by servers to ensure * `sessionIdContext` {string} Opaque identifier used by servers to ensure
session state is not shared between applications. Unused by clients. session state is not shared between applications. Unused by clients.

View File

@ -183,6 +183,14 @@ Specify process.title on startup.
Specify an alternative default TLS cipher list. Specify an alternative default TLS cipher list.
Requires Node.js to be built with crypto support. (Default) Requires Node.js to be built with crypto support. (Default)
. .
.It Fl -tls-v1.0
Enable TLSv1.0. This should only be used for compatibility with old TLS
clients or servers.
.
.It Fl -tls-v1.1
Enable TLSv1.1. This should only be used for compatibility with old TLS
clients or servers.
.
.It Fl -trace-deprecation .It Fl -trace-deprecation
Print stack traces for deprecations. Print stack traces for deprecations.
. .

View File

@ -396,10 +396,13 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder());
Environment* env = sc->env(); Environment* env = sc->env();
int min_version = 0; int min_version = TLS1_2_VERSION;
int max_version = 0; int max_version = 0;
const SSL_METHOD* method = TLS_method(); const SSL_METHOD* method = TLS_method();
if (env->options()->tls_v1_1) min_version = TLS1_1_VERSION;
if (env->options()->tls_v1_0) min_version = TLS1_VERSION;
if (args.Length() == 1 && args[0]->IsString()) { if (args.Length() == 1 && args[0]->IsString()) {
const node::Utf8Value sslmethod(env->isolate(), args[0]); const node::Utf8Value sslmethod(env->isolate(), args[0]);
@ -425,6 +428,9 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
method = TLS_server_method(); method = TLS_server_method();
} else if (strcmp(*sslmethod, "SSLv23_client_method") == 0) { } else if (strcmp(*sslmethod, "SSLv23_client_method") == 0) {
method = TLS_client_method(); method = TLS_client_method();
} else if (strcmp(*sslmethod, "TLS_method") == 0) {
min_version = 0;
max_version = 0;
} else if (strcmp(*sslmethod, "TLSv1_method") == 0) { } else if (strcmp(*sslmethod, "TLSv1_method") == 0) {
min_version = TLS1_VERSION; min_version = TLS1_VERSION;
max_version = TLS1_VERSION; max_version = TLS1_VERSION;

View File

@ -189,6 +189,17 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--napi-modules", "", NoOp{}, kAllowedInEnvironment); AddOption("--napi-modules", "", NoOp{}, kAllowedInEnvironment);
#if HAVE_OPENSSL
AddOption("--tls-v1.0",
"enable TLSv1.0",
&EnvironmentOptions::tls_v1_0,
kAllowedInEnvironment);
AddOption("--tls-v1.1",
"enable TLSv1.1",
&EnvironmentOptions::tls_v1_1,
kAllowedInEnvironment);
#endif
Insert(&DebugOptionsParser::instance, Insert(&DebugOptionsParser::instance,
&EnvironmentOptions::get_debug_options); &EnvironmentOptions::get_debug_options);
} }

View File

@ -92,6 +92,11 @@ class EnvironmentOptions : public Options {
bool print_eval = false; bool print_eval = false;
bool force_repl = false; bool force_repl = false;
#if HAVE_OPENSSL
bool tls_v1_0 = false;
bool tls_v1_1 = false;
#endif
std::vector<std::string> preload_modules; std::vector<std::string> preload_modules;
std::vector<std::string> user_argv; std::vector<std::string> user_argv;

View File

@ -1,3 +1,4 @@
// Flags: --tls-v1.1
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
if (!common.hasCrypto) if (!common.hasCrypto)
@ -34,7 +35,7 @@ const updatedValues = new Map([
['ecdhCurve', 'secp384r1'], ['ecdhCurve', 'secp384r1'],
['honorCipherOrder', true], ['honorCipherOrder', true],
['secureOptions', crypto.constants.SSL_OP_CIPHER_SERVER_PREFERENCE], ['secureOptions', crypto.constants.SSL_OP_CIPHER_SERVER_PREFERENCE],
['secureProtocol', 'TLSv1_method'], ['secureProtocol', 'TLSv1_1_method'],
['sessionIdContext', 'sessionIdContext'], ['sessionIdContext', 'sessionIdContext'],
]); ]);

View File

@ -1,3 +1,4 @@
// Flags: --tls-v1.0
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');

View File

@ -51,7 +51,8 @@ require('../common');
// assert all "canonical" flags begin with dash(es) // assert all "canonical" flags begin with dash(es)
{ {
process.allowedNodeEnvironmentFlags.forEach((flag) => { process.allowedNodeEnvironmentFlags.forEach((flag) => {
assert(/^--?[a-z8_-]+$/.test(flag), `Unexpected format for flag ${flag}`); assert(/^--?[a-z0-9._-]+$/.test(flag),
`Unexpected format for flag ${flag}`);
}); });
} }

View File

@ -17,6 +17,7 @@ const clientConfigs = [
]; ];
const serverConfig = { const serverConfig = {
secureProtocol: 'TLS_method',
key: fixtures.readSync('/keys/agent2-key.pem'), key: fixtures.readSync('/keys/agent2-key.pem'),
cert: fixtures.readSync('/keys/agent2-cert.pem') cert: fixtures.readSync('/keys/agent2-cert.pem')
}; };

View File

@ -48,7 +48,8 @@ function doTest(testOptions, callback) {
cert, cert,
ca: [cert], ca: [cert],
requestCert: true, requestCert: true,
rejectUnauthorized: false rejectUnauthorized: false,
secureProtocol: 'TLS_method',
}; };
let requestCount = 0; let requestCount = 0;
let resumeCount = 0; let resumeCount = 0;