From Naoyoshi Ueda:
[obnox/wireshark/wip.git] / epan / dissectors / packet-dtls.c
index 0f21bcd3abf636aa307a492c5858eb70ef65d26b..3ae3fd33c265bd10741d12eb0e7159857733b179 100644 (file)
  * See RFC 4347 for details about DTLS specs.
  *
  * Notes :
- * 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.
+ * This dissector is based on the TLS dissector (packet-ssl.c); Because of the similarity
+ *   of DTLS and TLS, decryption works like TLS with RSA key exchange.
+ * This dissector uses the sames things (file, libraries) as the SSL dissector (gnutls, packet-ssl-utils.h)
+ *  to make it easily maintainable.
  *
- * 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.
+ * It was developed to dissect and decrypt the OpenSSL v 0.9.8f DTLS implementation.
+ * It is limited to this implementation; there is no complete implementation.
  *
  * Implemented :
  *  - DTLS dissection
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-
 #include <glib.h>
 
+#include <epan/packet.h>
 #include <epan/conversation.h>
 #include <epan/prefs.h>
 #include <epan/asn1.h>
@@ -70,9 +61,6 @@
 #include <epan/emem.h>
 #include <epan/tap.h>
 #include <epan/reassemble.h>
-#ifdef NEED_INET_V6DEFS_H
-#include "wsutil/inet_v6defs.h"
-#endif
 #include "packet-ssl-utils.h"
 #include <wsutil/file_util.h>
 #include <epan/uat.h>
@@ -93,68 +81,68 @@ static proto_tree *top_tree;
  *********************************************************************/
 
 /* Initialize the protocol and registered fields */
-static gint dtls_tap                           = -1;
-static gint proto_dtls                         = -1;
-static gint hf_dtls_record                     = -1;
-static gint hf_dtls_record_content_type        = -1;
-static gint hf_dtls_record_version             = -1;
-static gint hf_dtls_record_epoch               = -1;
-static gint hf_dtls_record_sequence_number     = -1;
-static gint hf_dtls_record_length              = -1;
-static gint hf_dtls_record_appdata             = -1;
-static gint hf_dtls_change_cipher_spec         = -1;
-static gint hf_dtls_alert_message              = -1;
-static gint hf_dtls_alert_message_level        = -1;
-static gint hf_dtls_alert_message_description  = -1;
-static gint hf_dtls_handshake_protocol         = -1;
-static gint hf_dtls_handshake_type             = -1;
-static gint hf_dtls_handshake_length           = -1;
-static gint hf_dtls_handshake_message_seq      = -1;
-static gint hf_dtls_handshake_fragment_offset  = -1;
-static gint hf_dtls_handshake_fragment_length  = -1;
-static gint hf_dtls_handshake_client_version   = -1;
-static gint hf_dtls_handshake_server_version   = -1;
-static gint hf_dtls_handshake_random_time      = -1;
-static gint hf_dtls_handshake_random_bytes     = -1;
-static gint hf_dtls_handshake_cookie_len       = -1;
-static gint hf_dtls_handshake_cookie           = -1;
+static gint dtls_tap                            = -1;
+static gint proto_dtls                          = -1;
+static gint hf_dtls_record                      = -1;
+static gint hf_dtls_record_content_type         = -1;
+static gint hf_dtls_record_version              = -1;
+static gint hf_dtls_record_epoch                = -1;
+static gint hf_dtls_record_sequence_number      = -1;
+static gint hf_dtls_record_length               = -1;
+static gint hf_dtls_record_appdata              = -1;
+static gint hf_dtls_change_cipher_spec          = -1;
+static gint hf_dtls_alert_message               = -1;
+static gint hf_dtls_alert_message_level         = -1;
+static gint hf_dtls_alert_message_description   = -1;
+static gint hf_dtls_handshake_protocol          = -1;
+static gint hf_dtls_handshake_type              = -1;
+static gint hf_dtls_handshake_length            = -1;
+static gint hf_dtls_handshake_message_seq       = -1;
+static gint hf_dtls_handshake_fragment_offset   = -1;
+static gint hf_dtls_handshake_fragment_length   = -1;
+static gint hf_dtls_handshake_client_version    = -1;
+static gint hf_dtls_handshake_server_version    = -1;
+static gint hf_dtls_handshake_random_time       = -1;
+static gint hf_dtls_handshake_random_bytes      = -1;
+static gint hf_dtls_handshake_cookie_len        = -1;
+static gint hf_dtls_handshake_cookie            = -1;
 static gint hf_dtls_handshake_cipher_suites_len = -1;
-static gint hf_dtls_handshake_cipher_suites    = -1;
-static gint hf_dtls_handshake_cipher_suite     = -1;
-static gint hf_dtls_handshake_session_id       = -1;
-static gint hf_dtls_handshake_comp_methods_len = -1;
-static gint hf_dtls_handshake_comp_methods     = -1;
-static gint hf_dtls_handshake_comp_method      = -1;
-static gint hf_dtls_handshake_extensions_len   = -1;
-static gint hf_dtls_handshake_extension_type   = -1;
-static gint hf_dtls_handshake_extension_len    = -1;
-static gint hf_dtls_handshake_extension_data   = -1;
-static gint hf_dtls_handshake_certificates_len = -1;
-static gint hf_dtls_handshake_certificates     = -1;
-static gint hf_dtls_handshake_certificate      = -1;
-static gint hf_dtls_handshake_certificate_len  = -1;
-static gint hf_dtls_handshake_cert_types_count = -1;
-static gint hf_dtls_handshake_cert_types       = -1;
-static gint hf_dtls_handshake_cert_type        = -1;
-static gint hf_dtls_handshake_finished         = -1;
-static gint hf_dtls_handshake_md5_hash         = -1;
-static gint hf_dtls_handshake_sha_hash         = -1;
-static gint hf_dtls_handshake_session_id_len   = -1;
-static gint hf_dtls_handshake_dnames_len       = -1;
-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_fragment_count             = -1;
-static gint hf_dtls_reassembled_in             = -1;
-static gint hf_dtls_reassembled_length         = -1;
+static gint hf_dtls_handshake_cipher_suites     = -1;
+static gint hf_dtls_handshake_cipher_suite      = -1;
+static gint hf_dtls_handshake_session_id        = -1;
+static gint hf_dtls_handshake_comp_methods_len  = -1;
+static gint hf_dtls_handshake_comp_methods      = -1;
+static gint hf_dtls_handshake_comp_method       = -1;
+static gint hf_dtls_handshake_extensions_len    = -1;
+static gint hf_dtls_handshake_extension_type    = -1;
+static gint hf_dtls_handshake_extension_len     = -1;
+static gint hf_dtls_handshake_extension_data    = -1;
+static gint hf_dtls_handshake_certificates_len  = -1;
+static gint hf_dtls_handshake_certificates      = -1;
+static gint hf_dtls_handshake_certificate       = -1;
+static gint hf_dtls_handshake_certificate_len   = -1;
+static gint hf_dtls_handshake_cert_types_count  = -1;
+static gint hf_dtls_handshake_cert_types        = -1;
+static gint hf_dtls_handshake_cert_type         = -1;
+static gint hf_dtls_handshake_finished          = -1;
+static gint hf_dtls_handshake_md5_hash          = -1;
+static gint hf_dtls_handshake_sha_hash          = -1;
+static gint hf_dtls_handshake_session_id_len    = -1;
+static gint hf_dtls_handshake_dnames_len        = -1;
+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_fragment_count              = -1;
+static gint hf_dtls_reassembled_in              = -1;
+static gint hf_dtls_reassembled_length          = -1;
 
 /* Initialize the subtree pointers */
 static gint ett_dtls                   = -1;
@@ -171,21 +159,23 @@ 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 GTree* dtls_associations = NULL;
-static dissector_handle_t dtls_handle  = NULL;
-static StringInfo dtls_compressed_data = {NULL, 0};
-static StringInfo dtls_decrypted_data  = {NULL, 0};
-static gint dtls_decrypted_data_avail  = 0;
-
-static uat_t *dtlsdecrypt_uat = NULL;
-static gchar* dtls_keys_list = NULL;
+static GHashTable         *dtls_session_hash         = NULL;
+static GHashTable         *dtls_key_hash             = NULL;
+static GHashTable         *dtls_fragment_table       = NULL;
+static GTree*              dtls_associations         = NULL;
+static dissector_handle_t  dtls_handle               = NULL;
+static StringInfo          dtls_compressed_data      = {NULL, 0};
+static StringInfo          dtls_decrypted_data       = {NULL, 0};
+static gint                dtls_decrypted_data_avail = 0;
+
+static uat_t *dtlsdecrypt_uat      = NULL;
+static gchar *dtls_keys_list       = NULL;
 #ifdef HAVE_LIBGNUTLS
-static gchardtls_debug_file_name = NULL;
+static gchar *dtls_debug_file_name = NULL;
 #endif
 
+static heur_dissector_list_t heur_subdissector_list;
+
 static const fragment_items dtls_frag_items = {
   /* Fragment subtrees */
   &ett_dtls_fragment,
@@ -212,7 +202,7 @@ static void
 dtls_init(void)
 {
   module_t *dtls_module = prefs_find_module("dtls");
-  pref_t *keys_list_pref;
+  pref_t   *keys_list_pref;
 
   ssl_common_init(&dtls_session_hash, &dtls_decrypted_data, &dtls_compressed_data);
   fragment_table_init (&dtls_fragment_table);
@@ -228,19 +218,17 @@ dtls_init(void)
 
 /* parse dtls related preferences (private keys and ports association strings) */
 static void
-dtls_parse(void)
+dtls_parse_uat(void)
 {
-  ep_stack_t tmp_stack;
-  SslAssociation *tmp_assoc;
-  guint i;
-  gchar **old_keys, **parts, *err;
-  GString *uat_entry = g_string_new("");
+  ep_stack_t       tmp_stack;
+  SslAssociation  *tmp_assoc;
+  guint            i;
 
   if (dtls_key_hash)
-    {
+  {
       g_hash_table_foreach(dtls_key_hash, ssl_private_key_free, NULL);
       g_hash_table_destroy(dtls_key_hash);
-    }
+  }
 
   /* remove only associations created from key list */
   tmp_stack = ep_stack_new();
@@ -249,18 +237,43 @@ dtls_parse(void)
     ssl_association_remove(dtls_associations, tmp_assoc);
   }
 
+  /* parse private keys string, load available keys and put them in key hash*/
+  dtls_key_hash = g_hash_table_new(ssl_private_key_hash, ssl_private_key_equal);
+
+  ssl_set_debug(dtls_debug_file_name);
+
+  if (ndtlsdecrypt > 0)
+  {
+    for (i = 0; i < ndtlsdecrypt; i++)
+    {
+      ssldecrypt_assoc_t *d = &(dtlskeylist_uats[i]);
+      ssl_parse_key_list(d, dtls_key_hash, dtls_associations, dtls_handle, FALSE);
+    }
+  }
+
+  dissector_add_handle("sctp.port", dtls_handle);
+  dissector_add_handle("udp.port", dtls_handle);
+}
+
+static void
+dtls_parse_old_keys(void)
+{
+  gchar          **old_keys, **parts, *err;
+  guint            i;
+  GString         *uat_entry = g_string_new("");
+
   /* Import old-style keys */
   if (dtlsdecrypt_uat && dtls_keys_list && dtls_keys_list[0]) {
     old_keys = g_strsplit(dtls_keys_list, ";", 0);
     for (i = 0; old_keys[i] != NULL; i++) {
       parts = g_strsplit(old_keys[i], ",", 4);
       if (parts[0] && parts[1] && parts[2] && parts[3]) {
-       g_string_printf(uat_entry, "\"%s\",\"%s\",\"%s\",\"%s\",\"\"",
-                       parts[0], parts[1], parts[2], parts[3]);
-       if (!uat_load_str(dtlsdecrypt_uat, uat_entry->str, &err)) {
-         ssl_debug_printf("dtls_parse: Can't load UAT string %s: %s\n",
+        g_string_printf(uat_entry, "\"%s\",\"%s\",\"%s\",\"%s\",\"\"",
+                        parts[0], parts[1], parts[2], parts[3]);
+        if (!uat_load_str(dtlsdecrypt_uat, uat_entry->str, &err)) {
+          ssl_debug_printf("dtls_parse: Can't load UAT string %s: %s\n",
                            uat_entry->str, err);
-       }
+        }
       }
       g_strfreev(parts);
     }
@@ -268,23 +281,6 @@ dtls_parse(void)
   }
   g_string_free(uat_entry, TRUE);
 
-
-  /* parse private keys string, load available keys and put them in key hash*/
-  dtls_key_hash = g_hash_table_new(ssl_private_key_hash, ssl_private_key_equal);
-
-  if (ndtlsdecrypt > 0)
-  {
-         for (i = 0; i < ndtlsdecrypt; i++)
-         {
-                 ssldecrypt_assoc_t *d = &(dtlskeylist_uats[i]);
-                 ssl_parse_key_list(d, dtls_key_hash, dtls_associations, dtls_handle, FALSE);
-         }
-  }
-
-  ssl_set_debug(dtls_debug_file_name);
-
-  dissector_add_handle("sctp.port", dtls_handle);
-  dissector_add_handle("udp.port", dtls_handle);
 }
 
 /*
@@ -322,12 +318,12 @@ static void dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
                                        guint32 offset, guint32 length,
                                        SslDecryptSession* ssl);
 
-static void dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb,
+static int dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb,
                                                   proto_tree *tree,
                                                   guint32 offset,
                                                   SslDecryptSession* ssl);
 
-static void dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
+static int dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
                                        proto_tree *tree,
                                        guint32 offset, guint32 length,
                                        SslDecryptSession* ssl);
@@ -367,20 +363,22 @@ static void
 dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
 
-  conversation_t *conversation;
-  void *conv_data;
-  proto_item *ti;
-  proto_tree *dtls_tree;
-  guint32 offset;
-  gboolean first_record_in_frame;
-  SslDecryptSession* ssl_session;
-  guint* conv_version;
-  ti = NULL;
-  dtls_tree = NULL;
-  offset = 0;
+  conversation_t    *conversation;
+  void              *conv_data;
+  proto_item        *ti;
+  proto_tree        *dtls_tree;
+  guint32            offset;
+  gboolean           first_record_in_frame;
+  SslDecryptSession *ssl_session;
+  guint*             conv_version;
+  Ssl_private_key_t *private_key;
+
+  ti                    = NULL;
+  dtls_tree             = NULL;
+  offset                = 0;
   first_record_in_frame = TRUE;
-  ssl_session = NULL;
-  top_tree=tree;
+  ssl_session           = NULL;
+  top_tree              = tree;
 
   /* Track the version using conversations allows
    * us to more frequently set the protocol column properly
@@ -393,7 +391,7 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
    *       in addition to conv_version
    */
   conversation = find_or_create_conversation(pinfo);
-  conv_data = conversation_get_proto_data(conversation, proto_dtls);
+  conv_data    = conversation_get_proto_data(conversation, proto_dtls);
 
   /* manage dtls decryption data */
   /*get a valid ssl session pointer*/
@@ -423,16 +421,19 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
      * is not always available
      * Note that with HAVE_LIBGNUTLS undefined private_key is allways 0
      * and thus decryption never engaged*/
-    ssl_session->private_key = g_hash_table_lookup(dtls_key_hash, &dummy);
-    if (!ssl_session->private_key)
+    private_key = g_hash_table_lookup(dtls_key_hash, &dummy);
+    if (!private_key) {
       ssl_debug_printf("dissect_dtls can't find private key for this server!\n");
+    }
+    else {
+      ssl_session->private_key = private_key->sexp_pkey;
+    }
   }
   conv_version= & ssl_session->version;
 
   /* try decryption only the first time we see this packet
-   * (to keep cipher synchronized)and only if we have
-   * the server private key*/
-  if (!ssl_session->private_key || pinfo->fd->flags.visited)
+   * (to keep cipher synchronized) */
+  if (pinfo->fd->flags.visited)
     ssl_session = NULL;
 
   /* Initialize the protocol column; we'll set it later when we
@@ -446,7 +447,7 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   /* Create display subtree for SSL as a whole */
   if (tree)
     {
-      ti = proto_tree_add_item(tree, proto_dtls, tvb, 0, -1, FALSE);
+      ti = proto_tree_add_item(tree, proto_dtls, tvb, 0, -1, ENC_NA);
       dtls_tree = proto_item_add_subtree(ti, ett_dtls);
     }
 
@@ -504,20 +505,76 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   tap_queue_packet(dtls_tap, pinfo, NULL);
 }
 
+static gboolean
+dissect_dtls_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  /* Stronger confirmation of DTLS packet is provided by verifying the
+   * payload length against the remainder of the UDP packet size. */
+  guint length = tvb_length(tvb);
+  guint offset = 0;
+
+  if (tvb_reported_length(tvb) == length) {
+    while (offset + 13 <= length && looks_like_dtls(tvb, offset)) {
+      /* Advance offset to the end of the current DTLS record */
+      offset += tvb_get_ntohs(tvb, offset + 11) + 13;
+      if (offset == length) {
+        dissect_dtls(tvb, pinfo, tree);
+        return TRUE;
+      }
+    }
+
+    if (pinfo->fragmented && offset >= 13) {
+      dissect_dtls(tvb, pinfo, tree);
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /* We've got a truncated packet - do our best with what we've got. */
+  while (tvb_length_remaining(tvb, offset) >= 3) {
+    if (!looks_like_dtls(tvb, offset))
+      return FALSE;
+
+    offset += 3;
+    if (tvb_length_remaining(tvb, offset) >= 10 ) {
+      offset += tvb_get_ntohs(tvb, offset + 8) + 10;
+    } else {
+      /* Dissect what we've got, which might be as little as 3 bytes. */
+      dissect_dtls(tvb, pinfo, tree);
+      return TRUE;
+    }
+    if (offset == length) {
+      /* Can this ever happen?  Well, just in case ... */
+      dissect_dtls(tvb, pinfo, tree);
+      return TRUE;
+    }
+  }
+
+  /* One last check to see if the current offset is at least less than the
+   * original number of bytes present before truncation or we're dealing with
+   * a packet fragment that's also been truncated. */
+  if ((length >= 3) && (offset <= tvb_reported_length(tvb) || pinfo->fragmented)) {
+    dissect_dtls(tvb, pinfo, tree);
+    return TRUE;
+  }
+  return FALSE;
+}
+
 static gint
 decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
                     guint32 record_length, guint8 content_type, SslDecryptSession* ssl,
                     gboolean save_plaintext)
 {
-  gint ret;
-  SslDecoder* decoder;
+  gint        ret;
+  SslDecoder *decoder;
+
   ret = 0;
 
   /* if we can decrypt and decryption have success
    * add decrypted data to this packet info */
   ssl_debug_printf("decrypt_dtls_record: app_data len %d, ssl state %X\n",
                    record_length, ssl->state);
-  if (!(ssl->state & SSL_HAVE_SESSION_KEY)) {
+  if (!ssl || (!save_plaintext && !(ssl->state & SSL_HAVE_SESSION_KEY))) {
     ssl_debug_printf("decrypt_dtls_record: no session key\n");
     return ret;
   }
@@ -532,6 +589,11 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
     decoder = ssl->client;
   }
 
+  if (!decoder) {
+    ssl_debug_printf("decrypt_dtls_record: no decoder available\n");
+    return ret;
+  }
+
   /* ensure we have enough storage space for decrypted data */
   if (record_length > dtls_decrypted_data.data_len)
     {
@@ -546,14 +608,22 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
   /* run decryption and add decrypted payload to protocol data, if decryption
    * is successful*/
   dtls_decrypted_data_avail = dtls_decrypted_data.data_len;
-  if (ssl_decrypt_record(ssl, decoder,
-                         content_type, tvb_get_ptr(tvb, offset, record_length),
-                         record_length, &dtls_compressed_data, &dtls_decrypted_data, &dtls_decrypted_data_avail) == 0)
+  if (ssl->state & SSL_HAVE_SESSION_KEY) {
+    if (ssl_decrypt_record(ssl, decoder, content_type, tvb_get_ptr(tvb, offset, record_length), record_length,
+                           &dtls_compressed_data, &dtls_decrypted_data, &dtls_decrypted_data_avail) == 0)
+      ret = 1;
+  }
+  else if (ssl->cipher == 0x0001 || ssl->cipher == 0x0002) {
+    /* Non-encrypting cipher RSA-NULL-MD5 or RSA-NULL-SHA */
+    memcpy(dtls_decrypted_data.data, tvb_get_ptr(tvb, offset, record_length), record_length);
+    dtls_decrypted_data_avail = dtls_decrypted_data.data_len = record_length;
     ret = 1;
+  }
 
-    if (ret && save_plaintext) {
-      ssl_add_data_info(proto_dtls, pinfo, dtls_decrypted_data.data, dtls_decrypted_data_avail,  TVB_RAW_OFFSET(tvb)+offset, 0);
-    }
+  if (ret && save_plaintext) {
+    ssl_add_data_info(proto_dtls, pinfo, dtls_decrypted_data.data, dtls_decrypted_data_avail,
+                      tvb_raw_offset(tvb)+offset, 0);
+  }
 
   return ret;
 }
@@ -588,39 +658,39 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
    *    struct {
    *        ContentType type;
    *        ProtocolVersion version;
-   *       uint16 epoch;               // New field
-   *       uint48 sequence_number;       // New field
+   *        uint16 epoch;               // New field
+   *        uint48 sequence_number;     // New field
    *        uint16 length;
    *        opaque fragment[TLSPlaintext.length];
    *    } DTLSPlaintext;
    */
-  guint32 record_length;
-  guint16 version;
-  guint16 epoch;
-  gdouble sequence_number;
-  gint64 sequence_number_temp;
-  guint8 content_type;
-  guint8 next_byte;
-  proto_tree *ti;
-  proto_tree *dtls_record_tree;
-  guint32 available_bytes;
-  SslAssociation* association;
-  SslDataInfo *appl_data;
-  ti              = NULL;
+
+  guint32         record_length;
+  guint16         version;
+  guint16         epoch;
+  gdouble         sequence_number;
+  gint64          sequence_number_temp;
+  guint8          content_type;
+  guint8          next_byte;
+  proto_tree     *ti;
+  proto_tree     *dtls_record_tree;
+  SslAssociation *association;
+  SslDataInfo    *appl_data;
+
+  ti               = NULL;
   dtls_record_tree = NULL;
-  available_bytes = tvb_length_remaining(tvb, offset);
 
   /*
    * Get the record layer fields of interest
    */
-  content_type  = tvb_get_guint8(tvb, offset);
-  version       = tvb_get_ntohs(tvb, offset + 1);
-  epoch       = tvb_get_ntohs(tvb, offset + 3);
-  sequence_number  = tvb_get_ntohl(tvb, offset + 7);
-  sequence_number_temp=tvb_get_ntohs(tvb, offset + 5);
-  sequence_number_temp=sequence_number_temp<<32;
-  sequence_number+=sequence_number_temp;
-  record_length = tvb_get_ntohs(tvb, offset + 11);
+  content_type          = tvb_get_guint8(tvb, offset);
+  version               = tvb_get_ntohs(tvb, offset + 1);
+  epoch                 = tvb_get_ntohs(tvb, offset + 3);
+  sequence_number       = tvb_get_ntohl(tvb, offset + 7);
+  sequence_number_temp  = tvb_get_ntohs(tvb, offset + 5);
+  sequence_number_temp  = sequence_number_temp<<32;
+  sequence_number      += sequence_number_temp;
+  record_length         = tvb_get_ntohs(tvb, offset + 11);
 
   if(ssl){
     if(ssl_packet_from_server(ssl, dtls_associations, pinfo)){
@@ -657,7 +727,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
       /* add the record layer subtree header */
       tvb_ensure_bytes_exist(tvb, offset, 13 + record_length);
       ti = proto_tree_add_item(tree, hf_dtls_record, tvb,
-                               offset, 13 + record_length, 0);
+                               offset, 13 + record_length, ENC_NA);
       dtls_record_tree = proto_item_add_subtree(ti, ett_dtls_record);
     }
 
@@ -666,12 +736,12 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
 
       /* show the one-byte content type */
       proto_tree_add_item(dtls_record_tree, hf_dtls_record_content_type,
-                          tvb, offset, 1, FALSE);
+                          tvb, offset, 1, ENC_BIG_ENDIAN);
       offset++;
 
       /* add the version */
       proto_tree_add_item(dtls_record_tree, hf_dtls_record_version, tvb,
-                          offset, 2, FALSE);
+                          offset, 2, ENC_BIG_ENDIAN);
       offset += 2;
 
       /* show epoch */
@@ -746,6 +816,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
     col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
     dissect_dtls_change_cipher_spec(tvb, dtls_record_tree,
                                     offset, conv_version, content_type);
+    if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl, dtls_associations, pinfo));
     break;
   case SSL_ID_ALERT:
     {
@@ -757,13 +828,15 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
                             dtls_decrypted_data_avail, offset);
 
       /* try to retrive and use decrypted alert record, if any. */
-      decrypted = ssl_get_record_info(proto_dtls, pinfo, offset);
-      if (decrypted)
+      decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, offset);
+      if (decrypted) {
         dissect_dtls_alert(decrypted, pinfo, dtls_record_tree, 0,
                            conv_version);
-      else
+        add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
+      } else {
         dissect_dtls_alert(tvb, pinfo, dtls_record_tree, offset,
                            conv_version);
+      }
       break;
     }
   case SSL_ID_HANDSHAKE:
@@ -780,13 +853,15 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
                             dtls_decrypted_data_avail, offset);
 
       /* try to retrive and use decrypted handshake record, if any. */
-      decrypted = ssl_get_record_info(proto_dtls, pinfo, offset);
-      if (decrypted)
+      decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, offset);
+      if (decrypted) {
         dissect_dtls_handshake(decrypted, pinfo, dtls_record_tree, 0,
-                               decrypted->length, conv_version, ssl, content_type);
-      else
+                               tvb_length(decrypted), conv_version, ssl, content_type);
+        add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
+      } else {
         dissect_dtls_handshake(tvb, pinfo, dtls_record_tree, offset,
                                record_length, conv_version, ssl, content_type);
+      }
       break;
     }
   case SSL_ID_APP_DATA:
@@ -804,7 +879,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
      * ssl session pointer is NULL at that time, so we can't access
      * info cached there*/
     association = ssl_association_find(dtls_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
-    association = association ? association: ssl_association_find(dtls_associations, pinfo->destport, pinfo->ptype == PT_TCP);
+    association = association ? association : ssl_association_find(dtls_associations, pinfo->destport, pinfo->ptype == PT_TCP);
 
     proto_item_set_text(dtls_record_tree,
                         "%s Record Layer: %s Protocol: %s",
@@ -812,20 +887,21 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
                         val_to_str(content_type, ssl_31_content_type, "unknown"),
                         association?association->info:"Application Data");
 
-    proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb,
-                        offset, record_length, 0);
-
     /* show decrypted data info, if available */
-    appl_data = ssl_get_data_info(proto_dtls, pinfo, TVB_RAW_OFFSET(tvb)+offset);
+    appl_data = ssl_get_data_info(proto_dtls, pinfo, tvb_raw_offset(tvb)+offset);
     if (appl_data && (appl_data->plain_data.data_len > 0))
       {
         tvbuff_t *next_tvb;
+        gboolean  dissected;
         /* try to dissect decrypted data*/
         ssl_debug_printf("dissect_dtls_record decrypted len %d\n",
                          appl_data->plain_data.data_len);
 
         /* create a new TVB structure for desegmented data */
-        next_tvb = tvb_new_child_real_data(tvb, appl_data->plain_data.data, appl_data->plain_data.data_len, appl_data->plain_data.data_len);
+        next_tvb = tvb_new_child_real_data(tvb,
+                                           appl_data->plain_data.data,
+                                           appl_data->plain_data.data_len,
+                                           appl_data->plain_data.data_len);
 
         add_new_data_source(pinfo, next_tvb, "Decrypted DTLS data");
 
@@ -834,9 +910,18 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
           ssl_debug_printf("dissect_dtls_record found association %p\n", (void *)association);
           ssl_print_text_data("decrypted app data",appl_data->plain_data.data, appl_data->plain_data.data_len);
 
-          call_dissector(association->handle, next_tvb, pinfo, top_tree);
+          dissected = call_dissector_only(association->handle, next_tvb, pinfo, top_tree);
+        }
+        else {
+          /* try heuristic subdissectors */
+          dissected = dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, top_tree);
         }
+        if (dissected)
+          break;
       }
+
+    proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb,
+                        offset, record_length, ENC_NA);
     break;
 
   default:
@@ -868,7 +953,7 @@ dissect_dtls_change_cipher_spec(tvbuff_t *tvb,
                           val_to_str_const(*conv_version, ssl_version_short_names, "SSL"),
                           val_to_str(content_type, ssl_31_content_type, "unknown"));
       proto_tree_add_item(tree, hf_dtls_change_cipher_spec, tvb,
-                          offset++, 1, FALSE);
+                          offset, 1, ENC_NA);
     }
 }
 
@@ -883,17 +968,19 @@ dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
    *         AlertDescription description;
    *     } Alert;
    */
-  proto_tree *ti;
-  proto_tree *ssl_alert_tree;
+
+  proto_tree  *ti;
+  proto_tree  *ssl_alert_tree;
   const gchar *level;
   const gchar *desc;
-  guint8 byte;
+  guint8       byte;
+
   ssl_alert_tree = NULL;
 
   if (tree)
     {
       ti = proto_tree_add_item(tree, hf_dtls_alert_message, tvb,
-                               offset, 2, 0);
+                               offset, 2, ENC_NA);
       ssl_alert_tree = proto_item_add_subtree(ti, ett_dtls_alert);
     }
 
@@ -902,11 +989,11 @@ dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
    */
 
   /* first lookup the names for the alert level and description */
-  byte = tvb_get_guint8(tvb, offset); /* grab the level byte */
+  byte  = tvb_get_guint8(tvb, offset); /* grab the level byte */
   level = match_strval(byte, ssl_31_alert_level);
 
-  byte = tvb_get_guint8(tvb, offset+1); /* grab the desc byte */
-  desc = match_strval(byte, ssl_31_alert_description);
+  byte  = tvb_get_guint8(tvb, offset+1); /* grab the desc byte */
+  desc  = match_strval(byte, ssl_31_alert_description);
 
   /* now set the text in the record layer line */
   if (level && desc)
@@ -930,10 +1017,10 @@ dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
                               val_to_str_const(*conv_version, ssl_version_short_names, "SSL"),
                               level, desc);
           proto_tree_add_item(ssl_alert_tree, hf_dtls_alert_message_level,
-                              tvb, offset++, 1, FALSE);
+                              tvb, offset++, 1, ENC_BIG_ENDIAN);
 
           proto_tree_add_item(ssl_alert_tree, hf_dtls_alert_message_description,
-                              tvb, offset++, 1, FALSE);
+                              tvb, offset, 1, ENC_BIG_ENDIAN);
         }
       else
         {
@@ -958,8 +1045,8 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
    *         HandshakeType msg_type;
    *         uint24 length;
    *         uint16 message_seq;          //new field
-   *         uint24 fragment_offset;       //new field
-   *         uint24 fragment_length;        //new field
+   *         uint24 fragment_offset;      //new field
+   *         uint24 fragment_length;      //new field
    *         select (HandshakeType) {
    *             case hello_request:       HelloRequest;
    *             case client_hello:        ClientHello;
@@ -975,19 +1062,21 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
    *         } body;
    *     } Handshake;
    */
-  proto_tree *ti;
-  proto_tree *ssl_hand_tree;
+
+  proto_tree  *ti;
+  proto_tree  *ssl_hand_tree;
   const gchar *msg_type_str;
-  guint8 msg_type;
-  guint32 length;
-  guint16 message_seq;
-  guint32 fragment_offset;
-  guint32 fragment_length;
-  gboolean first_iteration;
-  ti               = NULL;
-  ssl_hand_tree    = NULL;
-  msg_type_str     = NULL;
-  first_iteration  = TRUE;
+  guint8       msg_type;
+  guint32      length;
+  guint16      message_seq;
+  guint32      fragment_offset;
+  guint32      fragment_length;
+  gboolean     first_iteration;
+
+  ti              = NULL;
+  ssl_hand_tree   = NULL;
+  msg_type_str    = NULL;
+  first_iteration = TRUE;
 
   /* just as there can be multiple records per packet, there
    * can be multiple messages per record as long as they have
@@ -1002,17 +1091,17 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
          first_iteration = FALSE) /* set up for next pass, if any */
     {
       fragment_data *frag_msg = NULL;
-      tvbuff_t *new_tvb = NULL;
-      const 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);
+      tvbuff_t      *new_tvb  = NULL;
+      const 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;
+      fragmented      = fragment_length != length;
 
       if (!msg_type_str && !first_iteration)
         {
@@ -1065,8 +1154,8 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
             /* Fragmented handshake message */
             pinfo->fragmented = TRUE;
 
-           /* Don't pass the reassembly code data that doesn't exist */
-           tvb_ensure_bytes_exist(tvb, fragment_offset, fragment_length);
+            /* Don't pass the reassembly code data that doesn't exist */
+            tvb_ensure_bytes_exist(tvb, offset, fragment_length);
 
             frag_msg = fragment_add(tvb, offset+12, pinfo, message_seq,
                                     dtls_fragment_table,
@@ -1117,7 +1206,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
 
           /* add a subtree for the handshake protocol */
           ti = proto_tree_add_item(tree, hf_dtls_handshake_protocol, tvb,
-                                   offset, fragment_length + 12, 0);
+                                   offset, fragment_length + 12, ENC_NA);
           ssl_hand_tree = proto_item_add_subtree(ti, ett_dtls_handshake);
 
           if (ssl_hand_tree)
@@ -1141,7 +1230,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
 
           /* add nodes for the message type and message length */
           if (ssl_hand_tree)
-            proto_tree_add_item(ssl_hand_tree, hf_dtls_handshake_type,
+            proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_type,
                                 tvb, offset, 1, msg_type);
           offset++;
           if (ssl_hand_tree)
@@ -1237,6 +1326,18 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
                 break;
               }
 
+              /* Skip leading two bytes length field. Older openssl's DTLS implementation seems not to have this field.
+               * See implementation note in RFC 4346 section 7.4.7.1
+               */
+              if (ssl->cipher_suite.kex==KEX_RSA && ssl->version_netorder != DTLSV1DOT0_VERSION_NOT) {
+                encrlen = tvb_get_ntohs(tvb, offset);
+                skip = 2;
+                if (encrlen > length - 2) {
+                  ssl_debug_printf("dissect_dtls_handshake wrong encrypted length (%d max %d)\n", encrlen, length);
+                  break;
+                }
+              }
+
               encrypted_pre_master.data = se_alloc(encrlen);
               encrypted_pre_master.data_len = encrlen;
               tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen);
@@ -1282,82 +1383,86 @@ dissect_dtls_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
 {
   /* show the client's random challenge */
   nstime_t gmt_unix_time;
-  guint8  session_id_length;
-  session_id_length = 0;
-  if (ssl)
-    {
-      /* get proper peer information*/
-      StringInfo* rnd;
-      if (from_server)
-        rnd = &ssl->server_random;
-      else
-        rnd = &ssl->client_random;
+  guint8   session_id_length;
 
-      /* get provided random for keyring generation*/
-      tvb_memcpy(tvb, rnd->data, offset, 32);
-      rnd->data_len = 32;
-      if (from_server)
-        ssl->state |= SSL_SERVER_RANDOM;
-      else
-        ssl->state |= SSL_CLIENT_RANDOM;
-      ssl_debug_printf("dissect_dtls_hnd_hello_common found random state %X\n",
-                       ssl->state);
-
-      session_id_length = tvb_get_guint8(tvb, offset + 32);
-      /* check stored session id info */
-      if (from_server && (session_id_length == ssl->session_id.data_len) &&
-          (tvb_memeql(tvb, offset+33, ssl->session_id.data, session_id_length) == 0))
-        {
-          /* clinet/server id match: try to restore a previous cached session*/
-          ssl_restore_session(ssl, dtls_session_hash);
+  if (tree || ssl)
+    {
+         if (ssl)
+               {
+                 /* get proper peer information*/
+                 StringInfo* rnd;
+                 if (from_server)
+                       rnd = &ssl->server_random;
+                 else
+                       rnd = &ssl->client_random;
+
+                 /* get provided random for keyring generation*/
+                 tvb_memcpy(tvb, rnd->data, offset, 32);
+                 rnd->data_len = 32;
+                 if (from_server)
+                       ssl->state |= SSL_SERVER_RANDOM;
+                 else
+                       ssl->state |= SSL_CLIENT_RANDOM;
+                 ssl_debug_printf("dissect_dtls_hnd_hello_common found random state %X\n",
+                                                  ssl->state);
         }
-      else {
-        tvb_memcpy(tvb,ssl->session_id.data, offset+33, session_id_length);
-        ssl->session_id.data_len = session_id_length;
-      }
-    }
 
-  if (tree)
-    {
       /* show the time */
-      gmt_unix_time.secs = tvb_get_ntohl(tvb, offset);
-      gmt_unix_time.nsecs = 0;
-      proto_tree_add_time(tree, hf_dtls_handshake_random_time,
-                          tvb, offset, 4, &gmt_unix_time);
+      if (tree)
+        {
+          gmt_unix_time.secs  = tvb_get_ntohl(tvb, offset);
+          gmt_unix_time.nsecs = 0;
+          proto_tree_add_time(tree, hf_dtls_handshake_random_time,
+                              tvb, offset, 4, &gmt_unix_time);
+        }
       offset += 4;
 
       /* show the random bytes */
-      proto_tree_add_item(tree, hf_dtls_handshake_random_bytes,
-                          tvb, offset, 28, 0);
+      if (tree)
+          proto_tree_add_item(tree, hf_dtls_handshake_random_bytes,
+                              tvb, offset, 28, ENC_NA);
       offset += 28;
 
       /* show the session id */
       session_id_length = tvb_get_guint8(tvb, offset);
-      proto_tree_add_item(tree, hf_dtls_handshake_session_id_len,
-                          tvb, offset++, 1, 0);
-      if (session_id_length > 0)
+      if (tree)
+          proto_tree_add_item(tree, hf_dtls_handshake_session_id_len,
+                              tvb, offset, 1, ENC_BIG_ENDIAN);
+         offset++;
+      if (ssl)
         {
-          proto_tree_add_bytes_format(tree, hf_dtls_handshake_session_id,
-                                      tvb, offset, session_id_length,
-                                      NULL, "Session ID (%u byte%s)",
-                                      session_id_length,
-                                      plurality(session_id_length, "", "s"));
-          offset += session_id_length;
+          /* check stored session id info */
+          if (from_server && (session_id_length == ssl->session_id.data_len) &&
+              (tvb_memeql(tvb, offset, ssl->session_id.data, session_id_length) == 0))
+            {
+              /* clinet/server id match: try to restore a previous cached session*/
+              ssl_restore_session(ssl, dtls_session_hash);
+            }
+          else {
+            tvb_memcpy(tvb,ssl->session_id.data, offset, session_id_length);
+            ssl->session_id.data_len = session_id_length;
+          }
         }
-
+         if (tree && session_id_length > 0)
+                 proto_tree_add_bytes_format(tree, hf_dtls_handshake_session_id,
+                                                                         tvb, offset, session_id_length,
+                                                                         NULL, "Session ID (%u byte%s)",
+                                                                         session_id_length,
+                                                                         plurality(session_id_length, "", "s"));
+         offset += session_id_length;
     }
 
   /* XXXX */
-  return session_id_length+33;
+  return offset;
 }
 
 static gint
 dissect_dtls_hnd_hello_ext(tvbuff_t *tvb,
                            proto_tree *tree, guint32 offset, guint32 left)
 {
-  guint16 extension_length;
-  guint16 ext_type;
-  guint16 ext_len;
+  guint16     extension_length;
+  guint16     ext_type;
+  guint16     ext_len;
   proto_item *pi;
   proto_tree *ext_tree;
 
@@ -1368,12 +1473,12 @@ dissect_dtls_hnd_hello_ext(tvbuff_t *tvb,
   proto_tree_add_uint(tree, hf_dtls_handshake_extensions_len,
                       tvb, offset, 2, extension_length);
   offset += 2;
-  left -= 2;
+  left   -= 2;
 
   while (left >= 4)
     {
       ext_type = tvb_get_ntohs(tvb, offset);
-      ext_len = tvb_get_ntohs(tvb, offset + 2);
+      ext_len  = tvb_get_ntohs(tvb, offset + 2);
 
       pi = proto_tree_add_text(tree, tvb, offset, 4 + ext_len,
                                "Extension: %s",
@@ -1395,9 +1500,9 @@ dissect_dtls_hnd_hello_ext(tvbuff_t *tvb,
       proto_tree_add_bytes_format(ext_tree, hf_dtls_handshake_extension_data,
                                   tvb, offset, ext_len, NULL,
                                   "Data (%u byte%s)", ext_len,
-                                 plurality(ext_len, "", "s"));
+                                  plurality(ext_len, "", "s"));
       offset += ext_len;
-      left -= 2 + 2 + ext_len;
+      left   -= 2 + 2 + ext_len;
     }
 
   return offset;
@@ -1419,27 +1524,25 @@ dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
    * } ClientHello;
    *
    */
+
   proto_tree *ti;
   proto_tree *cs_tree;
-  guint16 cipher_suite_length;
-  guint8  compression_methods_length;
-  guint8  compression_method;
-  guint16 start_offset = offset;
-  guint8 cookie_length;
-  cipher_suite_length = 0;
-  compression_methods_length = 0;
-  cookie_length = 0;
+  guint16     cipher_suite_length;
+  guint8      compression_methods_length;
+  guint8      compression_method;
+  guint16     start_offset   = offset;
+  guint8      cookie_length;
 
   if (tree || ssl)
     {
       /* show the client version */
       if (tree)
         proto_tree_add_item(tree, hf_dtls_handshake_client_version, tvb,
-                            offset, 2, FALSE);
+                            offset, 2, ENC_BIG_ENDIAN);
       offset += 2;
 
       /* show the fields in common with server hello */
-      offset += dissect_dtls_hnd_hello_common(tvb, tree, offset, ssl, 0);
+      offset = dissect_dtls_hnd_hello_common(tvb, tree, offset, ssl, 0);
 
       /* look for a cookie */
       cookie_length = tvb_get_guint8(tvb, offset);
@@ -1487,7 +1590,7 @@ dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
           while (cipher_suite_length > 0)
             {
               proto_tree_add_item(cs_tree, hf_dtls_handshake_cipher_suite,
-                                  tvb, offset, 2, FALSE);
+                                  tvb, offset, 2, ENC_BIG_ENDIAN);
               offset += 2;
               cipher_suite_length -= 2;
             }
@@ -1538,7 +1641,7 @@ dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
 
       if (length > offset - start_offset)
         {
-          offset = dissect_dtls_hnd_hello_ext(tvb, tree, offset,
+          dissect_dtls_hnd_hello_ext(tvb, tree, offset,
                                               length -
                                               (offset - start_offset));
         }
@@ -1546,9 +1649,9 @@ dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
 }
 
 
-static void
+static int
 dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb, proto_tree *tree,
-                                     guint32 offset, SslDecryptSession* ssl)
+                                      guint32 offset, SslDecryptSession* ssl)
 {
   /*
    * struct {
@@ -1558,21 +1661,21 @@ dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb, proto_tree *tree,
    */
 
   guint8 cookie_length;
-  cookie_length = 0;
+
 
   if (tree || ssl)
     {
       /* show the client version */
       if (tree)
         proto_tree_add_item(tree, hf_dtls_handshake_server_version, tvb,
-                            offset, 2, FALSE);
+                            offset, 2, ENC_BIG_ENDIAN);
       offset += 2;
 
 
       /* look for a cookie */
       cookie_length = tvb_get_guint8(tvb, offset);
       if (!tree)
-        return;
+        return offset;
 
       proto_tree_add_uint(tree, hf_dtls_handshake_cookie_len,
                           tvb, offset, 1, cookie_length);
@@ -1588,10 +1691,10 @@ dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb, proto_tree *tree,
           offset += cookie_length;
         }
     }
-
+    return offset;
 }
 
-static void
+static int
 dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
                            proto_tree *tree, guint32 offset, guint32 length, SslDecryptSession* ssl)
 {
@@ -1604,7 +1707,9 @@ dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
    *     Extension server_hello_extension_list<0..2^16-1>;
    * } ServerHello;
    */
+
   guint16 start_offset;
+
   start_offset = offset;
 
   if (tree || ssl)
@@ -1612,13 +1717,13 @@ dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
       /* show the server version */
       if (tree)
         proto_tree_add_item(tree, hf_dtls_handshake_server_version, tvb,
-                            offset, 2, FALSE);
+                            offset, 2, ENC_BIG_ENDIAN);
       offset += 2;
 
       /* first display the elements conveniently in
        * common with client hello
        */
-      offset += dissect_dtls_hnd_hello_common(tvb, tree, offset, ssl, 1);
+      offset = dissect_dtls_hnd_hello_common(tvb, tree, offset, ssl, 1);
 
       /* PAOLO: handle session cipher suite  */
       if (ssl) {
@@ -1651,17 +1756,21 @@ dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
         ssl->state |= SSL_HAVE_SESSION_KEY;
       }
     no_cipher:
+      if (ssl) {
+        /* store selected compression method for decompression */
+        ssl->compression = tvb_get_guint8(tvb, offset+2);
+      }
       if (!tree)
-        return;
+        return offset;
 
       /* now the server-selected cipher suite */
       proto_tree_add_item(tree, hf_dtls_handshake_cipher_suite,
-                          tvb, offset, 2, FALSE);
+                          tvb, offset, 2, ENC_BIG_ENDIAN);
       offset += 2;
 
       /* and the server-selected compression method */
       proto_tree_add_item(tree, hf_dtls_handshake_comp_method,
-                          tvb, offset, 1, FALSE);
+                          tvb, offset, 1, ENC_BIG_ENDIAN);
       offset++;
 
       if (length > offset - start_offset)
@@ -1671,6 +1780,7 @@ dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
                                               (offset - start_offset));
         }
     }
+    return offset;
 }
 
 static void
@@ -1684,10 +1794,12 @@ dissect_dtls_hnd_cert(tvbuff_t *tvb,
    *     ASN.1Cert certificate_list<1..2^24-1>;
    * } Certificate;
    */
-  guint32 certificate_list_length;
+
+  guint32     certificate_list_length;
   proto_tree *ti;
   proto_tree *subtree;
-  asn1_ctx_t asn1_ctx;
+  asn1_ctx_t  asn1_ctx;
+
   asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
 
   if (tree)
@@ -1723,7 +1835,7 @@ dissect_dtls_hnd_cert(tvbuff_t *tvb,
               certificate_list_length -= 3 + cert_length;
 
               proto_tree_add_item(subtree, hf_dtls_handshake_certificate_len,
-                                  tvb, offset, 3, FALSE);
+                                  tvb, offset, 3, ENC_BIG_ENDIAN);
               offset += 3;
 
               dissect_x509af_Certificate(FALSE, tvb, offset, &asn1_ctx, subtree, hf_dtls_handshake_certificate);
@@ -1752,12 +1864,11 @@ dissect_dtls_hnd_cert_req(tvbuff_t *tvb,
    *    } CertificateRequest;
    *
    */
+
   proto_tree *ti;
   proto_tree *subtree;
   guint8      cert_types_count;
-  gint         dnames_length;
-  cert_types_count = 0;
-  dnames_length = 0;
+  gint        dnames_length;
 
   if (tree)
     {
@@ -1783,7 +1894,7 @@ dissect_dtls_hnd_cert_req(tvbuff_t *tvb,
           while (cert_types_count > 0)
             {
               proto_tree_add_item(subtree, hf_dtls_handshake_cert_type,
-                                  tvb, offset, 1, FALSE);
+                                  tvb, offset, 1, ENC_BIG_ENDIAN);
               offset++;
               cert_types_count--;
             }
@@ -1816,7 +1927,7 @@ dissect_dtls_hnd_cert_req(tvbuff_t *tvb,
               dnames_length -= 2 + name_length;
 
               proto_tree_add_item(subtree, hf_dtls_handshake_dname_len,
-                                  tvb, offset, 2, FALSE);
+                                  tvb, offset, 2, ENC_BIG_ENDIAN);
               offset += 2;
 
               proto_tree_add_bytes_format(subtree,
@@ -1851,7 +1962,7 @@ dissect_dtls_hnd_finished(tvbuff_t *tvb, proto_tree *tree, guint32 offset,
   switch(*conv_version) {
   case SSL_VER_DTLS:
     proto_tree_add_item(tree, hf_dtls_handshake_finished,
-                        tvb, offset, 12, FALSE);
+                        tvb, offset, 12, ENC_NA);
     break;
   }
 }
@@ -1933,7 +2044,7 @@ looks_like_dtls(tvbuff_t *tvb, guint32 offset)
   /* have to have a valid content type followed by a valid
    * protocol version
    */
-  guint8 byte;
+  guint8  byte;
   guint16 version;
 
   /* see if the first byte is a valid content type */
@@ -1959,13 +2070,13 @@ looks_like_dtls(tvbuff_t *tvb, guint32 offset)
 static void
 dtlsdecrypt_free_cb(void* r)
 {
-       ssldecrypt_assoc_t* h = r;
+  ssldecrypt_assoc_t* h = r;
 
-       g_free(h->ipaddr);
-       g_free(h->port);
-       g_free(h->protocol);
-       g_free(h->keyfile);
-       g_free(h->password);
+  g_free(h->ipaddr);
+  g_free(h->port);
+  g_free(h->protocol);
+  g_free(h->keyfile);
+  g_free(h->password);
 }
 #endif
 
@@ -1973,7 +2084,7 @@ dtlsdecrypt_free_cb(void* r)
 static void
 dtlsdecrypt_update_cb(void* r _U_, const char** err _U_)
 {
-       return;
+  return;
 }
 #endif
 
@@ -1981,25 +2092,27 @@ dtlsdecrypt_update_cb(void* r _U_, const char** err _U_)
 static void *
 dtlsdecrypt_copy_cb(void* dest, const void* orig, size_t len _U_)
 {
-       const ssldecrypt_assoc_t* o = orig;
-       ssldecrypt_assoc_t* d = dest;
+  const ssldecrypt_assoc_t* o = orig;
+  ssldecrypt_assoc_t*       d = dest;
 
-       d->ipaddr    = g_strdup(o->ipaddr);
-       d->port          = g_strdup(o->port);
-       d->protocol  = g_strdup(o->protocol);
-       d->keyfile   = g_strdup(o->keyfile);
-       d->password  = g_strdup(o->password);
+  d->ipaddr    = g_strdup(o->ipaddr);
+  d->port      = g_strdup(o->port);
+  d->protocol  = g_strdup(o->protocol);
+  d->keyfile   = g_strdup(o->keyfile);
+  d->password  = g_strdup(o->password);
 
-       return d;
+  return d;
 }
 
 UAT_CSTRING_CB_DEF(sslkeylist_uats,ipaddr,ssldecrypt_assoc_t)
 UAT_CSTRING_CB_DEF(sslkeylist_uats,port,ssldecrypt_assoc_t)
 UAT_CSTRING_CB_DEF(sslkeylist_uats,protocol,ssldecrypt_assoc_t)
-UAT_CSTRING_CB_DEF(sslkeylist_uats,keyfile,ssldecrypt_assoc_t)
+UAT_FILENAME_CB_DEF(sslkeylist_uats,keyfile,ssldecrypt_assoc_t)
 UAT_CSTRING_CB_DEF(sslkeylist_uats,password,ssldecrypt_assoc_t)
 #endif
 
+void proto_reg_handoff_dtls(void);
+
 /*********************************************************************
  *
  * Standard Wireshark Protocol Registration and housekeeping
@@ -2097,12 +2210,12 @@ proto_register_dtls(void)
         "Fragment length of handshake message", HFILL }
     },
     { &hf_dtls_handshake_client_version,
-      { "Version", "dtls.handshake.version",
+      { "Version", "dtls.handshake.client_version",
         FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0,
         "Maximum version supported by client", HFILL }
     },
     { &hf_dtls_handshake_server_version,
-      { "Version", "dtls.handshake.version",
+      { "Version", "dtls.handshake.server_version",
         FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0,
         "Version selected by server", HFILL }
     },
@@ -2287,7 +2400,7 @@ proto_register_dtls(void)
         FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
     },
     { &hf_dtls_fragment_count,
-      { "Message fragment count", "dtls.fragment.error",
+      { "Message fragment count", "dtls.fragment.count",
         FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
     },
     { &hf_dtls_reassembled_in,
@@ -2327,45 +2440,45 @@ proto_register_dtls(void)
 
 #ifdef HAVE_LIBGNUTLS
   {
-    module_t *dtls_module = prefs_register_protocol(proto_dtls, dtls_parse);
-
-       static uat_field_t dtlskeylist_uats_flds[] = {
-               UAT_FLD_CSTRING_OTHER(sslkeylist_uats, ipaddr, "IP address", ssldecrypt_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"),
-               UAT_FLD_CSTRING_OTHER(sslkeylist_uats, port, "Port", ssldecrypt_uat_fld_port_chk_cb, "Port Number"),
-               UAT_FLD_CSTRING_OTHER(sslkeylist_uats, protocol, "Protocol", ssldecrypt_uat_fld_protocol_chk_cb, "Protocol"),
-               UAT_FLD_CSTRING_OTHER(sslkeylist_uats, keyfile, "Key File", ssldecrypt_uat_fld_fileopen_chk_cb, "Path to the keyfile."),
-               UAT_FLD_CSTRING_OTHER(sslkeylist_uats, password," Password (p12 file)", ssldecrypt_uat_fld_password_chk_cb, "Password"),
-               UAT_END_FIELDS
-       };
-
-       dtlsdecrypt_uat = uat_new("DTLS RSA Keylist",
-               sizeof(ssldecrypt_assoc_t),
-               "dtlsdecrypttablefile",         /* filename */
-               TRUE,                                   /* from_profile */
-               (void*) &dtlskeylist_uats,      /* data_ptr */
-               &ndtlsdecrypt,                  /* numitems_ptr */
-               UAT_CAT_FFMT,                           /* category */
-               "ChK12ProtocolsSection",                /* TODO, need revision - help */
-               dtlsdecrypt_copy_cb,
-               NULL, /* dtlsdecrypt_update_cb? */
-               dtlsdecrypt_free_cb,
-               NULL,
-               dtlskeylist_uats_flds);
-
-       prefs_register_uat_preference(dtls_module, "cfg",
-               "RSA keys list",
-               "A table of RSA keys for DTLS decryption",
-               dtlsdecrypt_uat);
-
-       prefs_register_string_preference(dtls_module, "debug_file", "DTLS debug file",
+    module_t *dtls_module = prefs_register_protocol(proto_dtls, proto_reg_handoff_dtls);
+
+    static uat_field_t dtlskeylist_uats_flds[] = {
+      UAT_FLD_CSTRING_OTHER(sslkeylist_uats, ipaddr, "IP address", ssldecrypt_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"),
+      UAT_FLD_CSTRING_OTHER(sslkeylist_uats, port, "Port", ssldecrypt_uat_fld_port_chk_cb, "Port Number"),
+      UAT_FLD_CSTRING_OTHER(sslkeylist_uats, protocol, "Protocol", ssldecrypt_uat_fld_protocol_chk_cb, "Protocol"),
+      UAT_FLD_FILENAME_OTHER(sslkeylist_uats, keyfile, "Key File", ssldecrypt_uat_fld_fileopen_chk_cb, "Path to the keyfile."),
+      UAT_FLD_CSTRING_OTHER(sslkeylist_uats, password," Password (p12 file)", ssldecrypt_uat_fld_password_chk_cb, "Password"),
+      UAT_END_FIELDS
+    };
+
+    dtlsdecrypt_uat = uat_new("DTLS RSA Keylist",
+                              sizeof(ssldecrypt_assoc_t),
+                              "dtlsdecrypttablefile",         /* filename */
+                              TRUE,                           /* from_profile */
+                              (void*) &dtlskeylist_uats,      /* data_ptr */
+                              &ndtlsdecrypt,                  /* numitems_ptr */
+                              UAT_CAT_FFMT,                   /* category */
+                              "ChK12ProtocolsSection",        /* TODO, need revision - help */
+                              dtlsdecrypt_copy_cb,
+                              NULL, /* dtlsdecrypt_update_cb? */
+                              dtlsdecrypt_free_cb,
+                              dtls_parse_uat,
+                              dtlskeylist_uats_flds);
+
+    prefs_register_uat_preference(dtls_module, "cfg",
+                                  "RSA keys list",
+                                  "A table of RSA keys for DTLS decryption",
+                                  dtlsdecrypt_uat);
+
+    prefs_register_string_preference(dtls_module, "debug_file", "DTLS debug file",
                                      "redirect dtls debug to file name; leave empty to disable debug, "
                                      "use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n",
                                      (const gchar **)&dtls_debug_file_name);
 
-        prefs_register_string_preference(dtls_module, "keys_list", "RSA keys list (deprecated)",
-             "Semicolon-separated list of private RSA keys used for DTLS decryption. "
-             "Used by versions of Wireshark prior to 1.6",
-             (const gchar **)&dtls_keys_list);
+    prefs_register_string_preference(dtls_module, "keys_list", "RSA keys list (deprecated)",
+                                     "Semicolon-separated list of private RSA keys used for DTLS decryption. "
+                                     "Used by versions of Wireshark prior to 1.6",
+                                     (const gchar **)&dtls_keys_list);
 
   }
 #endif
@@ -2380,8 +2493,11 @@ proto_register_dtls(void)
   dtls_tap = register_tap("dtls");
   ssl_debug_printf("proto_register_dtls: registered tap %s:%d\n",
                    "dtls", dtls_tap);
+
+  register_heur_dissector_list("dtls", &heur_subdissector_list);
 }
 
+
 /* If this dissector uses sub-dissector registration add a registration
  * routine.  This format is required because a script is used to find
  * these routines and create the code that calls these routines.
@@ -2389,7 +2505,14 @@ proto_register_dtls(void)
 void
 proto_reg_handoff_dtls(void)
 {
+  static gboolean initialized = FALSE;
 
   /* add now dissector to default ports.*/
-  dtls_parse();
+  dtls_parse_uat();
+  dtls_parse_old_keys();
+
+  if (initialized == FALSE)
+    heur_dissector_add("udp", dissect_dtls_heur, proto_dtls);
+
+  initialized = TRUE;
 }