Skip to content

Commit

Permalink
tls,cli: add --trace-tls command-line flag
Browse files Browse the repository at this point in the history
This commit adds a --trace-tls command-line flag. The
purpose is to enable tracing of TLS connections without the
need to modify existing application code.

PR-URL: nodejs#27497
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
cjihrig committed May 2, 2019
1 parent c6a2fdf commit 495822f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 2 deletions.
9 changes: 9 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,14 @@ added: v2.1.0
Prints a stack trace whenever synchronous I/O is detected after the first turn
of the event loop.

### `--trace-tls`
<!-- YAML
added: REPLACEME
-->

Prints TLS packet trace information to `stderr`. This can be used to debug TLS
connection problems.

### `--trace-warnings`
<!-- YAML
added: v6.0.0
Expand Down Expand Up @@ -889,6 +897,7 @@ Node.js options that are allowed are:
- `--trace-event-file-pattern`
- `--trace-events-enabled`
- `--trace-sync-io`
- `--trace-tls`
- `--trace-warnings`
- `--track-heap-objects`
- `--unhandled-rejections`
Expand Down
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ Enable the collection of trace event tracing information.
.It Fl -trace-sync-io
Print a stack trace whenever synchronous I/O is detected after the first turn of the event loop.
.
.It Fl -trace-tls
Prints TLS packet trace information to stderr.
.
.It Fl -trace-warnings
Print stack traces for process warnings (including deprecations).
.
Expand Down
15 changes: 13 additions & 2 deletions lib/_tls_wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ const {
ERR_TLS_SESSION_ATTACK,
ERR_TLS_SNI_FROM_SERVER
} = require('internal/errors').codes;
const { getOptionValue } = require('internal/options');
const { validateString } = require('internal/validators');
const traceTls = getOptionValue('--trace-tls');
const kConnectOptions = Symbol('connect-options');
const kDisableRenegotiation = Symbol('disable-renegotiation');
const kErrorEmitted = Symbol('error-emitted');
Expand All @@ -68,6 +70,7 @@ const kEnableTrace = Symbol('enableTrace');
const noop = () => {};

let ipServernameWarned = false;
let tlsTracingWarned = false;

// Server side times how long a handshake is taking to protect against slow
// handshakes being used for DoS.
Expand Down Expand Up @@ -343,9 +346,17 @@ function initRead(tlsSocket, socket) {

function TLSSocket(socket, opts) {
const tlsOptions = { ...opts };
const enableTrace = tlsOptions.enableTrace;
let enableTrace = tlsOptions.enableTrace;

if (typeof enableTrace !== 'boolean' && enableTrace != null) {
if (enableTrace == null) {
enableTrace = traceTls;

if (enableTrace && !tlsTracingWarned) {
tlsTracingWarned = true;
process.emitWarning('Enabling --trace-tls can expose sensitive data in ' +
'the resulting log.');
}
} else if (typeof enableTrace !== 'boolean') {
throw new ERR_INVALID_ARG_TYPE(
'options.enableTrace', 'boolean', enableTrace);
}
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"first tick",
&EnvironmentOptions::trace_sync_io,
kAllowedInEnvironment);
AddOption("--trace-tls",
"prints TLS packet trace information to stderr",
&EnvironmentOptions::trace_tls,
kAllowedInEnvironment);
AddOption("--trace-warnings",
"show stack traces on process warnings",
&EnvironmentOptions::trace_warnings,
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class EnvironmentOptions : public Options {
bool throw_deprecation = false;
bool trace_deprecation = false;
bool trace_sync_io = false;
bool trace_tls = false;
bool trace_warnings = false;
std::string unhandled_rejections;
std::string userland_loader;
Expand Down
59 changes: 59 additions & 0 deletions test/parallel/test-tls-enable-trace-cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
if (!common.hasCrypto) common.skip('missing crypto');
const fixtures = require('../common/fixtures');

// Test --trace-tls CLI flag.

const assert = require('assert');
const { fork } = require('child_process');

if (process.argv[2] === 'test')
return test();

const binding = require('internal/test/binding').internalBinding;

if (!binding('tls_wrap').HAVE_SSL_TRACE)
return common.skip('no SSL_trace() compiled into openssl');

const child = fork(__filename, ['test'], {
silent: true,
execArgv: ['--trace-tls']
});

let stderr = '';
child.stderr.setEncoding('utf8');
child.stderr.on('data', (data) => stderr += data);
child.on('close', common.mustCall(() => {
assert(/Warning: Enabling --trace-tls can expose sensitive/.test(stderr));
assert(/Received Record/.test(stderr));
assert(/ClientHello/.test(stderr));
}));

// For debugging and observation of actual trace output.
child.stderr.pipe(process.stderr);
child.stdout.pipe(process.stdout);

child.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 0);
}));

function test() {
const {
connect, keys
} = require(fixtures.path('tls-connect'));

connect({
client: {
checkServerIdentity: (servername, cert) => { },
ca: `${keys.agent1.cert}\n${keys.agent6.ca}`,
},
server: {
cert: keys.agent6.cert,
key: keys.agent6.key
},
}, common.mustCall((err, pair, cleanup) => {
return cleanup();
}));
}

0 comments on commit 495822f

Please sign in to comment.