From 3b61842f4327114c5e1eb7db68d1bdc30578baf0 Mon Sep 17 00:00:00 2001 From: Avocado Date: Tue, 11 Aug 2026 14:34:16 +0900 Subject: [PATCH] doc: document secure use of new tls.TLSSocket() Explain that constructing TLSSocket directly does not authenticate the peer. Document ssl.verifyError() and show how to validate certificates and identity on the 'secure' event. Fixes: https://github.com/nodejs/node/issues/43994 Signed-off-by: Avocado --- doc/api/tls.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/doc/api/tls.md b/doc/api/tls.md index f98bb2976721..9a40aa16f04b 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -911,6 +911,23 @@ changes: Construct a new `tls.TLSSocket` object from an existing TCP socket. +[`tls.connect()`][] is preferred when creating a new TLS session on top of a +new `net.Socket`. Constructing a `tls.TLSSocket` directly is useful when +implementing protocols that can start insecurely (such as SMTP) and then +upgrade an existing connection to TLS. + +> **Warning**: When constructing a `tls.TLSSocket` directly instead of using +> [`tls.connect()`][], it is the caller's responsibility to: +> +> * manage the lifetime of the underlying socket, including connecting it; +> * validate the peer certificate and identity before treating the connection +> as secure. See the [`'secure'`][] event. +> +> Unlike [`tls.connect()`][], direct construction does not emit +> [`'secureConnect'`][], does not set [`tlsSocket.authorized`][] / +> [`tlsSocket.authorizationError`][] after the handshake, and does not run +> [`tls.checkServerIdentity()`][] automatically. + ### Event: `'keylog'` The `'secure'` event is emitted after the TLS handshake has successfully -completed and a secure connection has been established. +completed. This event is emitted on both client and server {tls.TLSSocket} instances, including sockets created using the `new tls.TLSSocket()` constructor. +Handshake completion alone does not mean the peer was authenticated. When the +socket was created with [`tls.connect()`][], Node.js performs certificate and +identity checks and then emits [`'secureConnect'`][]. When using +`new tls.TLSSocket()` directly, those checks are the caller's responsibility. +Before using the connection, verify: + +1. The peer certificate is trusted, see [`tlsSocket.ssl.verifyError()`][]. +2. The peer certificate matches the expected host, see + [`tls.checkServerIdentity()`][] and [`tls.TLSSocket.getPeerCertificate()`][]. + +If these checks are skipped, the connection should be considered insecure. + +```js +const { checkServerIdentity } = require('node:tls'); + +// `hostname` is the expected server name (for example, 'example.com'). +tlsSocket.on('secure', () => { + const err = tlsSocket.ssl.verifyError() || + checkServerIdentity(hostname, tlsSocket.getPeerCertificate()); + if (err) { + tlsSocket.destroy(err); + } +}); +``` + ### Event: `'secureConnect'` + +* Type: {Object} + +The underlying OpenSSL `TLSWrap` handle for this socket. + +#### `tlsSocket.ssl.verifyError()` + +* Returns: {Error|null} + +Returns an {Error} object describing why certificate verification failed, or +`null` if verification succeeded (OpenSSL `X509_V_OK`). + +This is the certificate-chain verification result from OpenSSL. It does **not** +check that the certificate matches the expected host name; use +[`tls.checkServerIdentity()`][] for that. + +When using [`tls.connect()`][], prefer [`tlsSocket.authorized`][] and +[`tlsSocket.authorizationError`][], which are set after Node.js runs these +checks. For sockets created with `new tls.TLSSocket()`, call `verifyError()` +from a [`'secure'`][] listener before using the connection. + ### `tlsSocket.disableRenegotiation()`