Bug 1954 From Mikael Magnusson :

This patch updates the DTLS dissector to be compatible with OpenSSL 0.9.8f in
the following ways:
* Handle both SSL version number 0xfeff (RFC 4347 and OpenSSL 0.9.8f), and
0x100 (Used by OpenSSL 0.9.8e and earlier)
* Reassemble fragmented handshake messages.





svn path=/trunk/; revision=23369
This commit is contained in:
Sake Blok 2007-11-05 23:05:20 +00:00
parent a6850bb34e
commit 3c9a7b9dcd
4 changed files with 183 additions and 24 deletions

View File

@ -2812,6 +2812,7 @@ Scott Robinson <scott.robinson [AT] flukenetworks.com>
Martin Peylo <wireshark [AT] izac.de>
Stéphane Loeuillet <leroutier@gmail.com>
Andrei Rubaniuk <rubaniuk@mail.ru>
Mikael Magnusson <mikma264@gmail.com>
Alain Magloire <alainm[AT]rcsm.ece.mcgill.ca> was kind enough to
give his permission to use his version of snprintf.c.

View File

@ -1,6 +1,7 @@
/* packet-dtls.c
* Routines for dtls dissection
* Copyright (c) 2006, Authesserre Samuel <sauthess@gmail.com>
* Copyright (c) 2007, Mikael Magnusson <mikma@users.sourceforge.net>
*
* $Id$
*
@ -30,7 +31,7 @@
* This dissector is based on TLS one (packet-ssl.c) because of the proximity of DTLS and TLS, decryption works like him with RSA key exchange.
* It uses the sames things (file, libraries) that SSL one (gnutls, packet-ssl-utils.h) to make it easily maintenable.
*
* It was developped to dissect and decrypt OpenSSL v 0.9.8b DTLS implementation.
* It was developped to dissect and decrypt OpenSSL v 0.9.8f DTLS implementation.
* It is limited to this implementation while there is no complete implementation.
*
* Implemented :
@ -65,6 +66,7 @@
#include <epan/dissectors/packet-x509af.h>
#include <epan/emem.h>
#include <epan/tap.h>
#include <epan/reassemble.h>
#include "inet_v6defs.h"
#include "packet-ssl-utils.h"
@ -134,6 +136,15 @@ static gint hf_dtls_handshake_dnames = -1;
static gint hf_dtls_handshake_dname_len = -1;
static gint hf_dtls_handshake_dname = -1;
static gint hf_dtls_fragments = -1;
static gint hf_dtls_fragment = -1;
static gint hf_dtls_fragment_overlap = -1;
static gint hf_dtls_fragment_overlap_conflicts = -1;
static gint hf_dtls_fragment_multiple_tails = -1;
static gint hf_dtls_fragment_too_long_fragment = -1;
static gint hf_dtls_fragment_error = -1;
static gint hf_dtls_reassembled_in = -1;
/* Initialize the subtree pointers */
static gint ett_dtls = -1;
static gint ett_dtls_record = -1;
@ -146,8 +157,13 @@ static gint ett_dtls_certs = -1;
static gint ett_dtls_cert_types = -1;
static gint ett_dtls_dnames = -1;
static gint ett_dtls_fragment = -1;
static gint ett_dtls_fragments = -1;
static GHashTable *dtls_session_hash = NULL;
static GHashTable *dtls_key_hash = NULL;
static GHashTable *dtls_fragment_table = NULL;
static GHashTable *dtls_reassembled_table = NULL;
static GTree* dtls_associations = NULL;
static dissector_handle_t dtls_handle = NULL;
static StringInfo dtls_compressed_data = {NULL, 0};
@ -159,11 +175,31 @@ static gchar* dtls_keys_list = NULL;
static gchar* dtls_debug_file_name = NULL;
#endif
static const fragment_items dtls_frag_items = {
/* Fragment subtrees */
&ett_dtls_fragment,
&ett_dtls_fragments,
/* Fragment fields */
&hf_dtls_fragments,
&hf_dtls_fragment,
&hf_dtls_fragment_overlap,
&hf_dtls_fragment_overlap_conflicts,
&hf_dtls_fragment_multiple_tails,
&hf_dtls_fragment_too_long_fragment,
&hf_dtls_fragment_error,
/* Reassembled in field */
&hf_dtls_reassembled_in,
/* Tag */
"Message fragments"
};
/* initialize/reset per capture state data (dtls sessions cache) */
static void
dtls_init(void)
{
ssl_common_init(&dtls_session_hash, &dtls_decrypted_data, &dtls_compressed_data);
fragment_table_init (&dtls_fragment_table);
reassembled_table_init(&dtls_reassembled_table);
}
/* parse dtls related preferences (private keys and ports association strings) */
@ -642,7 +678,8 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
if (*conv_version == SSL_VER_UNKNOWN
&& dtls_is_authoritative_version_message(content_type, next_byte))
{
if (version == DTLSV1DOT0_VERSION)
if (version == DTLSV1DOT0_VERSION ||
version == DTLSV1DOT0_VERSION_NOT)
{
*conv_version = SSL_VER_DTLS;
@ -938,14 +975,21 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
/* set record_length to the max offset */
record_length += offset;
while (offset < record_length)
for (; offset < record_length; offset += fragment_length,
first_iteration = FALSE) /* set up for next pass, if any */
{
fragment_data *frag_msg = NULL;
tvbuff_t *new_tvb = NULL;
gchar *frag_str = NULL;
gboolean fragmented;
msg_type = tvb_get_guint8(tvb, offset);
msg_type_str = match_strval(msg_type, ssl_31_handshake_type);
length = tvb_get_ntoh24(tvb, offset + 1);
message_seq = tvb_get_ntohs(tvb,offset + 4);
fragment_offset = tvb_get_ntoh24(tvb, offset + 6);
fragment_length = tvb_get_ntoh24(tvb, offset + 9);
fragmented = fragment_length != length;
if (!msg_type_str && !first_iteration)
{
@ -970,36 +1014,93 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
col_append_str(pinfo->cinfo, COL_INFO, (msg_type_str != NULL)
? msg_type_str : "Encrypted Handshake Message");
/* Handle fragments of known message type */
if (fragmented)
{
gboolean frag_hand;
switch (msg_type) {
case SSL_HND_HELLO_REQUEST:
case SSL_HND_CLIENT_HELLO:
case SSL_HND_HELLO_VERIFY_REQUEST:
case SSL_HND_SERVER_HELLO:
case SSL_HND_CERTIFICATE:
case SSL_HND_SERVER_KEY_EXCHG:
case SSL_HND_CERT_REQUEST:
case SSL_HND_SVR_HELLO_DONE:
case SSL_HND_CERT_VERIFY:
case SSL_HND_CLIENT_KEY_EXCHG:
case SSL_HND_FINISHED:
frag_hand = TRUE;
break;
default:
/* Ignore encrypted handshake messages */
frag_hand = FALSE;
break;
}
if (frag_hand) {
/* Fragmented handshake message */
pinfo->fragmented = TRUE;
frag_msg = fragment_add(tvb, offset+12, pinfo, message_seq,
dtls_fragment_table,
fragment_offset, fragment_length, TRUE);
fragment_set_tot_len(pinfo, message_seq, dtls_fragment_table,
length);
if (frag_msg && (fragment_length + fragment_offset) == length)
{
/* Reassembled */
new_tvb = process_reassembled_data(tvb, offset+12, pinfo,
"Reassembled Message",
frag_msg,
&dtls_frag_items,
NULL, tree);
frag_str = " (Reassembled)";
}
else
{
frag_str = " (Fragment)";
}
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, frag_str);
}
}
if (tree)
{
/* set the label text on the record layer expanding node */
if (first_iteration)
{
proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s",
proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s%s",
ssl_version_short_names[*conv_version],
val_to_str(content_type, ssl_31_content_type, "unknown"),
(msg_type_str!=NULL) ? msg_type_str :
"Encrypted Handshake Message");
"Encrypted Handshake Message",
(frag_str!=NULL) ? frag_str : "");
}
else
{
proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s",
proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s%s",
ssl_version_short_names[*conv_version],
val_to_str(content_type, ssl_31_content_type, "unknown"),
"Multiple Handshake Messages");
"Multiple Handshake Messages",
(frag_str!=NULL) ? frag_str : "");
}
/* add a subtree for the handshake protocol */
ti = proto_tree_add_item(tree, hf_dtls_handshake_protocol, tvb,
offset, length + 12, 0);
offset, fragment_length + 12, 0);
ssl_hand_tree = proto_item_add_subtree(ti, ett_dtls_handshake);
if (ssl_hand_tree)
{
/* set the text label on the subtree node */
proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s",
proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s%s",
(msg_type_str != NULL) ? msg_type_str :
"Encrypted Handshake Message");
"Encrypted Handshake Message",
(frag_str!=NULL) ? frag_str : "");
}
}
@ -1010,6 +1111,8 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
/* if we are doing ssl decryption we must dissect some requests type */
if (ssl_hand_tree || ssl)
{
tvbuff_t *sub_tvb = NULL;
/* add nodes for the message type and message length */
if (ssl_hand_tree)
proto_tree_add_item(ssl_hand_tree, hf_dtls_handshake_type,
@ -1033,6 +1136,22 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
tvb, offset, 3, fragment_length);
offset += 3;
if (fragmented && !new_tvb)
{
/* Skip fragmented messages not reassembled yet */
continue;
}
if (new_tvb)
{
sub_tvb = new_tvb;
}
else
{
sub_tvb = tvb_new_subset(tvb, offset, fragment_length,
fragment_length);
}
/* now dissect the handshake message, if necessary */
switch (msg_type) {
case SSL_HND_HELLO_REQUEST:
@ -1040,19 +1159,19 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
break;
case SSL_HND_CLIENT_HELLO:
dissect_dtls_hnd_cli_hello(tvb, ssl_hand_tree, offset, length, ssl);
dissect_dtls_hnd_cli_hello(sub_tvb, ssl_hand_tree, 0, length, ssl);
break;
case SSL_HND_HELLO_VERIFY_REQUEST:
dissect_dtls_hnd_hello_verify_request(tvb, ssl_hand_tree, offset, ssl);
dissect_dtls_hnd_hello_verify_request(sub_tvb, ssl_hand_tree, 0, ssl);
break;
case SSL_HND_SERVER_HELLO:
dissect_dtls_hnd_srv_hello(tvb, ssl_hand_tree, offset, length, ssl);
dissect_dtls_hnd_srv_hello(sub_tvb, ssl_hand_tree, 0, length, ssl);
break;
case SSL_HND_CERTIFICATE:
dissect_dtls_hnd_cert(tvb, ssl_hand_tree, offset, pinfo);
dissect_dtls_hnd_cert(sub_tvb, ssl_hand_tree, 0, pinfo);
break;
case SSL_HND_SERVER_KEY_EXCHG:
@ -1060,7 +1179,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
break;
case SSL_HND_CERT_REQUEST:
dissect_dtls_hnd_cert_req(tvb, ssl_hand_tree, offset);
dissect_dtls_hnd_cert_req(sub_tvb, ssl_hand_tree, offset);
break;
case SSL_HND_SVR_HELLO_DONE:
@ -1119,8 +1238,8 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
break;
case SSL_HND_FINISHED:
dissect_dtls_hnd_finished(tvb, ssl_hand_tree,
offset, conv_version);
dissect_dtls_hnd_finished(sub_tvb, ssl_hand_tree,
0, conv_version);
break;
}
@ -1128,8 +1247,6 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
else{
offset += 12; /* skip the handshake header when handshake is not processed*/
}
offset += length;
first_iteration = FALSE; /* set up for next pass, if any */
}
}
@ -1822,7 +1939,7 @@ looks_like_dtls(tvbuff_t *tvb, guint32 offset)
/* now check to see if the version byte appears valid */
version = tvb_get_ntohs(tvb, offset + 1);
if (version != DTLSV1DOT0_VERSION)
if (version != DTLSV1DOT0_VERSION && version != DTLSV1DOT0_VERSION_NOT)
{
return 0;
}
@ -2086,6 +2203,40 @@ proto_register_dtls(void)
FT_BYTES, BASE_NONE, NULL, 0x0,
"Distinguished name of a CA that server trusts", HFILL }
},
{ &hf_dtls_fragments,
{ "Message fragments", "dtls.fragments",
FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_fragment,
{ "Message fragment", "dtls.fragment",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_fragment_overlap,
{ "Message fragment overlap", "dtls.fragment.overlap",
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_fragment_overlap_conflicts,
{ "Message fragment overlapping with conflicting data",
"dtls.fragment.overlap.conflicts",
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_fragment_multiple_tails,
{ "Message has multiple tail fragments",
"dtls.fragment.multiple_tails",
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_fragment_too_long_fragment,
{ "Message fragment too long", "dtls.fragment.too_long_fragment",
FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_fragment_error,
{ "Message defragmentation error", "dtls.fragment.error",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
{ &hf_dtls_reassembled_in,
{ "Reassembled in", "dtls.reassembled.in",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
};
/* Setup protocol subtree array */
@ -2100,6 +2251,8 @@ proto_register_dtls(void)
&ett_dtls_certs,
&ett_dtls_cert_types,
&ett_dtls_dnames,
&ett_dtls_fragment,
&ett_dtls_fragments,
};
/* Register the protocol name and description */

View File

@ -171,7 +171,8 @@ const value_string ssl_31_content_type[] = {
};
const value_string ssl_versions[] = {
{ 0x0100, "DTLS 1.0" },
{ 0xfeff, "DTLS 1.0" },
{ 0x0100, "DTLS 1.0 (OpenSSL pre 0.9.8f)" },
{ 0x0302, "TLS 1.1" },
{ 0x0301, "TLS 1.0" },
{ 0x0300, "SSL 3.0" },
@ -1764,7 +1765,8 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
worklen=worklen-decoder->cipher_suite->block;
memcpy(out_str->data,out_str->data+decoder->cipher_suite->block,worklen);
}
if(ssl->version_netorder==DTLSV1DOT0_VERSION){
if(ssl->version_netorder==DTLSV1DOT0_VERSION ||
ssl->version_netorder==DTLSV1DOT0_VERSION_NOT){
worklen=worklen-decoder->cipher_suite->block;
memcpy(out_str->data,out_str->data+decoder->cipher_suite->block,worklen);
}
@ -1783,8 +1785,10 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
return -1;
}
}
else if(ssl->version_netorder==DTLSV1DOT0_VERSION){
else if(ssl->version_netorder==DTLSV1DOT0_VERSION ||
ssl->version_netorder==DTLSV1DOT0_VERSION_NOT){
/* follow the openssl dtls errors the rigth test is : dtls_check_mac(decoder,ct,ssl->version_netorder,out,worklen,mac)< 0 */
/* if(dtls_check_mac(decoder,ct,ssl->version_netorder,out_str->data,worklen,mac)< 0) { */
if(tls_check_mac(decoder,ct,TLSV1_VERSION,out_str->data,worklen,mac)< 0) {
ssl_debug_printf("ssl_decrypt_record: mac failed\n");
return -1;

View File

@ -185,7 +185,8 @@ typedef struct _StringInfo {
#define SSLV3_VERSION 0x300
#define TLSV1_VERSION 0x301
#define TLSV1DOT1_VERSION 0x302
#define DTLSV1DOT0_VERSION 0x100
#define DTLSV1DOT0_VERSION 0xfeff
#define DTLSV1DOT0_VERSION_NOT 0x100
#define SSL_CLIENT_RANDOM 1
#define SSL_SERVER_RANDOM 2