|
NetBurner 3.5.8
PDF Version |
Example Path: examples/SSL/SslKeyLog
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.
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.
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:
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().
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.
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.
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.
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.
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.