11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciif (!common.hasCrypto)
51cb0ef41Sopenharmony_ci  common.skip('missing crypto');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciconst assert = require('assert');
81cb0ef41Sopenharmony_ciconst tls = require('tls');
91cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cifunction loadPEM(n) {
121cb0ef41Sopenharmony_ci  return fixtures.readKey(`${n}.pem`);
131cb0ef41Sopenharmony_ci}
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciconst serverIP = common.localhostIPv4;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cifunction checkResults(result, expected) {
181cb0ef41Sopenharmony_ci  assert.strictEqual(result.server.ALPN, expected.server.ALPN);
191cb0ef41Sopenharmony_ci  assert.strictEqual(result.client.ALPN, expected.client.ALPN);
201cb0ef41Sopenharmony_ci}
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_cifunction runTest(clientsOptions, serverOptions, cb) {
231cb0ef41Sopenharmony_ci  serverOptions.key = loadPEM('agent2-key');
241cb0ef41Sopenharmony_ci  serverOptions.cert = loadPEM('agent2-cert');
251cb0ef41Sopenharmony_ci  const results = [];
261cb0ef41Sopenharmony_ci  let clientIndex = 0;
271cb0ef41Sopenharmony_ci  let serverIndex = 0;
281cb0ef41Sopenharmony_ci  const server = tls.createServer(serverOptions, function(c) {
291cb0ef41Sopenharmony_ci    results[serverIndex++].server = { ALPN: c.alpnProtocol };
301cb0ef41Sopenharmony_ci  });
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  server.listen(0, serverIP, function() {
331cb0ef41Sopenharmony_ci    connectClient(clientsOptions);
341cb0ef41Sopenharmony_ci  });
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  function connectClient(options) {
371cb0ef41Sopenharmony_ci    const opt = options.shift();
381cb0ef41Sopenharmony_ci    opt.port = server.address().port;
391cb0ef41Sopenharmony_ci    opt.host = serverIP;
401cb0ef41Sopenharmony_ci    opt.rejectUnauthorized = false;
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci    results[clientIndex] = {};
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci    function startNextClient() {
451cb0ef41Sopenharmony_ci      if (options.length) {
461cb0ef41Sopenharmony_ci        clientIndex++;
471cb0ef41Sopenharmony_ci        connectClient(options);
481cb0ef41Sopenharmony_ci      } else {
491cb0ef41Sopenharmony_ci        server.close();
501cb0ef41Sopenharmony_ci        server.on('close', () => {
511cb0ef41Sopenharmony_ci          cb(results);
521cb0ef41Sopenharmony_ci        });
531cb0ef41Sopenharmony_ci      }
541cb0ef41Sopenharmony_ci    }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    const client = tls.connect(opt, function() {
571cb0ef41Sopenharmony_ci      results[clientIndex].client = { ALPN: client.alpnProtocol };
581cb0ef41Sopenharmony_ci      client.end();
591cb0ef41Sopenharmony_ci      startNextClient();
601cb0ef41Sopenharmony_ci    }).on('error', function(err) {
611cb0ef41Sopenharmony_ci      results[clientIndex].client = { error: err };
621cb0ef41Sopenharmony_ci      startNextClient();
631cb0ef41Sopenharmony_ci    });
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci}
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci// Server: ALPN, Client: ALPN
691cb0ef41Sopenharmony_cifunction Test1() {
701cb0ef41Sopenharmony_ci  const serverOptions = {
711cb0ef41Sopenharmony_ci    ALPNProtocols: ['a', 'b', 'c'],
721cb0ef41Sopenharmony_ci  };
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  const clientsOptions = [{
751cb0ef41Sopenharmony_ci    ALPNProtocols: ['a', 'b', 'c'],
761cb0ef41Sopenharmony_ci  }, {
771cb0ef41Sopenharmony_ci    ALPNProtocols: ['c', 'b', 'e'],
781cb0ef41Sopenharmony_ci  }, {
791cb0ef41Sopenharmony_ci    ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
801cb0ef41Sopenharmony_ci  }];
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  runTest(clientsOptions, serverOptions, function(results) {
831cb0ef41Sopenharmony_ci    // 'a' is selected by ALPN
841cb0ef41Sopenharmony_ci    checkResults(results[0],
851cb0ef41Sopenharmony_ci                 { server: { ALPN: 'a' },
861cb0ef41Sopenharmony_ci                   client: { ALPN: 'a' } });
871cb0ef41Sopenharmony_ci    // 'b' is selected by ALPN
881cb0ef41Sopenharmony_ci    checkResults(results[1],
891cb0ef41Sopenharmony_ci                 { server: { ALPN: 'b' },
901cb0ef41Sopenharmony_ci                   client: { ALPN: 'b' } });
911cb0ef41Sopenharmony_ci    // Nothing is selected by ALPN
921cb0ef41Sopenharmony_ci    checkResults(results[2],
931cb0ef41Sopenharmony_ci                 { server: { ALPN: false },
941cb0ef41Sopenharmony_ci                   client: { ALPN: false } });
951cb0ef41Sopenharmony_ci    // execute next test
961cb0ef41Sopenharmony_ci    Test2();
971cb0ef41Sopenharmony_ci  });
981cb0ef41Sopenharmony_ci}
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci// Server: ALPN, Client: Nothing
1011cb0ef41Sopenharmony_cifunction Test2() {
1021cb0ef41Sopenharmony_ci  const serverOptions = {
1031cb0ef41Sopenharmony_ci    ALPNProtocols: ['a', 'b', 'c'],
1041cb0ef41Sopenharmony_ci  };
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  const clientsOptions = [{}, {}, {}];
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  runTest(clientsOptions, serverOptions, function(results) {
1091cb0ef41Sopenharmony_ci    // Nothing is selected by ALPN
1101cb0ef41Sopenharmony_ci    checkResults(results[0],
1111cb0ef41Sopenharmony_ci                 { server: { ALPN: false },
1121cb0ef41Sopenharmony_ci                   client: { ALPN: false } });
1131cb0ef41Sopenharmony_ci    // Nothing is selected by ALPN
1141cb0ef41Sopenharmony_ci    checkResults(results[1],
1151cb0ef41Sopenharmony_ci                 { server: { ALPN: false },
1161cb0ef41Sopenharmony_ci                   client: { ALPN: false } });
1171cb0ef41Sopenharmony_ci    // Nothing is selected by ALPN
1181cb0ef41Sopenharmony_ci    checkResults(results[2],
1191cb0ef41Sopenharmony_ci                 { server: { ALPN: false },
1201cb0ef41Sopenharmony_ci                   client: { ALPN: false } });
1211cb0ef41Sopenharmony_ci    // execute next test
1221cb0ef41Sopenharmony_ci    Test3();
1231cb0ef41Sopenharmony_ci  });
1241cb0ef41Sopenharmony_ci}
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci// Server: Nothing, Client: ALPN
1271cb0ef41Sopenharmony_cifunction Test3() {
1281cb0ef41Sopenharmony_ci  const serverOptions = {};
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  const clientsOptions = [{
1311cb0ef41Sopenharmony_ci    ALPNrotocols: ['a', 'b', 'c'],
1321cb0ef41Sopenharmony_ci  }, {
1331cb0ef41Sopenharmony_ci    ALPNProtocols: ['c', 'b', 'e'],
1341cb0ef41Sopenharmony_ci  }, {
1351cb0ef41Sopenharmony_ci    ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
1361cb0ef41Sopenharmony_ci  }];
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  runTest(clientsOptions, serverOptions, function(results) {
1391cb0ef41Sopenharmony_ci    // nothing is selected
1401cb0ef41Sopenharmony_ci    checkResults(results[0], { server: { ALPN: false },
1411cb0ef41Sopenharmony_ci                               client: { ALPN: false } });
1421cb0ef41Sopenharmony_ci    // nothing is selected
1431cb0ef41Sopenharmony_ci    checkResults(results[1], { server: { ALPN: false },
1441cb0ef41Sopenharmony_ci                               client: { ALPN: false } });
1451cb0ef41Sopenharmony_ci    // nothing is selected
1461cb0ef41Sopenharmony_ci    checkResults(results[2],
1471cb0ef41Sopenharmony_ci                 { server: { ALPN: false },
1481cb0ef41Sopenharmony_ci                   client: { ALPN: false } });
1491cb0ef41Sopenharmony_ci    // execute next test
1501cb0ef41Sopenharmony_ci    Test4();
1511cb0ef41Sopenharmony_ci  });
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci// Server: Nothing, Client: Nothing
1551cb0ef41Sopenharmony_cifunction Test4() {
1561cb0ef41Sopenharmony_ci  const serverOptions = {};
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  const clientsOptions = [{}, {}, {}];
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  runTest(clientsOptions, serverOptions, function(results) {
1611cb0ef41Sopenharmony_ci    // nothing is selected
1621cb0ef41Sopenharmony_ci    checkResults(results[0], { server: { ALPN: false },
1631cb0ef41Sopenharmony_ci                               client: { ALPN: false } });
1641cb0ef41Sopenharmony_ci    // nothing is selected
1651cb0ef41Sopenharmony_ci    checkResults(results[1], { server: { ALPN: false },
1661cb0ef41Sopenharmony_ci                               client: { ALPN: false } });
1671cb0ef41Sopenharmony_ci    // nothing is selected
1681cb0ef41Sopenharmony_ci    checkResults(results[2],
1691cb0ef41Sopenharmony_ci                 { server: { ALPN: false },
1701cb0ef41Sopenharmony_ci                   client: { ALPN: false } });
1711cb0ef41Sopenharmony_ci  });
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  TestALPNCallback();
1741cb0ef41Sopenharmony_ci}
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_cifunction TestALPNCallback() {
1771cb0ef41Sopenharmony_ci  // Server always selects the client's 2nd preference:
1781cb0ef41Sopenharmony_ci  const serverOptions = {
1791cb0ef41Sopenharmony_ci    ALPNCallback: common.mustCall(({ protocols }) => {
1801cb0ef41Sopenharmony_ci      return protocols[1];
1811cb0ef41Sopenharmony_ci    }, 2)
1821cb0ef41Sopenharmony_ci  };
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  const clientsOptions = [{
1851cb0ef41Sopenharmony_ci    ALPNProtocols: ['a', 'b', 'c'],
1861cb0ef41Sopenharmony_ci  }, {
1871cb0ef41Sopenharmony_ci    ALPNProtocols: ['a'],
1881cb0ef41Sopenharmony_ci  }];
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  runTest(clientsOptions, serverOptions, function(results) {
1911cb0ef41Sopenharmony_ci    // Callback picks 2nd preference => picks 'b'
1921cb0ef41Sopenharmony_ci    checkResults(results[0],
1931cb0ef41Sopenharmony_ci                 { server: { ALPN: 'b' },
1941cb0ef41Sopenharmony_ci                   client: { ALPN: 'b' } });
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci    // Callback picks 2nd preference => undefined => ALPN rejected:
1971cb0ef41Sopenharmony_ci    assert.strictEqual(results[1].server, undefined);
1981cb0ef41Sopenharmony_ci    assert.strictEqual(results[1].client.error.code, 'ECONNRESET');
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci    TestBadALPNCallback();
2011cb0ef41Sopenharmony_ci  });
2021cb0ef41Sopenharmony_ci}
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_cifunction TestBadALPNCallback() {
2051cb0ef41Sopenharmony_ci  // Server always returns a fixed invalid value:
2061cb0ef41Sopenharmony_ci  const serverOptions = {
2071cb0ef41Sopenharmony_ci    ALPNCallback: common.mustCall(() => 'http/5')
2081cb0ef41Sopenharmony_ci  };
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  const clientsOptions = [{
2111cb0ef41Sopenharmony_ci    ALPNProtocols: ['http/1', 'h2'],
2121cb0ef41Sopenharmony_ci  }];
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  process.once('uncaughtException', common.mustCall((error) => {
2151cb0ef41Sopenharmony_ci    assert.strictEqual(error.code, 'ERR_TLS_ALPN_CALLBACK_INVALID_RESULT');
2161cb0ef41Sopenharmony_ci  }));
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci  runTest(clientsOptions, serverOptions, function(results) {
2191cb0ef41Sopenharmony_ci    // Callback returns 'http/5' => doesn't match client ALPN => error & reset
2201cb0ef41Sopenharmony_ci    assert.strictEqual(results[0].server, undefined);
2211cb0ef41Sopenharmony_ci    assert.strictEqual(results[0].client.error.code, 'ECONNRESET');
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci    TestALPNOptionsCallback();
2241cb0ef41Sopenharmony_ci  });
2251cb0ef41Sopenharmony_ci}
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_cifunction TestALPNOptionsCallback() {
2281cb0ef41Sopenharmony_ci  // Server sets two incompatible ALPN options:
2291cb0ef41Sopenharmony_ci  assert.throws(() => tls.createServer({
2301cb0ef41Sopenharmony_ci    ALPNCallback: () => 'a',
2311cb0ef41Sopenharmony_ci    ALPNProtocols: ['b', 'c']
2321cb0ef41Sopenharmony_ci  }), (error) => error.code === 'ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS');
2331cb0ef41Sopenharmony_ci}
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ciTest1();
236