diff options
author | Sake Blok <sake@euronet.nl> | 2007-11-05 23:05:20 +0000 |
---|---|---|
committer | Sake Blok <sake@euronet.nl> | 2007-11-05 23:05:20 +0000 |
commit | 3c9a7b9dcd476eb98cab0e416544091ae3fa80d4 (patch) | |
tree | f4392373dcb276c19e4a0268e9674e55aea9b1f3 /epan | |
parent | a6850bb34e3b6e73043d273af0c6ad691a08a3fb (diff) |
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
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-dtls.c | 193 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.c | 10 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.h | 3 |
3 files changed, 182 insertions, 24 deletions
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c index dd5e261ba6..3894f29816 100644 --- a/epan/dissectors/packet-dtls.c +++ b/epan/dissectors/packet-dtls.c @@ -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 */ diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c index 0626fce489..68057e9dd0 100644 --- a/epan/dissectors/packet-ssl-utils.c +++ b/epan/dissectors/packet-ssl-utils.c @@ -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; diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h index e6d45f4a93..cac2725450 100644 --- a/epan/dissectors/packet-ssl-utils.h +++ b/epan/dissectors/packet-ssl-utils.h @@ -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 |