mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
This existed for 'resumeSession', which needed to do an async lookup though SSL_CTX_sess_set_get_cb is sync-only. Nowadays both OpenSSL & BoringSSL have an early ClientHello callback for suspend/resume to handle this properly, so it was redundant, in addition to being complicated and generally a bit fragile & scary. This PR switches to use the modern OpenSSL/BoringSSL mechanisms for this and drops the client hello parser & related infrastructure completely. In addition, there's a new test here, covering a fixed bug: the hello parser silently dropped fragmented hellos, which we now do handle correctly. Signed-off-by: Tim Perry <pimterry@gmail.com> PR-URL: https://github.com/nodejs/node/pull/64827 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com>
76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
'use strict';
|
|
|
|
// A ClientHello split across several TLS records must still emit
|
|
// 'resumeSession'.
|
|
|
|
const common = require('../common');
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const assert = require('assert');
|
|
const fixtures = require('../common/fixtures');
|
|
const net = require('net');
|
|
const tls = require('tls');
|
|
|
|
const options = {
|
|
key: fixtures.readKey('rsa_private.pem'),
|
|
cert: fixtures.readKey('rsa_cert.crt'),
|
|
};
|
|
|
|
// Capture a real ClientHello record so the replayed bytes are well-formed.
|
|
function captureClientHello(callback) {
|
|
let hello = Buffer.alloc(0);
|
|
const collector = net.createServer((socket) => {
|
|
socket.on('data', (chunk) => {
|
|
hello = Buffer.concat([hello, chunk]);
|
|
if (hello.length < 5 || hello.length < 5 + hello.readUInt16BE(3)) return;
|
|
socket.destroy();
|
|
collector.close(() => callback(hello));
|
|
});
|
|
});
|
|
collector.listen(0, common.mustCall(() => {
|
|
tls.connect({ port: collector.address().port, rejectUnauthorized: false })
|
|
.on('error', () => {});
|
|
}));
|
|
}
|
|
|
|
captureClientHello(common.mustCall((hello) => {
|
|
assert.strictEqual(hello[0], 22);
|
|
|
|
// Split partway through the fixed-size header, before the session ID.
|
|
const body = hello.subarray(5);
|
|
const split = 20;
|
|
assert.ok(body.length > split);
|
|
|
|
const record = (payload) => Buffer.concat([
|
|
Buffer.from([22, hello[1], hello[2],
|
|
payload.length >> 8, payload.length & 0xff]),
|
|
payload,
|
|
]);
|
|
|
|
const server = tls.createServer(options);
|
|
server.on('tlsClientError', () => {}); // The replay never completes.
|
|
|
|
server.listen(0, common.mustCall(() => {
|
|
const client = net.connect(server.address().port, common.mustCall(() => {
|
|
client.write(record(body.subarray(0, split)));
|
|
setTimeout(() => client.write(record(body.subarray(split))), 10);
|
|
}));
|
|
client.on('error', () => {});
|
|
|
|
// Fail fast: a missing event stalls the handshake rather than erroring.
|
|
const guard = setTimeout(() => {
|
|
throw new Error('resumeSession was not emitted');
|
|
}, common.platformTimeout(10000));
|
|
|
|
server.on('resumeSession', common.mustCall((id, callback) => {
|
|
clearTimeout(guard);
|
|
assert.ok(id.length > 0);
|
|
callback(null, null);
|
|
client.destroy();
|
|
server.close();
|
|
}));
|
|
}));
|
|
}));
|