2017-01-03 21:16:48 +00:00
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
// following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2014-11-22 15:59:48 +00:00
|
|
|
'use strict';
|
|
|
|
|
2019-11-22 17:04:46 +00:00
|
|
|
const {
|
|
|
|
ObjectAssign,
|
|
|
|
ObjectDefineProperty,
|
|
|
|
ObjectSetPrototypeOf,
|
2020-11-17 22:09:52 +00:00
|
|
|
ReflectApply,
|
2020-01-06 02:48:14 +00:00
|
|
|
RegExp,
|
2019-11-30 15:55:29 +00:00
|
|
|
Symbol,
|
2019-12-08 17:33:33 +00:00
|
|
|
SymbolFor,
|
2019-11-22 17:04:46 +00:00
|
|
|
} = primordials;
|
2019-04-09 07:55:53 +00:00
|
|
|
|
2019-03-18 16:31:43 +00:00
|
|
|
const {
|
|
|
|
assertCrypto,
|
2022-05-21 09:57:01 +00:00
|
|
|
deprecate,
|
|
|
|
kEmptyObject,
|
2019-03-18 16:31:43 +00:00
|
|
|
} = require('internal/util');
|
|
|
|
|
|
|
|
assertCrypto();
|
2016-03-08 23:31:31 +00:00
|
|
|
|
2019-04-05 21:56:00 +00:00
|
|
|
const { setImmediate } = require('timers');
|
2019-02-06 05:45:46 +00:00
|
|
|
const assert = require('internal/assert');
|
2015-01-21 16:36:59 +00:00
|
|
|
const crypto = require('crypto');
|
2019-10-01 16:06:22 +00:00
|
|
|
const EE = require('events');
|
2015-01-21 16:36:59 +00:00
|
|
|
const net = require('net');
|
|
|
|
const tls = require('tls');
|
|
|
|
const common = require('_tls_common');
|
2023-02-23 09:47:13 +00:00
|
|
|
const { kReinitializeHandle } = require('internal/net');
|
2018-12-19 22:14:57 +00:00
|
|
|
const JSStreamSocket = require('internal/js_stream_socket');
|
2017-10-07 14:50:42 +00:00
|
|
|
const { Buffer } = require('buffer');
|
2020-03-14 11:55:44 +00:00
|
|
|
let debug = require('internal/util/debuglog').debuglog('tls', (fn) => {
|
|
|
|
debug = fn;
|
|
|
|
});
|
2018-08-21 06:54:02 +00:00
|
|
|
const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
|
2018-08-21 06:54:02 +00:00
|
|
|
const tls_wrap = internalBinding('tls_wrap');
|
2018-08-23 15:36:43 +00:00
|
|
|
const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
|
2018-07-27 12:35:39 +00:00
|
|
|
const { owner_symbol } = require('internal/async_hooks').symbols;
|
2018-10-29 08:38:43 +00:00
|
|
|
const { isArrayBufferView } = require('internal/util/types');
|
2018-08-21 06:54:02 +00:00
|
|
|
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
|
2018-03-04 21:16:24 +00:00
|
|
|
const {
|
2024-04-23 17:05:38 +00:00
|
|
|
ConnResetException,
|
|
|
|
codes: {
|
|
|
|
ERR_INVALID_ARG_TYPE,
|
|
|
|
ERR_INVALID_ARG_VALUE,
|
|
|
|
ERR_MULTIPLE_CALLBACK,
|
|
|
|
ERR_SOCKET_CLOSED,
|
|
|
|
ERR_TLS_ALPN_CALLBACK_INVALID_RESULT,
|
|
|
|
ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS,
|
|
|
|
ERR_TLS_DH_PARAM_SIZE,
|
|
|
|
ERR_TLS_HANDSHAKE_TIMEOUT,
|
|
|
|
ERR_TLS_INVALID_CONTEXT,
|
|
|
|
ERR_TLS_INVALID_STATE,
|
|
|
|
ERR_TLS_RENEGOTIATION_DISABLED,
|
|
|
|
ERR_TLS_REQUIRED_SERVER_NAME,
|
|
|
|
ERR_TLS_SESSION_ATTACK,
|
|
|
|
ERR_TLS_SNI_FROM_SERVER,
|
|
|
|
},
|
|
|
|
} = require('internal/errors');
|
2018-10-29 08:38:43 +00:00
|
|
|
const { onpskexchange: kOnPskExchange } = internalBinding('symbols');
|
2020-04-18 18:25:04 +00:00
|
|
|
const {
|
|
|
|
getOptionValue,
|
|
|
|
getAllowUnauthorized,
|
|
|
|
} = require('internal/options');
|
2020-02-15 17:55:59 +00:00
|
|
|
const {
|
2021-05-16 11:22:48 +00:00
|
|
|
validateBoolean,
|
2021-01-21 11:03:00 +00:00
|
|
|
validateBuffer,
|
2021-05-16 11:22:48 +00:00
|
|
|
validateFunction,
|
2021-04-09 17:12:59 +00:00
|
|
|
validateInt32,
|
2021-05-16 11:22:48 +00:00
|
|
|
validateNumber,
|
2021-01-21 11:03:00 +00:00
|
|
|
validateObject,
|
2020-02-15 17:55:59 +00:00
|
|
|
validateString,
|
2021-04-09 17:12:59 +00:00
|
|
|
validateUint32,
|
2020-02-15 17:55:59 +00:00
|
|
|
} = require('internal/validators');
|
2021-01-26 00:38:51 +00:00
|
|
|
const {
|
2023-02-22 00:22:23 +00:00
|
|
|
InternalX509Certificate,
|
2021-01-26 00:38:51 +00:00
|
|
|
} = require('internal/crypto/x509');
|
2019-04-30 16:19:10 +00:00
|
|
|
const traceTls = getOptionValue('--trace-tls');
|
2019-10-22 03:44:20 +00:00
|
|
|
const tlsKeylog = getOptionValue('--tls-keylog');
|
|
|
|
const { appendFile } = require('fs');
|
2017-09-23 18:18:28 +00:00
|
|
|
const kConnectOptions = Symbol('connect-options');
|
2016-11-04 19:37:36 +00:00
|
|
|
const kDisableRenegotiation = Symbol('disable-renegotiation');
|
2017-09-23 18:18:28 +00:00
|
|
|
const kErrorEmitted = Symbol('error-emitted');
|
|
|
|
const kHandshakeTimeout = Symbol('handshake-timeout');
|
|
|
|
const kRes = Symbol('res');
|
|
|
|
const kSNICallback = Symbol('snicallback');
|
2023-06-28 14:30:30 +00:00
|
|
|
const kALPNCallback = Symbol('alpncallback');
|
2019-02-13 22:54:07 +00:00
|
|
|
const kEnableTrace = Symbol('enableTrace');
|
2018-10-29 08:38:43 +00:00
|
|
|
const kPskCallback = Symbol('pskcallback');
|
|
|
|
const kPskIdentityHint = Symbol('pskidentityhint');
|
2020-03-18 03:51:38 +00:00
|
|
|
const kPendingSession = Symbol('pendingSession');
|
|
|
|
const kIsVerified = Symbol('verified');
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2024-07-07 00:56:04 +00:00
|
|
|
const noop = () => {};
|
2013-09-24 12:53:49 +00:00
|
|
|
|
2018-01-12 23:36:21 +00:00
|
|
|
let ipServernameWarned = false;
|
2019-04-30 16:19:10 +00:00
|
|
|
let tlsTracingWarned = false;
|
2018-01-12 23:36:21 +00:00
|
|
|
|
2019-01-31 22:41:10 +00:00
|
|
|
// Server side times how long a handshake is taking to protect against slow
|
|
|
|
// handshakes being used for DoS.
|
2018-02-04 16:51:18 +00:00
|
|
|
function onhandshakestart(now) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server onhandshakestart');
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-05-02 10:49:13 +00:00
|
|
|
const { lastHandshakeTime } = this;
|
2018-08-31 15:42:54 +00:00
|
|
|
assert(now >= lastHandshakeTime,
|
|
|
|
`now (${now}) < lastHandshakeTime (${lastHandshakeTime})`);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-05-02 10:49:13 +00:00
|
|
|
this.lastHandshakeTime = now;
|
2018-02-04 16:51:18 +00:00
|
|
|
|
2018-05-02 10:49:13 +00:00
|
|
|
// If this is the first handshake we can skip the rest of the checks.
|
|
|
|
if (lastHandshakeTime === 0)
|
|
|
|
return;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-05-02 10:49:13 +00:00
|
|
|
if ((now - lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000)
|
|
|
|
this.handshakes = 1;
|
|
|
|
else
|
|
|
|
this.handshakes++;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-07-27 12:35:39 +00:00
|
|
|
const owner = this[owner_symbol];
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
|
|
|
|
assert(owner._tlsOptions.isServer);
|
|
|
|
|
2018-05-02 10:49:13 +00:00
|
|
|
if (this.handshakes > tls.CLIENT_RENEG_LIMIT) {
|
|
|
|
owner._emitTLSError(new ERR_TLS_SESSION_ATTACK());
|
|
|
|
return;
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
2016-11-04 19:37:36 +00:00
|
|
|
|
2018-05-02 10:49:13 +00:00
|
|
|
if (owner[kDisableRenegotiation])
|
2018-03-04 21:16:24 +00:00
|
|
|
owner._emitTLSError(new ERR_TLS_RENEGOTIATION_DISABLED());
|
2017-09-23 18:18:28 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
function onhandshakedone() {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server onhandshakedone');
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2018-07-27 12:35:39 +00:00
|
|
|
const owner = this[owner_symbol];
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
assert(owner._tlsOptions.isServer);
|
2017-09-23 18:18:28 +00:00
|
|
|
|
|
|
|
// `newSession` callback wasn't called yet
|
|
|
|
if (owner._newSessionPending) {
|
|
|
|
owner._securePending = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
owner._finishInit();
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function loadSession(hello) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server onclienthello',
|
|
|
|
'sessionid.len', hello.sessionId.length,
|
2023-02-14 17:45:16 +00:00
|
|
|
'ticket?', hello.tlsTicket,
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
);
|
2018-07-27 12:35:39 +00:00
|
|
|
const owner = this[owner_symbol];
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2019-11-06 14:12:45 +00:00
|
|
|
let once = false;
|
2014-04-14 17:15:57 +00:00
|
|
|
function onSession(err, session) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server resumeSession callback(err %j, sess? %s)', err, !!session);
|
2014-04-14 17:15:57 +00:00
|
|
|
if (once)
|
2018-03-04 21:16:24 +00:00
|
|
|
return owner.destroy(new ERR_MULTIPLE_CALLBACK());
|
2014-04-14 17:15:57 +00:00
|
|
|
once = true;
|
2013-06-17 10:11:13 +00:00
|
|
|
|
|
|
|
if (err)
|
2017-09-23 18:18:28 +00:00
|
|
|
return owner.destroy(err);
|
2013-06-17 10:11:13 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
if (owner._handle === null)
|
2018-03-04 21:16:24 +00:00
|
|
|
return owner.destroy(new ERR_SOCKET_CLOSED());
|
2015-05-14 08:38:18 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._handle.loadSession(session);
|
2019-01-31 22:41:10 +00:00
|
|
|
// Session is loaded. End the parser to allow handshaking to continue.
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._handle.endParser();
|
2014-04-14 17:15:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hello.sessionId.length <= 0 ||
|
|
|
|
hello.tlsTicket ||
|
2019-10-03 16:35:41 +00:00
|
|
|
(owner.server &&
|
|
|
|
!owner.server.emit('resumeSession', hello.sessionId, onSession))) {
|
2019-01-31 22:41:10 +00:00
|
|
|
// Sessions without identifiers can't be resumed.
|
|
|
|
// Sessions with tickets can be resumed directly from the ticket, no server
|
|
|
|
// session storage is necessary.
|
|
|
|
// Without a call to a resumeSession listener, a session will never be
|
|
|
|
// loaded, so end the parser to allow handshaking to continue.
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._handle.endParser();
|
2014-04-14 17:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function loadSNI(info) {
|
2018-07-27 12:35:39 +00:00
|
|
|
const owner = this[owner_symbol];
|
2017-09-23 18:18:28 +00:00
|
|
|
const servername = info.servername;
|
|
|
|
if (!servername || !owner._SNICallback)
|
|
|
|
return requestOCSP(owner, info);
|
2014-04-14 17:15:57 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
let once = false;
|
|
|
|
owner._SNICallback(servername, (err, context) => {
|
2014-04-14 17:15:57 +00:00
|
|
|
if (once)
|
2018-03-04 21:16:24 +00:00
|
|
|
return owner.destroy(new ERR_MULTIPLE_CALLBACK());
|
2014-04-14 17:15:57 +00:00
|
|
|
once = true;
|
|
|
|
|
|
|
|
if (err)
|
2017-09-23 18:18:28 +00:00
|
|
|
return owner.destroy(err);
|
2014-04-14 17:15:57 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
if (owner._handle === null)
|
2018-03-04 21:16:24 +00:00
|
|
|
return owner.destroy(new ERR_SOCKET_CLOSED());
|
2015-05-14 08:38:18 +00:00
|
|
|
|
2014-04-14 17:15:57 +00:00
|
|
|
// TODO(indutny): eventually disallow raw `SecureContext`
|
|
|
|
if (context)
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._handle.sni_context = context.context || context;
|
2014-04-14 17:15:57 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
requestOCSP(owner, info);
|
2014-04-14 17:15:57 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-28 14:30:30 +00:00
|
|
|
function callALPNCallback(protocolsBuffer) {
|
|
|
|
const handle = this;
|
|
|
|
const socket = handle[owner_symbol];
|
|
|
|
|
|
|
|
const servername = handle.getServername();
|
|
|
|
|
|
|
|
// Collect all the protocols from the given buffer:
|
|
|
|
const protocols = [];
|
|
|
|
let offset = 0;
|
|
|
|
while (offset < protocolsBuffer.length) {
|
|
|
|
const protocolLen = protocolsBuffer[offset];
|
|
|
|
offset += 1;
|
|
|
|
|
|
|
|
const protocol = protocolsBuffer.slice(offset, offset + protocolLen);
|
|
|
|
offset += protocolLen;
|
|
|
|
|
|
|
|
protocols.push(protocol.toString('ascii'));
|
|
|
|
}
|
|
|
|
|
|
|
|
const selectedProtocol = socket[kALPNCallback]({
|
|
|
|
servername,
|
|
|
|
protocols,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Undefined -> all proposed protocols rejected
|
|
|
|
if (selectedProtocol === undefined) return undefined;
|
|
|
|
|
|
|
|
const protocolIndex = protocols.indexOf(selectedProtocol);
|
|
|
|
if (protocolIndex === -1) {
|
|
|
|
throw new ERR_TLS_ALPN_CALLBACK_INVALID_RESULT(selectedProtocol, protocols);
|
|
|
|
}
|
|
|
|
let protocolOffset = 0;
|
|
|
|
for (let i = 0; i < protocolIndex; i++) {
|
|
|
|
protocolOffset += 1 + protocols[i].length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return protocolOffset;
|
|
|
|
}
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function requestOCSP(socket, info) {
|
|
|
|
if (!info.OCSPRequest || !socket.server)
|
|
|
|
return requestOCSPDone(socket);
|
2014-04-14 17:15:57 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
let ctx = socket._handle.sni_context;
|
2017-01-09 13:38:31 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
if (!ctx) {
|
|
|
|
ctx = socket.server._sharedCreds;
|
|
|
|
|
|
|
|
// TLS socket is using a `net.Server` instead of a tls.TLSServer.
|
|
|
|
// Some TLS properties like `server._sharedCreds` will not be present
|
|
|
|
if (!ctx)
|
|
|
|
return requestOCSPDone(socket);
|
|
|
|
}
|
2017-01-09 13:38:31 +00:00
|
|
|
|
|
|
|
// TODO(indutny): eventually disallow raw `SecureContext`
|
2014-04-14 17:15:57 +00:00
|
|
|
if (ctx.context)
|
|
|
|
ctx = ctx.context;
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
if (socket.server.listenerCount('OCSPRequest') === 0) {
|
|
|
|
return requestOCSPDone(socket);
|
2014-04-14 17:15:57 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
let once = false;
|
|
|
|
const onOCSP = (err, response) => {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server OCSPRequest done', 'handle?', !!socket._handle, 'once?', once,
|
|
|
|
'response?', !!response, 'err?', err);
|
2014-04-14 17:15:57 +00:00
|
|
|
if (once)
|
2018-03-04 21:16:24 +00:00
|
|
|
return socket.destroy(new ERR_MULTIPLE_CALLBACK());
|
2014-04-14 17:15:57 +00:00
|
|
|
once = true;
|
|
|
|
|
|
|
|
if (err)
|
2017-09-23 18:18:28 +00:00
|
|
|
return socket.destroy(err);
|
2014-04-14 17:15:57 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
if (socket._handle === null)
|
2018-03-04 21:16:24 +00:00
|
|
|
return socket.destroy(new ERR_SOCKET_CLOSED());
|
2015-05-14 08:38:18 +00:00
|
|
|
|
2014-04-14 17:15:57 +00:00
|
|
|
if (response)
|
2017-09-23 18:18:28 +00:00
|
|
|
socket._handle.setOCSPResponse(response);
|
|
|
|
requestOCSPDone(socket);
|
|
|
|
};
|
2014-04-14 17:15:57 +00:00
|
|
|
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server oncertcb emit OCSPRequest');
|
2017-09-23 18:18:28 +00:00
|
|
|
socket.server.emit('OCSPRequest',
|
|
|
|
ctx.getCertificate(),
|
|
|
|
ctx.getIssuer(),
|
|
|
|
onOCSP);
|
2015-04-18 08:19:23 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function requestOCSPDone(socket) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server certcb done');
|
2017-09-23 18:18:28 +00:00
|
|
|
try {
|
|
|
|
socket._handle.certCbDone();
|
|
|
|
} catch (e) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server certcb done errored', e);
|
2017-09-23 18:18:28 +00:00
|
|
|
socket.destroy(e);
|
|
|
|
}
|
2013-06-17 10:11:13 +00:00
|
|
|
}
|
|
|
|
|
2019-01-30 20:18:04 +00:00
|
|
|
function onnewsessionclient(sessionId, session) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('client emit session');
|
2019-01-30 20:18:04 +00:00
|
|
|
const owner = this[owner_symbol];
|
2020-03-18 03:51:38 +00:00
|
|
|
if (owner[kIsVerified]) {
|
|
|
|
owner.emit('session', session);
|
|
|
|
} else {
|
|
|
|
owner[kPendingSession] = session;
|
|
|
|
}
|
2019-01-30 20:18:04 +00:00
|
|
|
}
|
|
|
|
|
2018-12-19 22:45:51 +00:00
|
|
|
function onnewsession(sessionId, session) {
|
2019-01-31 22:41:10 +00:00
|
|
|
debug('onnewsession');
|
2018-07-27 12:35:39 +00:00
|
|
|
const owner = this[owner_symbol];
|
2017-09-23 18:18:28 +00:00
|
|
|
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
// 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?
|
2017-09-23 18:18:28 +00:00
|
|
|
if (!owner.server)
|
2014-02-14 13:01:34 +00:00
|
|
|
return;
|
|
|
|
|
2019-11-06 14:12:45 +00:00
|
|
|
let once = false;
|
2017-09-23 18:18:28 +00:00
|
|
|
const done = () => {
|
2019-01-31 22:41:10 +00:00
|
|
|
debug('onnewsession done');
|
2014-02-14 13:01:34 +00:00
|
|
|
if (once)
|
|
|
|
return;
|
|
|
|
once = true;
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
if (owner._handle === null)
|
2018-03-04 21:16:24 +00:00
|
|
|
return owner.destroy(new ERR_SOCKET_CLOSED());
|
2015-05-14 08:38:18 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
this.newSessionDone();
|
2014-02-14 13:01:34 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._newSessionPending = false;
|
|
|
|
if (owner._securePending)
|
|
|
|
owner._finishInit();
|
|
|
|
owner._securePending = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
owner._newSessionPending = true;
|
2018-12-19 22:45:51 +00:00
|
|
|
if (!owner.server.emit('newSession', sessionId, session, done))
|
2017-09-23 18:18:28 +00:00
|
|
|
done();
|
2013-06-17 10:11:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 08:38:43 +00:00
|
|
|
function onPskServerCallback(identity, maxPskLen) {
|
|
|
|
const owner = this[owner_symbol];
|
|
|
|
const ret = owner[kPskCallback](owner, identity);
|
|
|
|
if (ret == null)
|
|
|
|
return undefined;
|
|
|
|
|
|
|
|
let psk;
|
|
|
|
if (isArrayBufferView(ret)) {
|
|
|
|
psk = ret;
|
|
|
|
} else {
|
|
|
|
if (typeof ret !== 'object') {
|
|
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
|
|
'ret',
|
|
|
|
['Object', 'Buffer', 'TypedArray', 'DataView'],
|
2023-02-14 17:45:16 +00:00
|
|
|
ret,
|
2018-10-29 08:38:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
psk = ret.psk;
|
|
|
|
validateBuffer(psk, 'psk');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psk.length > maxPskLen) {
|
|
|
|
throw new ERR_INVALID_ARG_VALUE(
|
|
|
|
'psk',
|
|
|
|
psk,
|
2023-02-14 17:45:16 +00:00
|
|
|
`Pre-shared key exceeds ${maxPskLen} bytes`,
|
2018-10-29 08:38:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return psk;
|
|
|
|
}
|
|
|
|
|
|
|
|
function onPskClientCallback(hint, maxPskLen, maxIdentityLen) {
|
|
|
|
const owner = this[owner_symbol];
|
|
|
|
const ret = owner[kPskCallback](hint);
|
|
|
|
if (ret == null)
|
|
|
|
return undefined;
|
|
|
|
|
2021-01-21 11:03:00 +00:00
|
|
|
validateObject(ret, 'ret');
|
2018-10-29 08:38:43 +00:00
|
|
|
|
|
|
|
validateBuffer(ret.psk, 'psk');
|
|
|
|
if (ret.psk.length > maxPskLen) {
|
|
|
|
throw new ERR_INVALID_ARG_VALUE(
|
|
|
|
'psk',
|
|
|
|
ret.psk,
|
2023-02-14 17:45:16 +00:00
|
|
|
`Pre-shared key exceeds ${maxPskLen} bytes`,
|
2018-10-29 08:38:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
validateString(ret.identity, 'identity');
|
|
|
|
if (Buffer.byteLength(ret.identity) > maxIdentityLen) {
|
|
|
|
throw new ERR_INVALID_ARG_VALUE(
|
|
|
|
'identity',
|
|
|
|
ret.identity,
|
2023-02-14 17:45:16 +00:00
|
|
|
`PSK identity exceeds ${maxIdentityLen} bytes`,
|
2018-10-29 08:38:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return { psk: ret.psk, identity: ret.identity };
|
|
|
|
}
|
2013-06-17 10:11:13 +00:00
|
|
|
|
2019-05-11 21:07:06 +00:00
|
|
|
function onkeylog(line) {
|
2020-05-12 12:53:12 +00:00
|
|
|
debug('onkeylog');
|
|
|
|
this[owner_symbol].emit('keylog', line);
|
2019-05-11 21:07:06 +00:00
|
|
|
}
|
|
|
|
|
2014-04-14 17:15:57 +00:00
|
|
|
function onocspresponse(resp) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('client onocspresponse');
|
2018-07-27 12:35:39 +00:00
|
|
|
this[owner_symbol].emit('OCSPResponse', resp);
|
2017-09-23 18:18:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function onerror(err) {
|
2018-07-27 12:35:39 +00:00
|
|
|
const owner = this[owner_symbol];
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('%s onerror %s had? %j',
|
2022-02-14 08:08:37 +00:00
|
|
|
(typeof owner._tlsOptions === 'object' && owner._tlsOptions !== null) ?
|
|
|
|
owner._tlsOptions.isServer ? 'server' : 'client' :
|
|
|
|
'unknown',
|
|
|
|
err, owner._hadError);
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2018-10-13 04:59:35 +00:00
|
|
|
if (owner._hadError)
|
2017-09-23 18:18:28 +00:00
|
|
|
return;
|
|
|
|
|
2018-10-13 04:59:35 +00:00
|
|
|
owner._hadError = true;
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
// Destroy socket if error happened before handshake's finish
|
|
|
|
if (!owner._secureEstablished) {
|
|
|
|
// When handshake fails control is not yet released,
|
|
|
|
// so self._tlsError will return null instead of actual error
|
2022-08-01 06:37:45 +00:00
|
|
|
|
|
|
|
// Set closing the socket after emitting an event since the socket needs to
|
2023-02-25 20:29:59 +00:00
|
|
|
// be accessible when the `tlsClientError` event is emitted.
|
2022-08-01 06:37:45 +00:00
|
|
|
owner._closeAfterHandlingError = true;
|
2017-09-23 18:18:28 +00:00
|
|
|
owner.destroy(err);
|
2022-02-14 08:08:37 +00:00
|
|
|
} else if (owner._tlsOptions?.isServer &&
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._rejectUnauthorized &&
|
2024-07-07 00:56:04 +00:00
|
|
|
/peer did not return a certificate/.test(err.message)) {
|
2017-09-23 18:18:28 +00:00
|
|
|
// Ignore server's authorization errors
|
|
|
|
owner.destroy();
|
|
|
|
} else {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
// Emit error
|
2017-09-23 18:18:28 +00:00
|
|
|
owner._emitTLSError(err);
|
|
|
|
}
|
2014-04-14 17:15:57 +00:00
|
|
|
}
|
|
|
|
|
2018-12-19 22:30:20 +00:00
|
|
|
// Used by both client and server TLSSockets to start data flowing from _handle,
|
|
|
|
// read(0) causes a StreamBase::ReadStart, via Socket._read.
|
2019-01-31 22:07:36 +00:00
|
|
|
function initRead(tlsSocket, socket) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('%s initRead',
|
|
|
|
tlsSocket._tlsOptions.isServer ? 'server' : 'client',
|
|
|
|
'handle?', !!tlsSocket._handle,
|
2023-02-14 17:45:16 +00:00
|
|
|
'buffered?', !!socket && socket.readableLength,
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
);
|
2015-06-08 22:25:06 +00:00
|
|
|
// If we were destroyed already don't bother reading
|
2019-01-31 22:07:36 +00:00
|
|
|
if (!tlsSocket._handle)
|
2015-06-08 22:25:06 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Socket already has some buffered data - emulate receiving it
|
2024-09-24 19:48:15 +00:00
|
|
|
if (socket?.readableLength) {
|
2019-11-06 14:12:45 +00:00
|
|
|
let buf;
|
2018-12-19 22:30:20 +00:00
|
|
|
while ((buf = socket.read()) !== null)
|
2019-01-31 22:07:36 +00:00
|
|
|
tlsSocket._handle.receive(buf);
|
2015-06-08 22:25:06 +00:00
|
|
|
}
|
|
|
|
|
2019-01-31 22:07:36 +00:00
|
|
|
tlsSocket.read(0);
|
2015-06-08 22:25:06 +00:00
|
|
|
}
|
2014-04-14 17:15:57 +00:00
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
/**
|
|
|
|
* Provides a wrap of socket stream to do encrypted communication.
|
|
|
|
*/
|
|
|
|
|
2017-10-31 20:03:28 +00:00
|
|
|
function TLSSocket(socket, opts) {
|
2018-12-18 01:28:09 +00:00
|
|
|
const tlsOptions = { ...opts };
|
2019-04-30 16:19:10 +00:00
|
|
|
let enableTrace = tlsOptions.enableTrace;
|
2019-04-30 15:46:56 +00:00
|
|
|
|
2019-04-30 16:19:10 +00:00
|
|
|
if (enableTrace == null) {
|
|
|
|
enableTrace = traceTls;
|
|
|
|
|
|
|
|
if (enableTrace && !tlsTracingWarned) {
|
|
|
|
tlsTracingWarned = true;
|
|
|
|
process.emitWarning('Enabling --trace-tls can expose sensitive data in ' +
|
|
|
|
'the resulting log.');
|
|
|
|
}
|
2021-05-16 11:22:48 +00:00
|
|
|
} else {
|
|
|
|
validateBoolean(enableTrace, 'options.enableTrace');
|
2019-04-30 15:46:56 +00:00
|
|
|
}
|
2017-10-31 20:03:28 +00:00
|
|
|
|
|
|
|
if (tlsOptions.ALPNProtocols)
|
|
|
|
tls.convertALPNProtocols(tlsOptions.ALPNProtocols, tlsOptions);
|
|
|
|
|
|
|
|
this._tlsOptions = tlsOptions;
|
2013-06-13 13:36:00 +00:00
|
|
|
this._secureEstablished = false;
|
2014-02-14 13:01:34 +00:00
|
|
|
this._securePending = false;
|
|
|
|
this._newSessionPending = false;
|
2013-06-13 13:36:00 +00:00
|
|
|
this._controlReleased = false;
|
2020-04-21 22:55:54 +00:00
|
|
|
this.secureConnecting = true;
|
2013-08-03 17:29:54 +00:00
|
|
|
this._SNICallback = null;
|
2023-06-28 14:30:30 +00:00
|
|
|
this[kALPNCallback] = null;
|
2013-06-13 13:36:00 +00:00
|
|
|
this.servername = null;
|
2015-04-23 06:25:15 +00:00
|
|
|
this.alpnProtocol = null;
|
2013-06-13 13:36:00 +00:00
|
|
|
this.authorized = false;
|
|
|
|
this.authorizationError = null;
|
2017-09-23 18:18:28 +00:00
|
|
|
this[kRes] = null;
|
2020-03-18 03:51:38 +00:00
|
|
|
this[kIsVerified] = false;
|
|
|
|
this[kPendingSession] = null;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2019-11-06 14:12:45 +00:00
|
|
|
let wrap;
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
let handle;
|
|
|
|
let wrapHasActiveWriteFromPrevOwner;
|
|
|
|
|
|
|
|
if (socket) {
|
|
|
|
if (socket instanceof net.Socket && socket._handle) {
|
|
|
|
// 1. connected socket
|
|
|
|
wrap = socket;
|
|
|
|
} else {
|
|
|
|
// 2. socket has no handle so it is js not c++
|
|
|
|
// 3. unconnected sockets are wrapped
|
|
|
|
// TLS expects to interact from C++ with a net.Socket that has a C++ stream
|
|
|
|
// handle, but a JS stream doesn't have one. Wrap it up to make it look like
|
|
|
|
// a socket.
|
|
|
|
wrap = new JSStreamSocket(socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
handle = wrap._handle;
|
|
|
|
wrapHasActiveWriteFromPrevOwner = wrap.writableLength > 0;
|
2018-11-10 20:11:17 +00:00
|
|
|
} else {
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
// 4. no socket, one will be created with net.Socket().connect
|
|
|
|
wrap = null;
|
|
|
|
wrapHasActiveWriteFromPrevOwner = false;
|
2018-11-10 20:11:17 +00:00
|
|
|
}
|
2015-02-23 20:09:44 +00:00
|
|
|
|
2013-12-19 09:04:34 +00:00
|
|
|
// Just a documented property to make secure sockets
|
|
|
|
// distinguishable from regular ones.
|
|
|
|
this.encrypted = true;
|
|
|
|
|
2020-11-17 22:09:52 +00:00
|
|
|
ReflectApply(net.Socket, this, [{
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
handle: this._wrapHandle(wrap, handle, wrapHasActiveWriteFromPrevOwner),
|
2019-05-23 09:48:52 +00:00
|
|
|
allowHalfOpen: socket ? socket.allowHalfOpen : tlsOptions.allowHalfOpen,
|
2019-09-20 18:15:16 +00:00
|
|
|
pauseOnCreate: tlsOptions.pauseOnConnect,
|
2020-04-11 18:07:35 +00:00
|
|
|
manualStart: true,
|
|
|
|
highWaterMark: tlsOptions.highWaterMark,
|
2020-10-22 09:04:35 +00:00
|
|
|
onread: !socket ? tlsOptions.onread : null,
|
2021-03-12 23:13:36 +00:00
|
|
|
signal: tlsOptions.signal,
|
2020-11-17 22:09:52 +00:00
|
|
|
}]);
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
|
|
|
|
// Proxy for API compatibility
|
2019-01-31 22:41:10 +00:00
|
|
|
this.ssl = this._handle; // C++ TLSWrap object
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
|
2016-10-01 19:17:51 +00:00
|
|
|
this.on('error', this._tlsError);
|
2013-08-07 12:50:36 +00:00
|
|
|
|
2015-03-03 20:17:43 +00:00
|
|
|
this._init(socket, wrap);
|
2014-04-14 10:12:35 +00:00
|
|
|
|
2019-04-30 15:46:56 +00:00
|
|
|
if (enableTrace && this._handle)
|
|
|
|
this._handle.enableTrace();
|
|
|
|
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
if (wrapHasActiveWriteFromPrevOwner) {
|
|
|
|
// `wrap` is a streams.Writable in JS. This empty write will be queued
|
|
|
|
// and hence finish after all existing writes, which is the timing
|
|
|
|
// we want to start to send any tls data to `wrap`.
|
|
|
|
wrap.write('', (err) => {
|
|
|
|
if (err) {
|
|
|
|
debug('error got before writing any tls data to the underlying stream');
|
|
|
|
this.destroy(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._handle.writesIssuedByPrevListenerDone();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-06-08 22:25:06 +00:00
|
|
|
// Read on next tick so the caller has a chance to setup listeners
|
|
|
|
process.nextTick(initRead, this, socket);
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
2019-11-22 17:04:46 +00:00
|
|
|
ObjectSetPrototypeOf(TLSSocket.prototype, net.Socket.prototype);
|
|
|
|
ObjectSetPrototypeOf(TLSSocket, net.Socket);
|
2013-07-03 07:46:01 +00:00
|
|
|
exports.TLSSocket = TLSSocket;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2019-03-26 04:21:27 +00:00
|
|
|
const proxiedMethods = [
|
2015-06-06 22:37:35 +00:00
|
|
|
'ref', 'unref', 'open', 'bind', 'listen', 'connect', 'bind6',
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
'connect6', 'getsockname', 'getpeername', 'setNoDelay', 'setKeepAlive',
|
|
|
|
'setSimultaneousAccepts', 'setBlocking',
|
2013-06-13 13:36:00 +00:00
|
|
|
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
// PipeWrap
|
2019-05-29 15:03:21 +00:00
|
|
|
'setPendingInstances',
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
];
|
|
|
|
|
2015-03-09 14:50:29 +00:00
|
|
|
// Proxy HandleWrap, PipeWrap and TCPWrap methods
|
2017-02-26 06:41:45 +00:00
|
|
|
function makeMethodProxy(name) {
|
|
|
|
return function methodProxy(...args) {
|
2015-03-09 14:50:29 +00:00
|
|
|
if (this._parent[name])
|
2020-11-17 22:09:52 +00:00
|
|
|
return ReflectApply(this._parent[name], this._parent, args);
|
2015-03-09 14:50:29 +00:00
|
|
|
};
|
2017-02-26 06:41:45 +00:00
|
|
|
}
|
2019-12-14 15:30:40 +00:00
|
|
|
for (const proxiedMethod of proxiedMethods) {
|
|
|
|
tls_wrap.TLSWrap.prototype[proxiedMethod] =
|
|
|
|
makeMethodProxy(proxiedMethod);
|
2017-02-26 06:41:45 +00:00
|
|
|
}
|
2015-03-09 14:50:29 +00:00
|
|
|
|
2016-10-15 22:02:43 +00:00
|
|
|
tls_wrap.TLSWrap.prototype.close = function close(cb) {
|
2016-11-12 21:08:59 +00:00
|
|
|
let ssl;
|
2018-07-27 12:35:39 +00:00
|
|
|
if (this[owner_symbol]) {
|
|
|
|
ssl = this[owner_symbol].ssl;
|
|
|
|
this[owner_symbol].ssl = null;
|
2016-11-12 21:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Invoke `destroySSL` on close to clean up possibly pending write requests
|
|
|
|
// that may self-reference TLSWrap, leading to leak
|
|
|
|
const done = () => {
|
|
|
|
if (ssl) {
|
|
|
|
ssl.destroySSL();
|
|
|
|
if (ssl._secureContext.singleUse) {
|
|
|
|
ssl._secureContext.context.close();
|
|
|
|
ssl._secureContext.context = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cb)
|
|
|
|
cb();
|
|
|
|
};
|
2016-02-09 21:00:24 +00:00
|
|
|
|
2023-10-04 14:19:42 +00:00
|
|
|
if (this._parentWrap) {
|
|
|
|
if (this._parentWrap._handle === null) {
|
|
|
|
// The socket handle was already closed.
|
|
|
|
done();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._parentWrap._handle === this._parent) {
|
|
|
|
this._parentWrap.once('close', done);
|
|
|
|
this._parentWrap.destroy();
|
|
|
|
return;
|
|
|
|
}
|
2015-06-06 22:37:35 +00:00
|
|
|
}
|
2023-10-04 14:19:42 +00:00
|
|
|
|
2016-11-12 21:08:59 +00:00
|
|
|
return this._parent.close(done);
|
2015-06-06 22:37:35 +00:00
|
|
|
};
|
|
|
|
|
2016-11-04 19:37:36 +00:00
|
|
|
TLSSocket.prototype.disableRenegotiation = function disableRenegotiation() {
|
|
|
|
this[kDisableRenegotiation] = true;
|
|
|
|
};
|
|
|
|
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {null|net.Socket} wrap
|
|
|
|
* @param {null|object} handle
|
|
|
|
* @param {boolean} wrapHasActiveWriteFromPrevOwner
|
|
|
|
* @returns {object}
|
|
|
|
*/
|
|
|
|
TLSSocket.prototype._wrapHandle = function(wrap, handle, wrapHasActiveWriteFromPrevOwner) {
|
2019-03-26 04:21:27 +00:00
|
|
|
const options = this._tlsOptions;
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
if (!handle) {
|
2017-11-20 16:18:40 +00:00
|
|
|
handle = options.pipe ?
|
|
|
|
new Pipe(PipeConstants.SOCKET) :
|
|
|
|
new TCP(TCPConstants.SOCKET);
|
2018-07-27 12:35:39 +00:00
|
|
|
handle[owner_symbol] = this;
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
// Wrap socket's handle
|
2017-09-23 18:18:28 +00:00
|
|
|
const context = options.secureContext ||
|
|
|
|
options.credentials ||
|
|
|
|
tls.createSecureContext(options);
|
2019-03-08 08:47:45 +00:00
|
|
|
assert(handle.isStreamBase, 'handle must be a StreamBase');
|
2019-11-29 20:02:04 +00:00
|
|
|
if (!(context.context instanceof NativeSecureContext)) {
|
|
|
|
throw new ERR_TLS_INVALID_CONTEXT('context');
|
|
|
|
}
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
|
|
|
|
const res = tls_wrap.wrap(handle, context.context,
|
|
|
|
!!options.isServer,
|
|
|
|
wrapHasActiveWriteFromPrevOwner);
|
2019-01-31 22:41:10 +00:00
|
|
|
res._parent = handle; // C++ "wrap" object: TCPWrap, JSStream, ...
|
|
|
|
res._parentWrap = wrap; // JS object: net.Socket, JSStreamSocket, ...
|
2015-03-06 01:27:58 +00:00
|
|
|
res._secureContext = context;
|
2015-02-27 23:07:25 +00:00
|
|
|
res.reading = handle.reading;
|
2017-09-23 18:18:28 +00:00
|
|
|
this[kRes] = res;
|
|
|
|
defineHandleReading(this, handle);
|
|
|
|
|
2023-10-18 19:44:40 +00:00
|
|
|
// Guard against adding multiple listeners, as this method may be called
|
|
|
|
// repeatedly on the same socket by reinitializeHandle
|
|
|
|
if (this.listenerCount('close', onSocketCloseDestroySSL) === 0) {
|
|
|
|
this.on('close', onSocketCloseDestroySSL);
|
|
|
|
}
|
|
|
|
|
2023-09-01 07:00:05 +00:00
|
|
|
if (wrap) {
|
|
|
|
wrap.on('close', () => this.destroy());
|
|
|
|
}
|
2017-09-23 18:18:28 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
};
|
|
|
|
|
2023-02-23 09:47:13 +00:00
|
|
|
TLSSocket.prototype[kReinitializeHandle] = function reinitializeHandle(handle) {
|
2023-05-26 14:28:34 +00:00
|
|
|
const originalServername = this.ssl ? this._handle.getServername() : null;
|
|
|
|
const originalSession = this.ssl ? this._handle.getSession() : null;
|
2023-02-23 09:47:13 +00:00
|
|
|
|
tls: fix bugs of double TLS
Fixs two issues in `TLSWrap`, one of them is reported in
https://github.com/nodejs/node/issues/30896.
1. `TLSWrap` has exactly one `StreamListener`, however,
that `StreamListener` can be replaced. We have not been
rigorous enough here: if an active write has not been
finished before the transition, the finish callback of it
will be wrongly fired the successor `StreamListener`.
2. A `TLSWrap` does not allow more than one active write,
as checked in the assertion about current_write in
`TLSWrap::DoWrite()`.
However, when users make use of an existing `tls.TLSSocket`
to establish double TLS, by
either
tls.connect({socket: tlssock})
or
tlsServer.emit('connection', tlssock)
we have both of the user provided `tls.TLSSocket`, tlssock and
a brand new created `TLSWrap` writing to the `TLSWrap` bound to
tlssock, which easily violates the constranint because two writers
have no idea of each other.
The design of the fix is:
when a `TLSWrap` is created on top of a user provided socket,
do not send any data to the socket until all existing writes
of the socket are done and ensure registered callbacks of
those writes can be fired.
PR-URL: https://github.com/nodejs/node/pull/48969
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2023-07-15 01:48:53 +00:00
|
|
|
this.handle = this._wrapHandle(null, handle, false);
|
2022-12-03 17:55:57 +00:00
|
|
|
this.ssl = this._handle;
|
2023-02-23 09:47:13 +00:00
|
|
|
|
|
|
|
net.Socket.prototype[kReinitializeHandle].call(this, this.handle);
|
2022-12-03 17:55:57 +00:00
|
|
|
this._init();
|
|
|
|
|
|
|
|
if (this._tlsOptions.enableTrace) {
|
|
|
|
this._handle.enableTrace();
|
|
|
|
}
|
2023-02-23 09:47:13 +00:00
|
|
|
|
|
|
|
if (originalSession) {
|
|
|
|
this.setSession(originalSession);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (originalServername) {
|
|
|
|
this.setServername(originalServername);
|
|
|
|
}
|
2022-12-03 17:55:57 +00:00
|
|
|
};
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
// This eliminates a cyclic reference to TLSWrap
|
|
|
|
// Ref: https://github.com/nodejs/node/commit/f7620fb96d339f704932f9bb9a0dceb9952df2d4
|
|
|
|
function defineHandleReading(socket, handle) {
|
2019-11-22 17:04:46 +00:00
|
|
|
ObjectDefineProperty(handle, 'reading', {
|
2022-06-03 08:23:58 +00:00
|
|
|
__proto__: null,
|
2017-09-23 18:18:28 +00:00
|
|
|
get: () => {
|
|
|
|
return socket[kRes].reading;
|
2015-02-28 18:14:07 +00:00
|
|
|
},
|
2017-09-23 18:18:28 +00:00
|
|
|
set: (value) => {
|
|
|
|
socket[kRes].reading = value;
|
2023-02-22 00:22:23 +00:00
|
|
|
},
|
2015-02-28 18:14:07 +00:00
|
|
|
});
|
2017-09-23 18:18:28 +00:00
|
|
|
}
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function onSocketCloseDestroySSL() {
|
|
|
|
// Make sure we are not doing it on OpenSSL's stack
|
|
|
|
setImmediate(destroySSL, this);
|
|
|
|
this[kRes] = null;
|
|
|
|
}
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
|
2015-05-18 18:24:19 +00:00
|
|
|
function destroySSL(self) {
|
|
|
|
self._destroySSL();
|
|
|
|
}
|
|
|
|
|
2015-04-26 12:26:57 +00:00
|
|
|
TLSSocket.prototype._destroySSL = function _destroySSL() {
|
2015-05-01 21:59:05 +00:00
|
|
|
if (!this.ssl) return;
|
2015-04-27 07:39:48 +00:00
|
|
|
this.ssl.destroySSL();
|
2015-05-01 21:59:05 +00:00
|
|
|
if (this.ssl._secureContext.singleUse) {
|
2015-04-27 07:39:48 +00:00
|
|
|
this.ssl._secureContext.context.close();
|
2015-05-01 21:59:05 +00:00
|
|
|
this.ssl._secureContext.context = null;
|
|
|
|
}
|
|
|
|
this.ssl = null;
|
2020-03-18 03:51:38 +00:00
|
|
|
this[kPendingSession] = null;
|
|
|
|
this[kIsVerified] = false;
|
2015-04-26 12:26:57 +00:00
|
|
|
};
|
|
|
|
|
2023-02-23 09:47:13 +00:00
|
|
|
function keylogNewListener(event) {
|
|
|
|
if (event !== 'keylog')
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Guard against enableKeylogCallback after destroy
|
|
|
|
if (!this._handle) return;
|
|
|
|
this._handle.enableKeylogCallback();
|
|
|
|
|
|
|
|
// Remove this listener since it's no longer needed.
|
|
|
|
this.removeListener('newListener', keylogNewListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
function newListener(event) {
|
|
|
|
if (event !== 'session')
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Guard against enableSessionCallbacks after destroy
|
|
|
|
if (!this._handle) return;
|
|
|
|
this._handle.enableSessionCallbacks();
|
|
|
|
|
|
|
|
// Remove this listener since it's no longer needed.
|
|
|
|
this.removeListener('newListener', newListener);
|
|
|
|
}
|
|
|
|
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
// Constructor guts, arbitrarily factored out.
|
2019-10-22 03:44:20 +00:00
|
|
|
let warnOnTlsKeylog = true;
|
|
|
|
let warnOnTlsKeylogError = true;
|
2015-03-03 20:17:43 +00:00
|
|
|
TLSSocket.prototype._init = function(socket, wrap) {
|
2019-03-26 04:21:27 +00:00
|
|
|
const options = this._tlsOptions;
|
|
|
|
const ssl = this._handle;
|
2015-06-06 22:37:35 +00:00
|
|
|
this.server = options.server;
|
|
|
|
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('%s _init',
|
|
|
|
options.isServer ? 'server' : 'client',
|
2023-02-14 17:45:16 +00:00
|
|
|
'handle?', !!ssl,
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
);
|
|
|
|
|
2019-01-31 22:41:10 +00:00
|
|
|
// Clients (!isServer) always request a cert, servers request a client cert
|
|
|
|
// only on explicit configuration.
|
2016-01-12 21:04:50 +00:00
|
|
|
const requestCert = !!options.requestCert || !options.isServer;
|
|
|
|
const rejectUnauthorized = !!options.rejectUnauthorized;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2013-08-23 13:53:16 +00:00
|
|
|
this._requestCert = requestCert;
|
|
|
|
this._rejectUnauthorized = rejectUnauthorized;
|
2013-06-13 13:36:00 +00:00
|
|
|
if (requestCert || rejectUnauthorized)
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
ssl.setVerifyMode(requestCert, rejectUnauthorized);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2020-05-12 12:53:12 +00:00
|
|
|
// Only call .onkeylog if there is a keylog listener.
|
|
|
|
ssl.onkeylog = onkeylog;
|
|
|
|
|
2023-02-23 09:47:13 +00:00
|
|
|
if (this.listenerCount('newListener', keylogNewListener) === 0) {
|
|
|
|
this.on('newListener', keylogNewListener);
|
2020-05-12 12:53:12 +00:00
|
|
|
}
|
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
if (options.isServer) {
|
2017-09-23 18:18:28 +00:00
|
|
|
ssl.onhandshakestart = onhandshakestart;
|
|
|
|
ssl.onhandshakedone = onhandshakedone;
|
|
|
|
ssl.onclienthello = loadSession;
|
|
|
|
ssl.oncertcb = loadSNI;
|
|
|
|
ssl.onnewsession = onnewsession;
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
ssl.lastHandshakeTime = 0;
|
|
|
|
ssl.handshakes = 0;
|
2013-06-17 10:11:13 +00:00
|
|
|
|
2023-06-28 14:30:30 +00:00
|
|
|
if (options.ALPNCallback) {
|
2023-09-02 16:10:09 +00:00
|
|
|
validateFunction(options.ALPNCallback, 'options.ALPNCallback');
|
2023-06-28 14:30:30 +00:00
|
|
|
this[kALPNCallback] = options.ALPNCallback;
|
|
|
|
ssl.ALPNCallback = callALPNCallback;
|
|
|
|
ssl.enableALPNCb();
|
|
|
|
}
|
|
|
|
|
2015-04-18 08:19:23 +00:00
|
|
|
if (this.server) {
|
2015-08-11 18:31:50 +00:00
|
|
|
if (this.server.listenerCount('resumeSession') > 0 ||
|
|
|
|
this.server.listenerCount('newSession') > 0) {
|
2019-01-31 22:41:10 +00:00
|
|
|
// Also starts the client hello parser as a side effect.
|
2015-04-18 08:19:23 +00:00
|
|
|
ssl.enableSessionCallbacks();
|
|
|
|
}
|
2015-08-11 18:31:50 +00:00
|
|
|
if (this.server.listenerCount('OCSPRequest') > 0)
|
2015-04-18 08:19:23 +00:00
|
|
|
ssl.enableCertCb();
|
2013-06-17 10:11:13 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
} else {
|
2017-09-23 18:18:28 +00:00
|
|
|
ssl.onhandshakestart = noop;
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
ssl.onhandshakedone = () => {
|
|
|
|
debug('client onhandshakedone');
|
|
|
|
this._finishInit();
|
|
|
|
};
|
2017-09-23 18:18:28 +00:00
|
|
|
ssl.onocspresponse = onocspresponse;
|
2014-02-03 21:32:13 +00:00
|
|
|
|
|
|
|
if (options.session)
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
ssl.setSession(options.session);
|
2019-01-30 20:18:04 +00:00
|
|
|
|
|
|
|
ssl.onnewsession = onnewsessionclient;
|
|
|
|
|
|
|
|
// Only call .onnewsession if there is a session listener.
|
2023-02-23 09:47:13 +00:00
|
|
|
if (this.listenerCount('newListener', newListener) === 0) {
|
|
|
|
this.on('newListener', newListener);
|
2019-01-30 20:18:04 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 03:44:20 +00:00
|
|
|
if (tlsKeylog) {
|
|
|
|
if (warnOnTlsKeylog) {
|
|
|
|
warnOnTlsKeylog = false;
|
|
|
|
process.emitWarning('Using --tls-keylog makes TLS connections insecure ' +
|
|
|
|
'by writing secret key material to file ' + tlsKeylog);
|
|
|
|
}
|
2020-05-12 12:53:12 +00:00
|
|
|
this.on('keylog', (line) => {
|
|
|
|
appendFile(tlsKeylog, line, { mode: 0o600 }, (err) => {
|
|
|
|
if (err && warnOnTlsKeylogError) {
|
|
|
|
warnOnTlsKeylogError = false;
|
|
|
|
process.emitWarning('Failed to write TLS keylog (this warning ' +
|
|
|
|
'will not be repeated): ' + err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-10-22 03:44:20 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
ssl.onerror = onerror;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2013-08-02 16:11:17 +00:00
|
|
|
// If custom SNICallback was given, or if
|
|
|
|
// there're SNI contexts to perform match against -
|
|
|
|
// set `.onsniselect` callback.
|
2018-06-02 08:52:59 +00:00
|
|
|
if (options.isServer &&
|
2015-06-06 22:37:35 +00:00
|
|
|
options.SNICallback &&
|
2013-08-02 16:11:17 +00:00
|
|
|
(options.SNICallback !== SNICallback ||
|
2017-12-23 08:01:58 +00:00
|
|
|
(options.server && options.server._contexts.length))) {
|
2023-11-10 13:04:07 +00:00
|
|
|
validateFunction(options.SNICallback, 'options.SNICallback');
|
2013-08-03 17:29:54 +00:00
|
|
|
this._SNICallback = options.SNICallback;
|
2015-04-18 08:19:23 +00:00
|
|
|
ssl.enableCertCb();
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
2022-10-03 11:00:53 +00:00
|
|
|
if (options.ALPNProtocols)
|
|
|
|
ssl.setALPNProtocols(options.ALPNProtocols);
|
2015-04-23 06:25:15 +00:00
|
|
|
|
2018-10-29 08:38:43 +00:00
|
|
|
if (options.pskCallback && ssl.enablePskCallback) {
|
2021-05-16 11:22:48 +00:00
|
|
|
validateFunction(options.pskCallback, 'pskCallback');
|
2018-10-29 08:38:43 +00:00
|
|
|
|
|
|
|
ssl[kOnPskExchange] = options.isServer ?
|
|
|
|
onPskServerCallback : onPskClientCallback;
|
|
|
|
|
|
|
|
this[kPskCallback] = options.pskCallback;
|
|
|
|
ssl.enablePskCallback();
|
|
|
|
|
|
|
|
if (options.pskIdentityHint) {
|
2021-05-16 11:22:48 +00:00
|
|
|
validateString(options.pskIdentityHint, 'options.pskIdentityHint');
|
2018-10-29 08:38:43 +00:00
|
|
|
ssl.setPskIdentityHint(options.pskIdentityHint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-02 04:40:47 +00:00
|
|
|
// We can only come here via [kWrapConnectedHandle]() call that happens
|
|
|
|
// if the connection is established with `autoSelectFamily` set to `true`.
|
|
|
|
const connectOptions = this[kConnectOptions];
|
|
|
|
if (!options.isServer && connectOptions) {
|
|
|
|
if (connectOptions.servername) {
|
|
|
|
this.setServername(connectOptions.servername);
|
|
|
|
}
|
|
|
|
}
|
2018-10-29 08:38:43 +00:00
|
|
|
|
2013-08-23 13:53:16 +00:00
|
|
|
if (options.handshakeTimeout > 0)
|
|
|
|
this.setTimeout(options.handshakeTimeout, this._handleTimeout);
|
2014-01-23 12:55:28 +00:00
|
|
|
|
2015-03-03 20:17:43 +00:00
|
|
|
if (socket instanceof net.Socket) {
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
this._parent = socket;
|
|
|
|
|
|
|
|
// To prevent assertion in afterConnect() and properly kick off readStart
|
2016-04-26 20:27:08 +00:00
|
|
|
this.connecting = socket.connecting || !socket._handle;
|
2017-09-23 18:18:28 +00:00
|
|
|
socket.once('connect', () => {
|
|
|
|
this.connecting = false;
|
|
|
|
this.emit('connect');
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
});
|
2014-01-23 12:55:28 +00:00
|
|
|
}
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
|
|
|
|
// Assume `tls.connect()`
|
2015-03-03 20:17:43 +00:00
|
|
|
if (wrap) {
|
2017-09-23 18:18:28 +00:00
|
|
|
wrap.on('error', (err) => this._emitTLSError(err));
|
2015-03-03 20:17:43 +00:00
|
|
|
} else {
|
|
|
|
assert(!socket);
|
2016-04-26 20:27:08 +00:00
|
|
|
this.connecting = true;
|
2015-03-03 20:17:43 +00:00
|
|
|
}
|
2013-08-23 13:53:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype.renegotiate = function(options, callback) {
|
2021-01-21 11:03:00 +00:00
|
|
|
validateObject(options, 'options');
|
2020-12-23 11:22:00 +00:00
|
|
|
if (callback !== undefined) {
|
2022-01-24 16:09:16 +00:00
|
|
|
validateFunction(callback, 'callback');
|
2020-12-23 11:22:00 +00:00
|
|
|
}
|
2019-02-01 18:57:04 +00:00
|
|
|
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('%s renegotiate()',
|
|
|
|
this._tlsOptions.isServer ? 'server' : 'client',
|
2023-02-14 17:45:16 +00:00
|
|
|
'destroyed?', this.destroyed,
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
);
|
|
|
|
|
2015-04-26 12:26:57 +00:00
|
|
|
if (this.destroyed)
|
|
|
|
return;
|
|
|
|
|
2018-01-10 17:42:08 +00:00
|
|
|
let requestCert = !!this._requestCert;
|
|
|
|
let rejectUnauthorized = !!this._rejectUnauthorized;
|
2017-09-23 18:18:28 +00:00
|
|
|
|
|
|
|
if (options.requestCert !== undefined)
|
2013-08-23 13:53:16 +00:00
|
|
|
requestCert = !!options.requestCert;
|
2017-09-23 18:18:28 +00:00
|
|
|
if (options.rejectUnauthorized !== undefined)
|
2013-08-23 13:53:16 +00:00
|
|
|
rejectUnauthorized = !!options.rejectUnauthorized;
|
|
|
|
|
|
|
|
if (requestCert !== this._requestCert ||
|
|
|
|
rejectUnauthorized !== this._rejectUnauthorized) {
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
this._handle.setVerifyMode(requestCert, rejectUnauthorized);
|
2013-08-23 13:53:16 +00:00
|
|
|
this._requestCert = requestCert;
|
|
|
|
this._rejectUnauthorized = rejectUnauthorized;
|
|
|
|
}
|
2019-02-07 21:27:14 +00:00
|
|
|
// Ensure that we'll cycle through internal openssl's state
|
|
|
|
this.write('');
|
|
|
|
|
2019-03-27 19:10:48 +00:00
|
|
|
try {
|
|
|
|
this._handle.renegotiate();
|
|
|
|
} catch (err) {
|
2013-08-23 13:53:16 +00:00
|
|
|
if (callback) {
|
2019-03-27 19:10:48 +00:00
|
|
|
process.nextTick(callback, err);
|
2013-08-23 13:53:16 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that we'll cycle through internal openssl's state
|
|
|
|
this.write('');
|
|
|
|
|
|
|
|
if (callback) {
|
2017-09-23 18:18:28 +00:00
|
|
|
this.once('secure', () => callback(null));
|
2013-08-23 13:53:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2020-02-15 17:55:59 +00:00
|
|
|
TLSSocket.prototype.exportKeyingMaterial = function(length, label, context) {
|
|
|
|
validateUint32(length, 'length', true);
|
|
|
|
validateString(label, 'label');
|
|
|
|
if (context !== undefined)
|
|
|
|
validateBuffer(context, 'context');
|
|
|
|
|
|
|
|
if (!this._secureEstablished)
|
|
|
|
throw new ERR_TLS_INVALID_STATE();
|
|
|
|
|
|
|
|
return this._handle.exportKeyingMaterial(length, label, context);
|
|
|
|
};
|
|
|
|
|
2014-01-17 18:46:49 +00:00
|
|
|
TLSSocket.prototype.setMaxSendFragment = function setMaxSendFragment(size) {
|
2021-04-09 17:12:59 +00:00
|
|
|
validateInt32(size, 'size');
|
2016-11-29 23:58:05 +00:00
|
|
|
return this._handle.setMaxSendFragment(size) === 1;
|
2014-01-17 18:46:49 +00:00
|
|
|
};
|
|
|
|
|
2013-08-23 13:53:16 +00:00
|
|
|
TLSSocket.prototype._handleTimeout = function() {
|
2018-03-04 21:16:24 +00:00
|
|
|
this._emitTLSError(new ERR_TLS_HANDSHAKE_TIMEOUT());
|
2015-05-15 19:21:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype._emitTLSError = function(err) {
|
2019-03-26 04:21:27 +00:00
|
|
|
const e = this._tlsError(err);
|
2015-05-15 19:21:06 +00:00
|
|
|
if (e)
|
|
|
|
this.emit('error', e);
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype._tlsError = function(err) {
|
|
|
|
this.emit('_tlsError', err);
|
|
|
|
if (this._controlReleased)
|
2015-05-15 19:21:06 +00:00
|
|
|
return err;
|
|
|
|
return null;
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
|
|
|
|
2013-08-07 12:50:36 +00:00
|
|
|
TLSSocket.prototype._releaseControl = function() {
|
|
|
|
if (this._controlReleased)
|
2013-08-23 13:53:16 +00:00
|
|
|
return false;
|
2013-08-07 12:50:36 +00:00
|
|
|
this._controlReleased = true;
|
2016-10-01 19:17:51 +00:00
|
|
|
this.removeListener('error', this._tlsError);
|
2013-08-23 13:53:16 +00:00
|
|
|
return true;
|
2013-08-07 12:50:36 +00:00
|
|
|
};
|
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
TLSSocket.prototype._finishInit = function() {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
// 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;
|
|
|
|
|
2018-06-02 08:52:59 +00:00
|
|
|
this.alpnProtocol = this._handle.getALPNNegotiatedProtocol();
|
2019-05-17 13:19:40 +00:00
|
|
|
// The servername could be set by TLSWrap::SelectSNIContextCallback().
|
|
|
|
if (this.servername === null) {
|
|
|
|
this.servername = this._handle.getServername();
|
|
|
|
}
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
|
|
|
|
debug('%s _finishInit',
|
|
|
|
this._tlsOptions.isServer ? 'server' : 'client',
|
|
|
|
'handle?', !!this._handle,
|
|
|
|
'alpn', this.alpnProtocol,
|
|
|
|
'servername', this.servername);
|
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
this._secureEstablished = true;
|
2013-08-23 13:53:16 +00:00
|
|
|
if (this._tlsOptions.handshakeTimeout > 0)
|
|
|
|
this.setTimeout(0, this._handleTimeout);
|
2013-06-13 13:36:00 +00:00
|
|
|
this.emit('secure');
|
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype._start = function() {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('%s _start',
|
|
|
|
this._tlsOptions.isServer ? 'server' : 'client',
|
|
|
|
'handle?', !!this._handle,
|
|
|
|
'connecting?', this.connecting,
|
|
|
|
'requestOCSP?', !!this._tlsOptions.requestOCSP,
|
|
|
|
);
|
2016-04-26 20:27:08 +00:00
|
|
|
if (this.connecting) {
|
2017-09-23 18:18:28 +00:00
|
|
|
this.once('connect', this._start);
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-06 22:37:35 +00:00
|
|
|
// Socket was destroyed before the connection was established
|
|
|
|
if (!this._handle)
|
|
|
|
return;
|
|
|
|
|
2014-04-14 17:15:57 +00:00
|
|
|
if (this._tlsOptions.requestOCSP)
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
this._handle.requestOCSP();
|
|
|
|
this._handle.start();
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype.setServername = function(name) {
|
2018-08-02 22:51:02 +00:00
|
|
|
validateString(name, 'name');
|
2018-01-10 19:33:49 +00:00
|
|
|
|
|
|
|
if (this._tlsOptions.isServer) {
|
2018-03-04 21:16:24 +00:00
|
|
|
throw new ERR_TLS_SNI_FROM_SERVER();
|
2018-01-10 19:33:49 +00:00
|
|
|
}
|
|
|
|
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
this._handle.setServername(name);
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype.setSession = function(session) {
|
2015-01-29 01:05:53 +00:00
|
|
|
if (typeof session === 'string')
|
2016-06-02 16:55:36 +00:00
|
|
|
session = Buffer.from(session, 'latin1');
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
this._handle.setSession(session);
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
|
|
|
|
2014-04-17 11:57:36 +00:00
|
|
|
TLSSocket.prototype.getPeerCertificate = function(detailed) {
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
if (this._handle) {
|
2014-04-17 11:57:36 +00:00
|
|
|
return common.translatePeerCertificate(
|
2018-11-08 21:40:46 +00:00
|
|
|
this._handle.getPeerCertificate(detailed)) || {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype.getCertificate = function() {
|
|
|
|
if (this._handle) {
|
|
|
|
// It's not a peer cert, but the formatting is identical.
|
|
|
|
return common.translatePeerCertificate(
|
|
|
|
this._handle.getCertificate()) || {};
|
2014-04-17 11:57:36 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
2021-01-26 00:38:51 +00:00
|
|
|
TLSSocket.prototype.getPeerX509Certificate = function(detailed) {
|
|
|
|
const cert = this._handle?.getPeerX509Certificate();
|
|
|
|
return cert ? new InternalX509Certificate(cert) : undefined;
|
|
|
|
};
|
|
|
|
|
|
|
|
TLSSocket.prototype.getX509Certificate = function() {
|
|
|
|
const cert = this._handle?.getX509Certificate();
|
|
|
|
return cert ? new InternalX509Certificate(cert) : undefined;
|
|
|
|
};
|
|
|
|
|
2024-07-15 15:17:59 +00:00
|
|
|
TLSSocket.prototype.setKeyCert = function(context) {
|
|
|
|
if (this._handle) {
|
|
|
|
let secureContext;
|
|
|
|
if (context instanceof common.SecureContext)
|
|
|
|
secureContext = context;
|
|
|
|
else
|
|
|
|
secureContext = tls.createSecureContext(context);
|
|
|
|
this._handle.setKeyCert(secureContext.context);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-05 20:20:02 +00:00
|
|
|
// Proxy TLSSocket handle methods
|
|
|
|
function makeSocketMethodProxy(name) {
|
|
|
|
return function socketMethodProxy(...args) {
|
|
|
|
if (this._handle)
|
2020-11-17 22:09:52 +00:00
|
|
|
return ReflectApply(this._handle[name], this._handle, args);
|
2013-06-13 13:36:00 +00:00
|
|
|
return null;
|
2018-08-05 20:20:02 +00:00
|
|
|
};
|
|
|
|
}
|
2015-05-22 09:20:26 +00:00
|
|
|
|
2024-07-07 00:56:04 +00:00
|
|
|
[
|
2019-03-12 19:09:24 +00:00
|
|
|
'getCipher',
|
2019-09-18 14:48:44 +00:00
|
|
|
'getSharedSigalgs',
|
2019-03-12 19:09:24 +00:00
|
|
|
'getEphemeralKeyInfo',
|
|
|
|
'getFinished',
|
|
|
|
'getPeerFinished',
|
|
|
|
'getProtocol',
|
|
|
|
'getSession',
|
|
|
|
'getTLSTicket',
|
|
|
|
'isSessionReused',
|
2019-02-13 22:54:07 +00:00
|
|
|
'enableTrace',
|
2024-07-07 00:56:04 +00:00
|
|
|
].forEach((method) => {
|
2018-08-05 20:20:02 +00:00
|
|
|
TLSSocket.prototype[method] = makeSocketMethodProxy(method);
|
|
|
|
});
|
2015-05-22 09:20:26 +00:00
|
|
|
|
2018-10-29 08:38:43 +00:00
|
|
|
// TODO: support anonymous (nocert)
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
|
2019-01-31 22:41:10 +00:00
|
|
|
function onServerSocketSecure() {
|
2017-09-23 18:18:28 +00:00
|
|
|
if (this._requestCert) {
|
|
|
|
const verifyError = this._handle.verifyError();
|
|
|
|
if (verifyError) {
|
|
|
|
this.authorizationError = verifyError.code;
|
|
|
|
|
|
|
|
if (this._rejectUnauthorized)
|
|
|
|
this.destroy();
|
|
|
|
} else {
|
|
|
|
this.authorized = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
if (!this.destroyed && this._releaseControl()) {
|
|
|
|
debug('server emit secureConnection');
|
2020-04-21 22:55:54 +00:00
|
|
|
this.secureConnecting = false;
|
2017-09-23 18:18:28 +00:00
|
|
|
this._tlsOptions.server.emit('secureConnection', this);
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
}
|
2017-09-23 18:18:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function onSocketTLSError(err) {
|
|
|
|
if (!this._controlReleased && !this[kErrorEmitted]) {
|
|
|
|
this[kErrorEmitted] = true;
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('server emit tlsClientError:', err);
|
2017-09-23 18:18:28 +00:00
|
|
|
this._tlsOptions.server.emit('tlsClientError', err, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 12:53:12 +00:00
|
|
|
function onSocketKeylog(line) {
|
|
|
|
this._tlsOptions.server.emit('keylog', line, this);
|
|
|
|
}
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function onSocketClose(err) {
|
|
|
|
// Closed because of error - no need to emit it twice
|
|
|
|
if (err)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Emit ECONNRESET
|
|
|
|
if (!this._controlReleased && !this[kErrorEmitted]) {
|
|
|
|
this[kErrorEmitted] = true;
|
2023-11-11 16:25:08 +00:00
|
|
|
const connReset = new ConnResetException('socket hang up');
|
2017-09-23 18:18:28 +00:00
|
|
|
this._tlsOptions.server.emit('tlsClientError', connReset, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function tlsConnectionListener(rawSocket) {
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('net.Server.on(connection): new TLSSocket');
|
2017-09-23 18:18:28 +00:00
|
|
|
const socket = new TLSSocket(rawSocket, {
|
|
|
|
secureContext: this._sharedCreds,
|
|
|
|
isServer: true,
|
|
|
|
server: this,
|
|
|
|
requestCert: this.requestCert,
|
|
|
|
rejectUnauthorized: this.rejectUnauthorized,
|
|
|
|
handshakeTimeout: this[kHandshakeTimeout],
|
|
|
|
ALPNProtocols: this.ALPNProtocols,
|
2023-06-28 14:30:30 +00:00
|
|
|
ALPNCallback: this.ALPNCallback,
|
2019-04-30 15:46:56 +00:00
|
|
|
SNICallback: this[kSNICallback] || SNICallback,
|
2019-09-20 18:15:16 +00:00
|
|
|
enableTrace: this[kEnableTrace],
|
|
|
|
pauseOnConnect: this.pauseOnConnect,
|
2018-10-29 08:38:43 +00:00
|
|
|
pskCallback: this[kPskCallback],
|
|
|
|
pskIdentityHint: this[kPskIdentityHint],
|
2017-09-23 18:18:28 +00:00
|
|
|
});
|
|
|
|
|
2019-01-31 22:41:10 +00:00
|
|
|
socket.on('secure', onServerSocketSecure);
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2020-05-12 12:53:12 +00:00
|
|
|
if (this.listenerCount('keylog') > 0)
|
|
|
|
socket.on('keylog', onSocketKeylog);
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
socket[kErrorEmitted] = false;
|
|
|
|
socket.on('close', onSocketClose);
|
|
|
|
socket.on('_tlsError', onSocketTLSError);
|
|
|
|
}
|
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
// AUTHENTICATION MODES
|
|
|
|
//
|
|
|
|
// There are several levels of authentication that TLS/SSL supports.
|
|
|
|
// Read more about this in "man SSL_set_verify".
|
|
|
|
//
|
|
|
|
// 1. The server sends a certificate to the client but does not request a
|
|
|
|
// cert from the client. This is common for most HTTPS servers. The browser
|
|
|
|
// can verify the identity of the server, but the server does not know who
|
|
|
|
// the client is. Authenticating the client is usually done over HTTP using
|
|
|
|
// login boxes and cookies and stuff.
|
|
|
|
//
|
|
|
|
// 2. The server sends a cert to the client and requests that the client
|
|
|
|
// also send it a cert. The client knows who the server is and the server is
|
|
|
|
// requesting the client also identify themselves. There are several
|
|
|
|
// outcomes:
|
|
|
|
//
|
|
|
|
// A) verifyError returns null meaning the client's certificate is signed
|
2017-06-17 13:11:45 +00:00
|
|
|
// by one of the server's CAs. The server now knows the client's identity
|
2013-06-13 13:36:00 +00:00
|
|
|
// and the client is authorized.
|
|
|
|
//
|
|
|
|
// B) For some reason the client's certificate is not acceptable -
|
|
|
|
// verifyError returns a string indicating the problem. The server can
|
|
|
|
// either (i) reject the client or (ii) allow the client to connect as an
|
|
|
|
// unauthorized connection.
|
|
|
|
//
|
|
|
|
// The mode is controlled by two boolean variables.
|
|
|
|
//
|
|
|
|
// requestCert
|
|
|
|
// If true the server requests a certificate from client connections. For
|
|
|
|
// the common HTTPS case, users will want this to be false, which is what
|
|
|
|
// it defaults to.
|
|
|
|
//
|
|
|
|
// rejectUnauthorized
|
|
|
|
// If true clients whose certificates are invalid for any reason will not
|
|
|
|
// be allowed to make connections. If false, they will simply be marked as
|
|
|
|
// unauthorized but secure communication will continue. By default this is
|
|
|
|
// true.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Options:
|
|
|
|
// - requestCert. Send verify request. Default to false.
|
|
|
|
// - rejectUnauthorized. Boolean, default to true.
|
|
|
|
// - key. string.
|
|
|
|
// - cert: string.
|
2016-04-15 14:49:36 +00:00
|
|
|
// - clientCertEngine: string.
|
2013-06-13 13:36:00 +00:00
|
|
|
// - ca: string or array of strings.
|
|
|
|
// - sessionTimeout: integer.
|
|
|
|
//
|
|
|
|
// emit 'secureConnection'
|
|
|
|
// function (tlsSocket) { }
|
|
|
|
//
|
|
|
|
// "UNABLE_TO_GET_ISSUER_CERT", "UNABLE_TO_GET_CRL",
|
|
|
|
// "UNABLE_TO_DECRYPT_CERT_SIGNATURE", "UNABLE_TO_DECRYPT_CRL_SIGNATURE",
|
|
|
|
// "UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY", "CERT_SIGNATURE_FAILURE",
|
|
|
|
// "CRL_SIGNATURE_FAILURE", "CERT_NOT_YET_VALID" "CERT_HAS_EXPIRED",
|
|
|
|
// "CRL_NOT_YET_VALID", "CRL_HAS_EXPIRED" "ERROR_IN_CERT_NOT_BEFORE_FIELD",
|
|
|
|
// "ERROR_IN_CERT_NOT_AFTER_FIELD", "ERROR_IN_CRL_LAST_UPDATE_FIELD",
|
|
|
|
// "ERROR_IN_CRL_NEXT_UPDATE_FIELD", "OUT_OF_MEM",
|
|
|
|
// "DEPTH_ZERO_SELF_SIGNED_CERT", "SELF_SIGNED_CERT_IN_CHAIN",
|
|
|
|
// "UNABLE_TO_GET_ISSUER_CERT_LOCALLY", "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
|
|
// "CERT_CHAIN_TOO_LONG", "CERT_REVOKED" "INVALID_CA",
|
|
|
|
// "PATH_LENGTH_EXCEEDED", "INVALID_PURPOSE" "CERT_UNTRUSTED",
|
|
|
|
// "CERT_REJECTED"
|
|
|
|
//
|
2016-11-21 21:50:02 +00:00
|
|
|
function Server(options, listener) {
|
|
|
|
if (!(this instanceof Server))
|
|
|
|
return new Server(options, listener);
|
2015-01-29 01:05:53 +00:00
|
|
|
|
2016-11-21 21:50:02 +00:00
|
|
|
if (typeof options === 'function') {
|
|
|
|
listener = options;
|
2022-05-21 09:57:01 +00:00
|
|
|
options = kEmptyObject;
|
2016-11-21 21:50:02 +00:00
|
|
|
} else if (options == null || typeof options === 'object') {
|
2024-10-09 06:42:16 +00:00
|
|
|
options ??= kEmptyObject;
|
2016-11-21 21:50:02 +00:00
|
|
|
} else {
|
2018-03-19 12:33:46 +00:00
|
|
|
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this._contexts = [];
|
2018-10-22 19:17:06 +00:00
|
|
|
this.requestCert = options.requestCert === true;
|
|
|
|
this.rejectUnauthorized = options.rejectUnauthorized !== false;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2023-06-28 14:30:30 +00:00
|
|
|
this.ALPNCallback = options.ALPNCallback;
|
|
|
|
if (this.ALPNCallback && options.ALPNProtocols) {
|
|
|
|
throw new ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS();
|
|
|
|
}
|
|
|
|
|
2018-10-22 19:17:06 +00:00
|
|
|
if (options.sessionTimeout)
|
|
|
|
this.sessionTimeout = options.sessionTimeout;
|
|
|
|
|
|
|
|
if (options.ticketKeys)
|
|
|
|
this.ticketKeys = options.ticketKeys;
|
|
|
|
|
|
|
|
if (options.ALPNProtocols)
|
|
|
|
tls.convertALPNProtocols(options.ALPNProtocols, this);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-10-13 18:18:31 +00:00
|
|
|
this.setSecureContext(options);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
this[kHandshakeTimeout] = options.handshakeTimeout || (120 * 1000);
|
|
|
|
this[kSNICallback] = options.SNICallback;
|
2018-10-29 08:38:43 +00:00
|
|
|
this[kPskCallback] = options.pskCallback;
|
|
|
|
this[kPskIdentityHint] = options.pskIdentityHint;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2021-05-16 11:22:48 +00:00
|
|
|
validateNumber(this[kHandshakeTimeout], 'options.handshakeTimeout');
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2023-01-14 09:52:26 +00:00
|
|
|
if (this[kSNICallback]) {
|
|
|
|
validateFunction(this[kSNICallback], 'options.SNICallback');
|
2018-05-25 20:21:43 +00:00
|
|
|
}
|
|
|
|
|
2023-01-14 09:52:26 +00:00
|
|
|
if (this[kPskCallback]) {
|
|
|
|
validateFunction(this[kPskCallback], 'options.pskCallback');
|
2018-10-29 08:38:43 +00:00
|
|
|
}
|
2023-01-14 09:52:26 +00:00
|
|
|
|
|
|
|
if (this[kPskIdentityHint]) {
|
|
|
|
validateString(this[kPskIdentityHint], 'options.pskIdentityHint');
|
2018-10-29 08:38:43 +00:00
|
|
|
}
|
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
// constructor call
|
2020-11-17 22:09:52 +00:00
|
|
|
ReflectApply(net.Server, this, [options, tlsConnectionListener]);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
this.on('secureConnection', listener);
|
|
|
|
}
|
2019-02-13 22:54:07 +00:00
|
|
|
|
2019-04-30 15:46:56 +00:00
|
|
|
this[kEnableTrace] = options.enableTrace;
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
2019-11-22 17:04:46 +00:00
|
|
|
ObjectSetPrototypeOf(Server.prototype, net.Server.prototype);
|
|
|
|
ObjectSetPrototypeOf(Server, net.Server);
|
2013-06-13 13:36:00 +00:00
|
|
|
exports.Server = Server;
|
2018-07-11 10:36:36 +00:00
|
|
|
exports.createServer = function createServer(options, listener) {
|
2013-06-13 13:36:00 +00:00
|
|
|
return new Server(options, listener);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-10-13 18:18:31 +00:00
|
|
|
Server.prototype.setSecureContext = function(options) {
|
2021-01-21 11:03:00 +00:00
|
|
|
validateObject(options, 'options');
|
2018-10-13 18:18:31 +00:00
|
|
|
|
|
|
|
if (options.pfx)
|
|
|
|
this.pfx = options.pfx;
|
|
|
|
else
|
|
|
|
this.pfx = undefined;
|
|
|
|
|
|
|
|
if (options.key)
|
|
|
|
this.key = options.key;
|
|
|
|
else
|
|
|
|
this.key = undefined;
|
|
|
|
|
|
|
|
if (options.passphrase)
|
|
|
|
this.passphrase = options.passphrase;
|
|
|
|
else
|
|
|
|
this.passphrase = undefined;
|
|
|
|
|
|
|
|
if (options.cert)
|
|
|
|
this.cert = options.cert;
|
|
|
|
else
|
|
|
|
this.cert = undefined;
|
|
|
|
|
|
|
|
if (options.clientCertEngine)
|
|
|
|
this.clientCertEngine = options.clientCertEngine;
|
|
|
|
else
|
|
|
|
this.clientCertEngine = undefined;
|
|
|
|
|
|
|
|
if (options.ca)
|
|
|
|
this.ca = options.ca;
|
|
|
|
else
|
|
|
|
this.ca = undefined;
|
|
|
|
|
2018-05-06 04:52:34 +00:00
|
|
|
if (options.minVersion)
|
|
|
|
this.minVersion = options.minVersion;
|
|
|
|
else
|
|
|
|
this.minVersion = undefined;
|
|
|
|
|
|
|
|
if (options.maxVersion)
|
|
|
|
this.maxVersion = options.maxVersion;
|
|
|
|
else
|
|
|
|
this.maxVersion = undefined;
|
|
|
|
|
2018-10-13 18:18:31 +00:00
|
|
|
if (options.secureProtocol)
|
|
|
|
this.secureProtocol = options.secureProtocol;
|
|
|
|
else
|
|
|
|
this.secureProtocol = undefined;
|
|
|
|
|
|
|
|
if (options.crl)
|
|
|
|
this.crl = options.crl;
|
|
|
|
else
|
|
|
|
this.crl = undefined;
|
|
|
|
|
2019-09-25 14:49:13 +00:00
|
|
|
this.sigalgs = options.sigalgs;
|
2019-09-18 14:48:44 +00:00
|
|
|
|
2018-10-13 18:18:31 +00:00
|
|
|
if (options.ciphers)
|
|
|
|
this.ciphers = options.ciphers;
|
|
|
|
else
|
|
|
|
this.ciphers = undefined;
|
|
|
|
|
2019-09-25 14:49:13 +00:00
|
|
|
this.ecdhCurve = options.ecdhCurve;
|
2018-10-13 18:18:31 +00:00
|
|
|
|
|
|
|
if (options.dhparam)
|
|
|
|
this.dhparam = options.dhparam;
|
|
|
|
else
|
|
|
|
this.dhparam = undefined;
|
|
|
|
|
|
|
|
if (options.honorCipherOrder !== undefined)
|
|
|
|
this.honorCipherOrder = !!options.honorCipherOrder;
|
|
|
|
else
|
|
|
|
this.honorCipherOrder = true;
|
|
|
|
|
|
|
|
const secureOptions = options.secureOptions || 0;
|
|
|
|
|
|
|
|
if (secureOptions)
|
|
|
|
this.secureOptions = secureOptions;
|
|
|
|
else
|
|
|
|
this.secureOptions = undefined;
|
|
|
|
|
|
|
|
if (options.sessionIdContext) {
|
|
|
|
this.sessionIdContext = options.sessionIdContext;
|
|
|
|
} else {
|
2024-07-07 00:56:04 +00:00
|
|
|
this.sessionIdContext = crypto.createHash('sha1')
|
|
|
|
.update(process.argv.join(' '))
|
|
|
|
.digest('hex')
|
|
|
|
.slice(0, 32);
|
2018-10-13 18:18:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 16:41:00 +00:00
|
|
|
if (options.sessionTimeout)
|
|
|
|
this.sessionTimeout = options.sessionTimeout;
|
|
|
|
|
|
|
|
if (options.ticketKeys)
|
|
|
|
this.ticketKeys = options.ticketKeys;
|
|
|
|
|
2020-12-06 18:06:07 +00:00
|
|
|
this.privateKeyIdentifier = options.privateKeyIdentifier;
|
|
|
|
this.privateKeyEngine = options.privateKeyEngine;
|
|
|
|
|
2018-10-13 18:18:31 +00:00
|
|
|
this._sharedCreds = tls.createSecureContext({
|
|
|
|
pfx: this.pfx,
|
|
|
|
key: this.key,
|
|
|
|
passphrase: this.passphrase,
|
|
|
|
cert: this.cert,
|
|
|
|
clientCertEngine: this.clientCertEngine,
|
|
|
|
ca: this.ca,
|
|
|
|
ciphers: this.ciphers,
|
2019-09-18 14:48:44 +00:00
|
|
|
sigalgs: this.sigalgs,
|
2018-10-13 18:18:31 +00:00
|
|
|
ecdhCurve: this.ecdhCurve,
|
|
|
|
dhparam: this.dhparam,
|
2018-05-06 04:52:34 +00:00
|
|
|
minVersion: this.minVersion,
|
|
|
|
maxVersion: this.maxVersion,
|
2018-10-13 18:18:31 +00:00
|
|
|
secureProtocol: this.secureProtocol,
|
|
|
|
secureOptions: this.secureOptions,
|
|
|
|
honorCipherOrder: this.honorCipherOrder,
|
|
|
|
crl: this.crl,
|
2020-06-19 16:41:00 +00:00
|
|
|
sessionIdContext: this.sessionIdContext,
|
|
|
|
ticketKeys: this.ticketKeys,
|
2020-12-06 18:06:07 +00:00
|
|
|
sessionTimeout: this.sessionTimeout,
|
|
|
|
privateKeyIdentifier: this.privateKeyIdentifier,
|
|
|
|
privateKeyEngine: this.privateKeyEngine,
|
2018-10-13 18:18:31 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-07-21 03:11:02 +00:00
|
|
|
Server.prototype._getServerData = function() {
|
|
|
|
return {
|
2023-02-22 00:22:23 +00:00
|
|
|
ticketKeys: this.getTicketKeys().toString('hex'),
|
2013-07-21 03:11:02 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Server.prototype._setServerData = function(data) {
|
2016-01-25 23:00:06 +00:00
|
|
|
this.setTicketKeys(Buffer.from(data.ticketKeys, 'hex'));
|
2015-07-22 20:52:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-01-16 19:12:30 +00:00
|
|
|
Server.prototype.getTicketKeys = function getTicketKeys() {
|
|
|
|
return this._sharedCreds.context.getTicketKeys();
|
2015-07-22 20:52:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Server.prototype.setTicketKeys = function setTicketKeys(keys) {
|
2021-04-20 09:59:02 +00:00
|
|
|
validateBuffer(keys);
|
|
|
|
assert(keys.byteLength === 48,
|
|
|
|
'Session ticket keys must be a 48-byte buffer');
|
2015-07-22 20:52:23 +00:00
|
|
|
this._sharedCreds.context.setTicketKeys(keys);
|
2013-07-21 03:11:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-03-18 16:31:43 +00:00
|
|
|
Server.prototype.setOptions = deprecate(function(options) {
|
2016-03-27 13:09:08 +00:00
|
|
|
this.requestCert = options.requestCert === true;
|
|
|
|
this.rejectUnauthorized = options.rejectUnauthorized !== false;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
if (options.pfx) this.pfx = options.pfx;
|
|
|
|
if (options.key) this.key = options.key;
|
|
|
|
if (options.passphrase) this.passphrase = options.passphrase;
|
|
|
|
if (options.cert) this.cert = options.cert;
|
2016-04-15 14:49:36 +00:00
|
|
|
if (options.clientCertEngine)
|
|
|
|
this.clientCertEngine = options.clientCertEngine;
|
2013-06-13 13:36:00 +00:00
|
|
|
if (options.ca) this.ca = options.ca;
|
2018-05-06 04:52:34 +00:00
|
|
|
if (options.minVersion) this.minVersion = options.minVersion;
|
|
|
|
if (options.maxVersion) this.maxVersion = options.maxVersion;
|
2013-06-13 13:36:00 +00:00
|
|
|
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
|
|
|
|
if (options.crl) this.crl = options.crl;
|
|
|
|
if (options.ciphers) this.ciphers = options.ciphers;
|
2015-01-29 01:05:53 +00:00
|
|
|
if (options.ecdhCurve !== undefined)
|
2013-10-14 14:53:59 +00:00
|
|
|
this.ecdhCurve = options.ecdhCurve;
|
2014-08-27 09:00:13 +00:00
|
|
|
if (options.dhparam) this.dhparam = options.dhparam;
|
2013-06-13 13:36:00 +00:00
|
|
|
if (options.sessionTimeout) this.sessionTimeout = options.sessionTimeout;
|
2014-02-03 21:32:13 +00:00
|
|
|
if (options.ticketKeys) this.ticketKeys = options.ticketKeys;
|
2019-03-26 04:21:27 +00:00
|
|
|
const secureOptions = options.secureOptions || 0;
|
2015-02-15 17:43:36 +00:00
|
|
|
if (options.honorCipherOrder !== undefined)
|
|
|
|
this.honorCipherOrder = !!options.honorCipherOrder;
|
2014-06-25 10:47:59 +00:00
|
|
|
else
|
2015-02-15 17:43:36 +00:00
|
|
|
this.honorCipherOrder = true;
|
2013-06-13 13:36:00 +00:00
|
|
|
if (secureOptions) this.secureOptions = secureOptions;
|
2015-04-23 06:25:15 +00:00
|
|
|
if (options.ALPNProtocols)
|
|
|
|
tls.convertALPNProtocols(options.ALPNProtocols, this);
|
2013-06-13 13:36:00 +00:00
|
|
|
if (options.sessionIdContext) {
|
|
|
|
this.sessionIdContext = options.sessionIdContext;
|
2013-08-23 13:53:16 +00:00
|
|
|
} else {
|
2024-07-07 00:56:04 +00:00
|
|
|
this.sessionIdContext = crypto.createHash('sha1')
|
|
|
|
.update(process.argv.join(' '))
|
|
|
|
.digest('hex')
|
|
|
|
.slice(0, 32);
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
2018-10-29 08:38:43 +00:00
|
|
|
if (options.pskCallback) this[kPskCallback] = options.pskCallback;
|
|
|
|
if (options.pskIdentityHint) this[kPskIdentityHint] = options.pskIdentityHint;
|
2020-12-06 18:06:07 +00:00
|
|
|
if (options.sigalgs) this.sigalgs = options.sigalgs;
|
|
|
|
if (options.privateKeyIdentifier !== undefined)
|
|
|
|
this.privateKeyIdentifier = options.privateKeyIdentifier;
|
|
|
|
if (options.privateKeyEngine !== undefined)
|
|
|
|
this.privateKeyEngine = options.privateKeyEngine;
|
2018-10-22 19:17:06 +00:00
|
|
|
}, 'Server.prototype.setOptions() is deprecated', 'DEP0122');
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
// SNI Contexts High-Level API
|
2014-03-06 23:27:01 +00:00
|
|
|
Server.prototype.addContext = function(servername, context) {
|
2013-06-13 13:36:00 +00:00
|
|
|
if (!servername) {
|
2018-03-04 21:16:24 +00:00
|
|
|
throw new ERR_TLS_REQUIRED_SERVER_NAME();
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
2024-07-07 00:56:04 +00:00
|
|
|
const re = new RegExp(`^${
|
|
|
|
servername
|
|
|
|
.replace(/([.^$+?\-\\[\]{}])/g, '\\$1')
|
|
|
|
.replaceAll('*', '[^.]*')
|
|
|
|
}$`);
|
2023-04-26 06:39:00 +00:00
|
|
|
|
|
|
|
const secureContext =
|
|
|
|
context instanceof common.SecureContext ? context : tls.createSecureContext(context);
|
2024-07-07 00:56:04 +00:00
|
|
|
this._contexts.push([re, secureContext.context]);
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
|
|
|
|
2019-10-01 16:06:22 +00:00
|
|
|
Server.prototype[EE.captureRejectionSymbol] = function(
|
|
|
|
err, event, sock) {
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case 'secureConnection':
|
|
|
|
sock.destroy(err);
|
|
|
|
break;
|
|
|
|
default:
|
2020-11-17 22:09:52 +00:00
|
|
|
ReflectApply(net.Server.prototype[SymbolFor('nodejs.rejection')], this,
|
|
|
|
[err, event, sock]);
|
2019-10-01 16:06:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-08-03 17:29:54 +00:00
|
|
|
function SNICallback(servername, callback) {
|
2017-09-23 18:18:28 +00:00
|
|
|
const contexts = this.server._contexts;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2020-08-05 22:32:07 +00:00
|
|
|
for (let i = contexts.length - 1; i >= 0; --i) {
|
|
|
|
const elem = contexts[i];
|
2024-07-07 00:56:04 +00:00
|
|
|
if (elem[0].test(servername)) {
|
2017-09-23 18:18:28 +00:00
|
|
|
callback(null, elem[1]);
|
|
|
|
return;
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
2017-09-23 18:18:28 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
callback(null, undefined);
|
2013-08-02 16:11:17 +00:00
|
|
|
}
|
|
|
|
|
2013-06-13 13:36:00 +00:00
|
|
|
|
|
|
|
// Target API:
|
|
|
|
//
|
2019-11-06 14:12:45 +00:00
|
|
|
// let s = tls.connect({port: 8000, host: "google.com"}, function() {
|
2013-06-13 13:36:00 +00:00
|
|
|
// if (!s.authorized) {
|
|
|
|
// s.destroy();
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // s.socket;
|
|
|
|
//
|
|
|
|
// s.end("hello world\n");
|
|
|
|
// });
|
|
|
|
//
|
|
|
|
//
|
|
|
|
function normalizeConnectArgs(listArgs) {
|
2018-12-18 02:15:57 +00:00
|
|
|
const args = net._normalizeArgs(listArgs);
|
|
|
|
const options = args[0];
|
|
|
|
const cb = args[1];
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2016-11-18 19:37:32 +00:00
|
|
|
// If args[0] was options, then normalize dealt with it.
|
2017-06-17 13:11:45 +00:00
|
|
|
// If args[0] is port, or args[0], args[1] is host, port, we need to
|
2016-11-18 19:37:32 +00:00
|
|
|
// find the options and merge them in, normalize's options has only
|
|
|
|
// the host/port/path args that it knows about, not the tls options.
|
|
|
|
// This means that options.host overrides a host arg.
|
2015-01-29 01:05:53 +00:00
|
|
|
if (listArgs[1] !== null && typeof listArgs[1] === 'object') {
|
2019-11-22 17:04:46 +00:00
|
|
|
ObjectAssign(options, listArgs[1]);
|
2015-01-29 01:05:53 +00:00
|
|
|
} else if (listArgs[2] !== null && typeof listArgs[2] === 'object') {
|
2019-11-22 17:04:46 +00:00
|
|
|
ObjectAssign(options, listArgs[2]);
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
2018-12-18 02:15:57 +00:00
|
|
|
return cb ? [options, cb] : [options];
|
2013-06-13 13:36:00 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
function onConnectSecure() {
|
|
|
|
const options = this[kConnectOptions];
|
|
|
|
|
|
|
|
// Check the size of DHE parameter above minimum requirement
|
|
|
|
// specified in options.
|
|
|
|
const ekeyinfo = this.getEphemeralKeyInfo();
|
|
|
|
if (ekeyinfo.type === 'DH' && ekeyinfo.size < options.minDHSize) {
|
2018-03-04 21:16:24 +00:00
|
|
|
const err = new ERR_TLS_DH_PARAM_SIZE(ekeyinfo.size);
|
tls: support TLSv1.3
This introduces TLS1.3 support and makes it the default max protocol,
but also supports CLI/NODE_OPTIONS switches to disable it if necessary.
TLS1.3 is a major update to the TLS protocol, with many security
enhancements. It should be preferred over TLS1.2 whenever possible.
TLS1.3 is different enough that even though the OpenSSL APIs are
technically API/ABI compatible, that when TLS1.3 is negotiated, the
timing of protocol records and of callbacks broke assumptions hard-coded
into the 'tls' module.
This change introduces no API incompatibilities when TLS1.2 is
negotiated. It is the intention that it be backported to current and LTS
release lines with the default maximum TLS protocol reset to 'TLSv1.2'.
This will allow users of those lines to explicitly enable TLS1.3 if they
want.
API incompatibilities between TLS1.2 and TLS1.3 are:
- Renegotiation is not supported by TLS1.3 protocol, attempts to call
`.renegotiate()` will always fail.
- Compiling against a system OpenSSL lower than 1.1.1 is no longer
supported (OpenSSL-1.1.0 used to be supported with configure flags).
- Variations of `conn.write('data'); conn.destroy()` have undefined
behaviour according to the streams API. They may or may not send the
'data', and may or may not cause a ERR_STREAM_DESTROYED error to be
emitted. This has always been true, but conditions under which the write
suceeds is slightly but observably different when TLS1.3 is negotiated
vs when TLS1.2 or below is negotiated.
- If TLS1.3 is negotiated, and a server calls `conn.end()` in its
'secureConnection' listener without any data being written, the client
will not receive session tickets (no 'session' events will be emitted,
and `conn.getSession()` will never return a resumable session).
- The return value of `conn.getSession()` API may not return a resumable
session if called right after the handshake. The effect will be that
clients using the legacy `getSession()` API will resume sessions if
TLS1.2 is negotiated, but will do full handshakes if TLS1.3 is
negotiated. See https://github.com/nodejs/node/pull/25831 for more
information.
PR-URL: https://github.com/nodejs/node/pull/26209
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rod Vagg <rod@vagg.org>
2018-11-29 01:58:08 +00:00
|
|
|
debug('client emit:', err);
|
2017-09-23 18:18:28 +00:00
|
|
|
this.emit('error', err);
|
|
|
|
this.destroy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let verifyError = this._handle.verifyError();
|
|
|
|
|
|
|
|
// Verify that server's identity matches it's certificate's names
|
|
|
|
// Unless server has resumed our existing session
|
|
|
|
if (!verifyError && !this.isSessionReused()) {
|
|
|
|
const hostname = options.servername ||
|
|
|
|
options.host ||
|
2024-09-24 19:48:15 +00:00
|
|
|
(options.socket?._host) ||
|
2017-09-23 18:18:28 +00:00
|
|
|
'localhost';
|
2017-12-14 23:45:44 +00:00
|
|
|
const cert = this.getPeerCertificate(true);
|
2017-09-23 18:18:28 +00:00
|
|
|
verifyError = options.checkServerIdentity(hostname, cert);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verifyError) {
|
|
|
|
this.authorized = false;
|
|
|
|
this.authorizationError = verifyError.code || verifyError.message;
|
|
|
|
|
2021-08-04 16:40:00 +00:00
|
|
|
// rejectUnauthorized property can be explicitly defined as `undefined`
|
|
|
|
// causing the assignment to default value (`true`) fail. Before assigning
|
|
|
|
// it to the tlssock connection options, explicitly check if it is false
|
|
|
|
// and update rejectUnauthorized property. The property gets used by
|
|
|
|
// TLSSocket connection handler to allow or reject connection if
|
|
|
|
// unauthorized.
|
|
|
|
// This check is potentially redundant, however it is better to keep it
|
|
|
|
// in case the option object gets modified somewhere.
|
|
|
|
if (options.rejectUnauthorized !== false) {
|
2017-09-23 18:18:28 +00:00
|
|
|
this.destroy(verifyError);
|
|
|
|
return;
|
|
|
|
}
|
2020-04-08 16:58:03 +00:00
|
|
|
debug('client emit secureConnect. rejectUnauthorized: %s, ' +
|
|
|
|
'authorizationError: %s', options.rejectUnauthorized,
|
|
|
|
this.authorizationError);
|
2017-09-23 18:18:28 +00:00
|
|
|
} else {
|
|
|
|
this.authorized = true;
|
2019-06-05 07:44:46 +00:00
|
|
|
debug('client emit secureConnect. authorized:', this.authorized);
|
2017-09-23 18:18:28 +00:00
|
|
|
}
|
2023-09-04 10:55:34 +00:00
|
|
|
this.secureConnecting = false;
|
|
|
|
this.emit('secureConnect');
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2020-03-18 03:51:38 +00:00
|
|
|
this[kIsVerified] = true;
|
|
|
|
const session = this[kPendingSession];
|
|
|
|
this[kPendingSession] = null;
|
|
|
|
if (session)
|
|
|
|
this.emit('session', session);
|
|
|
|
|
2017-09-23 18:18:28 +00:00
|
|
|
this.removeListener('end', onConnectEnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
function onConnectEnd() {
|
|
|
|
// NOTE: This logic is shared with _http_client.js
|
|
|
|
if (!this._hadError) {
|
|
|
|
const options = this[kConnectOptions];
|
|
|
|
this._hadError = true;
|
2023-11-11 16:25:08 +00:00
|
|
|
const error = new ConnResetException('Client network socket disconnected ' +
|
|
|
|
'before secure TLS connection was ' +
|
|
|
|
'established');
|
2017-09-23 18:18:28 +00:00
|
|
|
error.path = options.path;
|
|
|
|
error.host = options.host;
|
|
|
|
error.port = options.port;
|
|
|
|
error.localAddress = options.localAddress;
|
|
|
|
this.destroy(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-11 10:36:36 +00:00
|
|
|
// Arguments: [port,] [host,] [options,] [cb]
|
|
|
|
exports.connect = function connect(...args) {
|
2015-12-20 07:01:34 +00:00
|
|
|
args = normalizeConnectArgs(args);
|
2019-11-06 14:12:45 +00:00
|
|
|
let options = args[0];
|
2019-03-26 04:21:27 +00:00
|
|
|
const cb = args[1];
|
2020-04-18 18:25:04 +00:00
|
|
|
const allowUnauthorized = getAllowUnauthorized();
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-12-18 02:15:57 +00:00
|
|
|
options = {
|
2018-07-20 02:02:44 +00:00
|
|
|
rejectUnauthorized: !allowUnauthorized,
|
2014-09-05 14:56:55 +00:00
|
|
|
ciphers: tls.DEFAULT_CIPHERS,
|
2015-05-22 09:21:54 +00:00
|
|
|
checkServerIdentity: tls.checkServerIdentity,
|
2018-12-18 02:15:57 +00:00
|
|
|
minDHSize: 1024,
|
2023-02-22 00:22:23 +00:00
|
|
|
...options,
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|
2014-09-05 14:56:55 +00:00
|
|
|
|
2015-04-26 12:19:38 +00:00
|
|
|
if (!options.keepAlive)
|
|
|
|
options.singleUse = true;
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2023-09-30 22:38:10 +00:00
|
|
|
validateFunction(options.checkServerIdentity, 'options.checkServerIdentity');
|
2023-10-06 13:18:34 +00:00
|
|
|
validateNumber(options.minDHSize, 'options.minDHSize', 1);
|
2014-09-05 14:56:55 +00:00
|
|
|
|
2016-01-12 21:04:50 +00:00
|
|
|
const context = options.secureContext || tls.createSecureContext(options);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2019-03-26 04:21:27 +00:00
|
|
|
const tlssock = new TLSSocket(options.socket, {
|
2019-05-23 09:48:52 +00:00
|
|
|
allowHalfOpen: options.allowHalfOpen,
|
2017-08-01 06:58:39 +00:00
|
|
|
pipe: !!options.path,
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
secureContext: context,
|
|
|
|
isServer: false,
|
|
|
|
requestCert: true,
|
2016-03-27 13:09:08 +00:00
|
|
|
rejectUnauthorized: options.rejectUnauthorized !== false,
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
session: options.session,
|
2017-10-31 20:03:28 +00:00
|
|
|
ALPNProtocols: options.ALPNProtocols,
|
2019-04-30 15:46:56 +00:00
|
|
|
requestOCSP: options.requestOCSP,
|
2018-10-29 08:38:43 +00:00
|
|
|
enableTrace: options.enableTrace,
|
|
|
|
pskCallback: options.pskCallback,
|
2020-04-11 18:07:35 +00:00
|
|
|
highWaterMark: options.highWaterMark,
|
2020-10-22 09:04:35 +00:00
|
|
|
onread: options.onread,
|
2021-03-12 23:13:36 +00:00
|
|
|
signal: options.signal,
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
});
|
2013-09-24 12:53:49 +00:00
|
|
|
|
2021-08-04 16:40:00 +00:00
|
|
|
// rejectUnauthorized property can be explicitly defined as `undefined`
|
|
|
|
// causing the assignment to default value (`true`) fail. Before assigning
|
|
|
|
// it to the tlssock connection options, explicitly check if it is false
|
|
|
|
// and update rejectUnauthorized property. The property gets used by TLSSocket
|
|
|
|
// connection handler to allow or reject connection if unauthorized
|
|
|
|
options.rejectUnauthorized = options.rejectUnauthorized !== false;
|
|
|
|
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock[kConnectOptions] = options;
|
2017-09-23 18:18:28 +00:00
|
|
|
|
2013-09-24 12:53:49 +00:00
|
|
|
if (cb)
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock.once('secureConnect', cb);
|
2013-09-24 12:53:49 +00:00
|
|
|
|
|
|
|
if (!options.socket) {
|
2019-05-22 08:27:16 +00:00
|
|
|
// If user provided the socket, it's their responsibility to manage its
|
2018-12-19 22:42:58 +00:00
|
|
|
// connectivity. If we created one internally, we connect it.
|
2019-01-15 15:12:12 +00:00
|
|
|
if (options.timeout) {
|
|
|
|
tlssock.setTimeout(options.timeout);
|
|
|
|
}
|
|
|
|
|
2019-05-22 08:27:16 +00:00
|
|
|
tlssock.connect(options, tlssock._start);
|
2013-09-24 12:53:49 +00:00
|
|
|
}
|
|
|
|
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock._releaseControl();
|
2013-06-13 13:36:00 +00:00
|
|
|
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
if (options.session)
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock.setSession(options.session);
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-01-12 23:36:21 +00:00
|
|
|
if (options.servername) {
|
|
|
|
if (!ipServernameWarned && net.isIP(options.servername)) {
|
|
|
|
process.emitWarning(
|
|
|
|
'Setting the TLS ServerName to an IP address is not permitted by ' +
|
|
|
|
'RFC 6066. This will be ignored in a future version.',
|
|
|
|
'DeprecationWarning',
|
2023-02-14 17:45:16 +00:00
|
|
|
'DEP0123',
|
2018-01-12 23:36:21 +00:00
|
|
|
);
|
|
|
|
ipServernameWarned = true;
|
|
|
|
}
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock.setServername(options.servername);
|
2018-01-12 23:36:21 +00:00
|
|
|
}
|
2013-06-13 13:36:00 +00:00
|
|
|
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
if (options.socket)
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock._start();
|
2013-06-13 13:36:00 +00:00
|
|
|
|
2018-12-19 22:42:58 +00:00
|
|
|
tlssock.on('secure', onConnectSecure);
|
2019-08-18 21:38:35 +00:00
|
|
|
tlssock.prependListener('end', onConnectEnd);
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
2015-02-22 18:59:07 +00:00
|
|
|
|
2018-12-19 22:42:58 +00:00
|
|
|
return tlssock;
|
2013-06-13 13:36:00 +00:00
|
|
|
};
|