Skip to content

Commit 4f271ad

Browse files
committed
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
1 parent 53eb264 commit 4f271ad

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
@@ -701,7 +701,7 @@ added:
701701

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

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

lib/_tls_wrap.js

+32-37
Original file line numberDiff line numberDiff line change
@@ -372,16 +372,9 @@ function onPskClientCallback(hint, maxPskLen, maxIdentityLen) {
372372
return { psk: ret.psk, identity: ret.identity };
373373
}
374374

375-
function onkeylogclient(line) {
376-
debug('client onkeylog');
377-
this[owner_symbol].emit('keylog', line);
378-
}
379-
380375
function onkeylog(line) {
381-
debug('server onkeylog');
382-
const owner = this[owner_symbol];
383-
if (owner.server)
384-
owner.server.emit('keylog', line, owner);
376+
debug('onkeylog');
377+
this[owner_symbol].emit('keylog', line);
385378
}
386379

387380
function onocspresponse(resp) {
@@ -663,13 +656,26 @@ TLSSocket.prototype._init = function(socket, wrap) {
663656
if (requestCert || rejectUnauthorized)
664657
ssl.setVerifyMode(requestCert, rejectUnauthorized);
665658

659+
// Only call .onkeylog if there is a keylog listener.
660+
ssl.onkeylog = onkeylog;
661+
this.on('newListener', keylogNewListener);
662+
663+
function keylogNewListener(event) {
664+
if (event !== 'keylog')
665+
return;
666+
667+
ssl.enableKeylogCallback();
668+
669+
// Remove this listener since it's no longer needed.
670+
this.removeListener('newListener', keylogNewListener);
671+
}
672+
666673
if (options.isServer) {
667674
ssl.onhandshakestart = onhandshakestart;
668675
ssl.onhandshakedone = onhandshakedone;
669676
ssl.onclienthello = loadSession;
670677
ssl.oncertcb = loadSNI;
671678
ssl.onnewsession = onnewsession;
672-
ssl.onkeylog = onkeylog;
673679
ssl.lastHandshakeTime = 0;
674680
ssl.handshakes = 0;
675681

@@ -679,8 +685,6 @@ TLSSocket.prototype._init = function(socket, wrap) {
679685
// Also starts the client hello parser as a side effect.
680686
ssl.enableSessionCallbacks();
681687
}
682-
if (this.server.listenerCount('keylog') > 0)
683-
ssl.enableKeylogCallback();
684688
if (this.server.listenerCount('OCSPRequest') > 0)
685689
ssl.enableCertCb();
686690
}
@@ -709,39 +713,23 @@ TLSSocket.prototype._init = function(socket, wrap) {
709713
// Remove this listener since it's no longer needed.
710714
this.removeListener('newListener', newListener);
711715
}
712-
713-
ssl.onkeylog = onkeylogclient;
714-
715-
// Only call .onkeylog if there is a keylog listener.
716-
this.on('newListener', keylogNewListener);
717-
718-
function keylogNewListener(event) {
719-
if (event !== 'keylog')
720-
return;
721-
722-
ssl.enableKeylogCallback();
723-
724-
// Remove this listener since it's no longer needed.
725-
this.removeListener('newListener', keylogNewListener);
726-
}
727716
}
728717

729718
if (tlsKeylog) {
730719
if (warnOnTlsKeylog) {
731720
warnOnTlsKeylog = false;
732721
process.emitWarning('Using --tls-keylog makes TLS connections insecure ' +
733722
'by writing secret key material to file ' + tlsKeylog);
734-
ssl.enableKeylogCallback();
735-
this.on('keylog', (line) => {
736-
appendFile(tlsKeylog, line, { mode: 0o600 }, (err) => {
737-
if (err && warnOnTlsKeylogError) {
738-
warnOnTlsKeylogError = false;
739-
process.emitWarning('Failed to write TLS keylog (this warning ' +
740-
'will not be repeated): ' + err);
741-
}
742-
});
743-
});
744723
}
724+
this.on('keylog', (line) => {
725+
appendFile(tlsKeylog, line, { mode: 0o600 }, (err) => {
726+
if (err && warnOnTlsKeylogError) {
727+
warnOnTlsKeylogError = false;
728+
process.emitWarning('Failed to write TLS keylog (this warning ' +
729+
'will not be repeated): ' + err);
730+
}
731+
});
732+
});
745733
}
746734

747735
ssl.onerror = onerror;
@@ -1044,6 +1032,10 @@ function onSocketTLSError(err) {
10441032
}
10451033
}
10461034

1035+
function onSocketKeylog(line) {
1036+
this._tlsOptions.server.emit('keylog', line, this);
1037+
}
1038+
10471039
function onSocketClose(err) {
10481040
// Closed because of error - no need to emit it twice
10491041
if (err)
@@ -1076,6 +1068,9 @@ function tlsConnectionListener(rawSocket) {
10761068

10771069
socket.on('secure', onServerSocketSecure);
10781070

1071+
if (this.listenerCount('keylog') > 0)
1072+
socket.on('keylog', onSocketKeylog);
1073+
10791074
socket[kErrorEmitted] = false;
10801075
socket.on('close', onSocketClose);
10811076
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)