From 21958e4eaa6d57f4f6afb766ea2cf3a34d7180db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Thu, 28 Jul 2022 21:25:39 +0000 Subject: [PATCH] tls,http2: send fatal alert on ALPN mismatch To comply with RFC 7301, make TLS servers send a fatal alert during the TLS handshake if both the client and the server are configured to use ALPN and if the server does not support any of the protocols advertised by the client. This affects HTTP/2 servers. Until now, applications could intercept the 'unknownProtocol' event when the client either did not advertise any protocols or if the list of protocols advertised by the client did not include HTTP/2 (or HTTP/1.1 if allowHTTP1 was true). With this change, only the first case can be handled, and the 'unknownProtocol' event will not be emitted in the second case because the TLS handshake fails and no secure connection is established. --- doc/api/http2.md | 14 +++++ doc/api/tls.md | 9 +++- lib/internal/http2/core.js | 2 +- src/crypto/crypto_tls.cc | 14 ++--- test/parallel/test-http2-https-fallback.js | 16 ++++-- .../test-http2-server-unknown-protocol.js | 20 ++++++-- test/parallel/test-tls-alpn-server-client.js | 51 +++++++++++++++++-- 7 files changed, 107 insertions(+), 19 deletions(-) diff --git a/doc/api/http2.md b/doc/api/http2.md index 28057a58a45724..1d87b5127d9839 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -2275,6 +2275,11 @@ a given number of milliseconds set using `http2secureServer.setTimeout()`. * `socket` {stream.Duplex} @@ -2284,6 +2289,15 @@ negotiate an allowed protocol (i.e. HTTP/2 or HTTP/1.1). The event handler receives the socket for handling. If no listener is registered for this event, the connection is terminated. A timeout may be specified using the `'unknownProtocolTimeout'` option passed to [`http2.createSecureServer()`][]. + +In earlier versions of Node.js, this event would be emitted if `allowHTTP1` is +`false` and, during the TLS handshake, the client either does not send an ALPN +extension or sends an ALPN extension that does not include HTTP/2 (`h2`). Newer +versions of Node.js only emit this event if `allowHTTP1` is `false` and the +client does not send an ALPN extension. If the client sends an ALPN extension +that does not include HTTP/2 (or HTTP/1.1 if `allowHTTP1` is `true`), the TLS +handshake will fail and no secure connection will be established. + See the [Compatibility API][]. #### `server.close([callback])` diff --git a/doc/api/tls.md b/doc/api/tls.md index aa08ec62e948d6..da8f65e2533426 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -683,8 +683,8 @@ is set to describe how authorization failed. Depending on the settings of the TLS server, unauthorized connections may still be accepted. The `tlsSocket.alpnProtocol` property is a string that contains the selected -ALPN protocol. When ALPN has no selected protocol, `tlsSocket.alpnProtocol` -equals `false`. +ALPN protocol. When ALPN has no selected protocol because the client or the +server did not send an ALPN extension, `tlsSocket.alpnProtocol` equals `false`. The `tlsSocket.servername` property is a string containing the server name requested via SNI. @@ -2012,6 +2012,11 @@ where `secureSocket` has the same API as `pair.cleartext`.