• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23const common = require('../common');
24if (!common.hasCrypto)
25  common.skip('missing crypto');
26
27if (!common.opensslCli)
28  common.skip('node compiled without OpenSSL CLI.');
29
30const assert = require('assert');
31const tls = require('tls');
32const https = require('https');
33const fixtures = require('../common/fixtures');
34
35// Renegotiation as a protocol feature was dropped after TLS1.2.
36tls.DEFAULT_MAX_VERSION = 'TLSv1.2';
37
38// Renegotiation limits to test
39const LIMITS = [0, 1, 2, 3, 5, 10, 16];
40
41{
42  let n = 0;
43  function next() {
44    if (n >= LIMITS.length) return;
45    tls.CLIENT_RENEG_LIMIT = LIMITS[n++];
46    test(next);
47  }
48  next();
49}
50
51function test(next) {
52  const options = {
53    cert: fixtures.readKey('rsa_cert.crt'),
54    key: fixtures.readKey('rsa_private.pem'),
55  };
56
57  const server = https.createServer(options, (req, res) => {
58    const conn = req.connection;
59    conn.on('error', (err) => {
60      console.error(`Caught exception: ${err}`);
61      assert.match(err.message, /TLS session renegotiation attack/);
62      conn.destroy();
63    });
64    res.end('ok');
65  });
66
67  server.listen(0, () => {
68    const agent = https.Agent({
69      keepAlive: true,
70    });
71
72    let client;
73    let renegs = 0;
74
75    const options = {
76      rejectUnauthorized: false,
77      agent,
78    };
79
80    const { port } = server.address();
81
82    https.get(`https://localhost:${port}/`, options, (res) => {
83      client = res.socket;
84
85      client.on('close', (hadErr) => {
86        assert.strictEqual(hadErr, false);
87        assert.strictEqual(renegs, tls.CLIENT_RENEG_LIMIT + 1);
88        server.close();
89        process.nextTick(next);
90      });
91
92      client.on('error', (err) => {
93        console.log('CLIENT ERR', err);
94        throw err;
95      });
96
97      spam();
98
99      // Simulate renegotiation attack
100      function spam() {
101        client.renegotiate({}, (err) => {
102          assert.ifError(err);
103          assert.ok(renegs <= tls.CLIENT_RENEG_LIMIT);
104          setImmediate(spam);
105        });
106        renegs++;
107      }
108    });
109
110  });
111}
112