From af65dc50ab60797b46f1e71f7119e0896cc23923 Mon Sep 17 00:00:00 2001 From: Anders Broman Date: Fri, 2 Sep 2011 05:48:29 +0000 Subject: [PATCH] From Eric Wustrow: TLS Diffie-Hellman key exchange dissection support. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6277 svn path=/trunk/; revision=38858 --- epan/dissectors/packet-ssl.c | 204 +++++++++++++++++++++++++++++++++-- 1 file changed, 197 insertions(+), 7 deletions(-) diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c index 2c1e9d8dec..ede27a0255 100644 --- a/epan/dissectors/packet-ssl.c +++ b/epan/dissectors/packet-ssl.c @@ -191,6 +191,16 @@ static gint hf_ssl_handshake_certificate_len = -1; static gint hf_ssl_handshake_cert_types_count = -1; static gint hf_ssl_handshake_cert_types = -1; static gint hf_ssl_handshake_cert_type = -1; +static gint hf_ssl_handshake_server_keyex_p_len = -1; +static gint hf_ssl_handshake_server_keyex_g_len = -1; +static gint hf_ssl_handshake_server_keyex_ys_len = -1; +static gint hf_ssl_handshake_client_keyex_yc_len = -1; +static gint hf_ssl_handshake_server_keyex_sig_len = -1; +static gint hf_ssl_handshake_server_keyex_p = -1; +static gint hf_ssl_handshake_server_keyex_g = -1; +static gint hf_ssl_handshake_server_keyex_ys = -1; +static gint hf_ssl_handshake_client_keyex_yc = -1; +static gint hf_ssl_handshake_server_keyex_sig = -1; static gint hf_ssl_handshake_sig_hash_alg_len = -1; static gint hf_ssl_handshake_sig_hash_algs = -1; static gint hf_ssl_handshake_sig_hash_alg = -1; @@ -260,6 +270,7 @@ static gint ett_ssl_sig_hash_algs = -1; static gint ett_ssl_sig_hash_alg = -1; static gint ett_ssl_dnames = -1; static gint ett_ssl_random = -1; +static gint ett_ssl_keyex_params = -1; static gint ett_ssl_cert_status = -1; static gint ett_ssl_ocsp_resp = -1; static gint ett_pct_cipher_suites = -1; @@ -411,7 +422,7 @@ ssl_parse(void) /* record layer dissector */ static gint dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, + guint *conv_version, guint conv_cipher, gboolean *need_desegmentation, SslDecryptSession *conv_data, const gboolean first_record_in_frame); @@ -431,7 +442,7 @@ static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint32 record_length, - guint *conv_version, + guint *conv_version, guint conv_cipher, SslDecryptSession *conv_data, const guint8 content_type); /* hello extension dissector */ @@ -459,6 +470,14 @@ static void dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, const guint* conv_version); +static void dissect_ssl3_hnd_srv_keyex_dh(tvbuff_t *tvb, + proto_tree *tree, + guint32 offset, guint32 length); + +static void dissect_ssl3_hnd_cli_keyex_dh(tvbuff_t *tvb, + proto_tree *tree, + guint32 offset, guint32 length); + static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, proto_tree *tree, const guint32 offset, @@ -555,6 +574,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) gboolean need_desegmentation; SslDecryptSession* ssl_session; guint* conv_version; + guint conv_cipher; ti = NULL; ssl_tree = NULL; @@ -592,6 +612,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) conversation_add_proto_data(conversation, proto_ssl, ssl_session); } conv_version =& ssl_session->version; + conv_cipher = ssl_session->cipher; /* try decryption only the first time we see this packet * (to keep cipher synchronized) */ @@ -670,6 +691,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { offset = dissect_ssl3_record(tvb, pinfo, ssl_tree, offset, conv_version, + conv_cipher, &need_desegmentation, ssl_session, first_record_in_frame); @@ -694,6 +716,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* looks like sslv3 or tls */ offset = dissect_ssl3_record(tvb, pinfo, ssl_tree, offset, conv_version, + conv_cipher, &need_desegmentation, ssl_session, first_record_in_frame); @@ -1279,7 +1302,8 @@ dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *t static gint dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, gboolean *need_desegmentation, + guint *conv_version, guint conv_cipher, + gboolean *need_desegmentation, SslDecryptSession* ssl, const gboolean first_record_in_frame) { @@ -1561,10 +1585,10 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, /* add desegmented data to the data source list */ add_new_data_source(pinfo, decrypted, "Decrypted SSL record"); dissect_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0, - tvb_length(decrypted), conv_version, ssl, content_type); + tvb_length(decrypted), conv_version, conv_cipher, ssl, content_type); } else { dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset, - record_length, conv_version, ssl, content_type); + record_length, conv_version, conv_cipher, ssl, content_type); } break; } @@ -1711,7 +1735,7 @@ dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint32 record_length, guint *conv_version, + guint32 record_length, guint *conv_version, guint conv_cipher, SslDecryptSession* ssl, const guint8 content_type) { /* struct { @@ -1859,7 +1883,15 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, break; case SSL_HND_SERVER_KEY_EXCHG: - /* unimplemented */ + /* Only supports (a couple) Diffie-Hellman key exchanges. + Have to keep some state if you want to also support RSA + (server key exchange is optional and appears to be rare for RSA) + */ + { + if (conv_cipher == 0x39 || conv_cipher == 0x33) { + dissect_ssl3_hnd_srv_keyex_dh(tvb, ssl_hand_tree, offset, length); + } + } break; case SSL_HND_CERT_REQUEST: @@ -1875,6 +1907,9 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, break; case SSL_HND_CLIENT_KEY_EXCHG: + if (conv_cipher == 0x39 || conv_cipher == 0x33) { + dissect_ssl3_hnd_cli_keyex_dh(tvb, ssl_hand_tree, offset, length); + } { /* PAOLO: here we can have all the data to build session key*/ @@ -2696,6 +2731,110 @@ dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, } +static void +dissect_ssl3_hnd_srv_keyex_dh(tvbuff_t *tvb, proto_tree *tree, + guint32 offset, guint32 length) +{ + gint p_len, p_len_offset; + gint g_len, g_len_offset; + gint ys_len, ys_len_offset; + gint sig_len, sig_len_offset; + proto_item *ti_dh; + proto_tree *ssl_dh_tree; + guint32 orig_offset; + + orig_offset = offset; + + p_len_offset = offset; + p_len = tvb_get_ntohs(tvb, offset); + offset += 2 + p_len; + if ((offset - orig_offset) > length) { + return; + } + + g_len_offset = offset; + g_len = tvb_get_ntohs(tvb, offset); + offset += 2 + g_len; + if ((offset - orig_offset) > length) { + return; + } + + ys_len_offset = offset; + ys_len = tvb_get_ntohs(tvb, offset); + offset += 2 + ys_len; + if ((offset - orig_offset) > length) { + return; + } + + sig_len_offset = offset; + sig_len = tvb_get_ntohs(tvb, offset); + offset += 2 + sig_len; + if ((offset - orig_offset) != length) { + /* Lengths don't line up (wasn't what we expected?) */ + return; + } + + ti_dh = proto_tree_add_text(tree, tvb, orig_offset, + (offset - orig_offset), "Diffie-Hellman Server Params"); + ssl_dh_tree = proto_item_add_subtree(ti_dh, ett_ssl_keyex_params); + + /* p */ + proto_tree_add_uint(ssl_dh_tree, hf_ssl_handshake_server_keyex_p_len, + tvb, p_len_offset, 2, p_len); + proto_tree_add_item(ssl_dh_tree, hf_ssl_handshake_server_keyex_p, + tvb, p_len_offset + 2, p_len, FALSE); + + /* g */ + proto_tree_add_uint(ssl_dh_tree, hf_ssl_handshake_server_keyex_g_len, + tvb, g_len_offset, 2, g_len); + proto_tree_add_item(ssl_dh_tree, hf_ssl_handshake_server_keyex_g, + tvb, g_len_offset + 2, g_len, FALSE); + + /* Ys */ + proto_tree_add_uint(ssl_dh_tree, hf_ssl_handshake_server_keyex_ys_len, + tvb, ys_len_offset, 2, ys_len); + proto_tree_add_item(ssl_dh_tree, hf_ssl_handshake_server_keyex_ys, + tvb, ys_len_offset + 2, ys_len, FALSE); + + /* Sig */ + proto_tree_add_uint(ssl_dh_tree, hf_ssl_handshake_server_keyex_sig_len, + tvb, sig_len_offset, 2, sig_len); + proto_tree_add_item(ssl_dh_tree, hf_ssl_handshake_server_keyex_sig, + tvb, sig_len_offset + 2, sig_len, FALSE); + +} + +static void +dissect_ssl3_hnd_cli_keyex_dh(tvbuff_t *tvb, proto_tree *tree, + guint32 offset, guint32 length) +{ + gint yc_len, yc_len_offset; + proto_item *ti_dh; + proto_tree *ssl_dh_tree; + guint32 orig_offset; + + orig_offset = offset; + + yc_len_offset = offset; + yc_len = tvb_get_ntohs(tvb, offset); + offset += 2 + yc_len; + if ((offset - orig_offset) != length) { + return; + } + + ti_dh = proto_tree_add_text(tree, tvb, orig_offset, + (offset - orig_offset), "Diffie-Hellman Client Params"); + ssl_dh_tree = proto_item_add_subtree(ti_dh, ett_ssl_keyex_params); + + /* Yc */ + proto_tree_add_uint(ssl_dh_tree, hf_ssl_handshake_client_keyex_yc_len, + tvb, yc_len_offset, 2, yc_len); + proto_tree_add_item(ssl_dh_tree, hf_ssl_handshake_client_keyex_yc, + tvb, yc_len_offset + 2, yc_len, FALSE); +} + + + static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, proto_tree *tree, const guint32 offset, @@ -4492,6 +4631,56 @@ proto_register_ssl(void) FT_UINT8, BASE_DEC, VALS(ssl_31_client_certificate_type), 0x0, NULL, HFILL } }, + { &hf_ssl_handshake_server_keyex_p_len, + { "p Length", "ssl.handshake.p_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of p", HFILL } + }, + { &hf_ssl_handshake_server_keyex_g_len, + { "g Length", "ssl.handshake.g_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of g", HFILL } + }, + { &hf_ssl_handshake_server_keyex_ys_len, + { "Pubkey Length", "ssl.handshake.ys_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of server's Diffie-Hellman public key", HFILL } + }, + { &hf_ssl_handshake_client_keyex_yc_len, + { "Pubkey Length", "ssl.handshake.yc_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of client's Diffie-Hellman public key", HFILL } + }, + { &hf_ssl_handshake_server_keyex_sig_len, + { "Signature Length", "ssl.handshake.sig_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of Signature", HFILL } + }, + { &hf_ssl_handshake_server_keyex_p, + { "p", "ssl.handshake.p", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Diffie-Hellman p", HFILL } + }, + { &hf_ssl_handshake_server_keyex_g, + { "g", "ssl.handshake.g", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Diffie-Hellman g", HFILL } + }, + { &hf_ssl_handshake_server_keyex_ys, + { "pubkey", "ssl.handshake.ys", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Diffie-Hellman server pubkey", HFILL } + }, + { &hf_ssl_handshake_client_keyex_yc, + { "pubkey", "ssl.handshake.yc", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Diffie-Hellman client pubkey", HFILL } + }, + { &hf_ssl_handshake_server_keyex_sig, + { "signature", "ssl.handshake.sig", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Diffie-Hellman server signature", HFILL } + }, { &hf_ssl_handshake_sig_hash_alg_len, { "Signature Hash Algorithms Length", "ssl.handshake.sig_hash_alg_len", FT_UINT16, BASE_DEC, NULL, 0x0, @@ -4765,6 +4954,7 @@ proto_register_ssl(void) &ett_ssl_sig_hash_alg, &ett_ssl_dnames, &ett_ssl_random, + &ett_ssl_keyex_params, &ett_ssl_cert_status, &ett_ssl_ocsp_resp, &ett_pct_cipher_suites,