Capture only ssl handshake with tcpdump

I don't know what exactly you are calling handshake, but I propose this command that will probably capture more than 95% of what you can want:

tcpdump -ni eth0 "tcp port 443 and (tcp[((tcp[12] & 0xf0) >> 2)] = 0x16)"

Now what does it do:

  • eth0: is my network interface, change it if you need
  • tcp port 443: I suppose this is the port your server is listening on, change it if you need
  • tcp[((tcp[12] & 0xf0) >> 2)] = 0x16: a bit more tricky, let's detail this below

tcp[12] means capturing the 13th byte of the tcp packet, corresponding to first half being the offset, second half being reserved. The offset, once multiplied by 4 gives the byte count of the TCP header, meaning ((tcp[12] & 0xf0) >> 2) provides the size of the TCP header.

The first byte of a TLS packet define the content type. The value 22 (0x16 in hexadecimal) has been defined as being "Handshake" content.

As a consequence, tcp[((tcp[12] & 0xf0) >> 2)] = 0x16 captures every packet having the first byte after the TCP header set to 0x16.

More filtering can be performed, but this strictly answers your question.


I think the accepted answer is a premature optimization with a fragile solution.

SSL handshake occurs as soon at the connection is established.

Easy approach: start the capture before the client connects to the remote host, and capture the first, full N packets.

For example, for 300 packets:

/usr/sbin/tcpdump -i eth0 -p -s 65535 -c 300 "tcp and host 1.2.3.4 and port 443"

This way wireshark has the full payload of the SSL handshake, can decode it and show you all the bits.