11cb0ef41Sopenharmony_ci// One shot call to connect a TLS client and server based on options to
21cb0ef41Sopenharmony_ci// tls.createServer() and tls.connect(), so assertions can be made on both ends
31cb0ef41Sopenharmony_ci// of the connection.
41cb0ef41Sopenharmony_ci'use strict';
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciconst common = require('../common');
71cb0ef41Sopenharmony_ci// Check if Node was compiled --without-ssl and if so exit early
81cb0ef41Sopenharmony_ci// as the require of tls will otherwise throw an Error.
91cb0ef41Sopenharmony_ciif (!common.hasCrypto)
101cb0ef41Sopenharmony_ci  common.skip('missing crypto');
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
131cb0ef41Sopenharmony_ciconst tls = require('tls');
141cb0ef41Sopenharmony_ciconst util = require('util');
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciexports.assert = require('assert');
171cb0ef41Sopenharmony_ciexports.debug = util.debuglog('test');
181cb0ef41Sopenharmony_ciexports.tls = tls;
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci// Pre-load keys from common fixtures for ease of use by tests.
211cb0ef41Sopenharmony_ciexports.keys = {
221cb0ef41Sopenharmony_ci  agent1: load('agent1', 'ca1'),
231cb0ef41Sopenharmony_ci  agent2: load('agent2', 'agent2'),
241cb0ef41Sopenharmony_ci  agent3: load('agent3', 'ca2'),
251cb0ef41Sopenharmony_ci  agent4: load('agent4', 'ca2'),
261cb0ef41Sopenharmony_ci  agent5: load('agent5', 'ca2'),
271cb0ef41Sopenharmony_ci  agent6: load('agent6', 'ca1'),
281cb0ef41Sopenharmony_ci  agent7: load('agent7', 'fake-cnnic-root'),
291cb0ef41Sopenharmony_ci  agent10: load('agent10', 'ca2'),
301cb0ef41Sopenharmony_ci  ec10: load('ec10', 'ca5'),
311cb0ef41Sopenharmony_ci  ec: load('ec', 'ec'),
321cb0ef41Sopenharmony_ci};
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci// `root` is the self-signed root of the trust chain, not an intermediate ca.
351cb0ef41Sopenharmony_cifunction load(cert, root) {
361cb0ef41Sopenharmony_ci  root = root || cert; // Assume self-signed if no issuer.
371cb0ef41Sopenharmony_ci  const id = {
381cb0ef41Sopenharmony_ci    key: fixtures.readKey(cert + '-key.pem', 'binary'),
391cb0ef41Sopenharmony_ci    cert: fixtures.readKey(cert + '-cert.pem', 'binary'),
401cb0ef41Sopenharmony_ci    ca: fixtures.readKey(root + '-cert.pem', 'binary'),
411cb0ef41Sopenharmony_ci  };
421cb0ef41Sopenharmony_ci  return id;
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ciexports.connect = function connect(options, callback) {
461cb0ef41Sopenharmony_ci  callback = common.mustCall(callback);
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  const server = {};
491cb0ef41Sopenharmony_ci  const client = {};
501cb0ef41Sopenharmony_ci  const pair = { server, client };
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  try {
531cb0ef41Sopenharmony_ci    tls.createServer(options.server, function(conn) {
541cb0ef41Sopenharmony_ci      server.conn = conn;
551cb0ef41Sopenharmony_ci      conn.pipe(conn);
561cb0ef41Sopenharmony_ci      maybeCallback();
571cb0ef41Sopenharmony_ci    }).listen(0, function() {
581cb0ef41Sopenharmony_ci      server.server = this;
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci      const optClient = util._extend({
611cb0ef41Sopenharmony_ci        port: this.address().port,
621cb0ef41Sopenharmony_ci      }, options.client);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci      try {
651cb0ef41Sopenharmony_ci        tls.connect(optClient)
661cb0ef41Sopenharmony_ci          .on('secureConnect', function() {
671cb0ef41Sopenharmony_ci            client.conn = this;
681cb0ef41Sopenharmony_ci            maybeCallback();
691cb0ef41Sopenharmony_ci          })
701cb0ef41Sopenharmony_ci          .on('error', function(err) {
711cb0ef41Sopenharmony_ci            client.err = err;
721cb0ef41Sopenharmony_ci            client.conn = this;
731cb0ef41Sopenharmony_ci            maybeCallback();
741cb0ef41Sopenharmony_ci          });
751cb0ef41Sopenharmony_ci      } catch (err) {
761cb0ef41Sopenharmony_ci        client.err = err;
771cb0ef41Sopenharmony_ci        // The server won't get a connection, we are done.
781cb0ef41Sopenharmony_ci        callback(err, pair, cleanup);
791cb0ef41Sopenharmony_ci        callback = null;
801cb0ef41Sopenharmony_ci      }
811cb0ef41Sopenharmony_ci    }).on('tlsClientError', function(err, sock) {
821cb0ef41Sopenharmony_ci      server.conn = sock;
831cb0ef41Sopenharmony_ci      server.err = err;
841cb0ef41Sopenharmony_ci      maybeCallback();
851cb0ef41Sopenharmony_ci    });
861cb0ef41Sopenharmony_ci  } catch (err) {
871cb0ef41Sopenharmony_ci    // Invalid options can throw, report the error.
881cb0ef41Sopenharmony_ci    pair.server.err = err;
891cb0ef41Sopenharmony_ci    callback(err, pair, () => {});
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  function maybeCallback() {
931cb0ef41Sopenharmony_ci    if (!callback)
941cb0ef41Sopenharmony_ci      return;
951cb0ef41Sopenharmony_ci    if (server.conn && client.conn) {
961cb0ef41Sopenharmony_ci      const err = pair.client.err || pair.server.err;
971cb0ef41Sopenharmony_ci      callback(err, pair, cleanup);
981cb0ef41Sopenharmony_ci      callback = null;
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci  }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  function cleanup() {
1031cb0ef41Sopenharmony_ci    if (server.server)
1041cb0ef41Sopenharmony_ci      server.server.close();
1051cb0ef41Sopenharmony_ci    if (client.conn)
1061cb0ef41Sopenharmony_ci      client.conn.end();
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci};
109