-11.14.0
+11.15.0
+11.14.0 11.13.0 11.12.0 11.11.0
diff --git a/common.gypi b/common.gypi
index 338ed2cbbb9bb8..f405156a20b26c 100644
--- a/common.gypi
+++ b/common.gypi
@@ -30,7 +30,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.18',
+ 'v8_embedder_string': '-node.19',
# Turn on SipHash for hash seed generation, addresses HashWick
'v8_use_siphash': 'true',
diff --git a/deps/openssl/openssl/crypto/chacha/build.info b/deps/openssl/openssl/crypto/chacha/build.info
index 02f8e518aeca90..e75ca72b67d4fb 100644
--- a/deps/openssl/openssl/crypto/chacha/build.info
+++ b/deps/openssl/openssl/crypto/chacha/build.info
@@ -9,6 +9,8 @@ GENERATE[chacha-armv4.S]=asm/chacha-armv4.pl $(PERLASM_SCHEME)
INCLUDE[chacha-armv4.o]=..
GENERATE[chacha-armv8.S]=asm/chacha-armv8.pl $(PERLASM_SCHEME)
INCLUDE[chacha-armv8.o]=..
+GENERATE[chacha-s390x.S]=asm/chacha-s390x.pl $(PERLASM_SCHEME)
+INCLUDE[chacha-s390x.o]=..
BEGINRAW[Makefile(unix)]
##### CHACHA assembler implementations
diff --git a/deps/openssl/openssl/crypto/poly1305/build.info b/deps/openssl/openssl/crypto/poly1305/build.info
index 631b32b8e099ac..b730524afb1393 100644
--- a/deps/openssl/openssl/crypto/poly1305/build.info
+++ b/deps/openssl/openssl/crypto/poly1305/build.info
@@ -17,6 +17,8 @@ GENERATE[poly1305-armv8.S]=asm/poly1305-armv8.pl $(PERLASM_SCHEME)
INCLUDE[poly1305-armv8.o]=..
GENERATE[poly1305-mips.S]=asm/poly1305-mips.pl $(PERLASM_SCHEME)
INCLUDE[poly1305-mips.o]=..
+GENERATE[poly1305-s390x.S]=asm/poly1305-s390x.pl $(PERLASM_SCHEME)
+INCLUDE[poly1305-s390x.o]=..
BEGINRAW[Makefile(unix)]
{- $builddir -}/poly1305-%.S: {- $sourcedir -}/asm/poly1305-%.pl
diff --git a/deps/openssl/openssl/crypto/rc4/build.info b/deps/openssl/openssl/crypto/rc4/build.info
index 46ee66b61c68a2..913942b5e98003 100644
--- a/deps/openssl/openssl/crypto/rc4/build.info
+++ b/deps/openssl/openssl/crypto/rc4/build.info
@@ -11,6 +11,8 @@ GENERATE[rc4-md5-x86_64.s]=asm/rc4-md5-x86_64.pl $(PERLASM_SCHEME)
GENERATE[rc4-parisc.s]=asm/rc4-parisc.pl $(PERLASM_SCHEME)
+GENERATE[rc4-s390x.s]=asm/rc4-s390x.pl $(PERLASM_SCHEME)
+
BEGINRAW[Makefile]
# GNU make "catch all"
{- $builddir -}/rc4-%.s: {- $sourcedir -}/asm/rc4-%.pl
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 3f0cad545f5cee..372387e0c9ef51 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -2424,44 +2424,29 @@ MaybeLocal ScriptCompiler::CompileModule(
return ToApiHandle(i_isolate->factory()->NewModule(shared));
}
-
-class IsIdentifierHelper {
- public:
- IsIdentifierHelper() : is_identifier_(false), first_char_(true) {}
-
- bool Check(i::String* string) {
- i::ConsString* cons_string = i::String::VisitFlat(this, string, 0);
- if (cons_string == nullptr) return is_identifier_;
- // We don't support cons strings here.
- return false;
- }
- void VisitOneByteString(const uint8_t* chars, int length) {
- for (int i = 0; i < length; ++i) {
- if (first_char_) {
- first_char_ = false;
- is_identifier_ = unicode_cache_.IsIdentifierStart(chars[0]);
- } else {
- is_identifier_ &= unicode_cache_.IsIdentifierPart(chars[i]);
- }
+namespace {
+bool IsIdentifier(i::Isolate* isolate, i::Handle string) {
+ i::UnicodeCache unicode_cache_;
+ string = i::String::Flatten(isolate, string);
+ const int length = string->length();
+ if (length == 0) return false;
+ if (!unicode_cache_.IsIdentifierStart(string->Get(0))) return false;
+ i::DisallowHeapAllocation no_gc;
+ i::String::FlatContent flat = string->GetFlatContent();
+ if (flat.IsOneByte()) {
+ auto vector = flat.ToOneByteVector();
+ for (int i = 1; i < length; i++) {
+ if (!unicode_cache_.IsIdentifierPart(vector[i])) return false;
}
- }
- void VisitTwoByteString(const uint16_t* chars, int length) {
- for (int i = 0; i < length; ++i) {
- if (first_char_) {
- first_char_ = false;
- is_identifier_ = unicode_cache_.IsIdentifierStart(chars[0]);
- } else {
- is_identifier_ &= unicode_cache_.IsIdentifierPart(chars[i]);
- }
+ } else {
+ auto vector = flat.ToUC16Vector();
+ for (int i = 1; i < length; i++) {
+ if (!unicode_cache_.IsIdentifierPart(vector[i])) return false;
}
}
-
- private:
- bool is_identifier_;
- bool first_char_;
- i::UnicodeCache unicode_cache_;
- DISALLOW_COPY_AND_ASSIGN(IsIdentifierHelper);
-};
+ return true;
+}
+} // anonymous namespace
MaybeLocal ScriptCompiler::CompileFunctionInContext(
Local v8_context, Source* source, size_t arguments_count,
@@ -2486,9 +2471,8 @@ MaybeLocal ScriptCompiler::CompileFunctionInContext(
i::Handle arguments_list =
isolate->factory()->NewFixedArray(static_cast(arguments_count));
for (int i = 0; i < static_cast(arguments_count); i++) {
- IsIdentifierHelper helper;
i::Handle argument = Utils::OpenHandle(*arguments[i]);
- if (!helper.Check(*argument)) return Local();
+ if (!IsIdentifier(isolate, argument)) return Local();
arguments_list->set(i, *argument);
}
diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc
index 63904e086f7de3..0263d20c4891b0 100644
--- a/deps/v8/test/cctest/test-compiler.cc
+++ b/deps/v8/test/cctest/test-compiler.cc
@@ -487,8 +487,8 @@ TEST(CompileFunctionInContextArgs) {
v8::Local ext[1];
ext[0] = v8::Local::Cast(
env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
- v8::ScriptCompiler::Source script_source(v8_str("result = x + b"));
- v8::Local arg = v8_str("b");
+ v8::ScriptCompiler::Source script_source(v8_str("result = x + abc"));
+ v8::Local arg = v8_str("abc");
v8::Local fun =
v8::ScriptCompiler::CompileFunctionInContext(env.local(), &script_source,
1, &arg, 1, ext)
@@ -498,8 +498,8 @@ TEST(CompileFunctionInContextArgs) {
->ToInt32(env.local())
.ToLocalChecked()
->Value());
- v8::Local b_value = v8::Number::New(CcTest::isolate(), 42.0);
- fun->Call(env.local(), env->Global(), 1, &b_value).ToLocalChecked();
+ v8::Local arg_value = v8::Number::New(CcTest::isolate(), 42.0);
+ fun->Call(env.local(), env->Global(), 1, &arg_value).ToLocalChecked();
CHECK(env->Global()->Has(env.local(), v8_str("result")).FromJust());
v8::Local result =
env->Global()->Get(env.local(), v8_str("result")).ToLocalChecked();
@@ -516,16 +516,17 @@ TEST(CompileFunctionInContextComments) {
v8::Local ext[1];
ext[0] = v8::Local::Cast(
env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
- v8::ScriptCompiler::Source script_source(
- v8_str("result = /* y + */ x + b // + z"));
- v8::Local arg = v8_str("b");
+ v8::Local source =
+ CompileRun("'result = /* y + */ x + a\\u4e00 // + z'").As();
+ v8::ScriptCompiler::Source script_source(source);
+ v8::Local arg = CompileRun("'a\\u4e00'").As();
v8::Local fun =
v8::ScriptCompiler::CompileFunctionInContext(env.local(), &script_source,
1, &arg, 1, ext)
.ToLocalChecked();
CHECK(!fun.IsEmpty());
- v8::Local b_value = v8::Number::New(CcTest::isolate(), 42.0);
- fun->Call(env.local(), env->Global(), 1, &b_value).ToLocalChecked();
+ v8::Local arg_value = v8::Number::New(CcTest::isolate(), 42.0);
+ fun->Call(env.local(), env->Global(), 1, &arg_value).ToLocalChecked();
CHECK(env->Global()->Has(env.local(), v8_str("result")).FromJust());
v8::Local result =
env->Global()->Get(env.local(), v8_str("result")).ToLocalChecked();
diff --git a/doc/api/cli.md b/doc/api/cli.md
index 59554b1c679327..f1236a088abd5b 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -443,6 +443,54 @@ added: v4.0.0
Specify an alternative default TLS cipher list. Requires Node.js to be built
with crypto support (default).
+### `--tls-max-v1.2`
+
+
+Set [`tls.DEFAULT_MAX_VERSION`][] to 'TLSv1.2'. Use to disable support for
+TLSv1.3.
+
+### `--tls-max-v1.3`
+
+
+Set default [`tls.DEFAULT_MAX_VERSION`][] to 'TLSv1.3'. Use to enable support
+for TLSv1.3.
+
+### `--tls-min-v1.0`
+
+
+Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1'. Use for compatibility with
+old TLS clients or servers.
+
+### `--tls-min-v1.1`
+
+
+Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1.1'. Use for compatibility
+with old TLS clients or servers.
+
+### `--tls-min-v1.2`
+
+
+Set default [`minVersion`][] to `'TLSv1.2'`. Use to disable support for TLSv1
+and TLSv1.1 in favour of TLSv1.2, which is more secure.
+
+### `--tls-min-v1.3`
+
+
+Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1.3'. Use to disable support
+for TLSv1.2, which is not as secure as TLSv1.3.
+
### `--trace-deprecation`
@@ -136,6 +139,8 @@ threshold is exceeded. The limits are configurable:
The default renegotiation limits should not be modified without a full
understanding of the implications and risks.
+TLSv1.3 does not support renegotiation.
+
### Session Resumption
Establishing a TLS session can be relatively slow. The process can be sped
@@ -176,6 +181,10 @@ as for resumption with session tickets. For debugging, if
[`tls.TLSSocket.getTLSTicket()`][] returns a value, the session data contains a
ticket, otherwise it contains client-side session state.
+With TLSv1.3, be aware that multiple tickets may be sent by the server,
+resulting in multiple `'session'` events, see [`'session'`][] for more
+information.
+
Single process servers need no specific implementation to use session tickets.
To use session tickets across server restarts or load balancers, servers must
all have the same ticket keys. There are three 16-byte keys internally, but the
@@ -230,6 +239,9 @@ Node.js is built with a default suite of enabled and disabled TLS ciphers.
Currently, the default cipher suite is:
```txt
+TLS_AES_256_GCM_SHA384:
+TLS_CHACHA20_POLY1305_SHA256:
+TLS_AES_128_GCM_SHA256:
ECDHE-RSA-AES128-GCM-SHA256:
ECDHE-ECDSA-AES128-GCM-SHA256:
ECDHE-RSA-AES256-GCM-SHA384:
@@ -270,7 +282,19 @@ The default can also be replaced on a per client or server basis using the
in [`tls.createServer()`], [`tls.connect()`], and when creating new
[`tls.TLSSocket`]s.
-Consult [OpenSSL cipher list format documentation][] for details on the format.
+The ciphers list can contain a mixture of TLSv1.3 cipher suite names, the ones
+that start with `'TLS_'`, and specifications for TLSv1.2 and below cipher
+suites. The TLSv1.2 ciphers support a legacy specification format, consult
+the OpenSSL [cipher list format][] documentation for details, but those
+specifications do *not* apply to TLSv1.3 ciphers. The TLSv1.3 suites can only
+be enabled by including their full name in the cipher list. They cannot, for
+example, be enabled or disabled by using the legacy TLSv1.2 `'EECDH'` or
+`'!EECDH'` specification.
+
+Despite the relative order of TLSv1.3 and TLSv1.2 cipher suites, the TLSv1.3
+protocol is significantly more secure than TLSv1.2, and will always be chosen
+over TLSv1.2 if the handshake indicates it is supported, and if any TLSv1.3
+cipher suites are enabled.
The default cipher suite included within Node.js has been carefully
selected to reflect current security best practices and risk mitigation.
@@ -289,7 +313,18 @@ Old clients that rely on insecure and deprecated RC4 or DES-based ciphers
(like Internet Explorer 6) cannot complete the handshaking process with
the default configuration. If these clients _must_ be supported, the
[TLS recommendations] may offer a compatible cipher suite. For more details
-on the format, see the [OpenSSL cipher list format documentation].
+on the format, see the OpenSSL [cipher list format][] documentation.
+
+There are only 5 TLSv1.3 cipher suites:
+- `'TLS_AES_256_GCM_SHA384'`
+- `'TLS_CHACHA20_POLY1305_SHA256'`
+- `'TLS_AES_128_GCM_SHA256'`
+- `'TLS_AES_128_CCM_SHA256'`
+- `'TLS_AES_128_CCM_8_SHA256'`
+
+The first 3 are enabled by default. The last 2 `CCM`-based suites are supported
+by TLSv1.3 because they may be more performant on constrained systems, but they
+are not enabled by default since they offer less security.
## Class: tls.Server
+
+* {string} The default value of the `maxVersion` option of
+ [`tls.createSecureContext()`][]. It can be assigned any of the supported TLS
+ protocol versions, `TLSv1.3`, `TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`.
+ **Default:** `'TLSv1.2'`, unless changed using CLI options. Using
+ `--tls-max-v1.2` sets the default to `'TLSv1.2`'. Using `--tls-max-v1.3` sets
+ the default to `'TLSv1.3'`. If multiple of the options are provided, the
+ highest maximum is used.
+
+## tls.DEFAULT_MIN_VERSION
+
+
+* {string} The default value of the `minVersion` option of
+ [`tls.createSecureContext()`][]. It can be assigned any of the supported TLS
+ protocol versions, `'TLSv1.3'`, `TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`.
+ **Default:** `'TLSv1'`, unless changed using CLI options. Using
+ `--tls-min-v1.0` sets the default to `'TLSv1'`. Using `--tls-min-v1.1` sets
+ the default to `'TLSv1.1'`. Using `--tls-min-v1.3` sets the default to
+ `'TLSv1.3'`. If multiple of the options are provided, the lowest minimum is
+ used.
+
## Deprecated APIs
### Class: CryptoStream
@@ -1597,6 +1680,8 @@ where `secureSocket` has the same API as `pair.cleartext`.
[`server.setTicketKeys()`]: #tls_server_setticketkeys_keys
[`socket.setTimeout(timeout)`]: #net_socket_settimeout_timeout_callback
[`tls.DEFAULT_ECDH_CURVE`]: #tls_tls_default_ecdh_curve
+[`tls.DEFAULT_MAX_VERSION`]: #tls_tls_default_max_version
+[`tls.DEFAULT_MIN_VERSION`]: #tls_tls_default_min_version
[`tls.Server`]: #tls_class_tls_server
[`tls.TLSSocket.getPeerCertificate()`]: #tls_tlssocket_getpeercertificate_detailed
[`tls.TLSSocket.getSession()`]: #tls_tlssocket_getsession
@@ -1613,16 +1698,16 @@ where `secureSocket` has the same API as `pair.cleartext`.
[Forward secrecy]: https://en.wikipedia.org/wiki/Perfect_forward_secrecy
[OCSP request]: https://en.wikipedia.org/wiki/OCSP_stapling
[OpenSSL Options]: crypto.html#crypto_openssl_options
-[OpenSSL cipher list format documentation]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html#CIPHER-LIST-FORMAT
[Perfect Forward Secrecy]: #tls_perfect_forward_secrecy
[RFC 2246]: https://www.ietf.org/rfc/rfc2246.txt
[RFC 5077]: https://tools.ietf.org/html/rfc5077
[RFC 5929]: https://tools.ietf.org/html/rfc5929
-[SSL_METHODS]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html#Dealing-with-Protocol-Methods
+[SSL_METHODS]: https://www.openssl.org/docs/man1.1.1/man7/ssl.html#Dealing-with-Protocol-Methods
[Session Resumption]: #tls_session_resumption
[Stream]: stream.html#stream_stream
[TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS
[asn1.js]: https://www.npmjs.com/package/asn1.js
[certificate object]: #tls_certificate_object
+[cipher list format]: https://www.openssl.org/docs/man1.1.1/man1/ciphers.html#CIPHER-LIST-FORMAT
[modifying the default cipher suite]: #tls_modifying_the_default_tls_cipher_suite
[specific attacks affecting larger AES key sizes]: https://www.schneier.com/blog/archives/2009/07/another_new_aes.html
diff --git a/doc/changelogs/CHANGELOG_V11.md b/doc/changelogs/CHANGELOG_V11.md
index fffa3d9b1ba425..3eefa7ebe85184 100644
--- a/doc/changelogs/CHANGELOG_V11.md
+++ b/doc/changelogs/CHANGELOG_V11.md
@@ -9,6 +9,7 @@
+11.15.0 11.14.0 11.13.0 11.12.0
@@ -42,6 +43,38 @@
* [io.js](CHANGELOG_IOJS.md)
* [Archive](CHANGELOG_ARCHIVE.md)
+
+## 2019-04-30, Version 11.15.0 (Current), @codebytere
+
+### Notable changes
+
+* **deps**: add s390 asm rules for OpenSSL-1.1.1 (Shigeki Ohtsu) [#19794](https://github.com/nodejs/node/pull/19794)
+* **src**: add .code and SSL specific error properties (Sam Roberts) [#25093](https://github.com/nodejs/node/pull/25093)
+* **tls**:
+ * add --tls-min-v1.2 CLI switch (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+ * supported shared openssl 1.1.0 (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+ * revert default max toTLSv1.2 (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+ * revert change to invalid protocol error type (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+ * support TLSv1.3 (Sam Roberts) [#26209](https://github.com/nodejs/node/pull/26209)
+ * add code for ERR\_TLS\_INVALID\_PROTOCOL\_METHOD (Sam Roberts) [#24729](https://github.com/nodejs/node/pull/24729)
+
+### Commits
+
+* [[`7da23dcbfa`](https://github.com/nodejs/node/commit/7da23dcbfa)] - **deps**: V8: backport 61f4c22 (Anna Henningsen) [#27259](https://github.com/nodejs/node/pull/27259)
+* [[`8db791d0fe`](https://github.com/nodejs/node/commit/8db791d0fe)] - **deps**: update archs files for OpenSSL-1.1.1b (Sam Roberts) [#26327](https://github.com/nodejs/node/pull/26327)
+* [[`1c98b720b1`](https://github.com/nodejs/node/commit/1c98b720b1)] - **(SEMVER-MINOR)** **deps**: add s390 asm rules for OpenSSL-1.1.1 (Shigeki Ohtsu) [#19794](https://github.com/nodejs/node/pull/19794)
+* [[`d8cc478ae9`](https://github.com/nodejs/node/commit/d8cc478ae9)] - **deps**: upgrade openssl sources to 1.1.1b (Sam Roberts) [#26327](https://github.com/nodejs/node/pull/26327)
+* [[`fa6f0f1644`](https://github.com/nodejs/node/commit/fa6f0f1644)] - **doc**: describe tls.DEFAULT\_MIN\_VERSION/\_MAX\_VERSION (Sam Roberts) [#26821](https://github.com/nodejs/node/pull/26821)
+* [[`8b5d350a35`](https://github.com/nodejs/node/commit/8b5d350a35)] - **(SEMVER-MINOR)** **src**: add .code and SSL specific error properties (Sam Roberts) [#25093](https://github.com/nodejs/node/pull/25093)
+* [[`bf2c283555`](https://github.com/nodejs/node/commit/bf2c283555)] - **(SEMVER-MINOR)** **tls**: add --tls-min-v1.2 CLI switch (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+* [[`7aeca270f6`](https://github.com/nodejs/node/commit/7aeca270f6)] - **(SEMVER-MINOR)** **tls**: supported shared openssl 1.1.0 (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+* [[`d2666e6ded`](https://github.com/nodejs/node/commit/d2666e6ded)] - **tls**: add debugging to native TLS code (Anna Henningsen) [#26843](https://github.com/nodejs/node/pull/26843)
+* [[`225417b849`](https://github.com/nodejs/node/commit/225417b849)] - **tls**: add CHECK for impossible condition (AnnaHenningsen) [#26843](https://github.com/nodejs/node/pull/26843)
+* [[`109c097797`](https://github.com/nodejs/node/commit/109c097797)] - **(SEMVER-MINOR)** **tls**: revert default max toTLSv1.2 (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+* [[`7393e37af1`](https://github.com/nodejs/node/commit/7393e37af1)] - **(SEMVER-MINOR)** **tls**: support TLSv1.3 (Sam Roberts) [#26209](https://github.com/nodejs/node/pull/26209)
+* [[`8e14859459`](https://github.com/nodejs/node/commit/8e14859459)] - **(SEMVER-MINOR)** **tls**: revert change to invalid protocol error type (Sam Roberts) [#26951](https://github.com/nodejs/node/pull/26951)
+* [[`00688b6042`](https://github.com/nodejs/node/commit/00688b6042)] - **(SEMVER-MINOR)** **tls**: add code for ERR\_TLS\_INVALID\_PROTOCOL\_METHOD (Sam Roberts) [#24729](https://github.com/nodejs/node/pull/24729)
+
## 2019-04-11, Version 11.14.0 (Current), @BethGriggs
diff --git a/doc/node.1 b/doc/node.1
index 603d72d566c99c..4a3759ad0de031 100644
--- a/doc/node.1
+++ b/doc/node.1
@@ -236,6 +236,28 @@ Specify process.title on startup.
Specify an alternative default TLS cipher list.
Requires Node.js to be built with crypto support. (Default)
.
+.It Fl -tls-max-v1.2
+Set default maxVersion to 'TLSv1.2'. Use to disable support for TLSv1.3.
+.
+.It Fl -tls-max-v1.3
+Set default maxVersion to 'TLSv1.3'. Use to enable support for TLSv1.3.
+.
+.It Fl -tls-min-v1.0
+Set default minVersion to 'TLSv1'. Use for compatibility with old TLS clients
+or servers.
+.
+.It Fl -tls-min-v1.1
+Set default minVersion to 'TLSv1.1'. Use for compatibility with old TLS clients
+or servers.
+.
+.It Fl -tls-min-v1.2
+Set default minVersion to 'TLSv1.2'. Use to disable support for TLSv1 and
+TLSv1.1 in favour of TLSv1.2, which is more secure.
+.
+.It Fl -tls-min-v1.3
+Set default minVersion to 'TLSv1.3'. Use to disable support for TLSv1.2 in
+favour of TLSv1.3, which is more secure.
+.
.It Fl -trace-deprecation
Print stack traces for deprecations.
.
diff --git a/lib/_tls_common.js b/lib/_tls_common.js
index 78e67af23d46f0..a0970571be3383 100644
--- a/lib/_tls_common.js
+++ b/lib/_tls_common.js
@@ -27,6 +27,7 @@ const tls = require('tls');
const {
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED,
ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_OPT_VALUE,
ERR_TLS_INVALID_PROTOCOL_VERSION,
ERR_TLS_PROTOCOL_VERSION_CONFLICT,
} = require('internal/errors').codes;
@@ -35,6 +36,7 @@ const {
TLS1_VERSION,
TLS1_1_VERSION,
TLS1_2_VERSION,
+ TLS1_3_VERSION,
} = internalBinding('constants').crypto;
// Lazily loaded from internal/crypto/util.
@@ -45,6 +47,7 @@ function toV(which, v, def) {
if (v === 'TLSv1') return TLS1_VERSION;
if (v === 'TLSv1.1') return TLS1_1_VERSION;
if (v === 'TLSv1.2') return TLS1_2_VERSION;
+ if (v === 'TLSv1.3' && TLS1_3_VERSION) return TLS1_3_VERSION;
throw new ERR_TLS_INVALID_PROTOCOL_VERSION(v, which);
}
@@ -156,10 +159,35 @@ exports.createSecureContext = function createSecureContext(options, context) {
}
}
- if (options.ciphers)
- c.context.setCiphers(options.ciphers);
- else
- c.context.setCiphers(tls.DEFAULT_CIPHERS);
+ if (options.ciphers && typeof options.ciphers !== 'string') {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'options.ciphers', 'string', options.ciphers);
+ }
+
+ // Work around an OpenSSL API quirk. cipherList is for TLSv1.2 and below,
+ // cipherSuites is for TLSv1.3 (and presumably any later versions). TLSv1.3
+ // cipher suites all have a standard name format beginning with TLS_, so split
+ // the ciphers and pass them to the appropriate API.
+ const ciphers = (options.ciphers || tls.DEFAULT_CIPHERS).split(':');
+ const cipherList = ciphers.filter((_) => !_.match(/^TLS_/)).join(':');
+ const cipherSuites = ciphers.filter((_) => _.match(/^TLS_/)).join(':');
+
+ if (cipherSuites === '' && cipherList === '') {
+ // Specifying empty cipher suites for both TLS1.2 and TLS1.3 is invalid, its
+ // not possible to handshake with no suites.
+ throw ERR_INVALID_OPT_VALUE('ciphers', ciphers);
+ }
+
+ c.context.setCipherSuites(cipherSuites);
+ c.context.setCiphers(cipherList);
+
+ if (cipherSuites === '' && c.context.getMaxProto() > TLS1_2_VERSION &&
+ c.context.getMinProto() < TLS1_3_VERSION)
+ c.context.setMaxProto(TLS1_2_VERSION);
+
+ if (cipherList === '' && c.context.getMinProto() < TLS1_3_VERSION &&
+ c.context.getMaxProto() > TLS1_2_VERSION)
+ c.context.setMinProto(TLS1_3_VERSION);
if (options.ecdhCurve === undefined)
c.context.setECDHCurve(tls.DEFAULT_ECDH_CURVE);
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index 98f9fc98fbaa02..047d8391804ea0 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -39,6 +39,7 @@ const { owner_symbol } = require('internal/async_hooks').symbols;
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
const {
ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_CALLBACK,
ERR_MULTIPLE_CALLBACK,
ERR_SOCKET_CLOSED,
ERR_TLS_DH_PARAM_SIZE,
@@ -62,7 +63,7 @@ const noop = () => {};
// Server side times how long a handshake is taking to protect against slow
// handshakes being used for DoS.
function onhandshakestart(now) {
- debug('onhandshakestart');
+ debug('server onhandshakestart');
const { lastHandshakeTime } = this;
assert(now >= lastHandshakeTime,
@@ -80,6 +81,9 @@ function onhandshakestart(now) {
this.handshakes++;
const owner = this[owner_symbol];
+
+ assert(owner._tlsOptions.isServer);
+
if (this.handshakes > tls.CLIENT_RENEG_LIMIT) {
owner._emitTLSError(new ERR_TLS_SESSION_ATTACK());
return;
@@ -90,9 +94,10 @@ function onhandshakestart(now) {
}
function onhandshakedone() {
- debug('onhandshakedone');
+ debug('server onhandshakedone');
const owner = this[owner_symbol];
+ assert(owner._tlsOptions.isServer);
// `newSession` callback wasn't called yet
if (owner._newSessionPending) {
@@ -105,10 +110,15 @@ function onhandshakedone() {
function loadSession(hello) {
+ debug('server onclienthello',
+ 'sessionid.len', hello.sessionId.length,
+ 'ticket?', hello.tlsTicket
+ );
const owner = this[owner_symbol];
var once = false;
function onSession(err, session) {
+ debug('server resumeSession callback(err %j, sess? %s)', err, !!session);
if (once)
return owner.destroy(new ERR_MULTIPLE_CALLBACK());
once = true;
@@ -190,6 +200,8 @@ function requestOCSP(socket, info) {
let once = false;
const onOCSP = (err, response) => {
+ debug('server OCSPRequest done', 'handle?', !!socket._handle, 'once?', once,
+ 'response?', !!response, 'err?', err);
if (once)
return socket.destroy(new ERR_MULTIPLE_CALLBACK());
once = true;
@@ -205,6 +217,7 @@ function requestOCSP(socket, info) {
requestOCSPDone(socket);
};
+ debug('server oncertcb emit OCSPRequest');
socket.server.emit('OCSPRequest',
ctx.getCertificate(),
ctx.getIssuer(),
@@ -212,16 +225,17 @@ function requestOCSP(socket, info) {
}
function requestOCSPDone(socket) {
+ debug('server certcb done');
try {
socket._handle.certCbDone();
} catch (e) {
+ debug('server certcb done errored', e);
socket.destroy(e);
}
}
-
function onnewsessionclient(sessionId, session) {
- debug('client onnewsessionclient', sessionId, session);
+ debug('client emit session');
const owner = this[owner_symbol];
owner.emit('session', session);
}
@@ -230,8 +244,9 @@ function onnewsession(sessionId, session) {
debug('onnewsession');
const owner = this[owner_symbol];
- // XXX(sam) no server to emit the event on, but handshake won't continue
- // unless newSessionDone() is called, should it be?
+ // TODO(@sam-github) no server to emit the event on, but handshake won't
+ // continue unless newSessionDone() is called, should it be, or is that
+ // situation unreachable, or only occurring during shutdown?
if (!owner.server)
return;
@@ -260,11 +275,15 @@ function onnewsession(sessionId, session) {
function onocspresponse(resp) {
+ debug('client onocspresponse');
this[owner_symbol].emit('OCSPResponse', resp);
}
function onerror(err) {
const owner = this[owner_symbol];
+ debug('%s onerror %s had? %j',
+ owner._tlsOptions.isServer ? 'server' : 'client', err,
+ owner._hadError);
if (owner._hadError)
return;
@@ -282,7 +301,7 @@ function onerror(err) {
// Ignore server's authorization errors
owner.destroy();
} else {
- // Throw error
+ // Emit error
owner._emitTLSError(err);
}
}
@@ -290,6 +309,11 @@ function onerror(err) {
// Used by both client and server TLSSockets to start data flowing from _handle,
// read(0) causes a StreamBase::ReadStart, via Socket._read.
function initRead(tlsSocket, socket) {
+ debug('%s initRead',
+ tlsSocket._tlsOptions.isServer ? 'server' : 'client',
+ 'handle?', !!tlsSocket._handle,
+ 'buffered?', !!socket && socket.readableLength
+ );
// If we were destroyed already don't bother reading
if (!tlsSocket._handle)
return;
@@ -490,11 +514,17 @@ TLSSocket.prototype._destroySSL = function _destroySSL() {
this.ssl = null;
};
+// Constructor guts, arbitrarily factored out.
TLSSocket.prototype._init = function(socket, wrap) {
const options = this._tlsOptions;
const ssl = this._handle;
this.server = options.server;
+ debug('%s _init',
+ options.isServer ? 'server' : 'client',
+ 'handle?', !!ssl
+ );
+
// Clients (!isServer) always request a cert, servers request a client cert
// only on explicit configuration.
const requestCert = !!options.requestCert || !options.isServer;
@@ -525,7 +555,10 @@ TLSSocket.prototype._init = function(socket, wrap) {
}
} else {
ssl.onhandshakestart = noop;
- ssl.onhandshakedone = this._finishInit.bind(this);
+ ssl.onhandshakedone = () => {
+ debug('client onhandshakedone');
+ this._finishInit();
+ };
ssl.onocspresponse = onocspresponse;
if (options.session)
@@ -591,6 +624,16 @@ TLSSocket.prototype._init = function(socket, wrap) {
};
TLSSocket.prototype.renegotiate = function(options, callback) {
+ if (options === null || typeof options !== 'object')
+ throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
+ if (callback !== undefined && typeof callback !== 'function')
+ throw new ERR_INVALID_CALLBACK();
+
+ debug('%s renegotiate()',
+ this._tlsOptions.isServer ? 'server' : 'client',
+ 'destroyed?', this.destroyed
+ );
+
if (this.destroyed)
return;
@@ -658,9 +701,25 @@ TLSSocket.prototype._releaseControl = function() {
};
TLSSocket.prototype._finishInit = function() {
- debug('secure established');
+ // Guard against getting onhandshakedone() after .destroy().
+ // * 1.2: If destroy() during onocspresponse(), then write of next handshake
+ // record fails, the handshake done info callbacks does not occur, and the
+ // socket closes.
+ // * 1.3: The OCSP response comes in the same record that finishes handshake,
+ // so even after .destroy(), the handshake done info callback occurs
+ // immediately after onocspresponse(). Ignore it.
+ if (!this._handle)
+ return;
+
this.alpnProtocol = this._handle.getALPNNegotiatedProtocol();
this.servername = this._handle.getServername();
+
+ debug('%s _finishInit',
+ this._tlsOptions.isServer ? 'server' : 'client',
+ 'handle?', !!this._handle,
+ 'alpn', this.alpnProtocol,
+ 'servername', this.servername);
+
this._secureEstablished = true;
if (this._tlsOptions.handshakeTimeout > 0)
this.setTimeout(0, this._handleTimeout);
@@ -668,6 +727,12 @@ TLSSocket.prototype._finishInit = function() {
};
TLSSocket.prototype._start = function() {
+ debug('%s _start',
+ this._tlsOptions.isServer ? 'server' : 'client',
+ 'handle?', !!this._handle,
+ 'connecting?', this.connecting,
+ 'requestOCSP?', !!this._tlsOptions.requestOCSP,
+ );
if (this.connecting) {
this.once('connect', this._start);
return;
@@ -677,7 +742,6 @@ TLSSocket.prototype._start = function() {
if (!this._handle)
return;
- debug('start');
if (this._tlsOptions.requestOCSP)
this._handle.requestOCSP();
this._handle.start();
@@ -756,13 +820,16 @@ function onServerSocketSecure() {
}
}
- if (!this.destroyed && this._releaseControl())
+ if (!this.destroyed && this._releaseControl()) {
+ debug('server emit secureConnection');
this._tlsOptions.server.emit('secureConnection', this);
+ }
}
function onSocketTLSError(err) {
if (!this._controlReleased && !this[kErrorEmitted]) {
this[kErrorEmitted] = true;
+ debug('server emit tlsClientError:', err);
this._tlsOptions.server.emit('tlsClientError', err, this);
}
}
@@ -783,6 +850,7 @@ function onSocketClose(err) {
}
function tlsConnectionListener(rawSocket) {
+ debug('net.Server.on(connection): new TLSSocket');
const socket = new TLSSocket(rawSocket, {
secureContext: this._sharedCreds,
isServer: true,
@@ -1168,6 +1236,7 @@ function onConnectSecure() {
const ekeyinfo = this.getEphemeralKeyInfo();
if (ekeyinfo.type === 'DH' && ekeyinfo.size < options.minDHSize) {
const err = new ERR_TLS_DH_PARAM_SIZE(ekeyinfo.size);
+ debug('client emit:', err);
this.emit('error', err);
this.destroy();
return;
@@ -1194,10 +1263,12 @@ function onConnectSecure() {
this.destroy(verifyError);
return;
} else {
+ debug('client emit secureConnect');
this.emit('secureConnect');
}
} else {
this.authorized = true;
+ debug('client emit secureConnect');
this.emit('secureConnect');
}
diff --git a/lib/internal/stream_base_commons.js b/lib/internal/stream_base_commons.js
index a6805e39be8390..8f58ff56bb8a73 100644
--- a/lib/internal/stream_base_commons.js
+++ b/lib/internal/stream_base_commons.js
@@ -19,6 +19,8 @@ const kUpdateTimer = Symbol('kUpdateTimer');
const kAfterAsyncWrite = Symbol('kAfterAsyncWrite');
const kHandle = Symbol('kHandle');
+const debug = require('util').debuglog('stream');
+
function handleWriteReq(req, data, encoding) {
const { handle } = req;
@@ -55,6 +57,8 @@ function handleWriteReq(req, data, encoding) {
}
function onWriteComplete(status) {
+ debug('onWriteComplete', status, this.error);
+
const stream = this.handle[owner_symbol];
if (stream.destroyed) {
diff --git a/lib/tls.js b/lib/tls.js
index 2be6a15bc5c5e6..c951727e5589c3 100644
--- a/lib/tls.js
+++ b/lib/tls.js
@@ -31,6 +31,7 @@ internalUtil.assertCrypto();
const { isArrayBufferView } = require('internal/util/types');
const net = require('net');
+const { getOptionValue } = require('internal/options');
const url = require('url');
const binding = internalBinding('crypto');
const { Buffer } = require('buffer');
@@ -53,9 +54,24 @@ exports.DEFAULT_CIPHERS =
exports.DEFAULT_ECDH_CURVE = 'auto';
-exports.DEFAULT_MAX_VERSION = 'TLSv1.2';
+if (getOptionValue('--tls-min-v1.0'))
+ exports.DEFAULT_MIN_VERSION = 'TLSv1';
+else if (getOptionValue('--tls-min-v1.1'))
+ exports.DEFAULT_MIN_VERSION = 'TLSv1.1';
+else if (getOptionValue('--tls-min-v1.2'))
+ exports.DEFAULT_MIN_VERSION = 'TLSv1.2';
+else if (getOptionValue('--tls-min-v1.3'))
+ exports.DEFAULT_MIN_VERSION = 'TLSv1.3';
+else
+ exports.DEFAULT_MIN_VERSION = 'TLSv1';
+
+if (getOptionValue('--tls-max-v1.3'))
+ exports.DEFAULT_MAX_VERSION = 'TLSv1.3';
+else if (getOptionValue('--tls-max-v1.2'))
+ exports.DEFAULT_MAX_VERSION = 'TLSv1.2';
+else
+ exports.DEFAULT_MAX_VERSION = 'TLSv1.2'; // Will depend on node version.
-exports.DEFAULT_MIN_VERSION = 'TLSv1';
exports.getCiphers = internalUtil.cachedResult(
() => internalUtil.filterDuplicateStrings(binding.getSSLCiphers(), true)
diff --git a/src/env.h b/src/env.h
index 0516c49f36ddcd..e75e336f9d935b 100644
--- a/src/env.h
+++ b/src/env.h
@@ -185,6 +185,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(fingerprint_string, "fingerprint") \
V(flags_string, "flags") \
V(fragment_string, "fragment") \
+ V(function_string, "function") \
V(get_data_clone_error_string, "_getDataCloneError") \
V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
V(gid_string, "gid") \
@@ -208,6 +209,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(issuercert_string, "issuerCertificate") \
V(kill_signal_string, "killSignal") \
V(kind_string, "kind") \
+ V(library_string, "library") \
V(mac_string, "mac") \
V(main_string, "main") \
V(max_buffer_string, "maxBuffer") \
diff --git a/src/node_constants.cc b/src/node_constants.cc
index be27de4ed64430..4593760b2f3d94 100644
--- a/src/node_constants.cc
+++ b/src/node_constants.cc
@@ -1245,6 +1245,9 @@ void DefineCryptoConstants(Local