NetBurner 3.5.8
PDF Version
TLS Key Logging

Example Path: examples/SSL/SslKeyLog

TLS Key Logging

Overview

Makes a TLS connection and prints the session secrets to the console in NSS key log format, so that a packet capture of the same connection can be decrypted in Wireshark.

Every TLS 1.3 handshake after the ServerHello is encrypted, including the Certificate, CertificateRequest and CertificateVerify messages, and including alerts. Without the session secrets, a capture of a failing TLS connection shows a ClientHello, an opaque blob, and a connection that dies. With them, the whole handshake and the application data are readable.

Security warning

Key logging is for testing only. It works in release builds as well as debug builds. Anyone who can read the console can decrypt every TLS session the device makes, so never ship a product with it enabled. The library prints a warning banner to the console the first time it logs a secret, and again every 100 lines. Every build of the crypto library with key logging on also prints a compiler warning.

Enabling it

Key logging is a crypto library setting, NB_TLS_KEYLOG, not application code. This example turns it on with one file:

overload/libraries/include/crypto/platform/user_settings-overload.h

The file holds one line:

#define NB_TLS_KEYLOG

Every platform user_settings.h includes user_settings-overload.h after its own settings. The SDK ships that file empty. A project that has its own copy in its overload directory changes the crypto settings for that project only, and the SDK stays untouched. This works the same way in NBEclipse and in command line builds.

To turn key logging on in your own project:

  1. Create overload/libraries/include/crypto/platform/user_settings-overload.h in the project, with the line above.
  2. In NBEclipse, add the project folder overload/libraries/include to the C and C++ compiler include paths, above the paths that begin with $(NNDK_ROOT)/. This example ships an nbeclipse-rules.json file that does this on import. Command line builds need no change.
  3. Clean the build once, so the crypto library is rebuilt against the new file. On the command line, run make clean, then make. In NBEclipse, select "Clean NetBurner System Library" under the project's "Build Targets", then rebuild.

After that, editing the file rebuilds the crypto library automatically. To turn key logging off, delete the line or the file, and rebuild.

To turn it on for every project instead, uncomment NB_TLS_KEYLOG in the user_settings.h file for your platform, under libraries/include/crypto/platform/.

This covers TLS 1.2 and TLS 1.3. Do not define SHOW_SECRETS or WOLFSSL_SSLKEYLOGFILE. Those are wolfSSL options that write to a file, and these platforms set NO_FILESYSTEM.

Run the example and press K. It reports whether the library was built with key logging, using SSL_KeyLogEnabled().

Application code

None is needed. SSL_connect() is an ordinary synchronous call. There is no callback to register, no asynchronous connect, and no access to the wolfSSL handle:

int fds = SSL_connect(ipAddress, 443, TICKS_PER_SECOND * 30, SSL_SERVER_NAME);

Key logging is registered inside the library when each TLS socket is created, so it covers client sockets, the HTTPS server, and mail alike.

Sending the lines somewhere else

The lines go to the console by default. SSL_KeyLogWrite() is weak, so an application can replace it and send them to a TCP socket, a second UART, or flash:

void SSL_KeyLogWrite(const char *line)
{
    writestring(myLogFd, line);
    writestring(myLogFd, "\r\n");
}

Pass the line through unchanged. The SDK builds it in NSS format and Wireshark matches the labels exactly. The security warning banner does not pass through this function, so an override cannot silence it.

Output

One line per secret. A TLS 1.3 handshake produces several:

CLIENT_HANDSHAKE_TRAFFIC_SECRET 4f2c...8a1b 9d3e...77c0
SERVER_HANDSHAKE_TRAFFIC_SECRET 4f2c...8a1b 1a55...b204
CLIENT_TRAFFIC_SECRET_0 4f2c...8a1b 62f9...30ae
SERVER_TRAFFIC_SECRET_0 4f2c...8a1b c701...9d42
EXPORTER_SECRET 4f2c...8a1b 88ba...5e17

A TLS 1.2 handshake produces one:

CLIENT_RANDOM 4f2c...8a1b 3b6d...f409

The middle field is the client random, which is how Wireshark ties a line to a session.

Capturing and decrypting

Capture the traffic. Any tap will do; this uses dumpcap on the capture adapter:

dumpcap -i "Ethernet 2" -f "tcp port 443" -w tls.pcap -a duration:35

Save the console output, then keep only the key log lines:

cat console.txt | tr -d '\r' | grep -aE "^(CLIENT|SERVER|EARLY|EXPORTER)" > keys.log

Decrypt. The key log path must be absolute:

tshark -r tls.pcap -o "tls.keylog_file:/abs/path/keys.log" \
       -Y "tls.handshake.type" \
       -T fields -e frame.number -e ip.src -e tls.handshake.type

In the Wireshark GUI the same setting is Preferences, Protocols, TLS, "(Pre)-Master-Secret log filename".

Handshake type numbers worth knowing when reading the output: 1 ClientHello, 2 ServerHello, 8 EncryptedExtensions, 11 Certificate, 13 CertificateRequest, 15 CertificateVerify, 20 Finished, 4 NewSessionTicket. Types 8, 11, 15 and 20 are encrypted, so seeing them proves decryption worked. Types 1 and 2 alone mean it did not.

Two traps

  • The board caches TLS sessions. The second connection to the same server resumes, and its handshake carries no Certificate message at all. Reboot between captures when you need a full handshake.
  • A ServerHello whose random is cf21ad74e59a6111be1d8c021e65b891c2a211167abb8c5e079e09e2c8a8339c is not a ServerHello. That value is the fixed HelloRetryRequest marker from RFC 8446, and it means a second ClientHello follows.

Technical details

The library registers two callbacks on every TLS socket, one for each protocol version. The handshake decides which one fires, so the application does not need to know which version it negotiated. Each line is built whole and written under a critical section, so two handshakes running at once cannot interleave their output.

The example sets the clock from an NTP pool server. Certificate dates are checked, so the clock has to be right if you turn certificate verification on. This example leaves verification off to stay on one subject. For verification see SSL/TLS Client Verify Peer - Basic and SSL/TLS Client Certificate.

Files in this example

Build requirements

  • A platform with TLS support.
  • The overload file above, which this example already contains.
  • Wireshark, for the capture side.