From 6ad99ac1efe2a0c52f0652356dc397097b5d577c Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 7 Aug 2015 18:14:54 -0700 Subject: [PATCH] tls: fix check for reused session When TLS Session Ticket is renewed by server - no Certificate record is to the client. We are prepared for empty certificate in this case, but this relies on the session reuse check, which was implemented incorrectly and was returning false when the TLS Session Ticket was renewed. Use session reuse check provided by OpenSSL instead. Fix: https://github.com/nodejs/io.js/issues/2304 PR-URL: https://github.com/nodejs/io.js/pull/2312 Reviewed-By: Shigeki Ohtsu --- lib/_tls_wrap.js | 13 +---- .../parallel/test-https-resume-after-renew.js | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 test/parallel/test-https-resume-after-renew.js diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 182346904c..b5d1899480 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -584,17 +584,6 @@ TLSSocket.prototype._start = function() { this._handle.start(); }; -TLSSocket.prototype._isSessionResumed = function _isSessionResumed(session) { - if (!session) - return false; - - var next = this.getSession(); - if (!next) - return false; - - return next.equals(session); -}; - TLSSocket.prototype.setServername = function(name) { this._handle.setServername(name); }; @@ -1011,7 +1000,7 @@ exports.connect = function(/* [port, host], options, cb */) { // Verify that server's identity matches it's certificate's names // Unless server has resumed our existing session - if (!verifyError && !socket._isSessionResumed(options.session)) { + if (!verifyError && !socket.isSessionReused()) { var cert = socket.getPeerCertificate(); verifyError = options.checkServerIdentity(hostname, cert); } diff --git a/test/parallel/test-https-resume-after-renew.js b/test/parallel/test-https-resume-after-renew.js new file mode 100644 index 0000000000..23626ccb40 --- /dev/null +++ b/test/parallel/test-https-resume-after-renew.js @@ -0,0 +1,56 @@ +'use strict'; +var common = require('../common'); +var fs = require('fs'); +var https = require('https'); +var crypto = require('crypto'); + +var options = { + key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem'), + ca: fs.readFileSync(common.fixturesDir + '/keys/ca1-cert.pem') +}; + +var server = https.createServer(options, function(req, res) { + res.end('hello'); +}); + +var aes = new Buffer(16); +aes.fill('S'); +var hmac = new Buffer(16); +hmac.fill('H'); + +server._sharedCreds.context.enableTicketKeyCallback(); +server._sharedCreds.context.onticketkeycallback = function(name, iv, enc) { + if (enc) { + var newName = new Buffer(16); + var newIV = crypto.randomBytes(16); + newName.fill('A'); + } else { + // Renew + return [ 2, hmac, aes ]; + } + + return [ 1, hmac, aes, newName, newIV ]; +}; + +server.listen(common.PORT, function() { + var addr = this.address(); + + function doReq(callback) { + https.request({ + method: 'GET', + port: addr.port, + servername: 'agent1', + ca: options.ca + }, function(res) { + res.resume(); + res.once('end', callback); + }).end(); + } + + doReq(function() { + doReq(function() { + server.close(); + }); + }); +});