GeezerVison is showing github.com — test: add session reuse host verification regressions · nodejs/node@e3723ff
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboard +146Lines changed: 146 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | +const common = require('../common'); | | 3 | +if (!common.hasCrypto) | | 4 | + common.skip('missing crypto'); | | 5 | + | | 6 | +const assert = require('assert'); | | 7 | +const fixtures = require('../common/fixtures'); | | 8 | +const h2 = require('http2'); | | 9 | +const tls = require('tls'); | | 10 | +const { once } = require('events'); | | 11 | + | | 12 | +function load(name) { | | 13 | + return fixtures.readKey(name); | | 14 | +} | | 15 | + | | 16 | +const contexts = { | | 17 | + agent1: tls.createSecureContext({ | | 18 | + key: load('agent1-key.pem'), | | 19 | + cert: load('agent1-cert.pem'), | | 20 | + }), | | 21 | + agent3: tls.createSecureContext({ | | 22 | + key: load('agent3-key.pem'), | | 23 | + cert: load('agent3-cert.pem'), | | 24 | + }), | | 25 | +}; | | 26 | + | | 27 | +function makeRequest(server, authority, options) { | | 28 | + return new Promise((resolve, reject) => { | | 29 | + let session; | | 30 | + let settled = false; | | 31 | + | | 32 | + function done(err, result) { | | 33 | + if (settled) | | 34 | + return; | | 35 | + settled = true; | | 36 | + | | 37 | + if (err) { | | 38 | + client.destroy(); | | 39 | + reject(err); | | 40 | + return; | | 41 | + } | | 42 | + | | 43 | + client.close(); | | 44 | + resolve({ session, result }); | | 45 | + } | | 46 | + | | 47 | + const client = h2.connect(authority, { | | 48 | + ...options, | | 49 | + ALPNProtocols: ['h2'], | | 50 | + createConnection(url, connectOptions) { | | 51 | + const socket = tls.connect({ | | 52 | + ...connectOptions, | | 53 | + ALPNProtocols: ['h2'], | | 54 | + host: '127.0.0.1', | | 55 | + port: server.address().port, | | 56 | + servername: connectOptions.servername || url.hostname, | | 57 | + }); | | 58 | + | | 59 | + socket.once('session', (value) => { | | 60 | + if (session === undefined) | | 61 | + session = value; | | 62 | + }); | | 63 | + | | 64 | + return socket; | | 65 | + }, | | 66 | + }); | | 67 | + | | 68 | + client.once('error', (err) => done(err)); | | 69 | + client.once('connect', () => { | | 70 | + const req = client.request({ ':path': '/' }); | | 71 | + req.setEncoding('utf8'); | | 72 | + req.on('response', () => {}); | | 73 | + req.on('error', (err) => done(err)); | | 74 | + req.on('data', () => {}); | | 75 | + req.on('end', () => { | | 76 | + done(null, { | | 77 | + authority: client.socket.servername, | | 78 | + authorized: client.socket.authorized, | | 79 | + reused: client.socket.isSessionReused(), | | 80 | + authorizationError: client.socket.authorizationError, | | 81 | + }); | | 82 | + }); | | 83 | + req.end(); | | 84 | + }); | | 85 | + }); | | 86 | +} | | 87 | + | | 88 | +const server = h2.createSecureServer({ | | 89 | + key: load('agent1-key.pem'), | | 90 | + cert: load('agent1-cert.pem'), | | 91 | + allowHTTP1: false, | | 92 | + minVersion: 'TLSv1.2', | | 93 | + maxVersion: 'TLSv1.2', | | 94 | + SNICallback(servername, cb) { | | 95 | + cb(null, contexts[servername] || contexts.agent1); | | 96 | + }, | | 97 | +}); | | 98 | + | | 99 | +server.on('stream', (stream) => { | | 100 | + stream.respond({ ':status': 200 }); | | 101 | + stream.end('ok'); | | 102 | +}); | | 103 | + | | 104 | +(async function() { | | 105 | + server.listen(0); | | 106 | + await once(server, 'listening'); | | 107 | + | | 108 | + try { | | 109 | + const port = server.address().port; | | 110 | + const first = await makeRequest(server, `https://agent1:${port}`, { | | 111 | + ca: [load('ca1-cert.pem')], | | 112 | + minVersion: 'TLSv1.2', | | 113 | + maxVersion: 'TLSv1.2', | | 114 | + }); | | 115 | + | | 116 | + assert.strictEqual(first.result.authorized, true); | | 117 | + assert.strictEqual(first.result.reused, false); | | 118 | + assert(first.session); | | 119 | + | | 120 | + await assert.rejects( | | 121 | + makeRequest(server, `https://agent3:${port}`, { | | 122 | + ca: [load('ca1-cert.pem')], | | 123 | + minVersion: 'TLSv1.2', | | 124 | + maxVersion: 'TLSv1.2', | | 125 | + session: first.session, | | 126 | + }), | | 127 | + { | | 128 | + code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', | | 129 | + }, | | 130 | + ); | | 131 | + | | 132 | + await assert.rejects( | | 133 | + makeRequest(server, `https://agent3:${port}`, { | | 134 | + ca: [load('ca1-cert.pem')], | | 135 | + minVersion: 'TLSv1.2', | | 136 | + maxVersion: 'TLSv1.2', | | 137 | + }), | | 138 | + { | | 139 | + code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', | | 140 | + }, | | 141 | + ); | | 142 | + } finally { | | 143 | + server.close(); | | 144 | + await once(server, 'close'); | | 145 | + } | | 146 | +})().then(common.mustCall()); |
Collapse file Copy file name to clipboard +126Lines changed: 126 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | +const common = require('../common'); | | 3 | +if (!common.hasCrypto) | | 4 | + common.skip('missing crypto'); | | 5 | + | | 6 | +const assert = require('assert'); | | 7 | +const fixtures = require('../common/fixtures'); | | 8 | +const https = require('https'); | | 9 | +const tls = require('tls'); | | 10 | +const { once } = require('events'); | | 11 | + | | 12 | +function load(name) { | | 13 | + return fixtures.readKey(name); | | 14 | +} | | 15 | + | | 16 | +const contexts = { | | 17 | + agent1: tls.createSecureContext({ | | 18 | + key: load('agent1-key.pem'), | | 19 | + cert: load('agent1-cert.pem'), | | 20 | + }), | | 21 | + agent3: tls.createSecureContext({ | | 22 | + key: load('agent3-key.pem'), | | 23 | + cert: load('agent3-cert.pem'), | | 24 | + }), | | 25 | +}; | | 26 | + | | 27 | +function request(options) { | | 28 | + return new Promise((resolve, reject) => { | | 29 | + const req = https.get({ | | 30 | + ...options, | | 31 | + host: '127.0.0.1', | | 32 | + agent: false, | | 33 | + }, (res) => { | | 34 | + res.resume(); | | 35 | + res.once('end', () => resolve(res)); | | 36 | + }); | | 37 | + | | 38 | + req.once('error', reject); | | 39 | + }); | | 40 | +} | | 41 | + | | 42 | +async function requestAndCaptureSession(options) { | | 43 | + let sessionResolve; | | 44 | + const sessionPromise = new Promise((resolve) => { | | 45 | + sessionResolve = resolve; | | 46 | + }); | | 47 | + | | 48 | + const req = https.get({ | | 49 | + ...options, | | 50 | + host: '127.0.0.1', | | 51 | + agent: false, | | 52 | + }); | | 53 | + | | 54 | + req.on('socket', (socket) => { | | 55 | + socket.once('session', sessionResolve); | | 56 | + }); | | 57 | + | | 58 | + const res = await new Promise((resolve, reject) => { | | 59 | + req.once('response', resolve); | | 60 | + req.once('error', reject); | | 61 | + }); | | 62 | + | | 63 | + assert.strictEqual(res.socket.authorized, true); | | 64 | + assert.strictEqual(res.socket.isSessionReused(), false); | | 65 | + | | 66 | + res.resume(); | | 67 | + await once(res, 'end'); | | 68 | + | | 69 | + const session = await sessionPromise; | | 70 | + assert(session); | | 71 | + return session; | | 72 | +} | | 73 | + | | 74 | +const server = https.createServer({ | | 75 | + key: load('agent1-key.pem'), | | 76 | + cert: load('agent1-cert.pem'), | | 77 | + minVersion: 'TLSv1.2', | | 78 | + maxVersion: 'TLSv1.2', | | 79 | + SNICallback(servername, cb) { | | 80 | + cb(null, contexts[servername] || contexts.agent1); | | 81 | + }, | | 82 | +}, (req, res) => { | | 83 | + res.end('ok'); | | 84 | +}); | | 85 | + | | 86 | +(async function() { | | 87 | + server.listen(0); | | 88 | + await once(server, 'listening'); | | 89 | + | | 90 | + try { | | 91 | + const session = await requestAndCaptureSession({ | | 92 | + port: server.address().port, | | 93 | + servername: 'agent1', | | 94 | + rejectUnauthorized: true, | | 95 | + ca: [load('ca1-cert.pem')], | | 96 | + }); | | 97 | + | | 98 | + await assert.rejects( | | 99 | + request({ | | 100 | + port: server.address().port, | | 101 | + servername: 'agent3', | | 102 | + session, | | 103 | + rejectUnauthorized: true, | | 104 | + ca: [load('ca1-cert.pem')], | | 105 | + }), | | 106 | + { | | 107 | + code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', | | 108 | + }, | | 109 | + ); | | 110 | + | | 111 | + await assert.rejects( | | 112 | + request({ | | 113 | + port: server.address().port, | | 114 | + servername: 'agent3', | | 115 | + rejectUnauthorized: true, | | 116 | + ca: [load('ca1-cert.pem')], | | 117 | + }), | | 118 | + { | | 119 | + code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', | | 120 | + }, | | 121 | + ); | | 122 | + } finally { | | 123 | + server.close(); | | 124 | + await once(server, 'close'); | | 125 | + } | | 126 | +})().then(common.mustCall()); |
Collapse file Copy file name to clipboard +122Lines changed: 122 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | +const common = require('../common'); | | 3 | +if (!common.hasCrypto) | | 4 | + common.skip('missing crypto'); | | 5 | + | | 6 | +const assert = require('assert'); | | 7 | +const fixtures = require('../common/fixtures'); | | 8 | +const tls = require('tls'); | | 9 | +const { once } = require('events'); | | 10 | + | | 11 | +function load(name) { | | 12 | + return fixtures.readKey(name); | | 13 | +} | | 14 | + | | 15 | +const contexts = { | | 16 | + agent1: tls.createSecureContext({ | | 17 | + key: load('agent1-key.pem'), | | 18 | + cert: load('agent1-cert.pem'), | | 19 | + }), | | 20 | + agent3: tls.createSecureContext({ | | 21 | + key: load('agent3-key.pem'), | | 22 | + cert: load('agent3-cert.pem'), | | 23 | + }), | | 24 | +}; | | 25 | + | | 26 | +function connect(options) { | | 27 | + return new Promise((resolve, reject) => { | | 28 | + const socket = tls.connect(options); | | 29 | + socket.once('secureConnect', () => resolve(socket)); | | 30 | + socket.once('error', reject); | | 31 | + socket.resume(); | | 32 | + }); | | 33 | +} | | 34 | + | | 35 | +async function connectAndCaptureSession(options) { | | 36 | + const socket = tls.connect(options); | | 37 | + const sessionPromise = once(socket, 'session').then(([session]) => session); | | 38 | + | | 39 | + socket.resume(); | | 40 | + await once(socket, 'secureConnect'); | | 41 | + | | 42 | + assert.strictEqual(socket.authorized, true); | | 43 | + assert.strictEqual(socket.isSessionReused(), false); | | 44 | + | | 45 | + const session = await sessionPromise; | | 46 | + assert(session); | | 47 | + | | 48 | + await once(socket, 'close'); | | 49 | + return session; | | 50 | +} | | 51 | + | | 52 | +async function testVersion(minVersion, maxVersion) { | | 53 | + const server = tls.createServer({ | | 54 | + key: load('agent1-key.pem'), | | 55 | + cert: load('agent1-cert.pem'), | | 56 | + minVersion, | | 57 | + maxVersion, | | 58 | + SNICallback(servername, cb) { | | 59 | + cb(null, contexts[servername] || contexts.agent1); | | 60 | + }, | | 61 | + }, (socket) => { | | 62 | + socket.end('ok'); | | 63 | + }); | | 64 | + | | 65 | + server.listen(0); | | 66 | + await once(server, 'listening'); | | 67 | + | | 68 | + try { | | 69 | + const port = server.address().port; | | 70 | + const session = await connectAndCaptureSession({ | | 71 | + port, | | 72 | + host: '127.0.0.1', | | 73 | + servername: 'agent1', | | 74 | + minVersion, | | 75 | + maxVersion, | | 76 | + ca: [load('ca1-cert.pem')], | | 77 | + }); | | 78 | + | | 79 | + await assert.rejects( | | 80 | + connect({ | | 81 | + port, | | 82 | + host: '127.0.0.1', | | 83 | + servername: 'agent3', | | 84 | + session, | | 85 | + minVersion, | | 86 | + maxVersion, | | 87 | + ca: [load('ca1-cert.pem')], | | 88 | + }).then((socket) => { | | 89 | + socket.destroy(); | | 90 | + return socket; | | 91 | + }), | | 92 | + { | | 93 | + code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', | | 94 | + }, | | 95 | + ); | | 96 | + | | 97 | + await assert.rejects( | | 98 | + connect({ | | 99 | + port, | | 100 | + host: '127.0.0.1', | | 101 | + servername: 'agent3', | | 102 | + minVersion, | | 103 | + maxVersion, | | 104 | + ca: [load('ca1-cert.pem')], | | 105 | + }).then((socket) => { | | 106 | + socket.destroy(); | | 107 | + return socket; | | 108 | + }), | | 109 | + { | | 110 | + code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', | | 111 | + }, | | 112 | + ); | | 113 | + } finally { | | 114 | + server.close(); | | 115 | + await once(server, 'close'); | | 116 | + } | | 117 | +} | | 118 | + | | 119 | +(async function() { | | 120 | + await testVersion('TLSv1.2', 'TLSv1.2'); | | 121 | + await testVersion('TLSv1.3', 'TLSv1.3'); | | 122 | +})().then(common.mustCall()); |
|