• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3const assert = require('assert');
4if (!common.hasCrypto) common.skip('missing crypto');
5const fixtures = require('../common/fixtures');
6const tls = require('tls');
7const net = require('net');
8
9// Sending tls data on a server TLSSocket with an active write led to a crash:
10//
11// node[1296]: ../src/crypto/crypto_tls.cc:963:virtual int node::crypto::TLSWrap::DoWrite(node::WriteWrap*,
12//    uv_buf_t*, size_t, uv_stream_t*): Assertion `!current_write_' failed.
13//  1: 0xb090e0 node::Abort() [node]
14//  2: 0xb0915e  [node]
15//  3: 0xca8413 node::crypto::TLSWrap::DoWrite(node::WriteWrap*, uv_buf_t*, unsigned long, uv_stream_s*) [node]
16//  4: 0xcaa549 node::StreamBase::Write(uv_buf_t*, unsigned long, uv_stream_s*, v8::Local<v8::Object>) [node]
17//  5: 0xca88d7 node::crypto::TLSWrap::EncOut() [node]
18//  6: 0xca9ba8 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
19//  7: 0xca8eb0 node::crypto::TLSWrap::ClearOut() [node]
20//  8: 0xca9ba0 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
21//  9: 0xbe50dd node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) [node]
22// 10: 0xbe54c4  [node]
23// 11: 0x15583d7  [node]
24// 12: 0x1558c00  [node]
25// 13: 0x155ede4  [node]
26// 14: 0x154d008 uv_run [node]
27
28const serverReplaySize = 2 * 1024 * 1024;
29
30(async function() {
31  const tlsClientHello = await getClientHello();
32
33  const subserver = tls.createServer({
34    key: fixtures.readKey('agent1-key.pem'),
35    cert: fixtures.readKey('agent1-cert.pem'),
36  });
37
38  const server = tls.createServer({
39    key: fixtures.readKey('agent1-key.pem'),
40    cert: fixtures.readKey('agent1-cert.pem'),
41  })
42    .listen(startClient)
43    .on('secureConnection', (serverTlsSock) => {
44      // Craft writes that are large enough to stuck in sending
45      // In reality this can be a 200 response to the incoming HTTP CONNECT
46      const half = Buffer.alloc(serverReplaySize / 2, 0);
47      serverTlsSock.write(half, common.mustSucceed());
48      serverTlsSock.write(half, common.mustSucceed());
49
50      subserver.emit('connection', serverTlsSock);
51    });
52
53
54  function startClient() {
55    const clientTlsSock = tls.connect({
56      host: '127.0.0.1',
57      port: server.address().port,
58      rejectUnauthorized: false,
59    });
60
61    const recv = [];
62    let revcLen = 0;
63    clientTlsSock.on('data', (chunk) => {
64      revcLen += chunk.length;
65      recv.push(chunk);
66      if (revcLen > serverReplaySize) {
67        // Check the server's replay is followed by the subserver's TLS ServerHello
68        const serverHelloFstByte = Buffer.concat(recv).subarray(serverReplaySize, serverReplaySize + 1);
69        assert.strictEqual(serverHelloFstByte.toString('hex'), '16');
70        process.exit(0);
71      }
72    });
73
74    // In reality, one may want to send a HTTP CONNECT before starting this double TLS
75    clientTlsSock.write(tlsClientHello);
76  }
77})().then(common.mustCall());
78
79function getClientHello() {
80  return new Promise((resolve) => {
81    const server = net.createServer((sock) => {
82      sock.on('data', (chunk) => {
83        resolve(chunk);
84      });
85    })
86    .listen(() => {
87      tls.connect({
88        port: server.address().port,
89        host: '127.0.0.1',
90        ALPNProtocols: ['h2'],
91      }).on('error', () => {});
92    });
93  });
94}
95