tls: propagate singleUse to the secure context by ViniciusDev26 · Pull Request #66025 · nodejs/node · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/internal/tls/common.js
36 changes: 25 additions & 11 deletions lib/internal/tls/wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const kDisableRenegotiation = Symbol('disable-renegotiation');
const kErrorEmitted = Symbol('error-emitted');
const kHandshakeTimeout = Symbol('handshake-timeout');
const kRes = Symbol('res');
const kSecureContext = Symbol('secureContext');
const kSNICallback = Symbol('snicallback');
const kALPNCallback = Symbol('alpncallback');
const kEnableTrace = Symbol('enableTrace');
Expand Down Expand Up @@ -650,6 +651,7 @@ function TLSSocket(socket, opts) {
this.authorized = false;
this.authorizationError = null;
this[kRes] = null;
this[kSecureContext] = null;
this[kIsVerified] = false;
this[kPendingSession] = null;

Expand Down Expand Up @@ -748,6 +750,18 @@ for (const proxiedMethod of proxiedMethods) {
makeMethodProxy(proxiedMethod);
}

// A single-use context is owned by the socket that created it, so its SSL_CTX
// can be released as soon as the socket is gone instead of waiting for the JS
// wrapper to be garbage collected. It is shared by every handle the socket
// goes through, so it must outlive any individual TLSWrap.
function closeSingleUseContext(secureContext) {
if (secureContext !== null && secureContext.singleUse &&
secureContext.context !== null) {
secureContext.context.close();
secureContext.context = null;
}
}

tls_wrap.TLSWrap.prototype.close = function close(cb) {
let ssl;
if (this[owner_symbol]) {
Expand All @@ -760,10 +774,6 @@ tls_wrap.TLSWrap.prototype.close = function close(cb) {
const done = () => {
if (ssl) {
ssl.destroySSL();
if (ssl._secureContext.singleUse) {
ssl._secureContext.context.close();
ssl._secureContext.context = null;
}
}
if (cb)
cb();
Expand Down Expand Up @@ -821,6 +831,7 @@ TLSSocket.prototype._wrapHandle = function(wrap, handle, wrapHasActiveWriteFromP
res._parent = handle; // C++ "wrap" object: TCPWrap, JSStream, ...
res._parentWrap = wrap; // JS object: net.Socket, JSStreamSocket, ...
res._secureContext = context;
this[kSecureContext] = context;
res.reading = handle.reading;
this[kRes] = res;
defineHandleReading(this, handle);
Expand Down Expand Up @@ -886,13 +897,16 @@ function destroySSL(self) {
}

TLSSocket.prototype._destroySSL = function _destroySSL() {
if (!this.ssl) return;
this.ssl.destroySSL();
if (this.ssl._secureContext.singleUse) {
this.ssl._secureContext.context.close();
this.ssl._secureContext.context = null;
}
this.ssl = null;
if (this.ssl) {
this.ssl.destroySSL();
this.ssl = null;
}
// Release the context here rather than when a handle closes: a socket that
// swaps handles, as autoSelectFamily retries do, shares one context across
// the successive TLSWraps and still needs it after the old handle is gone.
// TLSWrap.close() may already have cleared `ssl` on the way here.
closeSingleUseContext(this[kSecureContext]);
this[kSecureContext] = null;
this[kPendingSession] = null;
this[kIsVerified] = false;
};
Expand Down
132 changes: 132 additions & 0 deletions test/parallel/test-tls-connect-single-use-context.js
Loading