11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
21cb0ef41Sopenharmony_ci//
31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
91cb0ef41Sopenharmony_ci// following conditions:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci'use strict';
231cb0ef41Sopenharmony_ciconst common = require('../common');
241cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
251cb0ef41Sopenharmony_ciif (!common.hasCrypto)
261cb0ef41Sopenharmony_ci  common.skip('missing crypto');
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci// Disable strict server certificate validation by the client
291cb0ef41Sopenharmony_ciprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cicommon.expectWarning(
321cb0ef41Sopenharmony_ci  'Warning',
331cb0ef41Sopenharmony_ci  'Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to \'0\' ' +
341cb0ef41Sopenharmony_ci  'makes TLS connections and HTTPS requests insecure by disabling ' +
351cb0ef41Sopenharmony_ci  'certificate verification.'
361cb0ef41Sopenharmony_ci);
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciconst assert = require('assert');
391cb0ef41Sopenharmony_ciconst https = require('https');
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cifunction read(fname) {
421cb0ef41Sopenharmony_ci  return fixtures.readKey(fname);
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci// key1 is signed by ca1.
461cb0ef41Sopenharmony_ciconst key1 = read('agent1-key.pem');
471cb0ef41Sopenharmony_ciconst cert1 = read('agent1-cert.pem');
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci// key2 has a self signed cert
501cb0ef41Sopenharmony_ciconst key2 = read('agent2-key.pem');
511cb0ef41Sopenharmony_ciconst cert2 = read('agent2-cert.pem');
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci// key3 is signed by ca2.
541cb0ef41Sopenharmony_ciconst key3 = read('agent3-key.pem');
551cb0ef41Sopenharmony_ciconst cert3 = read('agent3-cert.pem');
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ciconst ca1 = read('ca1-cert.pem');
581cb0ef41Sopenharmony_ciconst ca2 = read('ca2-cert.pem');
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci// Different agents to use different CA lists.
611cb0ef41Sopenharmony_ci// this api is beyond bad.
621cb0ef41Sopenharmony_ciconst agent0 = new https.Agent();
631cb0ef41Sopenharmony_ciconst agent1 = new https.Agent({ ca: [ca1] });
641cb0ef41Sopenharmony_ciconst agent2 = new https.Agent({ ca: [ca2] });
651cb0ef41Sopenharmony_ciconst agent3 = new https.Agent({ ca: [ca1, ca2] });
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ciconst options1 = {
681cb0ef41Sopenharmony_ci  key: key1,
691cb0ef41Sopenharmony_ci  cert: cert1
701cb0ef41Sopenharmony_ci};
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ciconst options2 = {
731cb0ef41Sopenharmony_ci  key: key2,
741cb0ef41Sopenharmony_ci  cert: cert2
751cb0ef41Sopenharmony_ci};
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ciconst options3 = {
781cb0ef41Sopenharmony_ci  key: key3,
791cb0ef41Sopenharmony_ci  cert: cert3
801cb0ef41Sopenharmony_ci};
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ciconst server1 = server(options1);
831cb0ef41Sopenharmony_ciconst server2 = server(options2);
841cb0ef41Sopenharmony_ciconst server3 = server(options3);
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cilet listenWait = 0;
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciserver1.listen(0, listening());
891cb0ef41Sopenharmony_ciserver2.listen(0, listening());
901cb0ef41Sopenharmony_ciserver3.listen(0, listening());
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ciconst responseErrors = {};
931cb0ef41Sopenharmony_cilet pending = 0;
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_cifunction server(options) {
971cb0ef41Sopenharmony_ci  const s = https.createServer(options, handler);
981cb0ef41Sopenharmony_ci  s.requests = [];
991cb0ef41Sopenharmony_ci  s.expectCount = 0;
1001cb0ef41Sopenharmony_ci  return s;
1011cb0ef41Sopenharmony_ci}
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_cifunction handler(req, res) {
1041cb0ef41Sopenharmony_ci  this.requests.push(req.url);
1051cb0ef41Sopenharmony_ci  res.statusCode = 200;
1061cb0ef41Sopenharmony_ci  res.setHeader('foo', 'bar');
1071cb0ef41Sopenharmony_ci  res.end('hello, world\n');
1081cb0ef41Sopenharmony_ci}
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_cifunction listening() {
1111cb0ef41Sopenharmony_ci  listenWait++;
1121cb0ef41Sopenharmony_ci  return () => {
1131cb0ef41Sopenharmony_ci    listenWait--;
1141cb0ef41Sopenharmony_ci    if (listenWait === 0) {
1151cb0ef41Sopenharmony_ci      allListening();
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci  };
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_cifunction makeReq(path, port, error, host, ca) {
1211cb0ef41Sopenharmony_ci  pending++;
1221cb0ef41Sopenharmony_ci  const options = { port, path, ca };
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  if (!ca) {
1251cb0ef41Sopenharmony_ci    options.agent = agent0;
1261cb0ef41Sopenharmony_ci  } else {
1271cb0ef41Sopenharmony_ci    if (!Array.isArray(ca)) ca = [ca];
1281cb0ef41Sopenharmony_ci    if (ca.includes(ca1) && ca.includes(ca2)) {
1291cb0ef41Sopenharmony_ci      options.agent = agent3;
1301cb0ef41Sopenharmony_ci    } else if (ca.includes(ca1)) {
1311cb0ef41Sopenharmony_ci      options.agent = agent1;
1321cb0ef41Sopenharmony_ci    } else if (ca.includes(ca2)) {
1331cb0ef41Sopenharmony_ci      options.agent = agent2;
1341cb0ef41Sopenharmony_ci    } else {
1351cb0ef41Sopenharmony_ci      options.agent = agent0;
1361cb0ef41Sopenharmony_ci    }
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  if (host) {
1401cb0ef41Sopenharmony_ci    options.headers = { host };
1411cb0ef41Sopenharmony_ci  }
1421cb0ef41Sopenharmony_ci  const req = https.get(options);
1431cb0ef41Sopenharmony_ci  const server = port === server1.address().port ? server1 :
1441cb0ef41Sopenharmony_ci    port === server2.address().port ? server2 :
1451cb0ef41Sopenharmony_ci      port === server3.address().port ? server3 :
1461cb0ef41Sopenharmony_ci        null;
1471cb0ef41Sopenharmony_ci  if (!server) throw new Error(`invalid port: ${port}`);
1481cb0ef41Sopenharmony_ci  server.expectCount++;
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  req.on('response', common.mustCall((res) => {
1511cb0ef41Sopenharmony_ci    assert.strictEqual(res.connection.authorizationError, error);
1521cb0ef41Sopenharmony_ci    responseErrors[path] = res.connection.authorizationError;
1531cb0ef41Sopenharmony_ci    pending--;
1541cb0ef41Sopenharmony_ci    if (pending === 0) {
1551cb0ef41Sopenharmony_ci      server1.close();
1561cb0ef41Sopenharmony_ci      server2.close();
1571cb0ef41Sopenharmony_ci      server3.close();
1581cb0ef41Sopenharmony_ci    }
1591cb0ef41Sopenharmony_ci    res.resume();
1601cb0ef41Sopenharmony_ci  }));
1611cb0ef41Sopenharmony_ci}
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_cifunction allListening() {
1641cb0ef41Sopenharmony_ci  // Ok, ready to start the tests!
1651cb0ef41Sopenharmony_ci  const port1 = server1.address().port;
1661cb0ef41Sopenharmony_ci  const port2 = server2.address().port;
1671cb0ef41Sopenharmony_ci  const port3 = server3.address().port;
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  // server1: host 'agent1', signed by ca1
1701cb0ef41Sopenharmony_ci  makeReq('/inv1', port1, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE');
1711cb0ef41Sopenharmony_ci  makeReq('/inv1-ca1', port1, 'ERR_TLS_CERT_ALTNAME_INVALID',
1721cb0ef41Sopenharmony_ci          null, ca1);
1731cb0ef41Sopenharmony_ci  makeReq('/inv1-ca1ca2', port1, 'ERR_TLS_CERT_ALTNAME_INVALID',
1741cb0ef41Sopenharmony_ci          null, [ca1, ca2]);
1751cb0ef41Sopenharmony_ci  makeReq('/val1-ca1', port1, null, 'agent1', ca1);
1761cb0ef41Sopenharmony_ci  makeReq('/val1-ca1ca2', port1, null, 'agent1', [ca1, ca2]);
1771cb0ef41Sopenharmony_ci  makeReq('/inv1-ca2', port1,
1781cb0ef41Sopenharmony_ci          'UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'agent1', ca2);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  // server2: self-signed, host = 'agent2'
1811cb0ef41Sopenharmony_ci  // doesn't matter that thename matches, all of these will error.
1821cb0ef41Sopenharmony_ci  makeReq('/inv2', port2, 'DEPTH_ZERO_SELF_SIGNED_CERT');
1831cb0ef41Sopenharmony_ci  makeReq('/inv2-ca1', port2, 'DEPTH_ZERO_SELF_SIGNED_CERT',
1841cb0ef41Sopenharmony_ci          'agent2', ca1);
1851cb0ef41Sopenharmony_ci  makeReq('/inv2-ca1ca2', port2, 'DEPTH_ZERO_SELF_SIGNED_CERT',
1861cb0ef41Sopenharmony_ci          'agent2', [ca1, ca2]);
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  // server3: host 'agent3', signed by ca2
1891cb0ef41Sopenharmony_ci  makeReq('/inv3', port3, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE');
1901cb0ef41Sopenharmony_ci  makeReq('/inv3-ca2', port3, 'ERR_TLS_CERT_ALTNAME_INVALID', null, ca2);
1911cb0ef41Sopenharmony_ci  makeReq('/inv3-ca1ca2', port3, 'ERR_TLS_CERT_ALTNAME_INVALID',
1921cb0ef41Sopenharmony_ci          null, [ca1, ca2]);
1931cb0ef41Sopenharmony_ci  makeReq('/val3-ca2', port3, null, 'agent3', ca2);
1941cb0ef41Sopenharmony_ci  makeReq('/val3-ca1ca2', port3, null, 'agent3', [ca1, ca2]);
1951cb0ef41Sopenharmony_ci  makeReq('/inv3-ca1', port3,
1961cb0ef41Sopenharmony_ci          'UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'agent1', ca1);
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci}
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ciprocess.on('exit', () => {
2011cb0ef41Sopenharmony_ci  assert.strictEqual(server1.requests.length, server1.expectCount);
2021cb0ef41Sopenharmony_ci  assert.strictEqual(server2.requests.length, server2.expectCount);
2031cb0ef41Sopenharmony_ci  assert.strictEqual(server3.requests.length, server3.expectCount);
2041cb0ef41Sopenharmony_ci});
205