Skip to content

Commit 1cfb457

Browse files
sam-githubBethGriggs
authored andcommittedFeb 24, 2020
tls: support TLS min/max protocol defaults in CLI
Backport CLI switches for default TLS versions: - `--tls-max-v1.2` - `--tls-min-v1.0` - `--tls-min-v1.1` - `--tls-min-v1.2` PR-URL: #27946 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com> Reviewed-By: Shelley Vohr <codebytere@gmail.com>
1 parent f1a8791 commit 1cfb457

12 files changed

+174
-10
lines changed
 

Diff for: ‎doc/api/cli.md

+32
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,38 @@ added: v4.0.0
359359
Specify an alternative default TLS cipher list. Requires Node.js to be built
360360
with crypto support (default).
361361

362+
### `--tls-max-v1.2`
363+
<!-- YAML
364+
added: REPLACEME
365+
-->
366+
367+
Does nothing, [`tls.DEFAULT_MAX_VERSION`][] is always 'TLSv1.2'. Exists for
368+
compatibility with Node.js 11.x and higher.
369+
370+
### `--tls-min-v1.0`
371+
<!-- YAML
372+
added: REPLACEME
373+
-->
374+
375+
Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1'. Use for compatibility with
376+
old TLS clients or servers.
377+
378+
### `--tls-min-v1.1`
379+
<!-- YAML
380+
added: REPLACEME
381+
-->
382+
383+
Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1.1'. Use for compatibility
384+
with old TLS clients or servers.
385+
386+
### `--tls-min-v1.2`
387+
<!-- YAML
388+
added: REPLACEME
389+
-->
390+
391+
Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1.2'. Use this to disable
392+
support for earlier TLS versions, which are less secure.
393+
362394
### `--trace-deprecation`
363395
<!-- YAML
364396
added: v0.8.0

Diff for: ‎doc/api/tls.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,11 @@ added: v10.6.0
13781378
* {string} The default value of the `minVersion` option of
13791379
[`tls.createSecureContext()`][]. It can be assigned any of the supported TLS
13801380
protocol versions, `TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`.
1381-
**Default:** `'TLSv1'`.
1381+
**Default:** `'TLSv1'`, unless changed using CLI options. Using
1382+
`--tls-min-v1.0` sets the default to `'TLSv1'`. Using `--tls-min-v1.1` sets
1383+
the default to `'TLSv1.1'`. Using `--tls-min-v1.2` sets the default to
1384+
`'TLSv1.2'`. If multiple of the options are provided, the lowest minimum is
1385+
used.
13821386

13831387
## Deprecated APIs
13841388

Diff for: ‎doc/node.1

+16
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,22 @@ Specify process.title on startup.
198198
Specify an alternative default TLS cipher list.
199199
Requires Node.js to be built with crypto support. (Default)
200200
.
201+
.It Fl -tls-max-v1.2
202+
Does nothing, the default maxVersion is always 'TLSv1.2'. Exists for
203+
compatibility with Node.js 11.x and higher.
204+
.
205+
.It Fl -tls-min-v1.0
206+
Set default minVersion to 'TLSv1'. Use for compatibility with old TLS clients
207+
or servers.
208+
.
209+
.It Fl -tls-min-v1.1
210+
Set default minVersion to 'TLSv1.1'. Use for compatibility with old TLS clients
211+
or servers.
212+
.
213+
.It Fl -tls-min-v1.2
214+
Set default minVersion to 'TLSv1.2'. Use to disable support for earlier TLS
215+
versions, which are less secure.
216+
.
201217
.It Fl -trace-deprecation
202218
Print stack traces for deprecations.
203219
.

Diff for: ‎lib/tls.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ internalUtil.assertCrypto();
3131
const { isUint8Array } = require('internal/util/types');
3232

3333
const net = require('net');
34+
const { getOptionValue } = require('internal/options');
3435
const url = require('url');
3536
const binding = internalBinding('crypto');
3637
const { Buffer } = require('buffer');
@@ -52,9 +53,19 @@ exports.DEFAULT_CIPHERS =
5253

5354
exports.DEFAULT_ECDH_CURVE = 'auto';
5455

55-
exports.DEFAULT_MAX_VERSION = 'TLSv1.2';
56-
57-
exports.DEFAULT_MIN_VERSION = 'TLSv1';
56+
if (getOptionValue('--tls-min-v1.0'))
57+
exports.DEFAULT_MIN_VERSION = 'TLSv1';
58+
else if (getOptionValue('--tls-min-v1.1'))
59+
exports.DEFAULT_MIN_VERSION = 'TLSv1.1';
60+
else if (getOptionValue('--tls-min-v1.2'))
61+
exports.DEFAULT_MIN_VERSION = 'TLSv1.2';
62+
else
63+
exports.DEFAULT_MIN_VERSION = 'TLSv1';
64+
65+
if (getOptionValue('--tls-max-v1.2'))
66+
exports.DEFAULT_MAX_VERSION = 'TLSv1.2';
67+
else
68+
exports.DEFAULT_MAX_VERSION = 'TLSv1.2'; // Will depend on node version.
5869

5970
exports.getCiphers = internalUtil.cachedResult(
6071
() => internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true)

Diff for: ‎src/node_options.cc

+17
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,23 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
210210

211211
Insert(&DebugOptionsParser::instance,
212212
&EnvironmentOptions::get_debug_options);
213+
214+
AddOption("--tls-min-v1.0",
215+
"set default TLS minimum to TLSv1.0 (default: TLSv1.0)",
216+
&EnvironmentOptions::tls_min_v1_0,
217+
kAllowedInEnvironment);
218+
AddOption("--tls-min-v1.1",
219+
"set default TLS minimum to TLSv1.1 (default: TLSv1.0)",
220+
&EnvironmentOptions::tls_min_v1_1,
221+
kAllowedInEnvironment);
222+
AddOption("--tls-min-v1.2",
223+
"set default TLS minimum to TLSv1.2 (default: TLSv1.0)",
224+
&EnvironmentOptions::tls_min_v1_2,
225+
kAllowedInEnvironment);
226+
AddOption("--tls-max-v1.2",
227+
"set default TLS maximum to TLSv1.2 (default: TLSv1.2)",
228+
&EnvironmentOptions::tls_max_v1_2,
229+
kAllowedInEnvironment);
213230
}
214231

215232
EnvironmentOptionsParser EnvironmentOptionsParser::instance;

Diff for: ‎src/node_options.h

+4
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ class EnvironmentOptions : public Options {
9494
bool force_repl = false;
9595

9696
bool insecure_http_parser = false;
97+
bool tls_min_v1_0 = false;
98+
bool tls_min_v1_1 = false;
99+
bool tls_min_v1_2 = false;
100+
bool tls_max_v1_2 = false;
97101

98102
std::vector<std::string> preload_modules;
99103

Diff for: ‎test/parallel/test-process-env-allowed-flags.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ require('../common');
5151
// assert all "canonical" flags begin with dash(es)
5252
{
5353
process.allowedNodeEnvironmentFlags.forEach((flag) => {
54-
assert(/^--?[a-z28_-]+$/.test(flag), `Unexpected format for flag ${flag}`);
54+
assert(/^--?[a-z.0-9_-]+$/.test(flag), `Unexpected format for flag ${flag}`);
5555
});
5656
}
5757

Diff for: ‎test/parallel/test-tls-cli-max-version-1.2.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Flags: --tls-max-v1.2
2+
'use strict';
3+
const common = require('../common');
4+
if (!common.hasCrypto) common.skip('missing crypto');
5+
6+
// Check that node `--tls-max-v1.2` is supported.
7+
8+
const assert = require('assert');
9+
const tls = require('tls');
10+
11+
assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.2');
12+
assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1');
13+
14+
// Check the min-max version protocol versions against these CLI settings.
15+
require('./test-tls-min-max-version.js');

Diff for: ‎test/parallel/test-tls-cli-min-version-1.0.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Flags: --tls-min-v1.0 --tls-min-v1.1
2+
'use strict';
3+
const common = require('../common');
4+
if (!common.hasCrypto) common.skip('missing crypto');
5+
6+
// Check that `node --tls-v1.0` is supported, and overrides --tls-v1.1.
7+
8+
const assert = require('assert');
9+
const tls = require('tls');
10+
11+
assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.2');
12+
assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1');
13+
14+
// Check the min-max version protocol versions against these CLI settings.
15+
require('./test-tls-min-max-version.js');

Diff for: ‎test/parallel/test-tls-cli-min-version-1.1.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Flags: --tls-min-v1.1
2+
'use strict';
3+
const common = require('../common');
4+
if (!common.hasCrypto) common.skip('missing crypto');
5+
6+
// Check that node `--tls-v1.1` is supported.
7+
8+
const assert = require('assert');
9+
const tls = require('tls');
10+
11+
assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.2');
12+
assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1.1');
13+
14+
// Check the min-max version protocol versions against these CLI settings.
15+
require('./test-tls-min-max-version.js');

Diff for: ‎test/parallel/test-tls-cli-min-version-1.2.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Flags: --tls-min-v1.2
2+
'use strict';
3+
const common = require('../common');
4+
if (!common.hasCrypto) common.skip('missing crypto');
5+
6+
// Check that node `--tls-min-v1.2` is supported.
7+
8+
const assert = require('assert');
9+
const tls = require('tls');
10+
11+
assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.2');
12+
assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1.2');
13+
14+
// Check the min-max version protocol versions against these CLI settings.
15+
require('./test-tls-min-max-version.js');

Diff for: ‎test/parallel/test-tls-min-max-version.js

+25-5
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ const {
1010
const DEFAULT_MIN_VERSION = tls.DEFAULT_MIN_VERSION;
1111
const DEFAULT_MAX_VERSION = tls.DEFAULT_MAX_VERSION;
1212

13-
// For v11.x, the default is fixed and cannot be changed via CLI.
14-
assert.strictEqual(DEFAULT_MIN_VERSION, 'TLSv1');
15-
1613
function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) {
1714
assert(proto || cerr || serr, 'test missing any expectations');
15+
// Report where test was called from. Strip leading garbage from
16+
// at Object.<anonymous> (file:line)
17+
// from the stack location, we only want the file:line part.
18+
const where = (new Error()).stack.split('\n')[2].replace(/[^(]*/, '');
1819
connect({
1920
client: {
2021
checkServerIdentity: (servername, cert) => { },
@@ -34,9 +35,28 @@ function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) {
3435
function u(_) { return _ === undefined ? 'U' : _; }
3536
console.log('test:', u(cmin), u(cmax), u(cprot), u(smin), u(smax), u(sprot),
3637
'expect', u(proto), u(cerr), u(serr));
38+
console.log(' ', where);
3739
if (!proto) {
38-
console.log('client', pair.client.err ? pair.client.err.code : undefined);
39-
console.log('server', pair.server.err ? pair.server.err.code : undefined);
40+
function setCode(err) {
41+
if (!err) return;
42+
if (err.code) return;
43+
// Convert error message to a .code, because .code wasn't always present
44+
// in older versions.
45+
if (/unsupported protocol/.test(err.message))
46+
err.code = 'ERR_SSL_UNSUPPORTED_PROTOCOL';
47+
else if (/wrong version number/.test(err.message))
48+
err.code = 'ERR_SSL_WRONG_VERSION_NUMBER';
49+
else if (/version too low/.test(err.message))
50+
err.code = 'ERR_SSL_UNSUPPORTED_PROTOCOL';
51+
else
52+
err.code = err.message;
53+
}
54+
setCode(pair.server.err);
55+
setCode(pair.client.err);
56+
console.log('client', pair.client.err ? pair.client.err.code :
57+
pair.client.err);
58+
console.log('server', pair.server.err ? pair.server.err.code :
59+
pair.server.err);
4060
// 11.x doesn't have https://github.com/nodejs/node/pull/24729
4161
if (cerr === 'ERR_TLS_INVALID_PROTOCOL_METHOD' &&
4262
pair.client.err &&

0 commit comments

Comments
 (0)
Please sign in to comment.