Dissecting SSL handshake

Not everyone knows that the SSL handshake is not encrypted. When you think about it - there isn't other way, before the keys are exchanged the communication must be unencrypted. But I doubt many people think about it.

Not only the SSL handshake is plain-text, but also it contains rather interesting data. I decided to find out how much information can be retrieved from it.

TLS

Here's how the TLS handshake works:

Client Server | | | ----------- ClientHello ---------> | | | | <---------- ServerHello ---------- | | <---------- Certificate ---------- | | ... | | <-------- ServerHelloDone -------- | | ... |

Let's focus on the first message - ClientHello . It is actually pretty interesting. RFC defines the structure as:

struct { ProtocolVersion client_version ; Random random ; SessionID session_id ; CipherSuite cipher_suites < 2..2 ^ 16 - 1 > ; CompressionMethod compression_methods < 1..2 ^ 8 - 1 > ; Extension extensions < 0..2 ^ 16 - 1 > ; } ClientHello ;

Translated to English:

That's it, now you know what's hiding in the SSL ClientHello message. For completeness, a few words on historical protocols.

SSL 3.0

SSLv3 is identical to TLS as described, with one exception - in theory SSLv3 ClientHello packet doesn't have an extensions field. In theory SSLv3 doesn't do SNI.

In practice this is more complicated. TLS 1.0 also doesn't specify extensions field, but most clients do send them anyway.

SSL 2.0

SSL 2.0 was originally developed by Netscape. It's old, barely documented and insecure. However few applications still support it for compatibility with old servers. Some versions of wget and google crawler use the SSLv2 handshake. A CLIENT-HELLO message is defined as:

char MSG - CLIENT - HELLO char CLIENT - VERSION - MSB char CLIENT - VERSION - LSB char CIPHER - SPECS - LENGTH - MSB char CIPHER - SPECS - LENGTH - LSB char SESSION - ID - LENGTH - MSB char SESSION - ID - LENGTH - LSB char CHALLENGE - LENGTH - MSB char CHALLENGE - LENGTH - LSB char CIPHER - SPECS - DATA [( MSB << 8 ) | LSB ] char SESSION - ID - DATA [( MSB << 8 ) | LSB ] char CHALLENGE - DATA [( MSB << 8 ) | LSB ]

The fields are familiar - client_version , cipher_suites , session_id and challenge . It's worth noting that SSLv2 doesn't have extensions - there is no way to specify SNI .

On a final note, challenge-data length must be between 16 and 32 bytes long. In real world I've only seen 16 and 32.

Summary

Things to remember:

Anyone snooping the HTTPS traffic is able to see the remote domain name in plain text due to SNI.

ClientHello message contains a lot of stuff and it is often possible to identify a client application just by looking at it.

During SSL handshake both the client and the server send their local time in plain-text.

Never enable SSLv2.

Continue reading about SSL fingerprinting →

Comment on YCombinator →