1'use strict'; 2const common = require('../common'); 3const fixtures = require('../common/fixtures'); 4 5if (!common.hasCrypto) 6 common.skip('missing crypto'); 7 8// This test ensures that when a TLS connection is established, the server 9// selects the most recently added SecureContext that matches the servername. 10 11const assert = require('assert'); 12const tls = require('tls'); 13 14function loadPEM(n) { 15 return fixtures.readKey(`${n}.pem`); 16} 17 18const serverOptions = { 19 key: loadPEM('agent2-key'), 20 cert: loadPEM('agent2-cert'), 21 requestCert: true, 22 rejectUnauthorized: false, 23}; 24 25const badSecureContext = { 26 key: loadPEM('agent1-key'), 27 cert: loadPEM('agent1-cert'), 28 ca: [ loadPEM('ca2-cert') ] 29}; 30 31const goodSecureContext = { 32 key: loadPEM('agent1-key'), 33 cert: loadPEM('agent1-cert'), 34 ca: [ loadPEM('ca1-cert') ] 35}; 36 37const server = tls.createServer(serverOptions, (c) => { 38 // The 'a' and 'b' subdomains are used to distinguish between client 39 // connections. 40 // Connection to subdomain 'a' is made when the 'bad' secure context is 41 // the only one in use. 42 if ('a.example.com' === c.servername) { 43 assert.strictEqual(c.authorized, false); 44 } 45 // Connection to subdomain 'b' is made after the 'good' context has been 46 // added. 47 if ('b.example.com' === c.servername) { 48 assert.strictEqual(c.authorized, true); 49 } 50}); 51 52// 1. Add the 'bad' secure context. A connection using this context will not be 53// authorized. 54server.addContext('*.example.com', badSecureContext); 55 56server.listen(0, () => { 57 const options = { 58 port: server.address().port, 59 key: loadPEM('agent1-key'), 60 cert: loadPEM('agent1-cert'), 61 ca: [loadPEM('ca1-cert')], 62 servername: 'a.example.com', 63 rejectUnauthorized: false, 64 }; 65 66 // 2. Make a connection using servername 'a.example.com'. Since a 'bad' 67 // secure context is used, this connection should not be authorized. 68 const client = tls.connect(options, () => { 69 client.end(); 70 }); 71 72 client.on('close', common.mustCall(() => { 73 // 3. Add a 'good' secure context. 74 server.addContext('*.example.com', goodSecureContext); 75 76 options.servername = 'b.example.com'; 77 // 4. Make a connection using servername 'b.example.com'. This connection 78 // should be authorized because the 'good' secure context is the most 79 // recently added matching context. 80 81 const other = tls.connect(options, () => { 82 other.end(); 83 }); 84 85 other.on('close', common.mustCall(() => { 86 // 5. Make another connection using servername 'b.example.com' to ensure 87 // that the array of secure contexts is not reversed in place with each 88 // SNICallback call, as someone might be tempted to refactor this piece of 89 // code by using Array.prototype.reverse() method. 90 const onemore = tls.connect(options, () => { 91 onemore.end(); 92 }); 93 94 onemore.on('close', common.mustCall(() => { 95 server.close(); 96 })); 97 })); 98 })); 99}); 100