The Blog

 

In this blog post, we look at some of the issues you need to be aware of and what you need to do when you migrate your Node.js application to use TLS 1.3.

These include:

  • Enabling TLS1.3
  • Ensuring your session resumption code is TLS1.3-capable
  • Being aware of a coding pattern that can prevent session ticket transmission

Make sure TLS1.3 is enabled

TLS1.3 is enabled by default in 12.x, but not in 11.x and earlier. This is because TLS1.3 causes some Node.js APIs to change behavior: Code that worked fine with TLS1.2 may not work if TLS1.3 is negotiated.

When using a Node.js version below 12.x, you need to enable TLS1.3 as described below.

However, even though TLS1.3 is enabled by default in 12.x, 12.x users should still read this carefully! If your code is explicitly configuring protocol versions, secure protocols, or cipher suites, it might inadvertently be overriding the default and disabling TLS1.3.

Enable TLS1.3 using CLI options

With Node.js 11.x or 10.x, you can use the --tls-max-v1.3 CLI option to enable TLS1.3 by default. It can be provided directly on the command line, or set in the environment with NODE_OPTIONS=--tls-max-v1.3. The option can also be specified to Node.js 12.x, even though its already the default.

The --tls-cipher-list option cannot be used to enable TLS1.3, but it can be used to disable it. If it is being set by your existing code, ensure that it includes one of the 5 TLS1.3 cipher suites, otherwise TLS1.3 will not be negotiated:

  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_128_GCM_SHA256
  • TLS_AES_128_CCM_8_SHA256
  • TLS_AES_128_CCM_SHA256

The first three suites are the recommended cipher suites, and are enabled by default by OpenSSL and Node.js. The last two may be useful in some situations, see TLS1.3 is coming to Node.js.

Enable TLS1.3 using tls.DEFAULT_MAX_VERSION

If it’s not possible to modify the command line or environment, the default max protocol version can be set programmatically:

        const tls = require('tls');

        tls.DEFAULT_MAX_VERSION = 'TLSv1.3';

Enable TLS1.3 using the maxVersion option

Three TLS options affect the protocol version supported:

  • maxVersion: If the max version is set to something other than 'TLSv1.3', TLS1.3 cannot be negotiated. The default value is tls.DEFAULT_MAX_VERSION, which can be set explicitly or via the CLI, as described above.
  • ciphers: If ciphers is set to a list that does not contain at least one of the 5 TLS1.3 cipher suites described earlier, TLS1.3 cannot be negotiated. The default value includes 3 TLS1.3 cipher suites, as decribed above.
  • secureProtocol: if the protocol is set to something other than 'TLS_method', 'TLS_server_method', or 'TLS_client_method', TLS1.3 cannot be negotiated. The default value is 'TLS_method'.

It’s possible to use these options to programmatically enable TLS1.3, even if it is disabled by default.

It is also possible that existing code using these options is disabling TLS1.3, even if it node is configured so that TLS1.3 is enabled by default. If TLS1.3 is not being negotiated, even when enabled by default, check to ensure it is not being disabled programmatically.

Making sure your session resumption code is TLS1.3 capable

Code that uses the 'session' event to get the session tickets will work for both TLS1.2 and TLS1.3 with no changes.

However, the 'session' even was introduced recently, so its likely that existing code is using the TLS1.2 session resumption API, tlsSocket.getSession(). That code will silently fail to resume sessions with TLS1.3. TLS1.3 will still be negotiated, but at the cost of full handshakes for every connection.

See the TLS Session Resumption documentation for a detailed discussion of the TLS session resumption in various TLS protocol versions, and see the 'session' event documentation for a description of how session resumption should be done.

Being aware of a coding pattern that can prevent session ticket transmission

There is an outstanding issue with very short-lived data-less connections that prevents session tickets from being received by the client. Code that in the 'newConnection' event listener calls .end() before writing any data will not cause 'session' events to be emitted on the client:

    tls.createServer(options, (socket) => {
        socket.end();
    });

or:

    tls.createServer(options).on('secureConnection', (socket) => {
        socket.end();
    });

The code examples are equivalent, the tls.createServer() callback is added as a listener to the 'secureConnection' event.

This is an unusual coding pattern, since the TLS socket is closed by the server immediately without any data being sent! If this is done, the server will not send TLS session tickets to the client, so the session cannot be resumed.

To work around this, either send data (as most applications will), or end the connection in the next tick.

Summary

TLS1.3 is a significant protocol update, offering much improvements to the security of TLS1.3. With this information, we hope your upgrade will be smooth and pleasant.