* 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>
#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>
+
+/* DTLS User Access Table */
+static ssldecrypt_assoc_t *dtlskeylist_uats = NULL;
+static guint ndtlsdecrypt = 0;
/* we need to remember the top tree so that subdissectors we call are created
* at the root and not deep down inside the DTLS decode
*********************************************************************/
/* 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_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;
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 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 gchar* dtls_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,
&hf_dtls_fragment_multiple_tails,
&hf_dtls_fragment_too_long_fragment,
&hf_dtls_fragment_error,
+ &hf_dtls_fragment_count,
/* Reassembled in field */
&hf_dtls_reassembled_in,
/* Reassembled length field */
static void
dtls_init(void)
{
+ module_t *dtls_module = prefs_find_module("dtls");
+ pref_t *keys_list_pref;
+
ssl_common_init(&dtls_session_hash, &dtls_decrypted_data, &dtls_compressed_data);
fragment_table_init (&dtls_fragment_table);
+
+ /* We should have loaded "keys_list" by now. Mark it obsolete */
+ if (dtls_module) {
+ keys_list_pref = prefs_find_preference(dtls_module, "keys_list");
+ if (! prefs_get_preference_obsolete(keys_list_pref)) {
+ prefs_set_preference_obsolete(keys_list_pref);
+ }
+ }
}
/* 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;
+ 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();
/* 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 (dtls_keys_list && (dtls_keys_list[0] != 0))
+ ssl_set_debug(dtls_debug_file_name);
+
+ if (ndtlsdecrypt > 0)
+ {
+ for (i = 0; i < ndtlsdecrypt; i++)
{
- ssl_parse_key_list(dtls_keys_list,dtls_key_hash,dtls_associations,dtls_handle,FALSE);
+ 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);
}
+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",
+ uat_entry->str, err);
+ }
+ }
+ g_strfreev(parts);
+ }
+ g_strfreev(old_keys);
+ }
+ g_string_free(uat_entry, TRUE);
+
+}
+
/*
* DTLS Dissection Routines
*
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);
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
* 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*/
* 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
/* 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);
}
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;
- gint direction;
- 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;
}
/* retrive decoder for this packet direction */
- if ((direction = ssl_packet_from_server(ssl, dtls_associations, pinfo)) != 0) {
+ if (ssl_packet_from_server(ssl, dtls_associations, pinfo) != 0) {
ssl_debug_printf("decrypt_dtls_record: using server decoder\n");
decoder = ssl->server;
}
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)
{
/* 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;
}
* 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)){
/* 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);
}
/* 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 */
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:
{
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:
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:
* 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",
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");
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:
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);
}
}
* 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);
}
*/
/* 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)
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
{
* 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;
* } 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
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)
{
/* 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,
/* 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)
/* 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)
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);
{
/* 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,
- tvb_get_ptr(tvb, offset, session_id_length),
- "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;
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",
offset += 2;
proto_tree_add_bytes_format(ext_tree, hf_dtls_handshake_extension_data,
- tvb, offset, ext_len,
- tvb_get_ptr(tvb, offset, ext_len),
- "Data (%u byte%s)",
- ext_len, plurality(ext_len, "", "s"));
+ tvb, offset, ext_len, NULL,
+ "Data (%u byte%s)", ext_len,
+ plurality(ext_len, "", "s"));
offset += ext_len;
- left -= 2 + 2 + ext_len;
+ left -= 2 + 2 + ext_len;
}
return offset;
* } 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);
{
proto_tree_add_bytes_format(tree, hf_dtls_handshake_cookie,
tvb, offset, cookie_length,
- tvb_get_ptr(tvb, offset, cookie_length),
- "Cookie (%u byte%s)",
+ NULL, "Cookie (%u byte%s)",
cookie_length,
plurality(cookie_length, "", "s"));
offset += cookie_length;
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;
}
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));
}
}
-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 {
*/
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);
{
proto_tree_add_bytes_format(tree, hf_dtls_handshake_cookie,
tvb, offset, cookie_length,
- tvb_get_ptr(tvb, offset, cookie_length),
- "Cookie (%u byte%s)",
+ NULL, "Cookie (%u byte%s)",
cookie_length,
plurality(cookie_length, "", "s"));
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)
{
* Extension server_hello_extension_list<0..2^16-1>;
* } ServerHello;
*/
+
guint16 start_offset;
+
start_offset = offset;
if (tree || ssl)
/* 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) {
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)
(offset - start_offset));
}
}
+ return offset;
}
static void
* 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)
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);
* } 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)
{
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--;
}
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,
hf_dtls_handshake_dname,
- tvb, offset, name_length,
- tvb_get_ptr(tvb, offset, name_length),
+ tvb, offset, name_length, NULL,
"Distinguished Name (%u byte%s)",
name_length,
plurality(name_length, "", "s"));
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;
}
}
/* 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 */
return 1;
}
+/* UAT */
+
+#ifdef HAVE_LIBGNUTLS
+static void
+dtlsdecrypt_free_cb(void* 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);
+}
+#endif
+
+#if 0
+static void
+dtlsdecrypt_update_cb(void* r _U_, const char** err _U_)
+{
+ return;
+}
+#endif
+
+#ifdef HAVE_LIBGNUTLS
+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;
+
+ 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;
+}
+
+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_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
"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 }
},
},
{ &hf_dtls_handshake_cipher_suite,
{ "Cipher Suite", "dtls.handshake.ciphersuite",
- FT_UINT16, BASE_HEX, VALS(ssl_31_ciphersuite), 0x0,
+ FT_UINT16, BASE_HEX|BASE_EXT_STRING, &ssl_31_ciphersuite_ext, 0x0,
NULL, HFILL }
},
{ &hf_dtls_handshake_cookie_len,
{ "Message defragmentation error", "dtls.fragment.error",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
+ { &hf_dtls_fragment_count,
+ { "Message fragment count", "dtls.fragment.count",
+ FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
+ },
{ &hf_dtls_reassembled_in,
{ "Reassembled in", "dtls.reassembled.in",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
#ifdef HAVE_LIBGNUTLS
{
- module_t *dtls_module = prefs_register_protocol(proto_dtls, dtls_parse);
- prefs_register_string_preference(dtls_module, "keys_list", "RSA keys list",
- "semicolon separated list of private RSA keys used for DTLS decryption; "
- "each list entry must be in the form of <ip>,<port>,<protocol>,<key_file_name>"
- "<key_file_name> is the local file name of the RSA private key used by the specified server\n",
- (const gchar **)&dtls_keys_list);
+ 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);
+
}
#endif
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.
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;
}