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