tls: add min/max protocol version options
The existing secureProtocol option only allows setting the allowed protocol to a specific version, or setting it to "all supported versions". It also used obscure strings based on OpenSSL C API functions. Directly setting the min or max is easier to use and explain. PR-URL: https://github.com/nodejs/node/pull/24405 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Rod Vagg <rod@vagg.org>
This commit is contained in:
parent
160ac0f325
commit
f512f5ea13
@ -1655,6 +1655,17 @@ recommended to use 2048 bits or larger for stronger security.
|
|||||||
A TLS/SSL handshake timed out. In this case, the server must also abort the
|
A TLS/SSL handshake timed out. In this case, the server must also abort the
|
||||||
connection.
|
connection.
|
||||||
|
|
||||||
|
<a id="ERR_TLS_INVALID_PROTOCOL_VERSION"></a>
|
||||||
|
### ERR_TLS_INVALID_PROTOCOL_VERSION
|
||||||
|
|
||||||
|
Valid TLS protocol versions are `'TLSv1'`, `'TLSv1.1'`, or `'TLSv1.2'`.
|
||||||
|
|
||||||
|
<a id="ERR_TLS_PROTOCOL_VERSION_CONFLICT"></a>
|
||||||
|
### ERR_TLS_PROTOCOL_VERSION_CONFLICT
|
||||||
|
|
||||||
|
Attempting to set a TLS protocol `minVersion` or `maxVersion` conflicts with an
|
||||||
|
attempt to set the `secureProtocol` explicitly. Use one mechanism or the other.
|
||||||
|
|
||||||
<a id="ERR_TLS_RENEGOTIATE"></a>
|
<a id="ERR_TLS_RENEGOTIATE"></a>
|
||||||
### ERR_TLS_RENEGOTIATE
|
### ERR_TLS_RENEGOTIATE
|
||||||
|
|
||||||
|
@ -1070,6 +1070,10 @@ changes:
|
|||||||
pr-url: https://github.com/nodejs/node/pull/4099
|
pr-url: https://github.com/nodejs/node/pull/4099
|
||||||
description: The `ca` option can now be a single string containing multiple
|
description: The `ca` option can now be a single string containing multiple
|
||||||
CA certificates.
|
CA certificates.
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: REPLACEME
|
||||||
|
description: The `minVersion` and `maxVersion` can be used to restrict
|
||||||
|
the allowed TLS protocol versions.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* `options` {Object}
|
* `options` {Object}
|
||||||
@ -1130,6 +1134,16 @@ changes:
|
|||||||
passphrase: <string>]}`. The object form can only occur in an array.
|
passphrase: <string>]}`. The object form can only occur in an array.
|
||||||
`object.passphrase` is optional. Encrypted keys will be decrypted with
|
`object.passphrase` is optional. Encrypted keys will be decrypted with
|
||||||
`object.passphrase` if provided, or `options.passphrase` if it is not.
|
`object.passphrase` if provided, or `options.passphrase` if it is not.
|
||||||
|
* `maxVersion` {string} Optionally set the maximum TLS version to allow. One
|
||||||
|
of `TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`. Cannot be specified along with the
|
||||||
|
`secureProtocol` option, use one or the other. **Default:** `'TLSv1.2'`.
|
||||||
|
* `minVersion` {string} Optionally set the minimum TLS version to allow. One
|
||||||
|
of `TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`. Cannot be specified along with the
|
||||||
|
`secureProtocol` option, use one or the other. It is not recommended to use
|
||||||
|
less than TLSv1.2, but it may be required for interoperability.
|
||||||
|
**Default:** `'TLSv1.2'`, unless changed using CLI options. Using
|
||||||
|
`--tls-v1.0` changes the default to `'TLSv1'`. Using `--tls-v1.1` changes
|
||||||
|
the default to `'TLSv1.1'`.
|
||||||
* `passphrase` {string} Shared passphrase used for a single private key and/or
|
* `passphrase` {string} Shared passphrase used for a single private key and/or
|
||||||
a PFX.
|
a PFX.
|
||||||
* `pfx` {string|string[]|Buffer|Buffer[]|Object[]} PFX or PKCS12 encoded
|
* `pfx` {string|string[]|Buffer|Buffer[]|Object[]} PFX or PKCS12 encoded
|
||||||
@ -1150,10 +1164,7 @@ changes:
|
|||||||
example, use `'TLSv1_1_method'` to force TLS version 1.1, or `'TLS_method'`
|
example, use `'TLSv1_1_method'` to force TLS version 1.1, or `'TLS_method'`
|
||||||
to allow any TLS protocol version. It is not recommended to use TLS versions
|
to allow any TLS protocol version. It is not recommended to use TLS versions
|
||||||
less than 1.2, but it may be required for interoperability. **Default:**
|
less than 1.2, but it may be required for interoperability. **Default:**
|
||||||
`'TLSv1_2_method'`, unless changed using CLI options. Using the `--tlsv1.0`
|
none, see `minVersion`.
|
||||||
CLI option is like `'TLS_method'` except protocols earlier than TLSv1.0 are
|
|
||||||
not allowed, and using the `--tlsv1.1` CLI option is like `'TLS_method'`
|
|
||||||
except that protocols earlier than TLSv1.1 are not allowed.
|
|
||||||
* `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.
|
||||||
|
|
||||||
|
@ -26,22 +26,46 @@ const { isArrayBufferView } = require('internal/util/types');
|
|||||||
const tls = require('tls');
|
const tls = require('tls');
|
||||||
const {
|
const {
|
||||||
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED,
|
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED,
|
||||||
ERR_INVALID_ARG_TYPE
|
ERR_INVALID_ARG_TYPE,
|
||||||
|
ERR_TLS_INVALID_PROTOCOL_VERSION,
|
||||||
|
ERR_TLS_PROTOCOL_VERSION_CONFLICT,
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
|
const {
|
||||||
const { SSL_OP_CIPHER_SERVER_PREFERENCE } = internalBinding('constants').crypto;
|
SSL_OP_CIPHER_SERVER_PREFERENCE,
|
||||||
|
TLS1_VERSION,
|
||||||
|
TLS1_1_VERSION,
|
||||||
|
TLS1_2_VERSION,
|
||||||
|
} = internalBinding('constants').crypto;
|
||||||
|
|
||||||
// Lazily loaded from internal/crypto/util.
|
// Lazily loaded from internal/crypto/util.
|
||||||
let toBuf = null;
|
let toBuf = null;
|
||||||
|
|
||||||
|
function toV(which, v, def) {
|
||||||
|
if (v == null) v = def;
|
||||||
|
if (v === 'TLSv1') return TLS1_VERSION;
|
||||||
|
if (v === 'TLSv1.1') return TLS1_1_VERSION;
|
||||||
|
if (v === 'TLSv1.2') return TLS1_2_VERSION;
|
||||||
|
throw new ERR_TLS_INVALID_PROTOCOL_VERSION(v, which);
|
||||||
|
}
|
||||||
|
|
||||||
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
|
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
|
||||||
function SecureContext(secureProtocol, secureOptions) {
|
function SecureContext(secureProtocol, secureOptions, minVersion, maxVersion) {
|
||||||
if (!(this instanceof SecureContext)) {
|
if (!(this instanceof SecureContext)) {
|
||||||
return new SecureContext(secureProtocol, secureOptions);
|
return new SecureContext(secureProtocol, secureOptions, minVersion,
|
||||||
|
maxVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secureProtocol) {
|
||||||
|
if (minVersion != null)
|
||||||
|
throw new ERR_TLS_PROTOCOL_VERSION_CONFLICT(minVersion, secureProtocol);
|
||||||
|
if (maxVersion != null)
|
||||||
|
throw new ERR_TLS_PROTOCOL_VERSION_CONFLICT(maxVersion, secureProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.context = new NativeSecureContext();
|
this.context = new NativeSecureContext();
|
||||||
this.context.init(secureProtocol);
|
this.context.init(secureProtocol,
|
||||||
|
toV('minimum', minVersion, tls.DEFAULT_MIN_VERSION),
|
||||||
|
toV('maximum', maxVersion, tls.DEFAULT_MAX_VERSION));
|
||||||
|
|
||||||
if (secureOptions) this.context.setOptions(secureOptions);
|
if (secureOptions) this.context.setOptions(secureOptions);
|
||||||
}
|
}
|
||||||
@ -66,7 +90,8 @@ exports.createSecureContext = function createSecureContext(options) {
|
|||||||
if (options.honorCipherOrder)
|
if (options.honorCipherOrder)
|
||||||
secureOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
secureOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||||
|
|
||||||
const c = new SecureContext(options.secureProtocol, secureOptions);
|
const c = new SecureContext(options.secureProtocol, secureOptions,
|
||||||
|
options.minVersion, options.maxVersion);
|
||||||
var i;
|
var i;
|
||||||
var val;
|
var val;
|
||||||
|
|
||||||
|
@ -918,6 +918,16 @@ Server.prototype.setSecureContext = function(options) {
|
|||||||
else
|
else
|
||||||
this.ca = undefined;
|
this.ca = undefined;
|
||||||
|
|
||||||
|
if (options.minVersion)
|
||||||
|
this.minVersion = options.minVersion;
|
||||||
|
else
|
||||||
|
this.minVersion = undefined;
|
||||||
|
|
||||||
|
if (options.maxVersion)
|
||||||
|
this.maxVersion = options.maxVersion;
|
||||||
|
else
|
||||||
|
this.maxVersion = undefined;
|
||||||
|
|
||||||
if (options.secureProtocol)
|
if (options.secureProtocol)
|
||||||
this.secureProtocol = options.secureProtocol;
|
this.secureProtocol = options.secureProtocol;
|
||||||
else
|
else
|
||||||
@ -974,6 +984,8 @@ Server.prototype.setSecureContext = function(options) {
|
|||||||
ciphers: this.ciphers,
|
ciphers: this.ciphers,
|
||||||
ecdhCurve: this.ecdhCurve,
|
ecdhCurve: this.ecdhCurve,
|
||||||
dhparam: this.dhparam,
|
dhparam: this.dhparam,
|
||||||
|
minVersion: this.minVersion,
|
||||||
|
maxVersion: this.maxVersion,
|
||||||
secureProtocol: this.secureProtocol,
|
secureProtocol: this.secureProtocol,
|
||||||
secureOptions: this.secureOptions,
|
secureOptions: this.secureOptions,
|
||||||
honorCipherOrder: this.honorCipherOrder,
|
honorCipherOrder: this.honorCipherOrder,
|
||||||
@ -1026,6 +1038,8 @@ Server.prototype.setOptions = util.deprecate(function(options) {
|
|||||||
if (options.clientCertEngine)
|
if (options.clientCertEngine)
|
||||||
this.clientCertEngine = options.clientCertEngine;
|
this.clientCertEngine = options.clientCertEngine;
|
||||||
if (options.ca) this.ca = options.ca;
|
if (options.ca) this.ca = options.ca;
|
||||||
|
if (options.minVersion) this.minVersion = options.minVersion;
|
||||||
|
if (options.maxVersion) this.maxVersion = options.maxVersion;
|
||||||
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
|
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
|
||||||
if (options.crl) this.crl = options.crl;
|
if (options.crl) this.crl = options.crl;
|
||||||
if (options.ciphers) this.ciphers = options.ciphers;
|
if (options.ciphers) this.ciphers = options.ciphers;
|
||||||
|
@ -186,6 +186,14 @@ Agent.prototype.getName = function getName(options) {
|
|||||||
if (options.servername && options.servername !== options.host)
|
if (options.servername && options.servername !== options.host)
|
||||||
name += options.servername;
|
name += options.servername;
|
||||||
|
|
||||||
|
name += ':';
|
||||||
|
if (options.minVersion)
|
||||||
|
name += options.minVersion;
|
||||||
|
|
||||||
|
name += ':';
|
||||||
|
if (options.maxVersion)
|
||||||
|
name += options.maxVersion;
|
||||||
|
|
||||||
name += ':';
|
name += ':';
|
||||||
if (options.secureProtocol)
|
if (options.secureProtocol)
|
||||||
name += options.secureProtocol;
|
name += options.secureProtocol;
|
||||||
|
@ -861,6 +861,10 @@ E('ERR_TLS_CERT_ALTNAME_INVALID',
|
|||||||
'Hostname/IP does not match certificate\'s altnames: %s', Error);
|
'Hostname/IP does not match certificate\'s altnames: %s', Error);
|
||||||
E('ERR_TLS_DH_PARAM_SIZE', 'DH parameter size %s is less than 2048', Error);
|
E('ERR_TLS_DH_PARAM_SIZE', 'DH parameter size %s is less than 2048', Error);
|
||||||
E('ERR_TLS_HANDSHAKE_TIMEOUT', 'TLS handshake timeout', Error);
|
E('ERR_TLS_HANDSHAKE_TIMEOUT', 'TLS handshake timeout', Error);
|
||||||
|
E('ERR_TLS_INVALID_PROTOCOL_VERSION',
|
||||||
|
'%j is not a valid %s TLS protocol version', TypeError);
|
||||||
|
E('ERR_TLS_PROTOCOL_VERSION_CONFLICT',
|
||||||
|
'TLS protocol version %j conflicts with secureProtocol %j', TypeError);
|
||||||
E('ERR_TLS_RENEGOTIATE', 'Attempt to renegotiate TLS session failed', Error);
|
E('ERR_TLS_RENEGOTIATE', 'Attempt to renegotiate TLS session failed', Error);
|
||||||
E('ERR_TLS_RENEGOTIATION_DISABLED',
|
E('ERR_TLS_RENEGOTIATION_DISABLED',
|
||||||
'TLS session renegotiation disabled for this socket', Error);
|
'TLS session renegotiation disabled for this socket', Error);
|
||||||
|
10
lib/tls.js
10
lib/tls.js
@ -31,6 +31,7 @@ internalUtil.assertCrypto();
|
|||||||
const { isArrayBufferView } = require('internal/util/types');
|
const { isArrayBufferView } = require('internal/util/types');
|
||||||
|
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
|
const { getOptionValue } = require('internal/options');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
const binding = internalBinding('crypto');
|
const binding = internalBinding('crypto');
|
||||||
const { Buffer } = require('buffer');
|
const { Buffer } = require('buffer');
|
||||||
@ -53,6 +54,15 @@ exports.DEFAULT_CIPHERS =
|
|||||||
|
|
||||||
exports.DEFAULT_ECDH_CURVE = 'auto';
|
exports.DEFAULT_ECDH_CURVE = 'auto';
|
||||||
|
|
||||||
|
exports.DEFAULT_MAX_VERSION = 'TLSv1.2';
|
||||||
|
|
||||||
|
if (getOptionValue('--tls-v1.0'))
|
||||||
|
exports.DEFAULT_MIN_VERSION = 'TLSv1';
|
||||||
|
else if (getOptionValue('--tls-v1.1'))
|
||||||
|
exports.DEFAULT_MIN_VERSION = 'TLSv1.1';
|
||||||
|
else
|
||||||
|
exports.DEFAULT_MIN_VERSION = 'TLSv1.2';
|
||||||
|
|
||||||
exports.getCiphers = internalUtil.cachedResult(
|
exports.getCiphers = internalUtil.cachedResult(
|
||||||
() => internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true)
|
() => internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true)
|
||||||
);
|
);
|
||||||
|
@ -1237,6 +1237,10 @@ void DefineCryptoConstants(Local<Object> target) {
|
|||||||
NODE_DEFINE_STRING_CONSTANT(target,
|
NODE_DEFINE_STRING_CONSTANT(target,
|
||||||
"defaultCipherList",
|
"defaultCipherList",
|
||||||
per_process_opts->tls_cipher_list.c_str());
|
per_process_opts->tls_cipher_list.c_str());
|
||||||
|
|
||||||
|
NODE_DEFINE_CONSTANT(target, TLS1_VERSION);
|
||||||
|
NODE_DEFINE_CONSTANT(target, TLS1_1_VERSION);
|
||||||
|
NODE_DEFINE_CONSTANT(target, TLS1_2_VERSION);
|
||||||
#endif
|
#endif
|
||||||
NODE_DEFINE_CONSTANT(target, INT_MAX);
|
NODE_DEFINE_CONSTANT(target, INT_MAX);
|
||||||
}
|
}
|
||||||
|
@ -405,14 +405,15 @@ 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 = TLS1_2_VERSION;
|
CHECK_EQ(args.Length(), 3);
|
||||||
int max_version = 0;
|
CHECK(args[1]->IsInt32());
|
||||||
|
CHECK(args[2]->IsInt32());
|
||||||
|
|
||||||
|
int min_version = args[1].As<Int32>()->Value();
|
||||||
|
int max_version = args[2].As<Int32>()->Value();
|
||||||
const SSL_METHOD* method = TLS_method();
|
const SSL_METHOD* method = TLS_method();
|
||||||
|
|
||||||
if (env->options()->tls_v1_1) min_version = TLS1_1_VERSION;
|
if (args[0]->IsString()) {
|
||||||
if (env->options()->tls_v1_0) min_version = TLS1_VERSION;
|
|
||||||
|
|
||||||
if (args.Length() == 1 && args[0]->IsString()) {
|
|
||||||
const node::Utf8Value sslmethod(env->isolate(), args[0]);
|
const node::Utf8Value sslmethod(env->isolate(), args[0]);
|
||||||
|
|
||||||
// Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends
|
// Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends
|
||||||
@ -509,6 +510,7 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
SSL_CTX_set_min_proto_version(sc->ctx_.get(), min_version);
|
SSL_CTX_set_min_proto_version(sc->ctx_.get(), min_version);
|
||||||
SSL_CTX_set_max_proto_version(sc->ctx_.get(), max_version);
|
SSL_CTX_set_max_proto_version(sc->ctx_.get(), max_version);
|
||||||
|
|
||||||
// OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was
|
// OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was
|
||||||
// exposed in the public API. To retain compatibility, install a callback
|
// exposed in the public API. To retain compatibility, install a callback
|
||||||
// which restores the old algorithm.
|
// which restores the old algorithm.
|
||||||
|
21
test/fixtures/tls-connect.js
vendored
21
test/fixtures/tls-connect.js
vendored
@ -46,6 +46,7 @@ exports.connect = function connect(options, callback) {
|
|||||||
const client = {};
|
const client = {};
|
||||||
const pair = { server, client };
|
const pair = { server, client };
|
||||||
|
|
||||||
|
try {
|
||||||
tls.createServer(options.server, function(conn) {
|
tls.createServer(options.server, function(conn) {
|
||||||
server.conn = conn;
|
server.conn = conn;
|
||||||
conn.pipe(conn);
|
conn.pipe(conn);
|
||||||
@ -57,6 +58,7 @@ exports.connect = function connect(options, callback) {
|
|||||||
port: this.address().port,
|
port: this.address().port,
|
||||||
}, options.client);
|
}, options.client);
|
||||||
|
|
||||||
|
try {
|
||||||
tls.connect(optClient)
|
tls.connect(optClient)
|
||||||
.on('secureConnect', function() {
|
.on('secureConnect', function() {
|
||||||
client.conn = this;
|
client.conn = this;
|
||||||
@ -67,7 +69,22 @@ exports.connect = function connect(options, callback) {
|
|||||||
client.conn = this;
|
client.conn = this;
|
||||||
maybeCallback();
|
maybeCallback();
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
client.err = err;
|
||||||
|
// The server won't get a connection, we are done.
|
||||||
|
callback(err, pair, cleanup);
|
||||||
|
callback = null;
|
||||||
|
}
|
||||||
|
}).on('tlsClientError', function(err, sock) {
|
||||||
|
server.conn = sock;
|
||||||
|
server.err = err;
|
||||||
|
maybeCallback();
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// Invalid options can throw, report the error.
|
||||||
|
pair.server.err = err;
|
||||||
|
callback(err, pair, () => {});
|
||||||
|
}
|
||||||
|
|
||||||
function maybeCallback() {
|
function maybeCallback() {
|
||||||
if (!callback)
|
if (!callback)
|
||||||
@ -76,6 +93,8 @@ exports.connect = function connect(options, callback) {
|
|||||||
const err = pair.client.err || pair.server.err;
|
const err = pair.client.err || pair.server.err;
|
||||||
callback(err, pair, cleanup);
|
callback(err, pair, cleanup);
|
||||||
callback = null;
|
callback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
if (server.server)
|
if (server.server)
|
||||||
@ -84,5 +103,3 @@ exports.connect = function connect(options, callback) {
|
|||||||
client.conn.end();
|
client.conn.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,7 +12,7 @@ const agent = new https.Agent();
|
|||||||
// empty options
|
// empty options
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
agent.getName({}),
|
agent.getName({}),
|
||||||
'localhost:::::::::::::::::'
|
'localhost:::::::::::::::::::'
|
||||||
);
|
);
|
||||||
|
|
||||||
// pass all options arguments
|
// pass all options arguments
|
||||||
@ -40,5 +40,5 @@ const options = {
|
|||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
agent.getName(options),
|
agent.getName(options),
|
||||||
'0.0.0.0:443:192.168.1.1:ca:cert:dynamic:ciphers:key:pfx:false:localhost:' +
|
'0.0.0.0:443:192.168.1.1:ca:cert:dynamic:ciphers:key:pfx:false:localhost:' +
|
||||||
'secureProtocol:c,r,l:false:ecdhCurve:dhparam:0:sessionIdContext'
|
'::secureProtocol:c,r,l:false:ecdhCurve:dhparam:0:sessionIdContext'
|
||||||
);
|
);
|
||||||
|
15
test/parallel/test-tls-cli-min-version-1.0.js
Normal file
15
test/parallel/test-tls-cli-min-version-1.0.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Flags: --tls-v1.0 --tls-v1.1
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
if (!common.hasCrypto) common.skip('missing crypto');
|
||||||
|
|
||||||
|
// Check that `node --tls-v1.0` is supported, and overrides --tls-v1.1.
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const tls = require('tls');
|
||||||
|
|
||||||
|
assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.2');
|
||||||
|
assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1');
|
||||||
|
|
||||||
|
// Check the min-max version protocol versions against these CLI settings.
|
||||||
|
require('./test-tls-min-max-version.js');
|
15
test/parallel/test-tls-cli-min-version-1.1.js
Normal file
15
test/parallel/test-tls-cli-min-version-1.1.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Flags: --tls-v1.1
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
if (!common.hasCrypto) common.skip('missing crypto');
|
||||||
|
|
||||||
|
// Check that node `--tls-v1.1` is supported.
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const tls = require('tls');
|
||||||
|
|
||||||
|
assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.2');
|
||||||
|
assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1.1');
|
||||||
|
|
||||||
|
// Check the min-max version protocol versions against these CLI settings.
|
||||||
|
require('./test-tls-min-max-version.js');
|
146
test/parallel/test-tls-min-max-version.js
Normal file
146
test/parallel/test-tls-min-max-version.js
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
|
// Check min/max protocol versions.
|
||||||
|
|
||||||
|
const {
|
||||||
|
assert, connect, keys, tls
|
||||||
|
} = require(fixtures.path('tls-connect'));
|
||||||
|
const DEFAULT_MIN_VERSION = tls.DEFAULT_MIN_VERSION;
|
||||||
|
|
||||||
|
function test(cmin, cmax, cprot, smin, smax, sprot, expect) {
|
||||||
|
connect({
|
||||||
|
client: {
|
||||||
|
checkServerIdentity: (servername, cert) => { },
|
||||||
|
ca: `${keys.agent1.cert}\n${keys.agent6.ca}`,
|
||||||
|
minVersion: cmin,
|
||||||
|
maxVersion: cmax,
|
||||||
|
secureProtocol: cprot,
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
cert: keys.agent6.cert,
|
||||||
|
key: keys.agent6.key,
|
||||||
|
minVersion: smin,
|
||||||
|
maxVersion: smax,
|
||||||
|
secureProtocol: sprot,
|
||||||
|
},
|
||||||
|
}, common.mustCall((err, pair, cleanup) => {
|
||||||
|
if (expect && !expect.match(/^TLS/)) {
|
||||||
|
assert(err.message.match(expect));
|
||||||
|
return cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expect) {
|
||||||
|
assert.ifError(pair.server.err);
|
||||||
|
assert.ifError(pair.client.err);
|
||||||
|
assert(pair.server.conn);
|
||||||
|
assert(pair.client.conn);
|
||||||
|
assert.strictEqual(pair.client.conn.getProtocol(), expect);
|
||||||
|
assert.strictEqual(pair.server.conn.getProtocol(), expect);
|
||||||
|
return cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pair.server.err);
|
||||||
|
assert(pair.client.err);
|
||||||
|
return cleanup();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const U = undefined;
|
||||||
|
|
||||||
|
// Default protocol is TLSv1.2.
|
||||||
|
test(U, U, U, U, U, U, 'TLSv1.2');
|
||||||
|
|
||||||
|
// Insecure or invalid protocols cannot be enabled.
|
||||||
|
test(U, U, U, U, U, 'SSLv2_method', 'SSLv2 methods disabled');
|
||||||
|
test(U, U, U, U, U, 'SSLv3_method', 'SSLv3 methods disabled');
|
||||||
|
test(U, U, 'SSLv2_method', U, U, U, 'SSLv2 methods disabled');
|
||||||
|
test(U, U, 'SSLv3_method', U, U, U, 'SSLv3 methods disabled');
|
||||||
|
test(U, U, 'hokey-pokey', U, U, U, 'Unknown method');
|
||||||
|
test(U, U, U, U, U, 'hokey-pokey', 'Unknown method');
|
||||||
|
|
||||||
|
// Cannot use secureProtocol and min/max versions simultaneously.
|
||||||
|
test(U, U, U, U, 'TLSv1.2', 'TLS1_2_method', 'conflicts with secureProtocol');
|
||||||
|
test(U, U, U, 'TLSv1.2', U, 'TLS1_2_method', 'conflicts with secureProtocol');
|
||||||
|
test(U, 'TLSv1.2', 'TLS1_2_method', U, U, U, 'conflicts with secureProtocol');
|
||||||
|
test('TLSv1.2', U, 'TLS1_2_method', U, U, U, 'conflicts with secureProtocol');
|
||||||
|
|
||||||
|
// TLS_method means "any supported protocol".
|
||||||
|
test(U, U, 'TLSv1_2_method', U, U, 'TLS_method', 'TLSv1.2');
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, 'TLS_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_method', U, U, 'TLS_method', 'TLSv1');
|
||||||
|
test(U, U, 'TLS_method', U, U, 'TLSv1_2_method', 'TLSv1.2');
|
||||||
|
test(U, U, 'TLS_method', U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'TLS_method', U, U, 'TLSv1_method', 'TLSv1');
|
||||||
|
|
||||||
|
// SSLv23 also means "any supported protocol" greater than the default
|
||||||
|
// minimum (which is configurable via command line).
|
||||||
|
test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method', 'TLSv1.2');
|
||||||
|
|
||||||
|
if (DEFAULT_MIN_VERSION === 'TLSv1.2') {
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method', null);
|
||||||
|
test(U, U, 'TLSv1_method', U, U, 'SSLv23_method', null);
|
||||||
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', null);
|
||||||
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEFAULT_MIN_VERSION === 'TLSv1.1') {
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_method', U, U, 'SSLv23_method', null);
|
||||||
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEFAULT_MIN_VERSION === 'TLSv1') {
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_method', U, U, 'SSLv23_method', 'TLSv1');
|
||||||
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', 'TLSv1');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSv1 thru TLSv1.2 are only supported with explicit configuration with API or
|
||||||
|
// CLI (--tls-v1.0 and --tls-v1.1).
|
||||||
|
test(U, U, 'TLSv1_2_method', U, U, 'TLSv1_2_method', 'TLSv1.2');
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_method', U, U, 'TLSv1_method', 'TLSv1');
|
||||||
|
|
||||||
|
// The default default.
|
||||||
|
if (DEFAULT_MIN_VERSION === 'TLSv1.2') {
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, U, null);
|
||||||
|
test(U, U, 'TLSv1_method', U, U, U, null);
|
||||||
|
test(U, U, U, U, U, 'TLSv1_1_method', null);
|
||||||
|
test(U, U, U, U, U, 'TLSv1_method', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default with --tls-v1.1.
|
||||||
|
if (DEFAULT_MIN_VERSION === 'TLSv1.1') {
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, U, 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_method', U, U, U, null);
|
||||||
|
test(U, U, U, U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test(U, U, U, U, U, 'TLSv1_method', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default with --tls-v1.0.
|
||||||
|
if (DEFAULT_MIN_VERSION === 'TLSv1') {
|
||||||
|
test(U, U, 'TLSv1_1_method', U, U, U, 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_method', U, U, U, 'TLSv1');
|
||||||
|
test(U, U, U, U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test(U, U, U, U, U, 'TLSv1_method', 'TLSv1');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLS min/max are respected when set with no secureProtocol.
|
||||||
|
test('TLSv1', 'TLSv1.2', U, U, U, 'TLSv1_method', 'TLSv1');
|
||||||
|
test('TLSv1', 'TLSv1.2', U, U, U, 'TLSv1_1_method', 'TLSv1.1');
|
||||||
|
test('TLSv1', 'TLSv1.2', U, U, U, 'TLSv1_2_method', 'TLSv1.2');
|
||||||
|
|
||||||
|
test(U, U, 'TLSv1_method', 'TLSv1', 'TLSv1.2', U, 'TLSv1');
|
||||||
|
test(U, U, 'TLSv1_1_method', 'TLSv1', 'TLSv1.2', U, 'TLSv1.1');
|
||||||
|
test(U, U, 'TLSv1_2_method', 'TLSv1', 'TLSv1.2', U, 'TLSv1.2');
|
||||||
|
|
||||||
|
test('TLSv1', 'TLSv1.1', U, 'TLSv1', 'TLSv1.2', U, 'TLSv1.1');
|
||||||
|
test('TLSv1', 'TLSv1.2', U, 'TLSv1', 'TLSv1.1', U, 'TLSv1.1');
|
||||||
|
test('TLSv1', 'TLSv1', U, 'TLSv1', 'TLSv1.1', U, 'TLSv1');
|
||||||
|
test('TLSv1', 'TLSv1.2', U, 'TLSv1', 'TLSv1', U, 'TLSv1');
|
||||||
|
test('TLSv1.1', 'TLSv1.1', U, 'TLSv1', 'TLSv1.2', U, 'TLSv1.1');
|
||||||
|
test('TLSv1', 'TLSv1.2', U, 'TLSv1.1', 'TLSv1.1', U, 'TLSv1.1');
|
Loading…
x
Reference in New Issue
Block a user