1// One shot call to connect a TLS client and server based on options to 2// tls.createServer() and tls.connect(), so assertions can be made on both ends 3// of the connection. 4'use strict'; 5 6const common = require('../common'); 7// Check if Node was compiled --without-ssl and if so exit early 8// as the require of tls will otherwise throw an Error. 9if (!common.hasCrypto) 10 common.skip('missing crypto'); 11 12const fixtures = require('../common/fixtures'); 13const tls = require('tls'); 14const util = require('util'); 15 16exports.assert = require('assert'); 17exports.debug = util.debuglog('test'); 18exports.tls = tls; 19 20// Pre-load keys from common fixtures for ease of use by tests. 21exports.keys = { 22 agent1: load('agent1', 'ca1'), 23 agent2: load('agent2', 'agent2'), 24 agent3: load('agent3', 'ca2'), 25 agent4: load('agent4', 'ca2'), 26 agent5: load('agent5', 'ca2'), 27 agent6: load('agent6', 'ca1'), 28 agent7: load('agent7', 'fake-cnnic-root'), 29 agent10: load('agent10', 'ca2'), 30 ec10: load('ec10', 'ca5'), 31 ec: load('ec', 'ec'), 32}; 33 34// `root` is the self-signed root of the trust chain, not an intermediate ca. 35function load(cert, root) { 36 root = root || cert; // Assume self-signed if no issuer. 37 const id = { 38 key: fixtures.readKey(cert + '-key.pem', 'binary'), 39 cert: fixtures.readKey(cert + '-cert.pem', 'binary'), 40 ca: fixtures.readKey(root + '-cert.pem', 'binary'), 41 }; 42 return id; 43} 44 45exports.connect = function connect(options, callback) { 46 callback = common.mustCall(callback); 47 48 const server = {}; 49 const client = {}; 50 const pair = { server, client }; 51 52 try { 53 tls.createServer(options.server, function(conn) { 54 server.conn = conn; 55 conn.pipe(conn); 56 maybeCallback(); 57 }).listen(0, function() { 58 server.server = this; 59 60 const optClient = util._extend({ 61 port: this.address().port, 62 }, options.client); 63 64 try { 65 tls.connect(optClient) 66 .on('secureConnect', function() { 67 client.conn = this; 68 maybeCallback(); 69 }) 70 .on('error', function(err) { 71 client.err = err; 72 client.conn = this; 73 maybeCallback(); 74 }); 75 } catch (err) { 76 client.err = err; 77 // The server won't get a connection, we are done. 78 callback(err, pair, cleanup); 79 callback = null; 80 } 81 }).on('tlsClientError', function(err, sock) { 82 server.conn = sock; 83 server.err = err; 84 maybeCallback(); 85 }); 86 } catch (err) { 87 // Invalid options can throw, report the error. 88 pair.server.err = err; 89 callback(err, pair, () => {}); 90 } 91 92 function maybeCallback() { 93 if (!callback) 94 return; 95 if (server.conn && client.conn) { 96 const err = pair.client.err || pair.server.err; 97 callback(err, pair, cleanup); 98 callback = null; 99 } 100 } 101 102 function cleanup() { 103 if (server.server) 104 server.server.close(); 105 if (client.conn) 106 client.conn.end(); 107 } 108}; 109