TLS (SSL)#

Stability: 2 - Stable

The node:tls module provides an implementation of the Transport Layer Security (TLS) and Secure Socket Layer (SSL) protocols that is built on top of OpenSSL. The module can be accessed using:

import tls from 'node:tls';
const tls = require('node:tls');
javascript

Determining if crypto support is unavailable#

It is possible for Node.js to be built without including support for the node:crypto module. In such cases, attempting to import from tls or calling require('node:tls') will result in an error being thrown.

When using CommonJS, the error thrown can be caught using try/catch:

let tls;
try {
  tls = require('node:tls');
} catch (err) {
  console.error('tls support is disabled!');
}
cjs

When using the lexical ESM import keyword, the error can only be caught if a handler for process.on('uncaughtException') is registered before any attempt to load the module is made (using, for instance, a preload module).

When using ESM, if there is a chance that the code may be run on a build of Node.js where crypto support is not enabled, consider using the import() function instead of the lexical import keyword:

let tls;
try {
  tls = await import('node:tls');
} catch (err) {
  console.error('tls support is disabled!');
}
mjs

TLS/SSL concepts#

TLS/SSL is a set of protocols that rely on a public key infrastructure (PKI) to enable secure communication between a client and a server. For most common cases, each server must have a private key.

Private keys can be generated in multiple ways. The example below illustrates use of the OpenSSL command-line interface to generate a 2048-bit RSA private key:

openssl genrsa -out ryans-key.pem 2048
bash

With TLS/SSL, all servers (and some clients) must have a certificate. Certificates are public keys that correspond to a private key, and that are digitally signed either by a Certificate Authority or by the owner of the private key (such certificates are referred to as "self-signed"). The first step to obtaining a certificate is to create a Certificate Signing Request (CSR) file.

The OpenSSL command-line interface can be used to generate a CSR for a private key:

openssl req -new -sha256 -key ryans-key.pem -out ryans-csr.pem
bash

Once the CSR file is generated, it can either be sent to a Certificate Authority for signing or used to generate a self-signed certificate.

Creating a self-signed certificate using the OpenSSL command-line interface is illustrated in the example below:

openssl x509 -req -in ryans-csr.pem -signkey ryans-key.pem -out ryans-cert.pem
bash

Once the certificate is generated, it can be used to generate a .pfx or .p12 file:

openssl pkcs12 -export -in ryans-cert.pem -inkey ryans-key.pem \
      -certfile ca-cert.pem -out ryans.pfx
bash

Where:

  • in: is the signed certificate
  • inkey: is the associated private key
  • certfile: is a concatenation of all Certificate Authority (CA) certs into a single file, e.g. cat ca1-cert.pem ca2-cert.pem > ca-cert.pem

Perfect forward secrecy#

The term forward secrecy or perfect forward secrecy describes a feature of key-agreement (i.e., key-exchange) methods. That is, the server and client keys are used to negotiate new temporary keys that are used specifically and only for the current communication session. Practically, this means that even if the server's private key is compromised, communication can only be decrypted by eavesdroppers if the attacker manages to obtain the key-pair specifically generated for the session.

Perfect forward secrecy is achieved by randomly generating a key pair for key-agreement on every TLS/SSL handshake (in contrast to using the same key for all sessions). Methods implementing this technique are called "ephemeral".

Currently two methods are commonly used to achieve perfect forward secrecy (note the character "E" appended to the traditional abbreviations):

  • ECDHE: An ephemeral version of the Elliptic Curve Diffie-Hellman key-agreement protocol.
  • DHE: An ephemeral version of the Diffie-Hellman key-agreement protocol.

Perfect forward secrecy using ECDHE is enabled by default. The ecdhCurve option can be used when creating a TLS server to customize the list of supported ECDH curves for TLSv1.2 and below, and the list of supported TLS groups for TLSv1.3. See tls.createServer() for more info.

DHE is disabled by default but can be enabled alongside ECDHE by setting the dhparam option to 'auto'. Custom DHE parameters are also supported but discouraged in favor of automatically selected, well-known parameters.

Perfect forward secrecy was optional up to TLSv1.2. As of TLSv1.3, (EC)DHE is always used (with the exception of PSK-only connections).

ALPN and SNI#

ALPN (Application-Layer Protocol Negotiation Extension) and SNI (Server Name Indication) are TLS handshake extensions:

  • ALPN: Allows the use of one TLS server for multiple protocols (HTTP, HTTP/2)
  • SNI: Allows the use of one TLS server for multiple hostnames with different certificates.

Pre-shared keys#

TLS-PSK support is available as an alternative to normal certificate-based authentication. It uses a pre-shared key instead of certificates to authenticate a TLS connection, providing mutual authentication. TLS-PSK and public key infrastructure are not mutually exclusive. Clients and servers can accommodate both, choosing either of them during the normal cipher negotiation step.

TLS-PSK is only a good choice where means exist to securely share a key with every connecting machine, so it does not replace the public key infrastructure (PKI) for the majority of TLS uses. The TLS-PSK implementation in OpenSSL has seen many security flaws in recent years, mostly because it is used only by a minority of applications. Please consider all alternative solutions before switching to PSK ciphers. Upon generating PSK it is of critical importance to use sufficient entropy as discussed in RFC 4086. Deriving a shared secret from a password or other low-entropy sources is not secure.

PSK ciphers are disabled by default, and using TLS-PSK thus requires explicitly specifying a cipher suite with the ciphers option. The list of available ciphers can be retrieved via openssl ciphers -v 'PSK'. All TLS 1.3 ciphers are eligible for PSK and can be retrieved via openssl ciphers -v -s -tls1_3 -psk. On the client connection, a custom checkServerIdentity should be passed because the default one will fail in the absence of a certificate.

According to the RFC 4279, PSK identities up to 128 bytes in length and PSKs up to 64 bytes in length must be supported. As of OpenSSL 1.1.0 maximum identity size is 128 bytes, and maximum PSK length is 256 bytes.

The current implementation doesn't support asynchronous PSK callbacks due to the limitations of the underlying OpenSSL API.

To use TLS-PSK, client and server must specify the pskCallback option, a function that returns the PSK to use (which must be compatible with the selected cipher's digest).

It will be called first on the client: