11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ciconst assert = require('assert');
41cb0ef41Sopenharmony_ciif (!common.hasCrypto) common.skip('missing crypto');
51cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
61cb0ef41Sopenharmony_ciconst tls = require('tls');
71cb0ef41Sopenharmony_ciconst net = require('net');
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci// Sending tls data on a server TLSSocket with an active write led to a crash:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// node[1296]: ../src/crypto/crypto_tls.cc:963:virtual int node::crypto::TLSWrap::DoWrite(node::WriteWrap*,
121cb0ef41Sopenharmony_ci//    uv_buf_t*, size_t, uv_stream_t*): Assertion `!current_write_' failed.
131cb0ef41Sopenharmony_ci//  1: 0xb090e0 node::Abort() [node]
141cb0ef41Sopenharmony_ci//  2: 0xb0915e  [node]
151cb0ef41Sopenharmony_ci//  3: 0xca8413 node::crypto::TLSWrap::DoWrite(node::WriteWrap*, uv_buf_t*, unsigned long, uv_stream_s*) [node]
161cb0ef41Sopenharmony_ci//  4: 0xcaa549 node::StreamBase::Write(uv_buf_t*, unsigned long, uv_stream_s*, v8::Local<v8::Object>) [node]
171cb0ef41Sopenharmony_ci//  5: 0xca88d7 node::crypto::TLSWrap::EncOut() [node]
181cb0ef41Sopenharmony_ci//  6: 0xca9ba8 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
191cb0ef41Sopenharmony_ci//  7: 0xca8eb0 node::crypto::TLSWrap::ClearOut() [node]
201cb0ef41Sopenharmony_ci//  8: 0xca9ba0 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
211cb0ef41Sopenharmony_ci//  9: 0xbe50dd node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) [node]
221cb0ef41Sopenharmony_ci// 10: 0xbe54c4  [node]
231cb0ef41Sopenharmony_ci// 11: 0x15583d7  [node]
241cb0ef41Sopenharmony_ci// 12: 0x1558c00  [node]
251cb0ef41Sopenharmony_ci// 13: 0x155ede4  [node]
261cb0ef41Sopenharmony_ci// 14: 0x154d008 uv_run [node]
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciconst serverReplaySize = 2 * 1024 * 1024;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci(async function() {
311cb0ef41Sopenharmony_ci  const tlsClientHello = await getClientHello();
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  const subserver = tls.createServer({
341cb0ef41Sopenharmony_ci    key: fixtures.readKey('agent1-key.pem'),
351cb0ef41Sopenharmony_ci    cert: fixtures.readKey('agent1-cert.pem'),
361cb0ef41Sopenharmony_ci  });
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  const server = tls.createServer({
391cb0ef41Sopenharmony_ci    key: fixtures.readKey('agent1-key.pem'),
401cb0ef41Sopenharmony_ci    cert: fixtures.readKey('agent1-cert.pem'),
411cb0ef41Sopenharmony_ci  })
421cb0ef41Sopenharmony_ci    .listen(startClient)
431cb0ef41Sopenharmony_ci    .on('secureConnection', (serverTlsSock) => {
441cb0ef41Sopenharmony_ci      // Craft writes that are large enough to stuck in sending
451cb0ef41Sopenharmony_ci      // In reality this can be a 200 response to the incoming HTTP CONNECT
461cb0ef41Sopenharmony_ci      const half = Buffer.alloc(serverReplaySize / 2, 0);
471cb0ef41Sopenharmony_ci      serverTlsSock.write(half, common.mustSucceed());
481cb0ef41Sopenharmony_ci      serverTlsSock.write(half, common.mustSucceed());
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci      subserver.emit('connection', serverTlsSock);
511cb0ef41Sopenharmony_ci    });
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  function startClient() {
551cb0ef41Sopenharmony_ci    const clientTlsSock = tls.connect({
561cb0ef41Sopenharmony_ci      host: '127.0.0.1',
571cb0ef41Sopenharmony_ci      port: server.address().port,
581cb0ef41Sopenharmony_ci      rejectUnauthorized: false,
591cb0ef41Sopenharmony_ci    });
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci    const recv = [];
621cb0ef41Sopenharmony_ci    let revcLen = 0;
631cb0ef41Sopenharmony_ci    clientTlsSock.on('data', (chunk) => {
641cb0ef41Sopenharmony_ci      revcLen += chunk.length;
651cb0ef41Sopenharmony_ci      recv.push(chunk);
661cb0ef41Sopenharmony_ci      if (revcLen > serverReplaySize) {
671cb0ef41Sopenharmony_ci        // Check the server's replay is followed by the subserver's TLS ServerHello
681cb0ef41Sopenharmony_ci        const serverHelloFstByte = Buffer.concat(recv).subarray(serverReplaySize, serverReplaySize + 1);
691cb0ef41Sopenharmony_ci        assert.strictEqual(serverHelloFstByte.toString('hex'), '16');
701cb0ef41Sopenharmony_ci        process.exit(0);
711cb0ef41Sopenharmony_ci      }
721cb0ef41Sopenharmony_ci    });
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci    // In reality, one may want to send a HTTP CONNECT before starting this double TLS
751cb0ef41Sopenharmony_ci    clientTlsSock.write(tlsClientHello);
761cb0ef41Sopenharmony_ci  }
771cb0ef41Sopenharmony_ci})().then(common.mustCall());
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_cifunction getClientHello() {
801cb0ef41Sopenharmony_ci  return new Promise((resolve) => {
811cb0ef41Sopenharmony_ci    const server = net.createServer((sock) => {
821cb0ef41Sopenharmony_ci      sock.on('data', (chunk) => {
831cb0ef41Sopenharmony_ci        resolve(chunk);
841cb0ef41Sopenharmony_ci      });
851cb0ef41Sopenharmony_ci    })
861cb0ef41Sopenharmony_ci    .listen(() => {
871cb0ef41Sopenharmony_ci      tls.connect({
881cb0ef41Sopenharmony_ci        port: server.address().port,
891cb0ef41Sopenharmony_ci        host: '127.0.0.1',
901cb0ef41Sopenharmony_ci        ALPNProtocols: ['h2'],
911cb0ef41Sopenharmony_ci      }).on('error', () => {});
921cb0ef41Sopenharmony_ci    });
931cb0ef41Sopenharmony_ci  });
941cb0ef41Sopenharmony_ci}
95