Saturday, April 30, 2011

Sniffing SPDY with ssldump

‹prev | My Chain | next›

Up today, I would like to mess about with SPDY over SSL. Last night, I was able to play around a bit with the eventmachine example implementation in the SPDY gem. I even got to inspect SPDY packets with tcpdump.

The only thing lacking from last night's experiment was SSL—a necessary component of SPDY. Tonight I hope to repeat that success with ssldump.

First, I re-enable the start_tls line in the example eventmachine code. I then open the application which now resides at: https://localhost:10000/.

I get a warning that the certificate is not trusted, but proceed anyway only to get... nothing. The browser never receives a result, though the event machine server kindly reports:
[:SPDY, :connection_closed]
This message indicates that the browser has unbound the connection:
  def unbind
p [:SPDY, :connection_closed]

Next up, I actually follow the instructions in the example server and start Chrome with the --use-spdy=ssl. According to the SPDY debugging page, this option "forces Chrome to always use SPDY, even if not negotiated over SSL". That actually does the trick:

Interesting. So if the debugging page is correct, then the reason this works is that, otherwise the connection is made while negotiating over plain text. That is something to investigate another day.

For today, if I am going to sniff SSL packets, I am going to need a server certificate. The whole point of SSL, of course, is to make packet sniffing impossible (or at least prohibitively difficult). It is possible, however, if you have the server's private key. To make one, I use openssl:
➜  spdy git:(master)     openssl genrsa -out key.pem 1024
Generating RSA private key, 1024 bit long modulus
e is 65537 (0x10001)
➜ spdy git:(master) ✗ openssl req -new -key key.pem -out request.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Maryland
Locality Name (eg, city) []:Baltimore
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:Chris Strom
Email Address []

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:password
An optional company name []:
➜ spdy git:(master) ✗ openssl x509 -req -days 30 -in request.pem -signkey key.pem -out cert.pem
Signature ok
subject=/C=US/ST=Maryland/L=Baltimore/O=Internet Widgits Pty Ltd/CN=Chris Strom/
Getting Private key
To use that in eventmachine, I change the start_tls:
  def post_init
@parser =
@parser.on_headers_complete do |stream_id, associated_stream, priority, headers|
# ...

start_tls(:private_key_file => 'key.pem', :cert_chain_file => 'cert.pem', :verify_peer => false)
After restarting the server, I verify that I can still access the example SPDY site. Once I am confident that everything still works with the new certificate, I am ready to try out ssldump:
sudo ssldump -k key.pem -i lo -dX
The -k option uses the same private key file that I just generated and that eventmachine is now using. The example server is listening on localhost, so I need to sniff the packets on the loopback interface, lo. The -dX option tells ssldump to dump the packet contents in hex—ideally this is exactly what I did last night using tcpdump, but now I will be able to see an (almost) real SPDY conversation take place.

And, sure enough, that does the trick:
➜  examples git:(master) ✗ sudo ssldump -k key.pem -i lo -dX
New TCP connection #1: localhost.localdomain(35098) <-> localhost.localdomain(10000)
New TCP connection #2: localhost.localdomain(35099) <-> localhost.localdomain(10000)
1 1 0.0071 (0.0071) C>S Handshake
Version 3.1
3 7 0.0040 (0.0000) C>S Handshake3 8 0.0040 (0.0000) C>S application_data
00 2c 01 d3 fe 80 02 00 01 01 00 01 24 00 00 00
01 00 00 00 00 00 00 38 ea df a2 51 b2 62 e0 61
60 83 a4 17 06 7b b8 0b 75 30 2c d6 ae 40 17 cd
cd b1 2e b4 35 d0 b3 d4 d1 d2 d7 02 b3 2c 18 f8
50 73 2c 83 9c 67 b0 3f d4 3d 3a 60 07 81 d5 99
eb 40 d4 1b 33 f0 a3 e5 69 06 41 90 8b 75 a0 4e
d6 29 4e 49 ce 80 ab 81 25 03 06 be d4 3c dd d0
60 9d d4 3c a8 a5 bc 28 89 8d 81 23 2f 5f 17 2c
c2 c0 02 ca fc 0c fc a0 14 92 03 62 5a 01 73 a4
81 01 03 5b 2e b0 d4 c9 4f 61 60 76 77 0d 61 60
2b 28 4a 4c cf 4d 44 d2 c5 56 0c 24 73 53 19 58
33 4a 4a 0a 8a 19 98 41 61 c4 a8 cf 00 10 17 22
63 33 a4 fb e6 57 65 e6 e4 24 ea 9b ea 19 28 68
44 18 1a 5a 2b f8 64 e6 95 56 28 54 58 98 c5 9b
99 68 2a 38 02 c3 29 35 3c 35 c9 3b b3 44 df d4
d8 44 cf 18 a8 cc db 23 c4 d7 47 47 21 27 33 3b
55 c1 3d 35 39 3b 5f 53 c1 39 03 58 42 a5 ea 1b
1a e9 01 03 c5 c4 48 cf d0 48 21 38 31 2d b1 28
13 aa 89 81 1d 1a 4f 0c 1c b0 e8 03 00 00 00 ff
ff 00 00 00 ff ff
The fourth byte in bold indicates that this is a SYN_STREAM just like I saw last night.

That is a good place to stop for the night. Hopefully I will not have to rely on this technique much while working with SPDY, but it is good to know that it is available if needed.

SPDY protocol (draft 2)

Day #6

No comments:

Post a Comment