summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2019-03-05 15:00:09 +0100
committerBeth Griggs <Bethany.Griggs@uk.ibm.com>2019-03-20 23:53:42 +0000
commit7573b55a1505e5ea0e2c903e15013bb409fe3c93 (patch)
tree87833098bdb5b2d5f291dbe26fd5087e1def6b0c
parent91620b8bd61bc7932198c2309b8f3158d04ae4ca (diff)
downloadnode-new-7573b55a1505e5ea0e2c903e15013bb409fe3c93.tar.gz
tls: fix legacy SecurePair clienthello race window
There is a time window between the first and the last step of processing the clienthello event and the SecurePair may have been destroyed during that interval. Fixes: https://github.com/nodejs/node/issues/26428 PR-URL: https://github.com/nodejs/node/pull/26452 Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com>
-rw-r--r--lib/_tls_legacy.js4
-rw-r--r--test/parallel/test-tls-async-cb-after-socket-end-securepair.js80
2 files changed, 84 insertions, 0 deletions
diff --git a/lib/_tls_legacy.js b/lib/_tls_legacy.js
index 52de70d479..7b9e34bb84 100644
--- a/lib/_tls_legacy.js
+++ b/lib/_tls_legacy.js
@@ -659,6 +659,10 @@ function onclienthello(hello) {
if (err) return self.socket.destroy(err);
setImmediate(function() {
+ // SecurePair might have been destroyed in the time window
+ // between callback() and this function.
+ if (!self.ssl) return;
+
self.ssl.loadSession(session);
self.ssl.endParser();
diff --git a/test/parallel/test-tls-async-cb-after-socket-end-securepair.js b/test/parallel/test-tls-async-cb-after-socket-end-securepair.js
new file mode 100644
index 0000000000..890c2b63ef
--- /dev/null
+++ b/test/parallel/test-tls-async-cb-after-socket-end-securepair.js
@@ -0,0 +1,80 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+const fixtures = require('../common/fixtures');
+const SSL_OP_NO_TICKET = require('crypto').constants.SSL_OP_NO_TICKET;
+const assert = require('assert');
+const net = require('net');
+const tls = require('tls');
+
+const options = {
+ secureOptions: SSL_OP_NO_TICKET,
+ key: fixtures.readSync('test_key.pem'),
+ cert: fixtures.readSync('test_cert.pem')
+};
+
+const server = net.createServer(function(socket) {
+ const sslcontext = tls.createSecureContext(options);
+ sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
+
+ const pair = tls.createSecurePair(sslcontext, true, false, false, { server });
+
+ assert.ok(pair.encrypted.writable);
+ assert.ok(pair.cleartext.writable);
+
+ pair.encrypted.pipe(socket);
+ socket.pipe(pair.encrypted);
+
+ pair.on('error', () => {}); // Expected, client s1 closes connection.
+});
+
+let sessionCb = null;
+let client = null;
+
+server.on('newSession', common.mustCall(function(key, session, done) {
+ done();
+}));
+
+server.on('resumeSession', common.mustCall(function(id, cb) {
+ sessionCb = cb;
+
+ next();
+}));
+
+server.listen(0, function() {
+ const clientOpts = {
+ port: this.address().port,
+ rejectUnauthorized: false,
+ session: false
+ };
+
+ const s1 = tls.connect(clientOpts, function() {
+ clientOpts.session = s1.getSession();
+ console.log('1st secure');
+
+ s1.destroy();
+ const s2 = tls.connect(clientOpts, function(s) {
+ console.log('2nd secure');
+
+ s2.destroy();
+ }).on('connect', function() {
+ console.log('2nd connected');
+ client = s2;
+
+ next();
+ });
+ });
+});
+
+function next() {
+ if (!client || !sessionCb)
+ return;
+
+ client.destroy();
+ setTimeout(function() {
+ sessionCb();
+ server.close();
+ }, 100);
+}