Skip to content

Commit f72e178

Browse files
author
Shigeki Ohtsu
committed
tls: add minDHSize option to tls.connect()
Add a new option to specifiy a minimum size of an ephemeral DH parameter to accept a tls connection. Default is 1024 bit. PR-URL: #1831 Reviewed-By: indutny - Fedor Indutny <[email protected]> Reviewed-By: bnoordhuis - Ben Noordhuis <[email protected]>
1 parent 6d92eba commit f72e178

File tree

3 files changed

+104
-1
lines changed

3 files changed

+104
-1
lines changed

doc/api/tls.markdown

+5
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,11 @@ Creates a new client connection to the given `port` and `host` (old API) or
388388

389389
- `session`: A `Buffer` instance, containing TLS session.
390390

391+
- `minDHSize`: Minimum size of DH parameter in bits to accept a TLS
392+
connection. When a server offers DH parameter with a size less
393+
than this, the TLS connection is destroyed and throws an
394+
error. Default: 1024.
395+
391396
The `callback` parameter will be added as a listener for the
392397
['secureConnect'][] event.
393398

lib/_tls_wrap.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -945,14 +945,20 @@ exports.connect = function(/* [port, host], options, cb */) {
945945
var defaults = {
946946
rejectUnauthorized: '0' !== process.env.NODE_TLS_REJECT_UNAUTHORIZED,
947947
ciphers: tls.DEFAULT_CIPHERS,
948-
checkServerIdentity: tls.checkServerIdentity
948+
checkServerIdentity: tls.checkServerIdentity,
949+
minDHSize: 1024
949950
};
950951

951952
options = util._extend(defaults, options || {});
952953
if (!options.keepAlive)
953954
options.singleUse = true;
954955

955956
assert(typeof options.checkServerIdentity === 'function');
957+
assert(typeof options.minDHSize === 'number',
958+
'options.minDHSize is not a number: ' + options.minDHSize);
959+
assert(options.minDHSize > 0,
960+
'options.minDHSize is not a posivie number: ' +
961+
options.minDHSize);
956962

957963
var hostname = options.servername ||
958964
options.host ||
@@ -1004,6 +1010,17 @@ exports.connect = function(/* [port, host], options, cb */) {
10041010
socket._start();
10051011

10061012
socket.on('secure', function() {
1013+
// Check the size of DHE parameter above minimum requirement
1014+
// specified in options.
1015+
var ekeyinfo = socket.getEphemeralKeyInfo();
1016+
if (ekeyinfo.type === 'DH' && ekeyinfo.size < options.minDHSize) {
1017+
var err = new Error('DH parameter size ' + ekeyinfo.size +
1018+
' is less than ' + options.minDHSize);
1019+
socket.emit('error', err);
1020+
socket.destroy();
1021+
return;
1022+
}
1023+
10071024
var verifyError = socket._handle.verifyError();
10081025

10091026
// Verify that server's identity matches it's certificate's names
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
'use strict';
2+
var common = require('../common');
3+
var assert = require('assert');
4+
5+
if (!common.hasCrypto) {
6+
console.log('1..0 # Skipped: missing crypto');
7+
process.exit();
8+
}
9+
var tls = require('tls');
10+
11+
var fs = require('fs');
12+
var key = fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem');
13+
var cert = fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem');
14+
15+
var nsuccess = 0;
16+
var nerror = 0;
17+
18+
function loadDHParam(n) {
19+
var path = common.fixturesDir;
20+
if (n !== 'error') path += '/keys';
21+
return fs.readFileSync(path + '/dh' + n + '.pem');
22+
}
23+
24+
function test(size, err, next) {
25+
var options = {
26+
key: key,
27+
cert: cert,
28+
dhparam: loadDHParam(size),
29+
ciphers: 'DHE-RSA-AES128-GCM-SHA256'
30+
};
31+
32+
var server = tls.createServer(options, function(conn) {
33+
conn.end();
34+
});
35+
36+
server.on('close', function(isException) {
37+
assert(!isException);
38+
if (next) next();
39+
});
40+
41+
server.listen(common.PORT, '127.0.0.1', function() {
42+
// client set minimum DH parameter size to 2048 bits so that
43+
// it fails when it make a connection to the tls server where
44+
// dhparams is 1024 bits
45+
var client = tls.connect({
46+
minDHSize: 2048,
47+
port: common.PORT,
48+
rejectUnauthorized: false
49+
}, function() {
50+
nsuccess++;
51+
server.close();
52+
});
53+
if (err) {
54+
client.on('error', function(e) {
55+
nerror++;
56+
assert.strictEqual(e.message, 'DH parameter size 1024 is less'
57+
+ ' than 2048');
58+
server.close();
59+
});
60+
}
61+
});
62+
}
63+
64+
// A client connection fails with an error when a client has an
65+
// 2048 bits minDHSize option and a server has 1024 bits dhparam
66+
function testDHE1024() {
67+
test(1024, true, testDHE2048);
68+
}
69+
70+
// A client connection successes when a client has an
71+
// 2048 bits minDHSize option and a server has 2048 bits dhparam
72+
function testDHE2048() {
73+
test(2048, false, null);
74+
}
75+
76+
testDHE1024();
77+
78+
process.on('exit', function() {
79+
assert.equal(nsuccess, 1);
80+
assert.equal(nerror, 1);
81+
});

0 commit comments

Comments
 (0)