Skip to content

Commit 7315c22

Browse files
mildsunrisecodebytere
authored andcommitted
tls: fix --tls-keylog option
There's a typo that causes only the first socket to be logged (i.e. when the warning is emitted). In addition, server sockets aren't logged because `keylog` events are not emitted on tls.Server, not the socket. This behaviour is counterintuitive and has caused more bugs in the past, so make all sockets (server or client) emit 'keylog'. tls.Server will just re-emit these events. Refs: nodejs#30055 PR-URL: nodejs#33366 Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
1 parent 33a7878 commit 7315c22

File tree

3 files changed

+41
-41
lines changed

3 files changed

+41
-41
lines changed

doc/api/tls.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ added: v12.3.0
697697

698698
* `line` {Buffer} Line of ASCII text, in NSS `SSLKEYLOGFILE` format.
699699

700-
The `keylog` event is emitted on a client `tls.TLSSocket` when key material
700+
The `keylog` event is emitted on a `tls.TLSSocket` when key material
701701
is generated or received by the socket. This keying material can be stored
702702
for debugging, as it allows captured TLS traffic to be decrypted. It may
703703
be emitted multiple times, before or after the handshake completes.

lib/_tls_wrap.js

+32-37
Original file line numberDiff line numberDiff line change
@@ -377,16 +377,9 @@ function onPskClientCallback(hint, maxPskLen, maxIdentityLen) {
377377
return { psk: ret.psk, identity: ret.identity };
378378
}
379379

380-
function onkeylogclient(line) {
381-
debug('client onkeylog');
382-
this[owner_symbol].emit('keylog', line);
383-
}
384-
385380
function onkeylog(line) {
386-
debug('server onkeylog');
387-
const owner = this[owner_symbol];
388-
if (owner.server)
389-
owner.server.emit('keylog', line, owner);
381+
debug('onkeylog');
382+
this[owner_symbol].emit('keylog', line);
390383
}
391384

392385
function onocspresponse(resp) {
@@ -678,13 +671,26 @@ TLSSocket.prototype._init = function(socket, wrap) {
678671
if (requestCert || rejectUnauthorized)
679672
ssl.setVerifyMode(requestCert, rejectUnauthorized);
680673

674+
// Only call .onkeylog if there is a keylog listener.
675+
ssl.onkeylog = onkeylog;
676+
this.on('newListener', keylogNewListener);
677+
678+
function keylogNewListener(event) {
679+
if (event !== 'keylog')
680+
return;
681+
682+
ssl.enableKeylogCallback();
683+
684+
// Remove this listener since it's no longer needed.
685+
this.removeListener('newListener', keylogNewListener);
686+
}
687+
681688
if (options.isServer) {
682689
ssl.onhandshakestart = onhandshakestart;
683690
ssl.onhandshakedone = onhandshakedone;
684691
ssl.onclienthello = loadSession;
685692
ssl.oncertcb = loadSNI;
686693
ssl.onnewsession = onnewsession;
687-
ssl.onkeylog = onkeylog;
688694
ssl.lastHandshakeTime = 0;
689695
ssl.handshakes = 0;
690696

@@ -694,8 +700,6 @@ TLSSocket.prototype._init = function(socket, wrap) {
694700
// Also starts the client hello parser as a side effect.
695701
ssl.enableSessionCallbacks();
696702
}
697-
if (this.server.listenerCount('keylog') > 0)
698-
ssl.enableKeylogCallback();
699703
if (this.server.listenerCount('OCSPRequest') > 0)
700704
ssl.enableCertCb();
701705
}
@@ -724,39 +728,23 @@ TLSSocket.prototype._init = function(socket, wrap) {
724728
// Remove this listener since it's no longer needed.
725729
this.removeListener('newListener', newListener);
726730
}
727-
728-
ssl.onkeylog = onkeylogclient;
729-
730-
// Only call .onkeylog if there is a keylog listener.
731-
this.on('newListener', keylogNewListener);
732-
733-
function keylogNewListener(event) {
734-
if (event !== 'keylog')
735-
return;
736-
737-
ssl.enableKeylogCallback();
738-
739-
// Remove this listener since it's no longer needed.
740-
this.removeListener('newListener', keylogNewListener);
741-
}
742731
}
743732

744733
if (tlsKeylog) {
745734
if (warnOnTlsKeylog) {
746735
warnOnTlsKeylog = false;
747736
process.emitWarning('Using --tls-keylog makes TLS connections insecure ' +
748737
'by writing secret key material to file ' + tlsKeylog);
749-
ssl.enableKeylogCallback();
750-
this.on('keylog', (line) => {
751-
appendFile(tlsKeylog, line, { mode: 0o600 }, (err) => {
752-
if (err && warnOnTlsKeylogError) {
753-
warnOnTlsKeylogError = false;
754-
process.emitWarning('Failed to write TLS keylog (this warning ' +
755-
'will not be repeated): ' + err);
756-
}
757-
});
758-
});
759738
}
739+
this.on('keylog', (line) => {
740+
appendFile(tlsKeylog, line, { mode: 0o600 }, (err) => {
741+
if (err && warnOnTlsKeylogError) {
742+
warnOnTlsKeylogError = false;
743+
process.emitWarning('Failed to write TLS keylog (this warning ' +
744+
'will not be repeated): ' + err);
745+
}
746+
});
747+
});
760748
}
761749

762750
ssl.onerror = onerror;
@@ -1059,6 +1047,10 @@ function onSocketTLSError(err) {
10591047
}
10601048
}
10611049

1050+
function onSocketKeylog(line) {
1051+
this._tlsOptions.server.emit('keylog', line, this);
1052+
}
1053+
10621054
function onSocketClose(err) {
10631055
// Closed because of error - no need to emit it twice
10641056
if (err)
@@ -1091,6 +1083,9 @@ function tlsConnectionListener(rawSocket) {
10911083

10921084
socket.on('secure', onServerSocketSecure);
10931085

1086+
if (this.listenerCount('keylog') > 0)
1087+
socket.on('keylog', onSocketKeylog);
1088+
10941089
socket[kErrorEmitted] = false;
10951090
socket.on('close', onSocketClose);
10961091
socket.on('_tlsError', onSocketTLSError);

test/parallel/test-tls-enable-keylog-cli.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ const child = fork(__filename, ['test'], {
2424
child.on('close', common.mustCall((code, signal) => {
2525
assert.strictEqual(code, 0);
2626
assert.strictEqual(signal, null);
27-
const log = fs.readFileSync(file, 'utf8');
28-
assert(/SECRET/.test(log));
27+
const log = fs.readFileSync(file, 'utf8').trim().split('\n');
28+
// Both client and server should log their secrets,
29+
// so we should have two identical lines in the log
30+
assert.strictEqual(log.length, 2);
31+
assert.strictEqual(log[0], log[1]);
2932
}));
3033

3134
function test() {
@@ -40,7 +43,9 @@ function test() {
4043
},
4144
server: {
4245
cert: keys.agent6.cert,
43-
key: keys.agent6.key
46+
key: keys.agent6.key,
47+
// Number of keylog events is dependent on protocol version
48+
maxVersion: 'TLSv1.2',
4449
},
4550
}, common.mustCall((err, pair, cleanup) => {
4651
if (pair.server.err) {

0 commit comments

Comments
 (0)