Skip to content

Commit 36fb6f1

Browse files
committed
tls: use the most recently added matching SecureContext in default SNICallback.
Fixes: https://github.com//issues/34110
1 parent 7343272 commit 36fb6f1

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

doc/api/tls.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ added: v0.5.3
582582
The `server.addContext()` method adds a secure context that will be used if
583583
the client request's SNI name matches the supplied `hostname` (or wildcard).
584584

585+
When there are multiple matching contexts, the most recently added one will be
586+
used.
587+
585588
### `server.address()`
586589
<!-- YAML
587590
added: v0.6.0

lib/_tls_wrap.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1436,7 +1436,7 @@ Server.prototype[EE.captureRejectionSymbol] = function(
14361436
function SNICallback(servername, callback) {
14371437
const contexts = this.server._contexts;
14381438

1439-
for (const elem of contexts) {
1439+
for (const elem of contexts.reverse()) {
14401440
if (elem[0].test(servername)) {
14411441
callback(null, elem[1]);
14421442
return;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
'use strict';
2+
const common = require('../common');
3+
const fixtures = require('../common/fixtures');
4+
5+
if (!common.hasCrypto)
6+
common.skip('missing crypto');
7+
8+
// This test ensures that when a TLS connection is estabilished, the server
9+
// selects the most recently added SecureContext that matches the servername.
10+
11+
const assert = require('assert');
12+
const tls = require('tls');
13+
14+
function loadPEM(n) {
15+
return fixtures.readKey(`${n}.pem`);
16+
}
17+
18+
const serverOptions = {
19+
key: loadPEM('agent2-key'),
20+
cert: loadPEM('agent2-cert'),
21+
requestCert: true,
22+
rejectUnauthorized: false,
23+
};
24+
25+
const badSecureContext = {
26+
key: loadPEM('agent1-key'),
27+
cert: loadPEM('agent1-cert'),
28+
ca: [ loadPEM('ca2-cert') ]
29+
};
30+
31+
const goodSecureContext = {
32+
key: loadPEM('agent1-key'),
33+
cert: loadPEM('agent1-cert'),
34+
ca: [ loadPEM('ca1-cert') ]
35+
};
36+
37+
const 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.
54+
server.addContext('*.example.com', badSecureContext);
55+
56+
server.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+
server.close();
87+
}));
88+
}));
89+
});

0 commit comments

Comments
 (0)