node/test/parallel/test-double-tls-server.js

102 lines
3.5 KiB
JavaScript
Raw Normal View History

'use strict';
const common = require('../common');
const assert = require('assert');
if (!common.hasCrypto) common.skip('missing crypto');
const fixtures = require('../common/fixtures');
const tls = require('tls');
const net = require('net');
// Sending tls data on a server TLSSocket with an active write led to a crash:
//
// node[1296]: ../src/crypto/crypto_tls.cc:963:virtual int node::crypto::TLSWrap::DoWrite(node::WriteWrap*,
// uv_buf_t*, size_t, uv_stream_t*): Assertion `!current_write_' failed.
// 1: 0xb090e0 node::Abort() [node]
// 2: 0xb0915e [node]
// 3: 0xca8413 node::crypto::TLSWrap::DoWrite(node::WriteWrap*, uv_buf_t*, unsigned long, uv_stream_s*) [node]
// 4: 0xcaa549 node::StreamBase::Write(uv_buf_t*, unsigned long, uv_stream_s*, v8::Local<v8::Object>) [node]
// 5: 0xca88d7 node::crypto::TLSWrap::EncOut() [node]
// 6: 0xca9ba8 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
// 7: 0xca8eb0 node::crypto::TLSWrap::ClearOut() [node]
// 8: 0xca9ba0 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
// 9: 0xbe50dd node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) [node]
// 10: 0xbe54c4 [node]
// 11: 0x15583d7 [node]
// 12: 0x1558c00 [node]
// 13: 0x155ede4 [node]
// 14: 0x154d008 uv_run [node]
const serverReplaySize = 2 * 1024 * 1024;
(async function() {
const tlsClientHello = await getClientHello();
const subserver = tls.createServer({
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
ALPNCallback: common.mustCall(({ sn, protocols }) => {
// Once `subserver` receives `tlsClientHello` from the underlying net.Socket,
// in this test, a TLSSocket actually, it should be able to proceed to the handshake
// and emit this event
assert.strictEqual(protocols[0], 'h2');
return 'h2';
}),
});
const server = tls.createServer({
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
})
.listen(startClient)
.on('secureConnection', (serverTlsSock) => {
// Craft writes that are large enough to stuck in sending
// In reality this can be a 200 response to the incoming HTTP CONNECT
const half = Buffer.alloc(serverReplaySize / 2, 0);
serverTlsSock.write(half, common.mustSucceed());
serverTlsSock.write(half, common.mustSucceed());
subserver.emit('connection', serverTlsSock);
});
function startClient() {
const clientTlsSock = tls.connect({
host: '127.0.0.1',
port: server.address().port,
rejectUnauthorized: false,
});
const recv = [];
let revcLen = 0;
clientTlsSock.on('data', (chunk) => {
revcLen += chunk.length;
recv.push(chunk);
if (revcLen > serverReplaySize) {
// Check the server's replay is followed by the subserver's TLS ServerHello
const serverHelloFstByte = Buffer.concat(recv).subarray(serverReplaySize, serverReplaySize + 1);
assert.strictEqual(serverHelloFstByte.toString('hex'), '16');
process.exit(0);
}
});
// In reality, one may want to send a HTTP CONNECT before starting this double TLS
clientTlsSock.write(tlsClientHello);
}
})().then(common.mustCall());
function getClientHello() {
return new Promise((resolve) => {
const server = net.createServer((sock) => {
sock.on('data', (chunk) => {
resolve(chunk);
});
})
.listen(() => {
tls.connect({
port: server.address().port,
host: '127.0.0.1',
ALPNProtocols: ['h2'],
}).on('error', () => {});
});
});
}