Using Wireshark to decrypt TLS gRPC Client-Server protobuf messages

2021-11-28

Sample client server in golang that demonstrates how to decode protobuf messages for a gRPC Client->Server over TLS.

This is nothing new and is described here in wireshark’s documentation (How to Export TLS Master keys of gRPC)

What drove me to write this sample was a co-woker who as interested in viewing gRPC protbuf message in java for Google Cloud Pubsub.

Since i earlier worked on similar stuff in other repos like

i figured i’d give it a shot..it took a little bit to get going since i had to decode TLS and ultimately upgrade wireshark (per wireshark issue#17744)).

Anyway, what this repo does show is a very simple go-based client/server gRPC system that does unary, client streaming, server streaming and full bidi. All along the tls traffic is seen by wireshark, decrypted and after that, parsed using the .proto files

you’ll find the source here

Lets get started

Sample gRPC Client/Server

First thing is to setup the client server and wireshark (plase note, use wireshark 3.6.0+

For wireshark, we will save the TLS encryption keys to /tmp/keylog.log. This file contains the TLS keys in NSS Key Log Format which golang can output and wireshark can consume.

First tell wireshark where to find it

images/wireshark_keylog.png

Now we need to tell wireshark how to decode the proto after TLS is done. For that, we will configure wireshark to look at src/echo/echo.proto.

You’ll also want to install protoc core

in my case, it was unzipped to /usr/local/include/ (i.,e the .proto are under /usr/local/include/google/protobuf/.

Then specify them in the configurations

images/wireshark_proto.png

Now we’re ready to start the gRPC Server

# optionally, if you really want to compile from source...
# protoc --go_out=. --go_opt=paths=source_relative --go-grpc_opt=require_unimplemented_servers=false --go-grpc_out=. --go-grpc_opt=paths=source_relative src/echo/echo.proto

  go run src/grpc_server.go \
    --grpcport 0.0.0.0:50051 \
    --tlsCert=certs/grpc_server_crt.pem \
    --tlsKey=certs/grpc_server_key.pem

Now start wireshark. In a new window run

sudo wireshark

Once you start wireshark, select the ’lo’ (local interface)

Run the client but first tell it where to log the keys

export SSLKEYLOGFILE=/tmp/keylog.log

  go run src/grpc_client.go \
    --host 127.0.0.1:50051 \
    --tlsCert=certs/CA_crt.pem \
    --servername=grpc.domain.com

Note, to use go, you need to first ask it to dump the keylog per crypto.tls.Config.KeyLogWriter. Please take careful note of the dangers described there…

The output of the various modes

Unary

images/unary.png

Client Streaming

images/grpc_client_stream.png

Server Streaming

images/grpc_server_stream.png

BiDi Streaming

client->server:

images/grpc_bidi_req.png

server->client:

images/grpc_bidi_response.png

note the Stream ID 15 is used in both paths

I’ve also left a sample keylog and wireshark file for you to load and test decoding

google PubSub

Ok, so now we’re back to what i really wanted to do…decode PubSub.

first install protoc if you haven’t already

# https://grpc.io/docs/protoc-installation/
# in my case, it was unzipped to /usr/local/include/google/protobuf/

# first get all the protos
git clone https://github.com/googleapis/googleapis.git

Then tell wireshark to load the proto files: (note, the spot where googleapis/ folder is will be different)

$ more /home/srashid/.config/wireshark/protobuf_search_paths
# This file is automatically generated, DO NOT MODIFY.
"/usr/local/include","TRUE"
"/home/srashid/Desktop/grpc_sslkeylog/googleapis","TRUE"

images/pubsub_search.png

Anyway, if you ran the grpc client in this repo, and prior to that set the SSLKEYLOGFILE parameter, you should be able to see the pubsub traffic if you use the following filter in wireshark:

tcp.port == 443 and tls.handshake.extensions_server_name=="pubsub.googleapis.com"

However, even if you cant’ see the traffic, you can still see the bytes…presumably, you can dump the DATA to a file from wireshark, then use go to read each payload as protoMessage

images/grpc_pubsub.png


JAVA

I tried to use jSSLKeyLog with Cloud PubSub in Java and while it did dump the keys to a file, I wasn’t able to use wireshark to decrypt the data

I’ve left off as far as i got with that here in he repo

YMMV

# run standalone
mvn clean install exec:java

# create fatjar
mvn clean package

# or as package
java -jar target/TestApp-1.0-SNAPSHOT-jar-with-dependencies.jar

This site supports webmentions. Send me a mention via this form.