pr-url: https://github.com/nodejs/node/pull/4099
description: The `ca` option can now be a single string containing multiple
CA certificates.
+ - version: XXX
+ pr-url: XXX
+ description: The `min_version` and `max_version` can be used to restrict
+ the allowed TLS protocol versions.
-->
* `options` {Object}
passphrase: <string>]}`. The object form can only occur in an array.
`object.passphrase` is optional. Encrypted keys will be decrypted with
`object.passphrase` if provided, or `options.passphrase` if it is not.
+ * `max_version`: Maximum TLS version to allow. One of `'TLSv1.3'`, `TLSv1.2'`,
+ `'TLSv1.1'`, or `'TLSv1'`. Optional, defaults to `'TLSv1.2'`. Note that
+ TLS1.3 is not currently supported, do not attempt to allow it. If
+ `secureProtocol` is used to select a specific protocol version,
+ `max_version` will be ignored.
+ * `min_version`: Minimum TLS version to allow. One of `'TLSv1.3'`, `TLSv1.2'`,
+ `'TLSv1.1'`, or `'TLSv1'`. Optional, defaults to `'TLSv1'`. Note that
+ TLS1.3 is not currently supported, do not attempt to allow it. If
+ `secureProtocol` is used to select a specific protocol version,
+ `min_version` will be ignored.
* `passphrase` {string} Shared passphrase used for a single private key and/or
a PFX.
* `pfx` {string|string[]|Buffer|Buffer[]|Object[]} PFX or PKCS12 encoded
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
-function SecureContext(secureProtocol, secureOptions, context) {
+function SecureContext(secureProtocol, secureOptions, context,
+ min_version, max_version) {
if (!(this instanceof SecureContext)) {
- return new SecureContext(secureProtocol, secureOptions, context);
+ return new SecureContext(secureProtocol, secureOptions, context,
+ min_version, max_version);
}
if (context) {
this.context = new NativeSecureContext();
if (secureProtocol) {
- this.context.init(secureProtocol);
+ this.context.init(min_version, max_version, secureProtocol);
} else {
- this.context.init();
+ this.context.init(min_version, max_version);
}
}
if (options.honorCipherOrder)
secureOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
- const c = new SecureContext(options.secureProtocol, secureOptions, context);
+ const c = new SecureContext(options.secureProtocol, secureOptions, context,
+ options.min_version || tls.DEFAULT_MIN_VERSION,
+ options.max_version || tls.DEFAULT_MAX_VERSION);
var i;
var val;
ciphers: this.ciphers,
ecdhCurve: this.ecdhCurve,
dhparam: this.dhparam,
+ min_version: this.min_version,
+ max_version: this.max_version,
secureProtocol: this.secureProtocol,
secureOptions: this.secureOptions,
honorCipherOrder: this.honorCipherOrder,
if (options.clientCertEngine)
this.clientCertEngine = options.clientCertEngine;
if (options.ca) this.ca = options.ca;
+ if (options.min_version) this.min_version = options.min_version;
+ if (options.max_version) this.max_version = options.max_version;
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
if (options.crl) this.crl = options.crl;
if (options.ciphers) this.ciphers = options.ciphers;
if (options.servername && options.servername !== options.host)
name += options.servername;
+ name += ':';
+ if (options.min_version)
+ name += options.min_version;
+
+ name += ':';
+ if (options.max_version)
+ name += options.max_version;
+
name += ':';
if (options.secureProtocol)
name += options.secureProtocol;
exports.DEFAULT_ECDH_CURVE = 'auto';
+// Disable TLS1.3 by default. The only reason for enabling it for now is to work
+// on fixing cipher suite incompatibilities with TLS1.2 that prevent node from
+// working with TLS1.3 in OpenSSL 1.1.1.
+exports.DEFAULT_MAX_VERSION = 'TLSv1.2';
+
+exports.DEFAULT_MIN_VERSION = 'TLSv1';
+
exports.getCiphers = internalUtil.cachedResult(
() => internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true)
);
}
+int string_to_tls_protocol(const char* version_str) {
+ int version;
+
+ if (strcmp(version_str, "TLSv1.3") == 0) {
+ version = TLS1_3_VERSION;
+ } else if (strcmp(version_str, "TLSv1.2") == 0) {
+ version = TLS1_2_VERSION;
+ } else if (strcmp(version_str, "TLSv1.1") == 0) {
+ version = TLS1_1_VERSION;
+ } else if (strcmp(version_str, "TLSv1") == 0) {
+ version = TLS1_VERSION;
+ } else {
+ version = 0;
+ }
+ return version;
+}
+
+
void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
SecureContext* sc;
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder());
int min_version = 0;
int max_version = 0;
+
+ if (args[0]->IsString()) {
+ const node::Utf8Value min(env->isolate(), args[0]);
+ min_version = string_to_tls_protocol(*min);
+ }
+
+ if (args[1]->IsString()) {
+ const node::Utf8Value max(env->isolate(), args[1]);
+ max_version = string_to_tls_protocol(*max);
+ }
+
const SSL_METHOD* method = TLS_method();
- if (args.Length() == 1 && args[0]->IsString()) {
- const node::Utf8Value sslmethod(env->isolate(), args[0]);
+ if (args.Length() == 3 && args[2]->IsString()) {
+ const node::Utf8Value sslmethod(env->isolate(), args[2]);
// Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends
// are still accepted. They are OpenSSL's way of saying that all known
// empty options
assert.strictEqual(
agent.getName({}),
- 'localhost:::::::::::::::::'
+ 'localhost:::::::::::::::::::'
);
// pass all options arguments
assert.strictEqual(
agent.getName(options),
'0.0.0.0:443:192.168.1.1:ca:cert::ciphers:key:pfx:false:localhost:' +
- 'secureProtocol:c,r,l:false:ecdhCurve:dhparam:0:sessionIdContext'
+ '::secureProtocol:c,r,l:false:ecdhCurve:dhparam:0:sessionIdContext'
);