From 9c7450027fe379c7432f4a8fea717b72f5d51c40 Mon Sep 17 00:00:00 2001 From: Shigeki Ohtsu Date: Fri, 22 May 2015 18:21:54 +0900 Subject: [PATCH] tls: add minDHkeylen option to tls.connect() Add a new option to specifiy a minimum key length of an ephemeral DH parameter to accept a tls connection. Default is 1024 bit. --- doc/api/tls.markdown | 5 ++ lib/_tls_wrap.js | 13 +++- test/parallel/test-tls-client-mindhkeylen.js | 80 ++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-tls-client-mindhkeylen.js diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index d9e32698dabb88..7a8a812b3201d0 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -347,6 +347,11 @@ Creates a new client connection to the given `port` and `host` (old API) or - `session`: A `Buffer` instance, containing TLS session. + - `minDHkeylen`: Minimum key length of an ephemeral DH parameter to + accept a tls connection. When a server offers an ephemeral DH + parameter of which key length is less than this, the tls + connection is destroyed and throws an error. Default: 1024. + The `callback` parameter will be added as a listener for the ['secureConnect'][] event. diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 073ae36df70d3d..fc8edcde039ac8 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -880,7 +880,8 @@ exports.connect = function(/* [port, host], options, cb */) { var defaults = { rejectUnauthorized: '0' !== process.env.NODE_TLS_REJECT_UNAUTHORIZED, ciphers: tls.DEFAULT_CIPHERS, - checkServerIdentity: tls.checkServerIdentity + checkServerIdentity: tls.checkServerIdentity, + minDHkeylen: 1024 }; options = util._extend(defaults, options || {}); @@ -939,6 +940,16 @@ exports.connect = function(/* [port, host], options, cb */) { socket._start(); socket.on('secure', function() { + // Check DHE keylength above minimum requirement specified in options. + var ekeyinfo = socket.getEphemeralKeyInfo(); + if (ekeyinfo.type === 'DH' && ekeyinfo.keylen < options.minDHkeylen) { + var err = new Error('DH key length ' + ekeyinfo.keylen + + ' is less than ' + options.minDHkeylen); + socket.emit('error', err); + socket.destroy(); + return; + } + var verifyError = socket._handle.verifyError(); // Verify that server's identity matches it's certificate's names diff --git a/test/parallel/test-tls-client-mindhkeylen.js b/test/parallel/test-tls-client-mindhkeylen.js new file mode 100644 index 00000000000000..6963601c7cc8d5 --- /dev/null +++ b/test/parallel/test-tls-client-mindhkeylen.js @@ -0,0 +1,80 @@ +'use strict'; +var common = require('../common'); +var assert = require('assert'); + +if (!common.hasCrypto) { + console.log('1..0 # Skipped: missing crypto'); + process.exit(); +} +var tls = require('tls'); + +var fs = require('fs'); +var key = fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem'); +var cert = fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem'); + +var nsuccess = 0; +var nerror = 0; + +function loadDHParam(n) { + var path = common.fixturesDir; + if (n !== 'error') path += '/keys'; + return fs.readFileSync(path + '/dh' + n + '.pem'); +} + +function test(keylen, err, cb) { + var options = { + key: key, + cert: cert, + dhparam: loadDHParam(keylen), + ciphers: 'DHE-RSA-AES128-GCM-SHA256' + }; + + var server = tls.createServer(options, function(conn) { + conn.end(); + }); + + server.on('close', function(isException) { + assert(!isException); + if (cb) cb(); + }); + + server.listen(common.PORT, '127.0.0.1', function() { + // client set minimum DH key length 2048 bits so that + // it fails when it make a connection to the tls server where + // dhparams is 1024 bits + var client = tls.connect({ + minDHkeylen: 2048, + port: common.PORT, + rejectUnauthorized: false + }, function() { + nsuccess++; + server.close(); + }); + if(err) { + client.on('error', function(e) { + nerror++; + assert.strictEqual(e.message, 'DH key length 1024 is less than 2048'); + server.close(); + }); + } + }); +} + +// A client connection fails with an error when a client has an +// 2048 bits minDHkeylen option and a server has 1024 bits dhparam +function testDHE1024() { + test(1024, true, testDHE2048); +} + +// A client connection successes when a client has an +// 2048 bits minDHkeylen option and a server has 2048 bits dhparam +function testDHE2048() { + test(2048, false, null); +} + +testDHE1024(); + +process.on('exit', function() { + assert.equal(nsuccess, 1); + assert.equal(nerror, 1); +});