tls: fix check for reused session
authorFedor Indutny <fedor@indutny.com>
Sat, 8 Aug 2015 01:14:54 +0000 (18:14 -0700)
committerShigeki Ohtsu <ohtsu@iij.ad.jp>
Fri, 7 Aug 2015 22:16:58 +0000 (07:16 +0900)
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 <ohtsu@iij.ad.jp>
lib/_tls_wrap.js
test/parallel/test-https-resume-after-renew.js [new file with mode: 0644]

index 1823469..b5d1899 100644 (file)
@@ -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 (file)
index 0000000..23626cc
--- /dev/null
@@ -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();
+    });
+  });
+});