Decrypting embedded TLS communication

2 minute read

Introduction

A typical cloud connected device communicates with the server over a TLS connection. All data in this communication will be encrypted using a set of session specific keys derived at the time of connection. Even if the network traffic is sniffed, this data cannot be decrypted unless you get access to either the negotiated key or the server’s private key. Getting access to the server’s private key in the case of a cloud service like AWS IoT is impractical. So we resort to the second (and most foolproof) method.

In the case I am describing below, the communication is happening between a PIC32 device running WolfSSL and AWS IoT core. The communication uses MQTT protocol and we need to decrypt the application level exchanges happening over the TLS1.2 transport layer. I will not be going into the details of how the Wi-Fi traffic was sniffed. We start from the point where we have a setup to capture and view the network traffic in Wireshark (v3.0.6-0-g908c8e357d0f) .

Modus operandi

To decrypt TLS traffic we need access to the master secret that is negotiated as part of the TLS connection process. Wireshark can accept a NSS Key Log Formatted file containing the client random and corresponding master secret for the session and use it to decrypt TLS traffic.

The simple file structure that we would be using looks like:

CLIENT_RANDOM <Client Hello Random> <master secret>

More details about the file format can be found here.

Code changes

We get this dumped out of the firmware by adding the following lines of code in WolfSSL’s tls.c file under the SHOW_SECRETS flag.

1
2
3
4
5
6
7
8
9
10
11
12
printf("CLIENT_RANDOM ");

//printf("\r\nclient Random (tls.c): ");
for (i = 0; i < RAN_LEN; i++)
  printf("%02x", ssl->arrays->clientRandom[i]);
printf(" ");
        
//printf("\r\nmaster secret (tls.c): ");
for (i = 0; i < SECRET_LEN; i++)
  printf("%02x", ssl->arrays->masterSecret[i]);
printf("\r\n");     

This will generate a print like the one below for each session it establishes.

CLIENT_RANDOM 1d38a12474f12447cff5013d88a85b1afc83b100a7ff92e5a1fc5171f6dfe101  331fd5c8d5e52fce44e4cd13a34beadd14c533b40f3a1839de0feb04d069ea58045cf04ef25f22e71dbcbe00b88ef4e2

Copy these into a text file. If there are multiple sessions , copy each of the prints into a newline within the file.

Decrypting TLS traffic with Wireshark

In your capture , right click on one of the TLS lines and click on the menu item to provide a master secret log file as shown in the menu below. (you can filter the capture with the tls expression to reduce clutter.)

Log file context menu

Log file context menu

Log file menu and options

Log file menu and options

Once this file is provided, Wireshark will decrypt all traffic in the stream that has a matching random from the client hello phase of the session.

Client Random

Client Random

Decrypted traffic

Decrypted traffic