11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciif (!common.hasCrypto)
61cb0ef41Sopenharmony_ci  common.skip('missing crypto');
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// This test ensures that when a TLS connection is established, the server
91cb0ef41Sopenharmony_ci// selects the most recently added SecureContext that matches the servername.
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciconst assert = require('assert');
121cb0ef41Sopenharmony_ciconst tls = require('tls');
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cifunction loadPEM(n) {
151cb0ef41Sopenharmony_ci  return fixtures.readKey(`${n}.pem`);
161cb0ef41Sopenharmony_ci}
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciconst serverOptions = {
191cb0ef41Sopenharmony_ci  key: loadPEM('agent2-key'),
201cb0ef41Sopenharmony_ci  cert: loadPEM('agent2-cert'),
211cb0ef41Sopenharmony_ci  requestCert: true,
221cb0ef41Sopenharmony_ci  rejectUnauthorized: false,
231cb0ef41Sopenharmony_ci};
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciconst badSecureContext = {
261cb0ef41Sopenharmony_ci  key: loadPEM('agent1-key'),
271cb0ef41Sopenharmony_ci  cert: loadPEM('agent1-cert'),
281cb0ef41Sopenharmony_ci  ca: [ loadPEM('ca2-cert') ]
291cb0ef41Sopenharmony_ci};
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciconst goodSecureContext = {
321cb0ef41Sopenharmony_ci  key: loadPEM('agent1-key'),
331cb0ef41Sopenharmony_ci  cert: loadPEM('agent1-cert'),
341cb0ef41Sopenharmony_ci  ca: [ loadPEM('ca1-cert') ]
351cb0ef41Sopenharmony_ci};
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciconst server = tls.createServer(serverOptions, (c) => {
381cb0ef41Sopenharmony_ci  // The 'a' and 'b' subdomains are used to distinguish between client
391cb0ef41Sopenharmony_ci  // connections.
401cb0ef41Sopenharmony_ci  // Connection to subdomain 'a' is made when the 'bad' secure context is
411cb0ef41Sopenharmony_ci  // the only one in use.
421cb0ef41Sopenharmony_ci  if ('a.example.com' === c.servername) {
431cb0ef41Sopenharmony_ci    assert.strictEqual(c.authorized, false);
441cb0ef41Sopenharmony_ci  }
451cb0ef41Sopenharmony_ci  // Connection to subdomain 'b' is made after the 'good' context has been
461cb0ef41Sopenharmony_ci  // added.
471cb0ef41Sopenharmony_ci  if ('b.example.com' === c.servername) {
481cb0ef41Sopenharmony_ci    assert.strictEqual(c.authorized, true);
491cb0ef41Sopenharmony_ci  }
501cb0ef41Sopenharmony_ci});
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci// 1. Add the 'bad' secure context. A connection using this context will not be
531cb0ef41Sopenharmony_ci// authorized.
541cb0ef41Sopenharmony_ciserver.addContext('*.example.com', badSecureContext);
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ciserver.listen(0, () => {
571cb0ef41Sopenharmony_ci  const options = {
581cb0ef41Sopenharmony_ci    port: server.address().port,
591cb0ef41Sopenharmony_ci    key: loadPEM('agent1-key'),
601cb0ef41Sopenharmony_ci    cert: loadPEM('agent1-cert'),
611cb0ef41Sopenharmony_ci    ca: [loadPEM('ca1-cert')],
621cb0ef41Sopenharmony_ci    servername: 'a.example.com',
631cb0ef41Sopenharmony_ci    rejectUnauthorized: false,
641cb0ef41Sopenharmony_ci  };
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  // 2. Make a connection using servername 'a.example.com'. Since a 'bad'
671cb0ef41Sopenharmony_ci  // secure context is used, this connection should not be authorized.
681cb0ef41Sopenharmony_ci  const client = tls.connect(options, () => {
691cb0ef41Sopenharmony_ci    client.end();
701cb0ef41Sopenharmony_ci  });
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  client.on('close', common.mustCall(() => {
731cb0ef41Sopenharmony_ci    // 3. Add a 'good' secure context.
741cb0ef41Sopenharmony_ci    server.addContext('*.example.com', goodSecureContext);
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci    options.servername = 'b.example.com';
771cb0ef41Sopenharmony_ci    // 4. Make a connection using servername 'b.example.com'. This connection
781cb0ef41Sopenharmony_ci    // should be authorized because the 'good' secure context is the most
791cb0ef41Sopenharmony_ci    // recently added matching context.
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    const other = tls.connect(options, () => {
821cb0ef41Sopenharmony_ci      other.end();
831cb0ef41Sopenharmony_ci    });
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    other.on('close', common.mustCall(() => {
861cb0ef41Sopenharmony_ci      // 5. Make another connection using servername 'b.example.com' to ensure
871cb0ef41Sopenharmony_ci      // that the array of secure contexts is not reversed in place with each
881cb0ef41Sopenharmony_ci      // SNICallback call, as someone might be tempted to refactor this piece of
891cb0ef41Sopenharmony_ci      // code by using Array.prototype.reverse() method.
901cb0ef41Sopenharmony_ci      const onemore = tls.connect(options, () => {
911cb0ef41Sopenharmony_ci        onemore.end();
921cb0ef41Sopenharmony_ci      });
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci      onemore.on('close', common.mustCall(() => {
951cb0ef41Sopenharmony_ci        server.close();
961cb0ef41Sopenharmony_ci      }));
971cb0ef41Sopenharmony_ci    }));
981cb0ef41Sopenharmony_ci  }));
991cb0ef41Sopenharmony_ci});
100