diff options
author | Ronnie Sahlberg <ronnie_sahlberg@ozemail.com.au> | 2006-08-02 08:15:51 +0000 |
---|---|---|
committer | Ronnie Sahlberg <ronnie_sahlberg@ozemail.com.au> | 2006-08-02 08:15:51 +0000 |
commit | 7b3b26fd394bb775174da17686ed024383443d98 (patch) | |
tree | 377d8758d7a45db9f0baff0cfd76facf97697bc4 /epan/dissectors | |
parent | 903a75ff72519c71836c18b22b92b25b71ad1be7 (diff) |
from a. samuel
ssl and dtls updates
svn path=/trunk/; revision=18816
Diffstat (limited to 'epan/dissectors')
-rw-r--r-- | epan/dissectors/packet-dtls.c | 4922 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.c | 579 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.h | 149 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl.c | 697 |
4 files changed, 2421 insertions, 3926 deletions
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c index ca12f21c79..902fb8cb4d 100644 --- a/epan/dissectors/packet-dtls.c +++ b/epan/dissectors/packet-dtls.c @@ -4,8 +4,8 @@ * * $Id$ * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@ethereal.com> + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or @@ -22,6 +22,26 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * + * DTLS dissection and decryption. + * 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. + * + * It was developped to dissect and decrypt OpenSSL v 0.9.8b DTLS implementation. + * It is limited to this implementation while there is no complete implementation. + * + * Implemented : + * - DTLS dissection + * - DTLS decryption (openssl one) + * + * Todo : + * - activate correct Mac calculation when openssl will be corrected + * (or if an other implementation works), + * corrected code is ready and commented in packet-ssl-utils.h file. + * - add missings things (desegmentation, reordering... that aren't present in actual OpenSSL implementation) */ #ifdef HAVE_CONFIG_H @@ -32,6 +52,11 @@ #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + #include <glib.h> #include <epan/conversation.h> @@ -42,7 +67,10 @@ #include <epan/tap.h> #include "packet-ssl-utils.h" -static gboolean ssl_desegment = TRUE; +/* 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 + */ +static proto_tree *top_tree; /********************************************************************* * @@ -51,89 +79,57 @@ static gboolean ssl_desegment = TRUE; *********************************************************************/ /* Initialize the protocol and registered fields */ -static int dtls_tap = -1; -static int proto_dtls = -1; -static int hf_dtls_record = -1; -static int hf_dtls_record_content_type = -1; -static int hf_dtls_record_version = -1; -static int hf_dtls_record_epoch = -1; -static int hf_dtls_record_sequence_number = -1; -static int hf_dtls_record_length = -1; -static int hf_dtls_record_appdata = -1; -static int hf_dtls_record_appdata_decrypted = -1; -static int hf_ssl2_record = -1; -static int hf_ssl2_record_is_escape = -1; -static int hf_ssl2_record_padding_length = -1; -static int hf_ssl2_msg_type = -1; -static int hf_pct_msg_type = -1; -static int hf_dtls_change_cipher_spec = -1; -static int hf_dtls_alert_message = -1; -static int hf_dtls_alert_message_level = -1; -static int hf_dtls_alert_message_description = -1; -static int hf_dtls_handshake_protocol = -1; -static int hf_dtls_handshake_type = -1; -static int hf_dtls_handshake_length = -1; -static int hf_dtls_handshake_message_seq = -1; -static int hf_dtls_handshake_fragment_offset = -1; -static int hf_dtls_handshake_fragment_length = -1; -static int hf_dtls_handshake_client_version = -1; -static int hf_dtls_handshake_server_version = -1; -static int hf_dtls_handshake_random_time = -1; -static int hf_dtls_handshake_random_bytes = -1; -static int hf_dtls_handshake_cookie_len = -1; -static int hf_dtls_handshake_cookie = -1; -static int hf_dtls_handshake_cipher_suites_len = -1; -static int hf_dtls_handshake_cipher_suites = -1; -static int hf_dtls_handshake_cipher_suite = -1; -static int hf_dtls_handshake_session_id = -1; -static int hf_dtls_handshake_comp_methods_len = -1; -static int hf_dtls_handshake_comp_methods = -1; -static int hf_dtls_handshake_comp_method = -1; -static int hf_dtls_handshake_extensions_len = -1; -static int hf_dtls_handshake_extension_type = -1; -static int hf_dtls_handshake_extension_len = -1; -static int hf_dtls_handshake_extension_data = -1; -static int hf_dtls_handshake_certificates_len = -1; -static int hf_dtls_handshake_certificates = -1; -static int hf_dtls_handshake_certificate = -1; -static int hf_dtls_handshake_certificate_len = -1; -static int hf_dtls_handshake_cert_types_count = -1; -static int hf_dtls_handshake_cert_types = -1; -static int hf_dtls_handshake_cert_type = -1; -static int hf_dtls_handshake_finished = -1; -static int hf_dtls_handshake_md5_hash = -1; -static int hf_dtls_handshake_sha_hash = -1; -static int hf_dtls_handshake_session_id_len = -1; -static int hf_dtls_handshake_dnames_len = -1; -static int hf_dtls_handshake_dnames = -1; -static int hf_dtls_handshake_dname_len = -1; -static int hf_dtls_handshake_dname = -1; -static int hf_ssl2_handshake_cipher_spec_len = -1; -static int hf_ssl2_handshake_session_id_len = -1; -static int hf_ssl2_handshake_challenge_len = -1; -static int hf_ssl2_handshake_cipher_spec = -1; -static int hf_ssl2_handshake_challenge = -1; -static int hf_ssl2_handshake_clear_key_len = -1; -static int hf_ssl2_handshake_enc_key_len = -1; -static int hf_ssl2_handshake_key_arg_len = -1; -static int hf_ssl2_handshake_clear_key = -1; -static int hf_ssl2_handshake_enc_key = -1; -static int hf_ssl2_handshake_key_arg = -1; -static int hf_ssl2_handshake_session_id_hit = -1; -static int hf_ssl2_handshake_cert_type = -1; -static int hf_ssl2_handshake_connection_id_len = -1; -static int hf_ssl2_handshake_connection_id = -1; -static int hf_pct_handshake_cipher_spec = -1; -static int hf_pct_handshake_hash_spec = -1; -static int hf_pct_handshake_cert_spec = -1; -static int hf_pct_handshake_cert = -1; -static int hf_pct_handshake_server_cert = -1; -static int hf_pct_handshake_exch_spec = -1; -static int hf_pct_handshake_hash = -1; -static int hf_pct_handshake_cipher = -1; -static int hf_pct_handshake_exch = -1; -static int hf_pct_handshake_sig = -1; -static int hf_pct_msg_error_type = -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; /* Initialize the subtree pointers */ static gint ett_dtls = -1; @@ -146,510 +142,122 @@ static gint ett_dtls_extension = -1; static gint ett_dtls_certs = -1; static gint ett_dtls_cert_types = -1; static gint ett_dtls_dnames = -1; -static gint ett_pct_cipher_suites = -1; -static gint ett_pct_hash_suites = -1; -static gint ett_pct_cert_suites = -1; -static gint ett_pct_exch_suites = -1; - -typedef struct { - unsigned int ssl_port; - unsigned int decrypted_port; - dissector_handle_t handle; - char* info; -} SslAssociation; - -static char* dtls_keys_list = NULL; -static char* dtls_ports_list = NULL; -static char* dtls_debug_file_name = NULL; - -typedef struct _SslService { - address addr; - guint port; -} SslService; - -static GHashTable *ssl_session_hash = NULL; -static GHashTable *ssl_key_hash = NULL; -static GTree* ssl_associations = NULL; -static dissector_handle_t dtls_handle = NULL; -static StringInfo ssl_decrypted_data = {NULL, 0}; -static int ssl_decrypted_data_avail = 0; - -/* Hash Functions for ssl sessions table and private keys table*/ -static gint -ssl_equal (gconstpointer v, gconstpointer v2) -{ - const StringInfo *val1 = (const StringInfo *)v; - const StringInfo *val2 = (const StringInfo *)v2; - - if (val1->data_len == val2->data_len && - !memcmp(val1->data, val2->data, val2->data_len)) { - return 1; - } - return 0; -} - -static guint -ssl_hash (gconstpointer v) -{ - guint l,hash = 0; - StringInfo* id = (StringInfo*) v; - guint* cur = (guint*) id->data; - for (l=4; (l<id->data_len); l+=4, cur++) - hash = hash ^ (*cur); - - return hash; -} - -static gint -ssl_private_key_equal (gconstpointer v, gconstpointer v2) -{ - const SslService *val1 = (const SslService *)v; - const SslService *val2 = (const SslService *)v2; - - if ((val1->port == val2->port) && - ! CMP_ADDRESS(&val1->addr, &val2->addr)) { - return 1; - } - return 0; -} - -static guint -ssl_private_key_hash (gconstpointer v) -{ - const SslService *key = (const SslService *)v; - guint l,hash = key->port, len = key->addr.len; - - guint* cur = (guint*) key->addr.data; - for (l=4; (l<len); l+=4, cur++) - hash = hash ^ (*cur); - - return hash; -} - -/* private key table entries have a scope 'larger' then packet capture, - * so we can't relay on se_alloc** function */ -static void -ssl_private_key_free(gpointer id, gpointer key, gpointer dummy _U_) -{ - g_free(id); - ssl_free_key((SSL_PRIVATE_KEY*) key); -} - -/* handling of association between ssl ports and clear text protocol */ -static void -ssl_association_add(unsigned int port, unsigned int ctport, - const char* info) -{ - dissector_table_t udp_dissectors = find_dissector_table( "udp.port"); - SslAssociation* assoc = g_malloc(sizeof(SslAssociation)+strlen(info)+1); - - assoc->info = (char*) assoc+sizeof(SslAssociation); - strcpy(assoc->info, info); - assoc->ssl_port = port; - assoc->decrypted_port = ctport; - assoc->handle = dissector_get_port_handle(udp_dissectors, ctport); - - ssl_debug_printf("ssl_association_add port %d ctport %d info %s handle %p\n", - port, ctport, info, assoc->handle); - - dissector_add("udp.port", port, dtls_handle); - g_tree_insert(ssl_associations, (gpointer)port, assoc); -} - -static gint -ssl_association_cmp(gconstpointer a, gconstpointer b) -{ - return (gint)a-(gint)b; -} - -static inline -SslAssociation* ssl_association_find(unsigned int port) -{ - register SslAssociation* ret = g_tree_lookup(ssl_associations, (gpointer)port); - ssl_debug_printf("ssl_association_find: port %d found %p\n", port, ret); - return ret; -} -static gint -ssl_association_remove_handle (gpointer key _U_, - gpointer data, gpointer user_data _U_) -{ - SslAssociation* assoc = (SslAssociation*) data; - ssl_debug_printf("ssl_association_remove_handle removing ptr %p handle %p\n", - data, assoc->handle); - if (assoc->handle) - dissector_delete("tcp.port", assoc->ssl_port, assoc->handle); - g_free(data); - return 0; -} - -static inline int -ssl_packet_from_server(unsigned int port) -{ - register int ret = ssl_association_find(port) != 0; - ssl_debug_printf("ssl_packet_from_server: is from server %d\n", ret); - return ret; -} - -/* add to packet data a newly allocated tvb with the specified real data*/ -static void -ssl_add_record_info(packet_info *pinfo, unsigned char* data, int data_len, int record_id) -{ - unsigned char* real_data = se_alloc(data_len); - SslRecordInfo* rec = se_alloc(sizeof(SslRecordInfo)); - SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_dtls); - if (!pi) - { - pi = se_alloc0(sizeof(SslPacketInfo)); - p_add_proto_data(pinfo->fd, proto_dtls,pi); - } - - rec->id = record_id; - rec->tvb = tvb_new_real_data(real_data, data_len, data_len); - memcpy(real_data, data, data_len); - - /* head insertion */ - rec->next= pi->handshake_data; - pi->handshake_data = rec; -} - -/* search in packet data the tvbuff associated to the specified id */ -static tvbuff_t* -ssl_get_record_info(packet_info *pinfo, int record_id) -{ - SslRecordInfo* rec; - SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_dtls); - if (!pi) - return NULL; - - for (rec = pi->handshake_data; rec; rec = rec->next) - if (rec->id == record_id) - return rec->tvb; +static GHashTable *dtls_session_hash = NULL; +static GHashTable *dtls_key_hash = NULL; +static GTree* dtls_associations = NULL; +static dissector_handle_t dtls_handle = NULL; +static StringInfo dtls_decrypted_data = {NULL, 0}; +static gint dtls_decrypted_data_avail = 0; - return NULL; -} +static gchar* dtls_keys_list = NULL; +static gchar* dtls_debug_file_name = NULL; -/* initialize/reset per capture state data (ssl sessions cache) */ +/* initialize/reset per capture state data (dtls sessions cache) */ static void -ssl_init(void) +dtls_init(void) { - if (ssl_session_hash) - g_hash_table_destroy(ssl_session_hash); - ssl_session_hash = g_hash_table_new(ssl_hash, ssl_equal); - if (ssl_decrypted_data.data) - g_free(ssl_decrypted_data.data); - ssl_decrypted_data.data = g_malloc0(32); - ssl_decrypted_data.data_len = 32; + ssl_common_init(&dtls_session_hash, &dtls_decrypted_data); } -/* parse ssl related preferences (private keys and ports association strings) */ +/* parse dtls related preferences (private keys and ports association strings) */ static void -ssl_parse(void) +dtls_parse(void) { - if (ssl_key_hash) + if (dtls_key_hash) { - g_hash_table_foreach(ssl_key_hash, ssl_private_key_free, NULL); - g_hash_table_destroy(ssl_key_hash); + g_hash_table_foreach(dtls_key_hash, ssl_private_key_free, NULL); + g_hash_table_destroy(dtls_key_hash); } - if (ssl_associations) + if (dtls_associations) { - g_tree_traverse(ssl_associations, ssl_association_remove_handle, G_IN_ORDER, NULL); - g_tree_destroy(ssl_associations); + g_tree_traverse(dtls_associations, ssl_association_remove_handle_udp, G_IN_ORDER, NULL); + g_tree_destroy(dtls_associations); } - /* parse private keys string, load available keys and put them in key hash*/ - ssl_key_hash = g_hash_table_new(ssl_private_key_hash,ssl_private_key_equal); - ssl_associations = g_tree_new(ssl_association_cmp); - - if (dtls_keys_list && (dtls_keys_list[0] != 0)) - { - char* end; - char* start = strdup(dtls_keys_list); - char* tmp = start; - - ssl_debug_printf("ssl_init keys string %s\n", start); - do { - char* addr, *port, *filename; - unsigned char* ip; - SslService* service; - SSL_PRIVATE_KEY * private_key; - FILE* fp; - - addr = start; - /* split ip/file couple with ',' separator*/ - end = strchr(start, ','); - if (end) { - *end = 0; - start = end+1; - } - - /* for each entry split ip, port, filename with ':' separator */ - ssl_debug_printf("ssl_init found host entry %s\n", addr); - port = strchr(addr, ':'); - if (!port) - { - ssl_debug_printf("ssl_init entry malformed can't find port in %s\n", addr); - break; - } - *port = 0; - port++; - - filename = strchr(port,':'); - if (!filename) - { - ssl_debug_printf("ssl_init entry malformed can't find filename in %s\n", port); - break; - } - *filename=0; - filename++; - - /* convert ip and port string to network rappresentation*/ - service = g_malloc(sizeof(SslService) + 4); - service->addr.type = AT_IPv4; - service->addr.len = 4; - service->addr.data = ip = ((unsigned char*)service) + sizeof(SslService); - sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &ip[0], &ip[1], &ip[2], &ip[3]); - service->port = atoi(port); - ssl_debug_printf("ssl_init addr %hhu.%hhu.%hhu.%hhu port %d filename %s\n", - ip[0], ip[1], ip[2], ip[3], service->port, filename); + /* 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); + dtls_associations = g_tree_new(ssl_association_cmp); - /* try to load pen file*/ - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "can't open file %s \n",filename); - break; - } - - private_key = ssl_load_key(fp); - if (!private_key) { - fprintf(stderr,"can't load private key from %s\n", - filename); - break; - } - fclose(fp); - - ssl_debug_printf("ssl_init private key file %s successfully loaded\n", - filename); - g_hash_table_insert(ssl_key_hash, service, private_key); - - } while (end != NULL); - free(tmp); + if (dtls_keys_list && (dtls_keys_list[0] != 0)) + { + ssl_parse_key_list(dtls_keys_list,dtls_key_hash,dtls_associations,dtls_handle,FALSE); } - /* parse ssl ports string and add ssl dissector to specifed port[s]*/ - if (dtls_ports_list && (dtls_ports_list[0] != 0)) - { - char* end; - char* start = strdup(dtls_ports_list); - char* tmp = start; - - ssl_debug_printf("ssl_init ports string %s\n", start); - do { - char* port, *ctport, *info; - unsigned int portn, ctportn; - - port = start; - /* split ip/file couple with ',' separator*/ - end = strchr(start, ','); - if (end) { - *end = 0; - start = end+1; - } - - /* for each entry split ip, port, filename with ':' separator */ - ssl_debug_printf("ssl_init found port entry %s\n", port); - ctport = strchr(port, ':'); - if (!ctport) - break; - *ctport = 0; - ctport++; - - info = strchr(ctport,':'); - if (!info) - break; - *info=0; - info++; - - /* add dissector to this port */ - portn = atoi(port); - ctportn = atoi(ctport); - if (!portn || !ctportn) - break; - - ssl_debug_printf("ssl_init adding dissector to port %d (ct port %d)\n", portn, ctportn); - ssl_association_add(portn, ctportn, info); - } while (end != NULL); - free(tmp); - } - - ssl_set_debug(dtls_debug_file_name); - - /* [re] add ssl dissection to defaults ports */ - ssl_association_add(4433, 80, "OpenSSL Implementation"); -} - -/* store master secret into session data cache */ -static void -ssl_save_session(SslDecryptSession* ssl) -{ - /* allocate stringinfo chunks for session id and master secret data*/ - StringInfo* session_id = se_alloc0(sizeof(StringInfo) + ssl->session_id.data_len); - StringInfo* master_secret = se_alloc0(48 + sizeof(StringInfo)); - - master_secret->data = ((unsigned char*)master_secret+sizeof(StringInfo)); - session_id->data = ((unsigned char*)session_id+sizeof(StringInfo)); - - ssl_data_set(session_id, ssl->session_id.data, ssl->session_id.data_len); - ssl_data_set(master_secret, ssl->master_secret.data, ssl->master_secret.data_len); - g_hash_table_insert(ssl_session_hash, session_id, master_secret); - ssl_print_string("ssl_save_session stored session id", session_id); - ssl_print_string("ssl_save_session stored master secret", master_secret); -} + ssl_set_debug(dtls_debug_file_name); -static void -ssl_restore_session(SslDecryptSession* ssl) -{ - StringInfo* ms = g_hash_table_lookup(ssl_session_hash, &ssl->session_id); - if (!ms) { - ssl_debug_printf("ssl_restore_session can't find stored session\n"); - return; - } - ssl_data_set(&ssl->master_secret, ms->data, ms->data_len); - ssl->state |= SSL_MASTER_SECRET; - ssl_debug_printf("ssl_restore_session master key retrived\n"); + /* [re] add dtls dissection to default port in openssl 0.9.8b implementation */ + ssl_association_add(dtls_associations, dtls_handle, 4433, "http", FALSE); } - -/********************************************************************* - * - * Forward Declarations - * - *********************************************************************/ - /* - * SSL version 3 and TLS dissectors + * DTLS Dissection Routines * */ + /* record layer dissector */ -static int dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, +static gint dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, - gboolean *need_desegmentation, + guint *conv_version, SslDecryptSession *conv_data); /* change cipher spec dissector */ -static void dissect_ssl3_change_cipher_spec(tvbuff_t *tvb, +static void dissect_dtls_change_cipher_spec(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint *conv_version, guint8 content_type); /* alert message dissector */ -static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, +static void dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint *conv_version); /* handshake protocol dissector */ -static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, +static void dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint32 record_length, guint *conv_version, SslDecryptSession *conv_data, guint8 content_type); -static void dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, +static void dissect_dtls_hnd_cli_hello(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, SslDecryptSession* ssl); -static void dissect_ssl3_hnd_hello_verify_request(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset, guint32 length, - SslDecryptSession* ssl); +static void dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb, + proto_tree *tree, + guint32 offset, + SslDecryptSession* ssl); -static void dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb, +static void dissect_dtls_hnd_srv_hello(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, SslDecryptSession* ssl); -static void dissect_ssl3_hnd_cert(tvbuff_t *tvb, +static void dissect_dtls_hnd_cert(tvbuff_t *tvb, proto_tree *tree, guint32 offset, packet_info *pinfo); -static void dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, +static void dissect_dtls_hnd_cert_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset); -static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, +static void dissect_dtls_hnd_finished(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint* conv_version); - -/* - * SSL version 2 dissectors - * - */ - -/* record layer dissector */ -static int dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree, guint32 offset, - guint *conv_version, - gboolean *need_desegmentation, - SslDecryptSession* ssl); - -/* client hello dissector */ -static void dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset, - SslDecryptSession* ssl); - -static void dissect_pct_msg_client_hello(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset); - -/* client master key dissector */ -static void dissect_ssl2_hnd_client_master_key(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset); -static void dissect_pct_msg_client_master_key(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset); - -/* server hello dissector */ -static void dissect_ssl2_hnd_server_hello(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset, packet_info *pinfo); -static void dissect_pct_msg_server_hello(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset, packet_info *pinfo); - - -static void dissect_pct_msg_server_verify(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset); - -static void dissect_pct_msg_error(tvbuff_t *tvb, - proto_tree *tree, - guint32 offset); - /* * Support Functions * */ /*static void ssl_set_conv_version(packet_info *pinfo, guint version);*/ -static int ssl_is_valid_handshake_type(guint8 type); -static int ssl_is_valid_content_type(guint8 type); -static int ssl_is_valid_ssl_version(guint16 version); -static int ssl_is_authoritative_version_message(guint8 content_type, - guint8 next_byte); -static int ssl_is_v2_client_hello(tvbuff_t *tvb, guint32 offset); -static int ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset); -static int ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset); -static int ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, - guint32 offset, - guint32 record_length); -static int ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, - guint32 offset, - guint32 record_length); +static gint dtls_is_valid_handshake_type(guint8 type); + +static gint dtls_is_authoritative_version_message(guint8 content_type, + guint8 next_byte); +static gint looks_like_dtls(tvbuff_t *tvb, guint32 offset); + /********************************************************************* * * Main dissector @@ -662,299 +270,246 @@ static void dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - conversation_t *conversation; - void *conv_data; - proto_item *ti = NULL; - proto_tree *dtls_tree = NULL; - guint32 offset = 0; - gboolean first_record_in_frame = TRUE; - gboolean need_desegmentation; - SslDecryptSession* ssl_session = NULL; - guint* conv_version; - - /* Track the version using conversations to reduce the - * chance that a packet that simply *looks* like a v2 or - * v3 packet is dissected improperly. This also allows - * us to more frequently set the protocol column properly - * for continuation data frames. - * - * Also: We use the copy in conv_version as our cached copy, - * so that we don't have to search the conversation - * table every time we want the version; when setting - * the conv_version, must set the copy in the conversation - * in addition to conv_version - */ - conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, - pinfo->srcport, pinfo->destport, 0); - if (!conversation) + 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; + first_record_in_frame = TRUE; + ssl_session = NULL; + top_tree=tree; + + /* Track the version using conversations allows + * us to more frequently set the protocol column properly + * for continuation data frames. + * + * Also: We use the copy in conv_version as our cached copy, + * so that we don't have to search the conversation + * table every time we want the version; when setting + * the conv_version, must set the copy in the conversation + * in addition to conv_version + */ + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (!conversation) { - /* create a new conversation */ - conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, - pinfo->srcport, pinfo->destport, 0); + /* create a new conversation */ + conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); } - conv_data = conversation_get_proto_data(conversation, proto_dtls); + conv_data = conversation_get_proto_data(conversation, proto_dtls); - /* PAOLO: manage ssl decryption data */ - /*get a valid ssl session pointer*/ - if (conv_data != NULL) - ssl_session = conv_data; - else { - SslService dummy; - - ssl_session = se_alloc0(sizeof(SslDecryptSession)); - ssl_session_init(ssl_session); - ssl_session->version = SSL_VER_UNKNOWN; - conversation_add_proto_data(conversation, proto_dtls, ssl_session); + /* manage dtls decryption data */ + /*get a valid ssl session pointer*/ + if (conv_data != NULL) + ssl_session = conv_data; + else { + SslService dummy; + + ssl_session = se_alloc0(sizeof(SslDecryptSession)); + ssl_session_init(ssl_session); + ssl_session->version = SSL_VER_UNKNOWN; + conversation_add_proto_data(conversation, proto_dtls, ssl_session); - /* we need to know witch side of conversation is speaking*/ - if (ssl_packet_from_server(pinfo->srcport)) { - dummy.addr = pinfo->src; - dummy.port = pinfo->srcport; - } - else { - dummy.addr = pinfo->dst; - dummy.port = pinfo->destport; - } - ssl_debug_printf("dissect_ssl server %hhd.%hhd.%hhd.%hhd:%d\n", - dummy.addr.data[0], - dummy.addr.data[1],dummy.addr.data[2], - dummy.addr.data[3],dummy.port); - - /* try to retrive private key for this service. Do it now 'cause pinfo - * 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(ssl_key_hash, &dummy); - if (!ssl_session->private_key) - ssl_debug_printf("dissect_ssl can't find private key for this server!\n"); + /* we need to know witch side of conversation is speaking */ + if (ssl_packet_from_server(dtls_associations, pinfo->srcport)) { + dummy.addr = pinfo->src; + dummy.port = pinfo->srcport; + } + else { + dummy.addr = pinfo->dst; + dummy.port = pinfo->destport; } - conv_version= & ssl_session->version; + ssl_debug_printf("dissect_dtls server %hhd.%hhd.%hhd.%hhd:%d\n", + dummy.addr.data[0], + dummy.addr.data[1],dummy.addr.data[2], + dummy.addr.data[3],dummy.port); - /* try decryption only the first time we see this packet - * (to keep cipher syncronized)and only if we have - * the server private key*/ - if (!ssl_session->private_key || pinfo->fd->flags.visited) - ssl_session = NULL; + /* try to retrive private key for this service. Do it now 'cause pinfo + * 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) + ssl_debug_printf("dissect_dtls can't find private key for this server!\n"); + } + conv_version= & ssl_session->version; - /* Initialize the protocol column; we'll set it later when we - * figure out what flavor of SSL it is (assuming we don't - * throw an exception before we get the chance to do so). */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) + /* try decryption only the first time we see this packet + * (to keep cipher syncronized)and only if we have + * the server private key*/ + if (!ssl_session->private_key || pinfo->fd->flags.visited) + ssl_session = NULL; + + /* Initialize the protocol column; we'll set it later when we + * figure out what flavor of DTLS it is (actually only one + version exists). */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) { - col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTLS"); + col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTLS"); } - /* clear the the info column */ - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); - - /* TCP packets and SSL records are orthogonal. - * A tcp packet may contain multiple ssl records and an ssl - * record may be spread across multiple tcp packets. - * - * This loop accounts for multiple ssl records in a single - * frame, but not a single ssl record across multiple tcp - * packets. - * - * Handling the single ssl record across multiple packets - * may be possible using ethereal conversations, but - * probably not cleanly. May have to wait for tcp stream - * reassembly. - */ + /* clear the the info column */ + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); - /* Create display subtree for SSL as a whole */ - if (tree) + /* Create display subtree for SSL as a whole */ + if (tree) { - ti = proto_tree_add_item(tree, proto_dtls, tvb, 0, -1, FALSE); - dtls_tree = proto_item_add_subtree(ti, ett_dtls); + ti = proto_tree_add_item(tree, proto_dtls, tvb, 0, -1, FALSE); + dtls_tree = proto_item_add_subtree(ti, ett_dtls); } - /* iterate through the records in this tvbuff */ - while (tvb_reported_length_remaining(tvb, offset) != 0) + /* iterate through the records in this tvbuff */ + while (tvb_reported_length_remaining(tvb, offset) != 0) { - /* on second and subsequent records per frame - * add a delimiter on info column - */ - if (!first_record_in_frame - && check_col(pinfo->cinfo, COL_INFO)) + /* on second and subsequent records per frame + * add a delimiter on info column + */ + if (!first_record_in_frame + && check_col(pinfo->cinfo, COL_INFO)) { - col_append_str(pinfo->cinfo, COL_INFO, ", "); + col_append_str(pinfo->cinfo, COL_INFO, ", "); } - /* - * Assume, for now, that this doesn't need desegmentation. - */ - need_desegmentation = FALSE; - - /* first try to dispatch off the cached version - * known to be associated with the conversation - */ - switch(*conv_version) { - case SSL_VER_SSLv2: - case SSL_VER_PCT: - offset = dissect_ssl2_record(tvb, pinfo, dtls_tree, - offset, conv_version, - &need_desegmentation, - ssl_session); - break; - - case SSL_VER_SSLv3: - case SSL_VER_TLS: - case SSL_VER_DTLS: - /* the version tracking code works too well ;-) - * at times, we may visit a v2 client hello after - * we already know the version of the connection; - * work around that here by detecting and calling - * the v2 dissector instead - */ - if (ssl_is_v2_client_hello(tvb, offset)) - { - offset = dissect_ssl2_record(tvb, pinfo, dtls_tree, - offset, conv_version, - &need_desegmentation, - ssl_session); - } - else - { - offset = dissect_ssl3_record(tvb, pinfo, dtls_tree, - offset, conv_version, - &need_desegmentation, - ssl_session); - } - break; + /* first try to dispatch off the cached version + * known to be associated with the conversation + */ + switch(*conv_version) { + case SSL_VER_DTLS: + offset = dissect_dtls_record(tvb, pinfo, dtls_tree, + offset, conv_version, + ssl_session); + break; - /* that failed, so apply some heuristics based - * on this individual packet - */ - default: - if (ssl_looks_like_sslv2(tvb, offset)) - { - /* looks like sslv2 or pct client hello */ - offset = dissect_ssl2_record(tvb, pinfo, dtls_tree, - offset, conv_version, - &need_desegmentation, - ssl_session); - } - else if (ssl_looks_like_sslv3(tvb, offset)) - { - /* looks like sslv3 or tls */ - offset = dissect_ssl3_record(tvb, pinfo, dtls_tree, - offset, conv_version, - &need_desegmentation, - ssl_session); - } - else - { - /* looks like something unknown, so lump into - * continuation data - */ - offset = tvb_length(tvb); - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, - "Continuation Data"); - - /* Set the protocol column */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - { - col_set_str(pinfo->cinfo, COL_PROTOCOL, - ssl_version_short_names[*conv_version]); - } - } - break; - } + /* that failed, so apply some heuristics based + * on this individual packet + */ + default: + if (looks_like_dtls(tvb, offset)) + { + /* looks like dtls */ + offset = dissect_dtls_record(tvb, pinfo, dtls_tree, + offset, conv_version, + ssl_session); + } + else + { + /* looks like something unknown, so lump into + * continuation data + */ + offset = tvb_length(tvb); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, + "Continuation Data"); + + /* Set the protocol column */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL,"DTLS"); + } + } + break; + } - /* Desegmentation return check */ - if (need_desegmentation) - return; - /* set up for next record in frame, if any */ - first_record_in_frame = FALSE; + /* set up for next record in frame, if any */ + first_record_in_frame = FALSE; } - tap_queue_packet(dtls_tap, pinfo, (gpointer)proto_dtls); + tap_queue_packet(dtls_tap, pinfo, (gpointer)proto_dtls); } -static int -decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, - guint32 record_length, guint8 content_type, SslDecryptSession* ssl, - gboolean save_plaintext) +static gint +decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, + guint32 record_length, guint8 content_type, SslDecryptSession* ssl, + gboolean save_plaintext) { - int ret = 0; - int direction; - SslDecoder* decoder; - - /* if we can decrypt and decryption have success - * add decrypted data to this packet info*/ - ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl state %X\n", - record_length, ssl->state); - if (!(ssl->state & SSL_HAVE_SESSION_KEY)) { - ssl_debug_printf("decrypt_ssl3_record: no session key\n"); - return ret; - } + gint ret; + gint direction; + 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)) { + ssl_debug_printf("decrypt_dtls_record: no session key\n"); + return ret; + } - /* retrive decoder for this packet direction*/ - if ((direction = ssl_packet_from_server(pinfo->srcport)) != 0) { - ssl_debug_printf("decrypt_ssl3_record: using server decoder\n"); - decoder = &ssl->server; - } - else { - ssl_debug_printf("decrypt_ssl3_record: using client decoder\n"); - decoder = &ssl->client; - } + /* retrive decoder for this packet direction */ + if ((direction = ssl_packet_from_server(dtls_associations, pinfo->srcport)) != 0) { + ssl_debug_printf("decrypt_dtls_record: using server decoder\n"); + decoder = &ssl->server; + } + else { + ssl_debug_printf("decrypt_dtls_record: using client decoder\n"); + decoder = &ssl->client; + } - /* ensure we have enough storage space for decrypted data */ - if (record_length > ssl_decrypted_data.data_len) + /* ensure we have enough storage space for decrypted data */ + if (record_length > dtls_decrypted_data.data_len) { - ssl_debug_printf("decrypt_ssl3_record: allocating %d bytes" - " for decrypt data (old len %d)\n", - record_length + 32, ssl_decrypted_data.data_len); - ssl_decrypted_data.data = g_realloc(ssl_decrypted_data.data, - record_length + 32); - ssl_decrypted_data.data_len = record_length + 32; + ssl_debug_printf("decrypt_dtls_record: allocating %d bytes" + " for decrypt data (old len %d)\n", + record_length + 32, dtls_decrypted_data.data_len); + dtls_decrypted_data.data = g_realloc(dtls_decrypted_data.data, + record_length + 32); + dtls_decrypted_data.data_len = record_length + 32; } - /* run decryption and add decrypted payload to protocol data, if decryption - * is successful*/ - ssl_decrypted_data_avail = ssl_decrypted_data.data_len; - if (ssl_decrypt_record(ssl, decoder, - content_type, tvb_get_ptr(tvb, offset, record_length), - record_length, ssl_decrypted_data.data, &ssl_decrypted_data_avail) == 0) - ret = 1; - if (ret && save_plaintext) - { - SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_dtls); - if (!pi) + /* 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_decrypted_data.data, &dtls_decrypted_data_avail) == 0) + ret = 1; + if (ret && save_plaintext) + { + SslPacketInfo* pi; + pi = p_get_proto_data(pinfo->fd, proto_dtls); + + if (!pi) { - ssl_debug_printf("decrypt_ssl3_record: allocating app_data %d " - "bytes for app data\n", ssl_decrypted_data_avail); - /* first app data record: allocate and put packet data*/ - pi = se_alloc0(sizeof(SslPacketInfo)); - pi->app_data.data = se_alloc(ssl_decrypted_data_avail); - pi->app_data.data_len = ssl_decrypted_data_avail; - memcpy(pi->app_data.data, ssl_decrypted_data.data, ssl_decrypted_data_avail); + ssl_debug_printf("decrypt_dtls_record: allocating app_data %d " + "bytes for app data\n", dtls_decrypted_data_avail); + /* first app data record: allocate and put packet data*/ + pi = se_alloc0(sizeof(SslPacketInfo)); + pi->app_data.data = se_alloc(dtls_decrypted_data_avail); + pi->app_data.data_len = dtls_decrypted_data_avail; + memcpy(pi->app_data.data, dtls_decrypted_data.data, dtls_decrypted_data_avail); } - else { - unsigned char* store; - /* update previus record*/ - ssl_debug_printf("decrypt_ssl3_record: reallocating app_data " - "%d bytes for app data (total %d appdata bytes)\n", - ssl_decrypted_data_avail, pi->app_data.data_len + ssl_decrypted_data_avail); - store = se_alloc(pi->app_data.data_len + ssl_decrypted_data_avail); - memcpy(store, pi->app_data.data, pi->app_data.data_len); - memcpy(&store[pi->app_data.data_len], ssl_decrypted_data.data, ssl_decrypted_data_avail); - pi->app_data.data_len += (ssl_decrypted_data_avail); + else { + guchar* store; + /* update previus record*/ + ssl_debug_printf("decrypt_dtls_record: reallocating app_data " + "%d bytes for app data (total %d appdata bytes)\n", + dtls_decrypted_data_avail, pi->app_data.data_len + dtls_decrypted_data_avail); + store = se_alloc(pi->app_data.data_len + dtls_decrypted_data_avail); + memcpy(store, pi->app_data.data, pi->app_data.data_len); + memcpy(&store[pi->app_data.data_len], dtls_decrypted_data.data, dtls_decrypted_data_avail); + pi->app_data.data_len += (dtls_decrypted_data_avail); - /* old decrypted data ptr here appare to be leaked, but it's - * collected by emem allocator */ - pi->app_data.data = store; + /* old decrypted data ptr here appare to be leaked, but it's + * collected by emem allocator */ + pi->app_data.data = store; - /* data ptr is changed, so remove old one and re-add the new one*/ - ssl_debug_printf("decrypt_ssl3_record: removing old app_data ptr\n"); - p_remove_proto_data(pinfo->fd, proto_dtls); - } + /* data ptr is changed, so remove old one and re-add the new one*/ + ssl_debug_printf("decrypt_dtls_record: removing old app_data ptr\n"); + p_remove_proto_data(pinfo->fd, proto_dtls); + } - ssl_debug_printf("decrypt_ssl3_record: setting decrypted app_data ptr %p\n",pi); - p_add_proto_data(pinfo->fd, proto_dtls, pi); + ssl_debug_printf("decrypt_dtls_record: setting decrypted app_data ptr %p\n",pi); + p_add_proto_data(pinfo->fd, proto_dtls, pi); } - return ret; + return ret; } @@ -963,469 +518,392 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, /********************************************************************* * - * SSL version 3 and TLS Dissection Routines + * DTLS Dissection Routines * *********************************************************************/ -static int -dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, +static gint +dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, gboolean *need_desegmentation, + guint *conv_version, SslDecryptSession* ssl) { - /* - * struct { - * uint8 major, minor; - * } ProtocolVersion; - * - * - * enum { - * change_cipher_spec(20), alert(21), handshake(22), - * application_data(23), (255) - * } ContentType; - * - * struct { - * ContentType type; - * ProtocolVersion version; - * uint16 epoch; // New field - * uint48 sequence_number; // New field - * uint16 length; - * opaque fragment[TLSPlaintext.length]; - * } TLSPlaintext; - */ - guint32 record_length; - guint16 version; - guint16 epoch; - gdouble sequence_number; - gint64 sequence_number_temp; - - guint8 content_type; - guint8 next_byte; - proto_tree *ti = NULL; - proto_tree *dtls_record_tree = NULL; - guint32 available_bytes = 0; - SslPacketInfo* pi; - SslAssociation* association; - - available_bytes = tvb_length_remaining(tvb, offset); - - /* - * Can we do reassembly? - */ - if (ssl_desegment && pinfo->can_desegment) { - /* - * Yes - is the record header split across segment boundaries? - */ - if (available_bytes < 13) { - /* - * Yes. Tell the TCP dissector where the data for this - * message starts in the data it handed us, and how many - * more bytes we need, and return. - */ - pinfo->desegment_offset = offset; - pinfo->desegment_len = 13 - available_bytes; - *need_desegmentation = TRUE; - return 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); - - if(ssl){ - if(ssl_packet_from_server(pinfo->srcport)){ - ssl->server.seq=sequence_number; - ssl->server.epoch=epoch; - } - else{ - ssl->client.seq=sequence_number; - ssl->client.epoch=epoch; - } - } - if (ssl_is_valid_content_type(content_type)) { - - /* - * Can we do reassembly? - */ - if (ssl_desegment && pinfo->can_desegment) { - /* - * Yes - is the record split across segment boundaries? - */ - if (available_bytes < record_length + 13) { - /* - * Yes. Tell the TCP dissector where the data for this - * message starts in the data it handed us, and how many - * more bytes we need, and return. - */ - pinfo->desegment_offset = offset; - pinfo->desegment_len = (record_length + 13) - available_bytes; - *need_desegmentation = TRUE; - return offset; - } - } - - } else { - + /* + * struct { + * uint8 major, minor; + * } ProtocolVersion; + * + * + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + * + * struct { + * ContentType type; + * ProtocolVersion version; + * 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; + SslPacketInfo* pi; + SslAssociation* association; + 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); + + if(ssl){ + if(ssl_packet_from_server(dtls_associations, pinfo->srcport)){ + ssl->server.seq=sequence_number; + ssl->server.epoch=epoch; + } + else{ + ssl->client.seq=sequence_number; + ssl->client.epoch=epoch; + } + } + if (!ssl_is_valid_content_type(content_type)) { + /* if we don't have a valid content_type, there's no sense * continuing any further */ - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, "Continuation Data"); - - /* Set the protocol column */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - { - col_set_str(pinfo->cinfo, COL_PROTOCOL, - ssl_version_short_names[*conv_version]); - } - return offset + 13 + record_length; - } - - /* - * If GUI, fill in record layer part of tree - */ + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Continuation Data"); - if (tree) + /* Set the protocol column */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) { - /* 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); - dtls_record_tree = proto_item_add_subtree(ti, ett_dtls_record); + col_set_str(pinfo->cinfo, COL_PROTOCOL,"DTLS"); } + return offset + 13 + record_length; + } + + /* + * If GUI, fill in record layer part of tree + */ + + if (tree) + { + /* 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); + dtls_record_tree = proto_item_add_subtree(ti, ett_dtls_record); + } - if (dtls_record_tree) + if (dtls_record_tree) { - /* show the one-byte content type */ - proto_tree_add_item(dtls_record_tree, hf_dtls_record_content_type, - tvb, offset, 1, FALSE); - offset++; - - /* add the version */ - proto_tree_add_item(dtls_record_tree, hf_dtls_record_version, tvb, - offset, 2, FALSE); - offset += 2; + /* show the one-byte content type */ + proto_tree_add_item(dtls_record_tree, hf_dtls_record_content_type, + tvb, offset, 1, FALSE); + offset++; - /* show epoch */ - proto_tree_add_uint(dtls_record_tree, hf_dtls_record_epoch, tvb, offset, 2, epoch); + /* add the version */ + proto_tree_add_item(dtls_record_tree, hf_dtls_record_version, tvb, + offset, 2, FALSE); + offset += 2; - offset += 2; + /* show epoch */ + proto_tree_add_uint(dtls_record_tree, hf_dtls_record_epoch, tvb, offset, 2, epoch); - /* add sequence_number */ + offset += 2; - proto_tree_add_double(dtls_record_tree, hf_dtls_record_sequence_number, tvb, offset, 6, sequence_number); + /* add sequence_number */ - offset += 6; + proto_tree_add_double(dtls_record_tree, hf_dtls_record_sequence_number, tvb, offset, 6, sequence_number); - /* add the length */ - proto_tree_add_uint(dtls_record_tree, hf_dtls_record_length, tvb, - offset, 2, record_length); - offset += 2; /* move past length field itself */ + offset += 6; + /* add the length */ + proto_tree_add_uint(dtls_record_tree, hf_dtls_record_length, tvb, + offset, 2, record_length); + offset += 2; /* move past length field itself */ } - else + else { - /* if no GUI tree, then just skip over those fields */ - offset += 13; + /* if no GUI tree, then just skip over those fields */ + offset += 13; } - - /* - * if we don't already have a version set for this conversation, - * but this message's version is authoritative (i.e., it's - * not client_hello, then save the version to to conversation - * structure and print the column version - */ - next_byte = tvb_get_guint8(tvb, offset); - if (*conv_version == SSL_VER_UNKNOWN - && ssl_is_authoritative_version_message(content_type, next_byte)) + /* + * if we don't already have a version set for this conversation, + * but this message's version is authoritative (i.e., it's + * not client_hello, then save the version to to conversation + * structure and print the column version + */ + next_byte = tvb_get_guint8(tvb, offset); + if (*conv_version == SSL_VER_UNKNOWN + && dtls_is_authoritative_version_message(content_type, next_byte)) { - if (version == SSLV3_VERSION) - { - *conv_version = SSL_VER_SSLv3; - if (ssl) { - ssl->version_netorder = version; - ssl->state |= SSL_VERSION; - } - /*ssl_set_conv_version(pinfo, ssl->version);*/ - } - else if (version == TLSV1_VERSION) - { - - *conv_version = SSL_VER_TLS; - if (ssl) { - ssl->version_netorder = version; - ssl->state |= SSL_VERSION; - } - /*ssl_set_conv_version(pinfo, ssl->version);*/ - } - else if (version == TLSV1DOT1_VERSION) - { - - *conv_version = SSL_VER_TLSv1DOT1; - if (ssl) { - ssl->version_netorder = version; - ssl->state |= SSL_VERSION; - } - /*ssl_set_conv_version(pinfo, ssl->version);*/ - } - else if (version == DTLSV1DOT0_VERSION) + if (version == DTLSV1DOT0_VERSION) { - *conv_version = SSL_VER_DTLS; - if (ssl) { - ssl->version_netorder = version; - ssl->state |= SSL_VERSION; - } - /*ssl_set_conv_version(pinfo, ssl->version);*/ + *conv_version = SSL_VER_DTLS; + if (ssl) { + ssl->version_netorder = version; + ssl->state |= SSL_VERSION; + } + /*ssl_set_conv_version(pinfo, ssl->version);*/ } } - if (check_col(pinfo->cinfo, COL_PROTOCOL)) + if (check_col(pinfo->cinfo, COL_PROTOCOL)) { - if (version == DTLSV1DOT0_VERSION) + if (version == DTLSV1DOT0_VERSION) { - col_set_str(pinfo->cinfo, COL_PROTOCOL, - ssl_version_short_names[SSL_VER_DTLS]); + col_set_str(pinfo->cinfo, COL_PROTOCOL, + ssl_version_short_names[SSL_VER_DTLS]); } - else + else { - col_set_str(pinfo->cinfo, COL_PROTOCOL, - ssl_version_short_names[*conv_version]); + col_set_str(pinfo->cinfo, COL_PROTOCOL,"DTLS"); } } - /* - * now dissect the next layer - */ - ssl_debug_printf("dissect_ssl3_record: content_type %d\n",content_type); + /* + * now dissect the next layer + */ + ssl_debug_printf("dissect_dtls_record: content_type %d\n",content_type); - /* PAOLO try to decrypt each record (we must keep ciphers "in sync") - * store plain text only for app data */ - - switch (content_type) { - case SSL_ID_CHG_CIPHER_SPEC: - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec"); - dissect_ssl3_change_cipher_spec(tvb, dtls_record_tree, - offset, conv_version, content_type); - ssl_debug_printf("dissect_ssl3_change_cipher_spec\n"); - break; - case SSL_ID_ALERT: - { - tvbuff_t* decrypted=0; - if (ssl&&decrypt_ssl3_record(tvb, pinfo, offset, - record_length, content_type, ssl, FALSE)) - ssl_add_record_info(pinfo, ssl_decrypted_data.data, - ssl_decrypted_data_avail, offset); - - /* try to retrive and use decrypted alert record, if any. */ - decrypted = ssl_get_record_info(pinfo, offset); - if (decrypted) - dissect_ssl3_alert(decrypted, pinfo, dtls_record_tree, 0, - conv_version); - else - dissect_ssl3_alert(tvb, pinfo, dtls_record_tree, offset, - conv_version); - break; - } - case SSL_ID_HANDSHAKE: - { - tvbuff_t* decrypted=0; - /* try to decrypt handshake record, if possible. Store decrypted - * record for later usage. The offset is used as 'key' to itentify - * this record into the packet (we can have multiple handshake records - * in the same frame) */ - if (ssl && decrypt_ssl3_record(tvb, pinfo, offset, - record_length, content_type, ssl, FALSE)) - ssl_add_record_info(pinfo, ssl_decrypted_data.data, - ssl_decrypted_data_avail, offset); + /* PAOLO try to decrypt each record (we must keep ciphers "in sync") + * store plain text only for app data */ + + switch (content_type) { + case SSL_ID_CHG_CIPHER_SPEC: + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec"); + dissect_dtls_change_cipher_spec(tvb, dtls_record_tree, + offset, conv_version, content_type); + break; + case SSL_ID_ALERT: + { + tvbuff_t* decrypted; + decrypted = 0; + if (ssl&&decrypt_dtls_record(tvb, pinfo, offset, + record_length, content_type, ssl, FALSE)) + ssl_add_record_info(proto_dtls, pinfo, dtls_decrypted_data.data, + 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) + dissect_dtls_alert(decrypted, pinfo, dtls_record_tree, 0, + conv_version); + else + dissect_dtls_alert(tvb, pinfo, dtls_record_tree, offset, + conv_version); + break; + } + case SSL_ID_HANDSHAKE: + { + tvbuff_t* decrypted; + decrypted = 0; + /* try to decrypt handshake record, if possible. Store decrypted + * record for later usage. The offset is used as 'key' to itentify + * this record into the packet (we can have multiple handshake records + * in the same frame) */ + if (ssl && decrypt_dtls_record(tvb, pinfo, offset, + record_length, content_type, ssl, FALSE)) + ssl_add_record_info(proto_dtls, pinfo, dtls_decrypted_data.data, + dtls_decrypted_data_avail, offset); - /* try to retrive and use decrypted handshake record, if any. */ - decrypted = ssl_get_record_info(pinfo, offset); - if (decrypted) - dissect_ssl3_handshake(decrypted, pinfo, dtls_record_tree, 0, - decrypted->length, conv_version, ssl, content_type); - else - dissect_ssl3_handshake(tvb, pinfo, dtls_record_tree, offset, + /* try to retrive and use decrypted handshake record, if any. */ + decrypted = ssl_get_record_info(proto_dtls, pinfo, offset); + if (decrypted) + dissect_dtls_handshake(decrypted, pinfo, dtls_record_tree, 0, + decrypted->length, conv_version, ssl, content_type); + else + dissect_dtls_handshake(tvb, pinfo, dtls_record_tree, offset, record_length, conv_version, ssl, content_type); - break; + break; } - case SSL_ID_APP_DATA: - if (ssl) - decrypt_ssl3_record(tvb, pinfo, offset, - record_length, content_type, ssl, TRUE); + case SSL_ID_APP_DATA: + if (ssl) + decrypt_dtls_record(tvb, pinfo, offset, + record_length, content_type, ssl, TRUE); - /* show on info colum what we are decoding */ - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, "Application Data"); + /* show on info colum what we are decoding */ + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Application Data"); - if (!dtls_record_tree) - break; + if (!dtls_record_tree) + break; - /* we need dissector information when the selected packet is shown. - * ssl session pointer is NULL at that time, so we can't access - * info cached there*/ - association = ssl_association_find(pinfo->srcport); - association = association ? association: ssl_association_find(pinfo->destport); - - proto_item_set_text(dtls_record_tree, - "%s Record Layer: %s Protocol: %s", - ssl_version_short_names[*conv_version], - val_to_str(content_type, ssl_31_content_type, "unknown"), - association?association->info:"Application Data"); + /* we need dissector information when the selected packet is shown. + * ssl session pointer is NULL at that time, so we can't access + * info cached there*/ + association = ssl_association_find(dtls_associations, pinfo->srcport); + association = association ? association: ssl_association_find(dtls_associations, pinfo->destport); + + proto_item_set_text(dtls_record_tree, + "%s Record Layer: %s Protocol: %s", + ssl_version_short_names[*conv_version], + val_to_str(content_type, ssl_31_content_type, "unknown"), + association?association->info:"Application Data"); - /* show decrypted data info, if available */ - pi = p_get_proto_data(pinfo->fd, proto_dtls); - if (pi && pi->app_data.data) - { - tvbuff_t* new_tvb; + proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb, + offset, record_length, 0); + + /* show decrypted data info, if available */ + pi = p_get_proto_data(pinfo->fd, proto_dtls); + if (pi && pi->app_data.data) + { + tvbuff_t* new_tvb; - /* try to dissect decrypted data*/ - ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", - pi->app_data.data_len); + /* try to dissect decrypted data*/ + ssl_debug_printf("dissect_dtls_record decrypted len %d\n", + pi->app_data.data_len); - /* create new tvbuff for the decrypted data */ - new_tvb = tvb_new_real_data(pi->app_data.data, - pi->app_data.data_len, pi->app_data.data_len); - tvb_set_free_cb(new_tvb, g_free); - /* tvb_set_child_real_data_tvbuff(tvb, new_tvb); */ + /* create new tvbuff for the decrypted data */ + new_tvb = tvb_new_real_data(pi->app_data.data, + pi->app_data.data_len, pi->app_data.data_len); + tvb_set_free_cb(new_tvb, g_free); + /* tvb_set_child_real_data_tvbuff(tvb, new_tvb); */ - /* find out a dissector using server port*/ - if (association && association->handle) { - ssl_debug_printf("dissect_ssl3_record found association %p\n", association); - ssl_print_text_data("decrypted app data",pi->app_data.data, - pi->app_data.data_len); + add_new_data_source(pinfo, new_tvb, "Decrypted DTLS data"); + + /* find out a dissector using server port*/ + if (association && association->handle) { + ssl_debug_printf("dissect_dtls_record found association %p\n", association); + ssl_print_text_data("decrypted app data",pi->app_data.data, + pi->app_data.data_len); - call_dissector(association->handle, new_tvb, pinfo, dtls_record_tree); - } - /* add raw decrypted data only if a decoder is not found*/ - else - proto_tree_add_string(dtls_record_tree, hf_dtls_record_appdata_decrypted, tvb, - offset, pi->app_data.data_len, (char*) pi->app_data.data); - } - else { - tvb_ensure_bytes_exist(tvb, offset, record_length); - proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb, - offset, record_length, 0); - } - break; - - default: - /* shouldn't get here since we check above for valid types */ - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, "Bad SSLv3 Content Type"); - break; - } - offset += record_length; /* skip to end of record */ + call_dissector(association->handle, new_tvb, pinfo, top_tree); + } + } + break; - return offset; + default: + /* shouldn't get here since we check above for valid types */ + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Bad DTLS Content Type"); + break; + } + offset += record_length; /* skip to end of record */ + + return offset; } /* dissects the change cipher spec procotol, filling in the tree */ static void -dissect_ssl3_change_cipher_spec(tvbuff_t *tvb, +dissect_dtls_change_cipher_spec(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint* conv_version, guint8 content_type) { - /* - * struct { - * enum { change_cipher_spec(1), (255) } type; - * } ChangeCipherSpec; - * - */ - if (tree) + /* + * struct { + * enum { change_cipher_spec(1), (255) } type; + * } ChangeCipherSpec; + * + */ + if (tree) { - proto_item_set_text(tree, - "%s Record Layer: %s Protocol: Change Cipher Spec", - ssl_version_short_names[*conv_version], - val_to_str(content_type, ssl_31_content_type, "unknown")); - proto_tree_add_item(tree, hf_dtls_change_cipher_spec, tvb, - offset++, 1, FALSE); + proto_item_set_text(tree, + "%s Record Layer: %s Protocol: Change Cipher Spec", + ssl_version_short_names[*conv_version], + val_to_str(content_type, ssl_31_content_type, "unknown")); + proto_tree_add_item(tree, hf_dtls_change_cipher_spec, tvb, + offset++, 1, FALSE); } } /* dissects the alert message, filling in the tree */ static void -dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, +dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint* conv_version) { - /* struct { - * AlertLevel level; - * AlertDescription description; - * } Alert; - */ - proto_tree *ti; - proto_tree *ssl_alert_tree = NULL; - const gchar *level; - const gchar *desc; - guint8 byte; + /* struct { + * AlertLevel level; + * AlertDescription description; + * } Alert; + */ + proto_tree *ti; + proto_tree *ssl_alert_tree; + const gchar *level; + const gchar *desc; + guint8 byte; + ssl_alert_tree = NULL; - if (tree) + if (tree) { - ti = proto_tree_add_item(tree, hf_dtls_alert_message, tvb, - offset, 2, 0); - ssl_alert_tree = proto_item_add_subtree(ti, ett_dtls_alert); + ti = proto_tree_add_item(tree, hf_dtls_alert_message, tvb, + offset, 2, 0); + ssl_alert_tree = proto_item_add_subtree(ti, ett_dtls_alert); } - /* - * set the record layer label - */ + /* + * set the record layer label + */ - /* first lookup the names for the alert level and description */ - byte = tvb_get_guint8(tvb, offset); /* grab the level byte */ - level = match_strval(byte, ssl_31_alert_level); + /* first lookup the names for the alert level and description */ + 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) + /* now set the text in the record layer line */ + if (level && desc) { - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, - "Alert (Level: %s, Description: %s)", - level, desc); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, + "Alert (Level: %s, Description: %s)", + level, desc); } - else + else { - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Alert"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Alert"); } - if (tree) + if (tree) { - if (level && desc) + if (level && desc) { - proto_item_set_text(tree, "%s Record Layer: Alert " - "(Level: %s, Description: %s)", - ssl_version_short_names[*conv_version], - level, desc); - proto_tree_add_item(ssl_alert_tree, hf_dtls_alert_message_level, - tvb, offset++, 1, FALSE); - - proto_tree_add_item(ssl_alert_tree, hf_dtls_alert_message_description, - tvb, offset++, 1, FALSE); + proto_item_set_text(tree, "%s Record Layer: Alert " + "(Level: %s, Description: %s)", + ssl_version_short_names[*conv_version], + level, desc); + proto_tree_add_item(ssl_alert_tree, hf_dtls_alert_message_level, + tvb, offset++, 1, FALSE); + + proto_tree_add_item(ssl_alert_tree, hf_dtls_alert_message_description, + tvb, offset++, 1, FALSE); } - else + else { - proto_item_set_text(tree, - "%s Record Layer: Encrypted Alert", - ssl_version_short_names[*conv_version]); - proto_item_set_text(ssl_alert_tree, - "Alert Message: Encrypted Alert"); + proto_item_set_text(tree, + "%s Record Layer: Encrypted Alert", + ssl_version_short_names[*conv_version]); + proto_item_set_text(ssl_alert_tree, + "Alert Message: Encrypted Alert"); } } } @@ -1433,522 +911,528 @@ dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, /* dissects the handshake protocol, filling the tree */ static void -dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, +dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint32 record_length, guint *conv_version, SslDecryptSession* ssl, guint8 content_type) { - /* struct { - * HandshakeType msg_type; - * uint24 length; - * uint16 message_seq; //new field - * uint24 fragment_offset; //new field - * uint24 fragment_length; //new field - * select (HandshakeType) { - * case hello_request: HelloRequest; - * case client_hello: ClientHello; - * case server_hello: ServerHello; - * case hello_verify_request: HelloVerifyRequest; //new field - * case certificate: Certificate; - * case server_key_exchange: ServerKeyExchange; - * case certificate_request: CertificateRequest; - * case server_hello_done: ServerHelloDone; - * case certificate_verify: CertificateVerify; - * case client_key_exchange: ClientKeyExchange; - * case finished: Finished; - * } body; - * } Handshake; - */ - proto_tree *ti = NULL; - proto_tree *ssl_hand_tree = NULL; - const gchar *msg_type_str = NULL; - guint8 msg_type; - guint32 length; - guint16 message_seq; - guint32 fragment_offset; - guint32 fragment_length; - - gboolean first_iteration = TRUE; - - - /* just as there can be multiple records per packet, there - * can be multiple messages per record as long as they have - * the same content type - * - * we really only care about this for handshake messages - */ + /* struct { + * HandshakeType msg_type; + * uint24 length; + * uint16 message_seq; //new field + * uint24 fragment_offset; //new field + * uint24 fragment_length; //new field + * select (HandshakeType) { + * case hello_request: HelloRequest; + * case client_hello: ClientHello; + * case server_hello: ServerHello; + * case hello_verify_request: HelloVerifyRequest; //new field + * case certificate: Certificate; + * case server_key_exchange: ServerKeyExchange; + * case certificate_request: CertificateRequest; + * case server_hello_done: ServerHelloDone; + * case certificate_verify: CertificateVerify; + * case client_key_exchange: ClientKeyExchange; + * case finished: Finished; + * } body; + * } Handshake; + */ + 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; + + /* just as there can be multiple records per packet, there + * can be multiple messages per record as long as they have + * the same content type + * + * we really only care about this for handshake messages + */ - /* set record_length to the max offset */ - record_length += offset; - while (offset < record_length) - { - 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); + /* set record_length to the max offset */ + record_length += offset; + while (offset < record_length) + { + 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); - if (!msg_type_str && !first_iteration) + if (!msg_type_str && !first_iteration) { - /* only dissect / report messages if they're - * either the first message in this record - * or they're a valid message type - */ - return; + /* only dissect / report messages if they're + * either the first message in this record + * or they're a valid message type + */ + return; } - /* on second and later iterations, add comma to info col */ - if (!first_iteration) + /* on second and later iterations, add comma to info col */ + if (!first_iteration) { - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, ", "); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", "); } - /* - * Update our info string - */ - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, "%s", (msg_type_str != NULL) - ? msg_type_str : "Encrypted Handshake Message"); + /* + * Update our info string + */ + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s", (msg_type_str != NULL) + ? msg_type_str : "Encrypted Handshake Message"); - if (tree) + if (tree) { - /* set the label text on the record layer expanding node */ - if (first_iteration) + /* set the label text on the record layer expanding node */ + if (first_iteration) { - proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s", - ssl_version_short_names[*conv_version], - val_to_str(content_type, ssl_31_content_type, "unknown"), - (msg_type_str!=NULL) ? msg_type_str : - "Encrypted Handshake Message"); + proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s", + ssl_version_short_names[*conv_version], + val_to_str(content_type, ssl_31_content_type, "unknown"), + (msg_type_str!=NULL) ? msg_type_str : + "Encrypted Handshake Message"); } - else + else { - proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s", - ssl_version_short_names[*conv_version], - val_to_str(content_type, ssl_31_content_type, "unknown"), - "Multiple Handshake Messages"); + proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s", + ssl_version_short_names[*conv_version], + val_to_str(content_type, ssl_31_content_type, "unknown"), + "Multiple Handshake Messages"); } - /* add a subtree for the handshake protocol */ - ti = proto_tree_add_item(tree, hf_dtls_handshake_protocol, tvb, - offset, length + 12, 0); - ssl_hand_tree = proto_item_add_subtree(ti, ett_dtls_handshake); + /* add a subtree for the handshake protocol */ + ti = proto_tree_add_item(tree, hf_dtls_handshake_protocol, tvb, + offset, length + 12, 0); + ssl_hand_tree = proto_item_add_subtree(ti, ett_dtls_handshake); - if (ssl_hand_tree) + if (ssl_hand_tree) { - /* set the text label on the subtree node */ - proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s", - (msg_type_str != NULL) ? msg_type_str : - "Encrypted Handshake Message"); + /* set the text label on the subtree node */ + proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s", + (msg_type_str != NULL) ? msg_type_str : + "Encrypted Handshake Message"); } } - /* if we don't have a valid handshake type, just quit dissecting */ - if (!msg_type_str) - return; + /* if we don't have a valid handshake type, just quit dissecting */ + if (!msg_type_str) + return; - /* PAOLO: if we are doing ssl decryption we must dissect some requests type */ - if (ssl_hand_tree || ssl) + /* if we are doing ssl decryption we must dissect some requests type */ + if (ssl_hand_tree || ssl) { - /* add nodes for the message type and message length */ - if (ssl_hand_tree) - proto_tree_add_item(ssl_hand_tree, hf_dtls_handshake_type, - tvb, offset, 1, msg_type); - offset++; - if (ssl_hand_tree) - proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_length, + /* add nodes for the message type and message length */ + if (ssl_hand_tree) + proto_tree_add_item(ssl_hand_tree, hf_dtls_handshake_type, + tvb, offset, 1, msg_type); + offset++; + if (ssl_hand_tree) + proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_length, tvb, offset, 3, length); - offset += 3; + offset += 3; - if (ssl_hand_tree) - proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_message_seq, + if (ssl_hand_tree) + proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_message_seq, tvb, offset, 2, message_seq); - offset += 2; - if (ssl_hand_tree) - proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_fragment_offset, + offset += 2; + if (ssl_hand_tree) + proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_fragment_offset, tvb, offset, 3, fragment_offset); - offset += 3; - if (ssl_hand_tree) - proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_fragment_length, + offset += 3; + if (ssl_hand_tree) + proto_tree_add_uint(ssl_hand_tree, hf_dtls_handshake_fragment_length, tvb, offset, 3, fragment_length); - offset += 3; + offset += 3; - /* now dissect the handshake message, if necessary */ - switch (msg_type) { - case SSL_HND_HELLO_REQUEST: - /* hello_request has no fields, so nothing to do! */ - break; + /* now dissect the handshake message, if necessary */ + switch (msg_type) { + case SSL_HND_HELLO_REQUEST: + /* hello_request has no fields, so nothing to do! */ + break; - case SSL_HND_CLIENT_HELLO: - dissect_ssl3_hnd_cli_hello(tvb, ssl_hand_tree, offset, length, ssl); - break; + case SSL_HND_CLIENT_HELLO: + dissect_dtls_hnd_cli_hello(tvb, ssl_hand_tree, offset, length, ssl); + break; - case SSL_HND_HELLO_VERIFY_REQUEST: - dissect_ssl3_hnd_hello_verify_request(tvb, ssl_hand_tree, offset, length, ssl); - break; + case SSL_HND_HELLO_VERIFY_REQUEST: + dissect_dtls_hnd_hello_verify_request(tvb, ssl_hand_tree, offset, ssl); + break; - case SSL_HND_SERVER_HELLO: - dissect_ssl3_hnd_srv_hello(tvb, ssl_hand_tree, offset, length, ssl); - break; - - case SSL_HND_CERTIFICATE: - dissect_ssl3_hnd_cert(tvb, ssl_hand_tree, offset, pinfo); - break; - - case SSL_HND_SERVER_KEY_EXCHG: - /* unimplemented */ - break; - - case SSL_HND_CERT_REQUEST: - dissect_ssl3_hnd_cert_req(tvb, ssl_hand_tree, offset); - break; - - case SSL_HND_SVR_HELLO_DONE: - /* server_hello_done has no fields, so nothing to do! */ - break; - - case SSL_HND_CERT_VERIFY: - /* unimplemented */ - break; - - case SSL_HND_CLIENT_KEY_EXCHG: - { - /* PAOLO: here we can have all the data to build session key*/ - StringInfo encrypted_pre_master; - int ret; - unsigned encrlen = length, skip = 0; - - if (!ssl) - break; + case SSL_HND_SERVER_HELLO: + dissect_dtls_hnd_srv_hello(tvb, ssl_hand_tree, offset, length, ssl); + break; + + case SSL_HND_CERTIFICATE: + dissect_dtls_hnd_cert(tvb, ssl_hand_tree, offset, pinfo); + break; + + case SSL_HND_SERVER_KEY_EXCHG: + /* unimplemented */ + break; + + case SSL_HND_CERT_REQUEST: + dissect_dtls_hnd_cert_req(tvb, ssl_hand_tree, offset); + break; + + case SSL_HND_SVR_HELLO_DONE: + /* server_hello_done has no fields, so nothing to do! */ + break; + + case SSL_HND_CERT_VERIFY: + /* unimplemented */ + break; + + case SSL_HND_CLIENT_KEY_EXCHG: + { + /* here we can have all the data to build session key */ + StringInfo encrypted_pre_master; + gint ret; + guint encrlen = length, skip; + skip = 0; + + if (!ssl) + break; - /* check for required session data */ - ssl_debug_printf("dissect_ssl3_handshake found SSL_HND_CLIENT_KEY_EXCHG state %X\n", - ssl->state); - if ((ssl->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) != - (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) { - ssl_debug_printf("dissect_ssl3_handshake not enough data to generate key (required %X)\n", - (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)); - break; - } + /* check for required session data */ + ssl_debug_printf("dissect_dtls_handshake found SSL_HND_CLIENT_KEY_EXCHG state %X\n", + ssl->state); + if ((ssl->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) != + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) { + ssl_debug_printf("dissect_dtls_handshake not enough data to generate key (required %X)\n", + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)); + break; + } - encrypted_pre_master.data = se_alloc(encrlen); - encrypted_pre_master.data_len = encrlen; - tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen); + encrypted_pre_master.data = se_alloc(encrlen); + encrypted_pre_master.data_len = encrlen; + tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen); - if (!ssl->private_key) { - ssl_debug_printf("dissect_ssl3_handshake can't find private key\n"); - break; - } + if (!ssl->private_key) { + ssl_debug_printf("dissect_dtls_handshake can't find private key\n"); + break; + } - /* go with ssl key processessing; encrypted_pre_master - * will be used for master secret store*/ - ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key); - if (ret < 0) { - ssl_debug_printf("dissect_ssl3_handshake can't decrypt pre master secret\n"); - break; - } - if (ssl_generate_keyring_material(ssl)<0) { - ssl_debug_printf("dissect_ssl3_handshake can't generate keyring material\n"); - break; - } - ssl->state |= SSL_HAVE_SESSION_KEY; - ssl_save_session(ssl); - ssl_debug_printf("dissect_ssl3_handshake session keys succesfully generated\n"); - } - break; - - case SSL_HND_FINISHED: - dissect_ssl3_hnd_finished(tvb, ssl_hand_tree, - offset, conv_version); - break; - } + /* go with ssl key processessing; encrypted_pre_master + * will be used for master secret store*/ + ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key); + if (ret < 0) { + ssl_debug_printf("dissect_dtls_handshake can't decrypt pre master secret\n"); + break; + } + if (ssl_generate_keyring_material(ssl)<0) { + ssl_debug_printf("dissect_dtls_handshake can't generate keyring material\n"); + break; + } + ssl->state |= SSL_HAVE_SESSION_KEY; + ssl_save_session(ssl, dtls_session_hash); + ssl_debug_printf("dissect_dtls_handshake session keys succesfully generated\n"); + } + break; + + case SSL_HND_FINISHED: + dissect_dtls_hnd_finished(tvb, ssl_hand_tree, + offset, conv_version); + break; + } } - else{ - offset += 12; /* skip the handshake header when handshake is not processed*/ - } - offset += length; - first_iteration = FALSE; /* set up for next pass, if any */ + else{ + offset += 12; /* skip the handshake header when handshake is not processed*/ + } + offset += length; + first_iteration = FALSE; /* set up for next pass, if any */ } } -static int -dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, +static gint +dissect_dtls_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, guint32 offset, SslDecryptSession* ssl, gint from_server) { - /* show the client's random challenge */ - nstime_t gmt_unix_time; - guint8 session_id_length = 0; - - if (ssl) - { - /* PAOLO: get proper peer information*/ - StringInfo* rnd; - if (from_server) - rnd = &ssl->server_random; - else - rnd = &ssl->client_random; + /* 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; - /* 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_ssl3_hnd_hello_common found random state %X\n", - ssl->state); + /* 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)) + 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); + /* 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+33, session_id_length); - ssl->session_id.data_len = session_id_length; - } + 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); - offset += 4; - - /* show the random bytes */ - proto_tree_add_item(tree, hf_dtls_handshake_random_bytes, - tvb, offset, 28, 0); - 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) + { + /* 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); + offset += 4; + + /* show the random bytes */ + proto_tree_add_item(tree, hf_dtls_handshake_random_bytes, + tvb, offset, 28, 0); + 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) { - tvb_ensure_bytes_exist(tvb, offset, session_id_length); - 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; + tvb_ensure_bytes_exist(tvb, offset, session_id_length); + 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; } } - /* XXXX */ - return session_id_length+33; + /* XXXX */ + return session_id_length+33; } -static int -dissect_ssl3_hnd_hello_ext(tvbuff_t *tvb, +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; - proto_item *pi; - proto_tree *ext_tree; - - if (left < 2) - return offset; - - extension_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_extensions_len, - tvb, offset, 2, extension_length); - offset += 2; - left -= 2; - - while (left >= 4) + guint16 extension_length; + guint16 ext_type; + guint16 ext_len; + proto_item *pi; + proto_tree *ext_tree; + + if (left < 2) + return offset; + + extension_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_dtls_handshake_extensions_len, + tvb, offset, 2, extension_length); + offset += 2; + left -= 2; + + while (left >= 4) { - ext_type = tvb_get_ntohs(tvb, offset); - ext_len = tvb_get_ntohs(tvb, offset + 2); - - pi = proto_tree_add_text(tree, tvb, offset, 4 + ext_len, - "Extension: %s", - val_to_str(ext_type, - tls_hello_extension_types, - "Unknown %u")); - ext_tree = proto_item_add_subtree(pi, ett_dtls_extension); - if (!ext_tree) - ext_tree = tree; - - proto_tree_add_uint(ext_tree, hf_dtls_handshake_extension_type, - tvb, offset, 2, ext_type); - offset += 2; - - proto_tree_add_uint(ext_tree, hf_dtls_handshake_extension_len, - tvb, offset, 2, ext_len); - 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")); - offset += ext_len; - left -= 2 + 2 + ext_len; + ext_type = tvb_get_ntohs(tvb, offset); + ext_len = tvb_get_ntohs(tvb, offset + 2); + + pi = proto_tree_add_text(tree, tvb, offset, 4 + ext_len, + "Extension: %s", + val_to_str(ext_type, + tls_hello_extension_types, + "Unknown %u")); + ext_tree = proto_item_add_subtree(pi, ett_dtls_extension); + if (!ext_tree) + ext_tree = tree; + + proto_tree_add_uint(ext_tree, hf_dtls_handshake_extension_type, + tvb, offset, 2, ext_type); + offset += 2; + + proto_tree_add_uint(ext_tree, hf_dtls_handshake_extension_len, + tvb, offset, 2, ext_len); + 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")); + offset += ext_len; + left -= 2 + 2 + ext_len; } - return offset; + return offset; } static void -dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, - proto_tree *tree, guint32 offset, guint32 length, - SslDecryptSession*ssl) +dissect_dtls_hnd_cli_hello(tvbuff_t *tvb, + proto_tree *tree, guint32 offset, guint32 length, + SslDecryptSession*ssl) { - /* struct { - * ProtocolVersion client_version; - * Random random; - * SessionID session_id; - * opaque cookie<0..32>; //new field - * CipherSuite cipher_suites<2..2^16-1>; - * CompressionMethod compression_methods<1..2^8-1>; - * Extension client_hello_extension_list<0..2^16-1>; - * } ClientHello; - * - */ - proto_tree *ti; - proto_tree *cs_tree; - guint16 cipher_suite_length = 0; - guint8 compression_methods_length = 0; - guint8 compression_method; - guint16 start_offset = offset; - guint8 cookie_length = 0; - - if (tree || ssl) + /* struct { + * ProtocolVersion client_version; + * Random random; + * SessionID session_id; + * opaque cookie<0..32>; //new field + * CipherSuite cipher_suites<2..2^16-1>; + * CompressionMethod compression_methods<1..2^8-1>; + * Extension client_hello_extension_list<0..2^16-1>; + * } 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; + + if (tree || ssl) { - /* show the client version */ - if (tree) - proto_tree_add_item(tree, hf_dtls_handshake_client_version, tvb, + /* show the client version */ + if (tree) + proto_tree_add_item(tree, hf_dtls_handshake_client_version, tvb, offset, 2, FALSE); - offset += 2; + offset += 2; - /* show the fields in common with server hello */ - offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 0); + /* show the fields in common with server hello */ + offset += dissect_dtls_hnd_hello_common(tvb, tree, offset, ssl, 0); - /* look for a cookie */ - cookie_length = tvb_get_guint8(tvb, offset); - if (!tree) - return; + /* look for a cookie */ + cookie_length = tvb_get_guint8(tvb, offset); + if (!tree) + return; - proto_tree_add_uint(tree, hf_dtls_handshake_cookie_len, - tvb, offset, 1, cookie_length); - offset ++; /* skip opaque length */ + proto_tree_add_uint(tree, hf_dtls_handshake_cookie_len, + tvb, offset, 1, cookie_length); + offset ++; /* skip opaque length */ - if (cookie_length > 0) - { - tvb_ensure_bytes_exist(tvb, offset, 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)", - cookie_length, - plurality(cookie_length, "", "s")); - offset += cookie_length; - } + if (cookie_length > 0) + { + tvb_ensure_bytes_exist(tvb, offset, 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)", + cookie_length, + plurality(cookie_length, "", "s")); + offset += cookie_length; + } - /* tell the user how many cipher suites there are */ - cipher_suite_length = tvb_get_ntohs(tvb, offset); + /* tell the user how many cipher suites there are */ + cipher_suite_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_cipher_suites_len, - tvb, offset, 2, cipher_suite_length); - offset += 2; /* skip opaque length */ + proto_tree_add_uint(tree, hf_dtls_handshake_cipher_suites_len, + tvb, offset, 2, cipher_suite_length); + offset += 2; /* skip opaque length */ - if (cipher_suite_length > 0) + if (cipher_suite_length > 0) { - tvb_ensure_bytes_exist(tvb, offset, cipher_suite_length); - ti = proto_tree_add_none_format(tree, - hf_dtls_handshake_cipher_suites, - tvb, offset, cipher_suite_length, - "Cipher Suites (%u suite%s)", - cipher_suite_length / 2, - plurality(cipher_suite_length/2, "", "s")); - - /* make this a subtree */ - cs_tree = proto_item_add_subtree(ti, ett_dtls_cipher_suites); - if (!cs_tree) + tvb_ensure_bytes_exist(tvb, offset, cipher_suite_length); + ti = proto_tree_add_none_format(tree, + hf_dtls_handshake_cipher_suites, + tvb, offset, cipher_suite_length, + "Cipher Suites (%u suite%s)", + cipher_suite_length / 2, + plurality(cipher_suite_length/2, "", "s")); + + /* make this a subtree */ + cs_tree = proto_item_add_subtree(ti, ett_dtls_cipher_suites); + if (!cs_tree) { - cs_tree = tree; /* failsafe */ + cs_tree = tree; /* failsafe */ } - while (cipher_suite_length > 0) + while (cipher_suite_length > 0) { - proto_tree_add_item(cs_tree, hf_dtls_handshake_cipher_suite, - tvb, offset, 2, FALSE); - offset += 2; - cipher_suite_length -= 2; + proto_tree_add_item(cs_tree, hf_dtls_handshake_cipher_suite, + tvb, offset, 2, FALSE); + offset += 2; + cipher_suite_length -= 2; } } - /* tell the user how man compression methods there are */ - compression_methods_length = tvb_get_guint8(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_comp_methods_len, - tvb, offset, 1, compression_methods_length); - offset++; + /* tell the user how man compression methods there are */ + compression_methods_length = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_dtls_handshake_comp_methods_len, + tvb, offset, 1, compression_methods_length); + offset++; - if (compression_methods_length > 0) + if (compression_methods_length > 0) { - tvb_ensure_bytes_exist(tvb, offset, compression_methods_length); - ti = proto_tree_add_none_format(tree, - hf_dtls_handshake_comp_methods, - tvb, offset, compression_methods_length, - "Compression Methods (%u method%s)", - compression_methods_length, - plurality(compression_methods_length, - "", "s")); - - /* make this a subtree */ - cs_tree = proto_item_add_subtree(ti, ett_dtls_comp_methods); - if (!cs_tree) + tvb_ensure_bytes_exist(tvb, offset, compression_methods_length); + ti = proto_tree_add_none_format(tree, + hf_dtls_handshake_comp_methods, + tvb, offset, compression_methods_length, + "Compression Methods (%u method%s)", + compression_methods_length, + plurality(compression_methods_length, + "", "s")); + + /* make this a subtree */ + cs_tree = proto_item_add_subtree(ti, ett_dtls_comp_methods); + if (!cs_tree) { - cs_tree = tree; /* failsafe */ + cs_tree = tree; /* failsafe */ } - while (compression_methods_length > 0) + while (compression_methods_length > 0) { - compression_method = tvb_get_guint8(tvb, offset); - if (compression_method < 64) - proto_tree_add_uint(cs_tree, hf_dtls_handshake_comp_method, + compression_method = tvb_get_guint8(tvb, offset); + if (compression_method < 64) + proto_tree_add_uint(cs_tree, hf_dtls_handshake_comp_method, tvb, offset, 1, compression_method); - else if (compression_method > 63 && compression_method < 193) - proto_tree_add_text(cs_tree, tvb, offset, 1, - "Compression Method: Reserved - to be assigned by IANA (%u)", - compression_method); - else - proto_tree_add_text(cs_tree, tvb, offset, 1, - "Compression Method: Private use range (%u)", - compression_method); - offset++; - compression_methods_length--; + else if (compression_method > 63 && compression_method < 193) + proto_tree_add_text(cs_tree, tvb, offset, 1, + "Compression Method: Reserved - to be assigned by IANA (%u)", + compression_method); + else + proto_tree_add_text(cs_tree, tvb, offset, 1, + "Compression Method: Private use range (%u)", + compression_method); + offset++; + compression_methods_length--; } } - if (length > offset - start_offset) + if (length > offset - start_offset) { - offset = dissect_ssl3_hnd_hello_ext(tvb, tree, offset, - length - - (offset - start_offset)); + offset = dissect_dtls_hnd_hello_ext(tvb, tree, offset, + length - + (offset - start_offset)); } } } -static void dissect_ssl3_hnd_hello_verify_request(tvbuff_t *tvb, +static void dissect_dtls_hnd_hello_verify_request(tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 length, + guint32 offset, SslDecryptSession* ssl) { /* @@ -1958,10 +1442,9 @@ static void dissect_ssl3_hnd_hello_verify_request(tvbuff_t *tvb, * } HelloVerifyRequest; */ - proto_tree *ti; - proto_tree *cs_tree; - guint8 cookie_length = 0; - + guint8 cookie_length; + cookie_length = 0; + if (tree || ssl) { /* show the client version */ @@ -1996,139 +1479,140 @@ static void dissect_ssl3_hnd_hello_verify_request(tvbuff_t *tvb, } static void -dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb, +dissect_dtls_hnd_srv_hello(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, SslDecryptSession* ssl) { - /* struct { - * ProtocolVersion server_version; - * Random random; - * SessionID session_id; - * CipherSuite cipher_suite; - * CompressionMethod compression_method; - * Extension server_hello_extension_list<0..2^16-1>; - * } ServerHello; - */ - guint16 start_offset = offset; + /* struct { + * ProtocolVersion server_version; + * Random random; + * SessionID session_id; + * CipherSuite cipher_suite; + * CompressionMethod compression_method; + * Extension server_hello_extension_list<0..2^16-1>; + * } ServerHello; + */ + guint16 start_offset; + start_offset = offset; - if (tree || ssl) + if (tree || ssl) { - /* show the server version */ - if (tree) - proto_tree_add_item(tree, hf_dtls_handshake_server_version, tvb, + /* show the server version */ + if (tree) + proto_tree_add_item(tree, hf_dtls_handshake_server_version, tvb, offset, 2, FALSE); - offset += 2; - - /* first display the elements conveniently in - * common with client hello - */ - offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 1); - - /* PAOLO: handle session cipher suite */ - if (ssl) { - /* store selected cipher suite for decryption */ - ssl->cipher = tvb_get_ntohs(tvb, offset); - if (ssl_find_cipher(ssl->cipher,&ssl->cipher_suite) < 0) { - ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't find cipher suite %X\n", ssl->cipher); - goto no_cipher; - } + offset += 2; - ssl->state |= SSL_CIPHER; - ssl_debug_printf("dissect_ssl3_hnd_srv_hello found cipher %X, state %X\n", - ssl->cipher, ssl->state); - - /* if we have restored a session now we can have enought material - * to build session key, check it out*/ - if ((ssl->state & - (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)) != - (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)) { - ssl_debug_printf("dissect_ssl3_hnd_srv_hello not enough data to generate key (required %X)\n", - (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)); - goto no_cipher; - } + /* first display the elements conveniently in + * common with client hello + */ + offset += dissect_dtls_hnd_hello_common(tvb, tree, offset, ssl, 1); + + /* PAOLO: handle session cipher suite */ + if (ssl) { + /* store selected cipher suite for decryption */ + ssl->cipher = tvb_get_ntohs(tvb, offset); + if (ssl_find_cipher(ssl->cipher,&ssl->cipher_suite) < 0) { + ssl_debug_printf("dissect_dtls_hnd_srv_hello can't find cipher suite %X\n", ssl->cipher); + goto no_cipher; + } + + ssl->state |= SSL_CIPHER; + ssl_debug_printf("dissect_dtls_hnd_srv_hello found cipher %X, state %X\n", + ssl->cipher, ssl->state); + + /* if we have restored a session now we can have enought material + * to build session key, check it out*/ + if ((ssl->state & + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)) != + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)) { + ssl_debug_printf("dissect_dtls_hnd_srv_hello not enough data to generate key (required %X)\n", + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)); + goto no_cipher; + } - ssl_debug_printf("dissect_ssl3_hnd_srv_hello trying to generate keys\n"); - if (ssl_generate_keyring_material(ssl)<0) { - ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't generate keyring material\n"); - goto no_cipher; - } - ssl->state |= SSL_HAVE_SESSION_KEY; - } -no_cipher: - if (!tree) - return; + ssl_debug_printf("dissect_dtls_hnd_srv_hello trying to generate keys\n"); + if (ssl_generate_keyring_material(ssl)<0) { + ssl_debug_printf("dissect_dtls_hnd_srv_hello can't generate keyring material\n"); + goto no_cipher; + } + ssl->state |= SSL_HAVE_SESSION_KEY; + } + no_cipher: + if (!tree) + return; - /* now the server-selected cipher suite */ - proto_tree_add_item(tree, hf_dtls_handshake_cipher_suite, - tvb, offset, 2, FALSE); - offset += 2; + /* now the server-selected cipher suite */ + proto_tree_add_item(tree, hf_dtls_handshake_cipher_suite, + tvb, offset, 2, FALSE); + offset += 2; - /* and the server-selected compression method */ - proto_tree_add_item(tree, hf_dtls_handshake_comp_method, - tvb, offset, 1, FALSE); - offset++; + /* and the server-selected compression method */ + proto_tree_add_item(tree, hf_dtls_handshake_comp_method, + tvb, offset, 1, FALSE); + offset++; - if (length > offset - start_offset) + if (length > offset - start_offset) { - offset = dissect_ssl3_hnd_hello_ext(tvb, tree, offset, - length - - (offset - start_offset)); + offset = dissect_dtls_hnd_hello_ext(tvb, tree, offset, + length - + (offset - start_offset)); } } } static void -dissect_ssl3_hnd_cert(tvbuff_t *tvb, +dissect_dtls_hnd_cert(tvbuff_t *tvb, proto_tree *tree, guint32 offset, packet_info *pinfo) { - /* opaque ASN.1Cert<2^24-1>; - * - * struct { - * ASN.1Cert certificate_list<1..2^24-1>; - * } Certificate; - */ - guint32 certificate_list_length; - proto_tree *ti; - proto_tree *subtree; + /* opaque ASN.1Cert<2^24-1>; + * + * struct { + * ASN.1Cert certificate_list<1..2^24-1>; + * } Certificate; + */ + guint32 certificate_list_length; + proto_tree *ti; + proto_tree *subtree; - if (tree) + if (tree) { - certificate_list_length = tvb_get_ntoh24(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_certificates_len, - tvb, offset, 3, certificate_list_length); - offset += 3; /* 24-bit length value */ + certificate_list_length = tvb_get_ntoh24(tvb, offset); + proto_tree_add_uint(tree, hf_dtls_handshake_certificates_len, + tvb, offset, 3, certificate_list_length); + offset += 3; /* 24-bit length value */ - if (certificate_list_length > 0) + if (certificate_list_length > 0) { - tvb_ensure_bytes_exist(tvb, offset, certificate_list_length); - ti = proto_tree_add_none_format(tree, - hf_dtls_handshake_certificates, - tvb, offset, certificate_list_length, - "Certificates (%u byte%s)", - certificate_list_length, - plurality(certificate_list_length, - "", "s")); - - /* make it a subtree */ - subtree = proto_item_add_subtree(ti, ett_dtls_certs); - if (!subtree) + tvb_ensure_bytes_exist(tvb, offset, certificate_list_length); + ti = proto_tree_add_none_format(tree, + hf_dtls_handshake_certificates, + tvb, offset, certificate_list_length, + "Certificates (%u byte%s)", + certificate_list_length, + plurality(certificate_list_length, + "", "s")); + + /* make it a subtree */ + subtree = proto_item_add_subtree(ti, ett_dtls_certs); + if (!subtree) { - subtree = tree; /* failsafe */ + subtree = tree; /* failsafe */ } - /* iterate through each certificate */ - while (certificate_list_length > 0) + /* iterate through each certificate */ + while (certificate_list_length > 0) { - /* get the length of the current certificate */ - guint32 cert_length = tvb_get_ntoh24(tvb, offset); - certificate_list_length -= 3 + cert_length; + /* get the length of the current certificate */ + guint32 cert_length = tvb_get_ntoh24(tvb, offset); + certificate_list_length -= 3 + cert_length; - proto_tree_add_item(subtree, hf_dtls_handshake_certificate_len, - tvb, offset, 3, FALSE); - offset += 3; + proto_tree_add_item(subtree, hf_dtls_handshake_certificate_len, + tvb, offset, 3, FALSE); + offset += 3; - dissect_x509af_Certificate(FALSE, tvb, offset, pinfo, subtree, hf_dtls_handshake_certificate); - offset += cert_length; + dissect_x509af_Certificate(FALSE, tvb, offset, pinfo, subtree, hf_dtls_handshake_certificate); + offset += cert_length; } } @@ -2136,97 +1620,99 @@ dissect_ssl3_hnd_cert(tvbuff_t *tvb, } static void -dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, +dissect_dtls_hnd_cert_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { - /* - * enum { - * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), - * (255) - * } ClientCertificateType; - * - * opaque DistinguishedName<1..2^16-1>; - * - * struct { - * ClientCertificateType certificate_types<1..2^8-1>; - * DistinguishedName certificate_authorities<3..2^16-1>; - * } CertificateRequest; - * - */ - proto_tree *ti; - proto_tree *subtree; - guint8 cert_types_count = 0; - int dnames_length = 0; + /* + * enum { + * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), + * (255) + * } ClientCertificateType; + * + * opaque DistinguishedName<1..2^16-1>; + * + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * DistinguishedName certificate_authorities<3..2^16-1>; + * } CertificateRequest; + * + */ + proto_tree *ti; + proto_tree *subtree; + guint8 cert_types_count; + gint dnames_length; + cert_types_count = 0; + dnames_length = 0; - if (tree) + if (tree) { - cert_types_count = tvb_get_guint8(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_cert_types_count, - tvb, offset, 1, cert_types_count); - offset++; + cert_types_count = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_dtls_handshake_cert_types_count, + tvb, offset, 1, cert_types_count); + offset++; - if (cert_types_count > 0) + if (cert_types_count > 0) { - ti = proto_tree_add_none_format(tree, - hf_dtls_handshake_cert_types, - tvb, offset, cert_types_count, - "Certificate types (%u type%s)", - cert_types_count, - plurality(cert_types_count, "", "s")); - subtree = proto_item_add_subtree(ti, ett_dtls_cert_types); - if (!subtree) + ti = proto_tree_add_none_format(tree, + hf_dtls_handshake_cert_types, + tvb, offset, cert_types_count, + "Certificate types (%u type%s)", + cert_types_count, + plurality(cert_types_count, "", "s")); + subtree = proto_item_add_subtree(ti, ett_dtls_cert_types); + if (!subtree) { - subtree = tree; + subtree = tree; } - while (cert_types_count > 0) + while (cert_types_count > 0) { - proto_tree_add_item(subtree, hf_dtls_handshake_cert_type, - tvb, offset, 1, FALSE); - offset++; - cert_types_count--; + proto_tree_add_item(subtree, hf_dtls_handshake_cert_type, + tvb, offset, 1, FALSE); + offset++; + cert_types_count--; } } - dnames_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_dnames_len, - tvb, offset, 2, dnames_length); - offset += 2; + dnames_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_dtls_handshake_dnames_len, + tvb, offset, 2, dnames_length); + offset += 2; - if (dnames_length > 0) + if (dnames_length > 0) { - tvb_ensure_bytes_exist(tvb, offset, dnames_length); - ti = proto_tree_add_none_format(tree, - hf_dtls_handshake_dnames, - tvb, offset, dnames_length, - "Distinguished Names (%d byte%s)", - dnames_length, - plurality(dnames_length, "", "s")); - subtree = proto_item_add_subtree(ti, ett_dtls_dnames); - if (!subtree) + tvb_ensure_bytes_exist(tvb, offset, dnames_length); + ti = proto_tree_add_none_format(tree, + hf_dtls_handshake_dnames, + tvb, offset, dnames_length, + "Distinguished Names (%d byte%s)", + dnames_length, + plurality(dnames_length, "", "s")); + subtree = proto_item_add_subtree(ti, ett_dtls_dnames); + if (!subtree) { - subtree = tree; + subtree = tree; } - while (dnames_length > 0) + while (dnames_length > 0) { - /* get the length of the current certificate */ - guint16 name_length = tvb_get_ntohs(tvb, offset); - dnames_length -= 2 + name_length; - - proto_tree_add_item(subtree, hf_dtls_handshake_dname_len, - tvb, offset, 2, FALSE); - offset += 2; - - tvb_ensure_bytes_exist(tvb, offset, name_length); - proto_tree_add_bytes_format(subtree, - hf_dtls_handshake_dname, - tvb, offset, name_length, - tvb_get_ptr(tvb, offset, name_length), - "Distinguished Name (%u byte%s)", - name_length, - plurality(name_length, "", "s")); - offset += name_length; + /* get the length of the current certificate */ + guint16 name_length = tvb_get_ntohs(tvb, offset); + dnames_length -= 2 + name_length; + + proto_tree_add_item(subtree, hf_dtls_handshake_dname_len, + tvb, offset, 2, FALSE); + offset += 2; + + tvb_ensure_bytes_exist(tvb, offset, name_length); + proto_tree_add_bytes_format(subtree, + hf_dtls_handshake_dname, + tvb, offset, name_length, + tvb_get_ptr(tvb, offset, name_length), + "Distinguished Name (%u byte%s)", + name_length, + plurality(name_length, "", "s")); + offset += name_length; } } } @@ -2234,997 +1720,30 @@ dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, } static void -dissect_ssl3_hnd_finished(tvbuff_t *tvb, +dissect_dtls_hnd_finished(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint* conv_version) { - /* For TLS: - * struct { - * opaque verify_data[12]; - * } Finished; - * - * For SSLv3: - * struct { - * opaque md5_hash[16]; - * opaque sha_hash[20]; - * } Finished; - */ - - /* this all needs a tree, so bail if we don't have one */ - if (!tree) - { - return; - } - - switch(*conv_version) { - case SSL_VER_DTLS: - case SSL_VER_TLS: - proto_tree_add_item(tree, hf_dtls_handshake_finished, - tvb, offset, 12, FALSE); - break; - - case SSL_VER_SSLv3: - proto_tree_add_item(tree, hf_dtls_handshake_md5_hash, - tvb, offset, 16, FALSE); - offset += 16; - proto_tree_add_item(tree, hf_dtls_handshake_sha_hash, - tvb, offset, 20, FALSE); - offset += 20; - break; - } -} - -/********************************************************************* - * - * SSL version 2 Dissectors - * - *********************************************************************/ - - -/* record layer dissector */ -static int -dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - guint32 offset, guint* conv_version, - gboolean *need_desegmentation, - SslDecryptSession* ssl) -{ - guint32 initial_offset = offset; - guint8 byte = 0; - guint8 record_length_length = 0; - guint32 record_length = 0; - gint is_escape = -1; - gint16 padding_length = -1; - guint8 msg_type = 0; - const gchar *msg_type_str = NULL; - guint32 available_bytes = 0; - - proto_tree *ti; - proto_tree *dtls_record_tree = NULL; - - /* pull first byte; if high bit is set, then record - * length is three bytes due to padding; otherwise - * record length is two bytes - */ - byte = tvb_get_guint8(tvb, offset); - record_length_length = (byte & 0x80) ? 2 : 3; - - /* - * Can we do reassembly? - */ - available_bytes = tvb_length_remaining(tvb, offset); - - if (ssl_desegment && pinfo->can_desegment) { - /* - * Yes - is the record header split across segment boundaries? - */ - if (available_bytes < record_length_length) { - /* - * Yes. Tell the TCP dissector where the data for this - * message starts in the data it handed us, and how many - * more bytes we need, and return. - */ - pinfo->desegment_offset = offset; - pinfo->desegment_len = record_length_length - available_bytes; - *need_desegmentation = TRUE; - return offset; - } - } - - /* parse out the record length */ - switch(record_length_length) { - case 2: /* two-byte record length */ - record_length = (byte & 0x7f) << 8; - byte = tvb_get_guint8(tvb, offset + 1); - record_length += byte; - break; - case 3: /* three-byte record length */ - is_escape = (byte & 0x40) ? TRUE : FALSE; - record_length = (byte & 0x3f) << 8; - byte = tvb_get_guint8(tvb, offset + 1); - record_length += byte; - byte = tvb_get_guint8(tvb, offset + 2); - padding_length = byte; - } - - /* - * Can we do reassembly? - */ - if (ssl_desegment && pinfo->can_desegment) { - /* - * Yes - is the record split across segment boundaries? - */ - if (available_bytes < (record_length_length + record_length)) { - /* - * Yes. Tell the TCP dissector where the data for this - * message starts in the data it handed us, and how many - * more bytes we need, and return. - */ - pinfo->desegment_offset = offset; - pinfo->desegment_len = (record_length_length + record_length) - - available_bytes; - *need_desegmentation = TRUE; - return offset; - } - } - offset += record_length_length; - - /* add the record layer subtree header */ - ti = proto_tree_add_item(tree, hf_ssl2_record, tvb, initial_offset, - record_length_length + record_length, 0); - dtls_record_tree = proto_item_add_subtree(ti, ett_dtls_record); - - /* pull the msg_type so we can bail if it's unknown */ - msg_type = tvb_get_guint8(tvb, initial_offset + record_length_length); - - /* if we get a server_hello or later handshake in v2, then set - * this to sslv2 - */ - if (*conv_version == SSL_VER_UNKNOWN) - { - if (ssl_looks_like_valid_pct_handshake(tvb, - (initial_offset + - record_length_length), - record_length)) { - *conv_version = SSL_VER_PCT; - /*ssl_set_conv_version(pinfo, ssl->version);*/ - } - else if (msg_type >= 2 && msg_type <= 8) - { - *conv_version = SSL_VER_SSLv2; - /*ssl_set_conv_version(pinfo, ssl->version);*/ - } - } - - /* if we get here, but don't have a version set for the - * conversation, then set a version for just this frame - * (e.g., on a client hello) - */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - { - col_set_str(pinfo->cinfo, COL_PROTOCOL, - (*conv_version == SSL_VER_PCT) ? "PCT" : "SSLv2"); - } - - /* see if the msg_type is valid; if not the payload is - * probably encrypted, so note that fact and bail - */ - msg_type_str = match_strval(msg_type, - (*conv_version == SSL_VER_PCT) - ? pct_msg_types : ssl_20_msg_types); - if (!msg_type_str - || ((*conv_version != SSL_VER_PCT) && - !ssl_looks_like_valid_v2_handshake(tvb, initial_offset - + record_length_length, - record_length)) - || ((*conv_version == SSL_VER_PCT) && - !ssl_looks_like_valid_pct_handshake(tvb, initial_offset - + record_length_length, - record_length))) - { - if (dtls_record_tree) - { - proto_item_set_text(dtls_record_tree, "%s Record Layer: %s", - (*conv_version == SSL_VER_PCT) - ? "PCT" : "SSLv2", - "Encrypted Data"); - } - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Data"); - return initial_offset + record_length_length + record_length; - } - else - { - if (check_col(pinfo->cinfo, COL_INFO)) - col_append_str(pinfo->cinfo, COL_INFO, msg_type_str); - - if (dtls_record_tree) - { - proto_item_set_text(dtls_record_tree, "%s Record Layer: %s", - (*conv_version == SSL_VER_PCT) - ? "PCT" : "SSLv2", - msg_type_str); - } - } - - /* We have a valid message type, so move foward, filling in the - * tree by adding the length, is_escape boolean and padding_length, - * if present in the original packet - */ - if (dtls_record_tree) - { - /* add the record length */ - tvb_ensure_bytes_exist(tvb, offset, record_length_length); - ti = proto_tree_add_uint (dtls_record_tree, - hf_dtls_record_length, tvb, - initial_offset, record_length_length, - record_length); - } - if (dtls_record_tree && is_escape != -1) - { - proto_tree_add_boolean(dtls_record_tree, - hf_ssl2_record_is_escape, tvb, - initial_offset, 1, is_escape); - } - if (dtls_record_tree && padding_length != -1) - { - proto_tree_add_uint(dtls_record_tree, - hf_ssl2_record_padding_length, tvb, - initial_offset + 2, 1, padding_length); - } - - /* - * dissect the record data - */ - - /* jump forward to the start of the record data */ - offset = initial_offset + record_length_length; - - /* add the message type */ - if (dtls_record_tree) - { - proto_tree_add_item(dtls_record_tree, - (*conv_version == SSL_VER_PCT) - ? hf_pct_msg_type : hf_ssl2_msg_type, - tvb, offset, 1, 0); - } - offset++; /* move past msg_type byte */ - - if (*conv_version != SSL_VER_PCT) - { - /* dissect the message (only handle client hello right now) */ - switch (msg_type) { - case SSL2_HND_CLIENT_HELLO: - dissect_ssl2_hnd_client_hello(tvb, dtls_record_tree, offset, ssl); - break; - - case SSL2_HND_CLIENT_MASTER_KEY: - dissect_ssl2_hnd_client_master_key(tvb, dtls_record_tree, offset); - break; - - case SSL2_HND_SERVER_HELLO: - dissect_ssl2_hnd_server_hello(tvb, dtls_record_tree, offset, pinfo); - break; - - case SSL2_HND_ERROR: - case SSL2_HND_CLIENT_FINISHED: - case SSL2_HND_SERVER_VERIFY: - case SSL2_HND_SERVER_FINISHED: - case SSL2_HND_REQUEST_CERTIFICATE: - case SSL2_HND_CLIENT_CERTIFICATE: - /* unimplemented */ - break; - - default: /* unknown */ - break; - } - } - else - { - /* dissect the message */ - switch (msg_type) { - case PCT_MSG_CLIENT_HELLO: - dissect_pct_msg_client_hello(tvb, dtls_record_tree, offset); - break; - case PCT_MSG_SERVER_HELLO: - dissect_pct_msg_server_hello(tvb, dtls_record_tree, offset, pinfo); - break; - case PCT_MSG_CLIENT_MASTER_KEY: - dissect_pct_msg_client_master_key(tvb, dtls_record_tree, offset); - break; - case PCT_MSG_SERVER_VERIFY: - dissect_pct_msg_server_verify(tvb, dtls_record_tree, offset); - break; - case PCT_MSG_ERROR: - dissect_pct_msg_error(tvb, dtls_record_tree, offset); - break; - - default: /* unknown */ - break; - } - } - return (initial_offset + record_length_length + record_length); -} - -static void -dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, - proto_tree *tree, guint32 offset, - SslDecryptSession* ssl) -{ - /* struct { - * uint8 msg_type; - * Version version; - * uint16 cipher_spec_length; - * uint16 session_id_length; - * uint16 challenge_length; - * V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length]; - * opaque session_id[V2ClientHello.session_id_length]; - * Random challenge; - * } V2ClientHello; - * - * Note: when we get here, offset's already pointing at Version - * - */ - guint16 version; - guint16 cipher_spec_length; - guint16 session_id_length; - guint16 challenge_length; - - proto_tree *ti; - proto_tree *cs_tree=0; - - version = tvb_get_ntohs(tvb, offset); - if (!ssl_is_valid_ssl_version(version)) - { - /* invalid version; probably encrypted data */ - return; - } - - if (tree || ssl) - { - /* show the version */ - if (tree) - proto_tree_add_item(tree, hf_dtls_record_version, tvb, - offset, 2, FALSE); - offset += 2; - - cipher_spec_length = tvb_get_ntohs(tvb, offset); - if (tree) - proto_tree_add_item(tree, hf_ssl2_handshake_cipher_spec_len, - tvb, offset, 2, FALSE); - offset += 2; - - session_id_length = tvb_get_ntohs(tvb, offset); - if (tree) - proto_tree_add_item(tree, hf_ssl2_handshake_session_id_len, - tvb, offset, 2, FALSE); - offset += 2; - - challenge_length = tvb_get_ntohs(tvb, offset); - if (tree) - proto_tree_add_item(tree, hf_ssl2_handshake_challenge_len, - tvb, offset, 2, FALSE); - offset += 2; - - if (tree) - { - /* tell the user how many cipher specs they've won */ - tvb_ensure_bytes_exist(tvb, offset, cipher_spec_length); - ti = proto_tree_add_none_format(tree, hf_dtls_handshake_cipher_suites, - tvb, offset, cipher_spec_length, - "Cipher Specs (%u specs)", - cipher_spec_length/3); - - /* make this a subtree and expand the actual specs below */ - cs_tree = proto_item_add_subtree(ti, ett_dtls_cipher_suites); - if (!cs_tree) - { - cs_tree = tree; /* failsafe */ - } - } - - /* iterate through the cipher specs, showing them */ - while (cipher_spec_length > 0) - { - if (cs_tree) - proto_tree_add_item(cs_tree, hf_ssl2_handshake_cipher_spec, - tvb, offset, 3, FALSE); - offset += 3; /* length of one cipher spec */ - cipher_spec_length -= 3; - } - - /* if there's a session id, show it */ - if (session_id_length > 0) - { - if (tree) - { - tvb_ensure_bytes_exist(tvb, offset, session_id_length); - 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")); - } - - /* PAOLO: get session id and reset session state for key [re]negotiation */ - if (ssl) - { - tvb_memcpy(tvb,ssl->session_id.data, offset, session_id_length); - ssl->session_id.data_len = session_id_length; - ssl->state &= ~(SSL_HAVE_SESSION_KEY|SSL_MASTER_SECRET| - SSL_CIPHER|SSL_SERVER_RANDOM); - } - offset += session_id_length; - } - - /* if there's a challenge, show it */ - if (challenge_length > 0) - { - tvb_ensure_bytes_exist(tvb, offset, challenge_length); - - if (tree) - proto_tree_add_item(tree, hf_ssl2_handshake_challenge, - tvb, offset, challenge_length, 0); - if (ssl) - { - /* PAOLO: get client random data; we get at most 32 bytes from - challenge */ - int max = challenge_length > 32? 32: challenge_length; - - ssl_debug_printf("client random len: %d padded to 32\n", - challenge_length); - - /* client random is padded with zero and 'right' aligned */ - memset(ssl->client_random.data, 0, 32 - max); - tvb_memcpy(tvb, &ssl->client_random.data[32 - max], offset, max); - ssl->client_random.data_len = 32; - ssl->state |= SSL_CLIENT_RANDOM; - - } - offset += challenge_length; - } - } -} - -static void -dissect_pct_msg_client_hello(tvbuff_t *tvb, - proto_tree *tree, guint32 offset) -{ - guint16 CH_CLIENT_VERSION, CH_OFFSET, CH_CIPHER_SPECS_LENGTH, CH_HASH_SPECS_LENGTH, CH_CERT_SPECS_LENGTH, CH_EXCH_SPECS_LENGTH, CH_KEY_ARG_LENGTH; - proto_item *CH_CIPHER_SPECS_ti, *CH_HASH_SPECS_ti, *CH_CERT_SPECS_ti, *CH_EXCH_SPECS_ti; - proto_tree *CH_CIPHER_SPECS_tree, *CH_HASH_SPECS_tree, *CH_CERT_SPECS_tree, *CH_EXCH_SPECS_tree; - gint i; - - CH_CLIENT_VERSION = tvb_get_ntohs(tvb, offset); - if(CH_CLIENT_VERSION != PCT_VERSION_1) - proto_tree_add_text(tree, tvb, offset, 2, "Client Version, should be %x in PCT version 1", PCT_VERSION_1); - else - proto_tree_add_text(tree, tvb, offset, 2, "Client Version (%x)", PCT_VERSION_1); - offset += 2; - - proto_tree_add_text(tree, tvb, offset, 1, "PAD"); - offset += 1; - - proto_tree_add_text(tree, tvb, offset, 32, "Client Session ID Data (32 bytes)"); - offset += 32; - - proto_tree_add_text(tree, tvb, offset, 32, "Challange Data(32 bytes)"); - offset += 32; - - CH_OFFSET = tvb_get_ntohs(tvb, offset); - if(CH_OFFSET != PCT_CH_OFFSET_V1) - proto_tree_add_text(tree, tvb, offset, 2, "CH_OFFSET: %d, should be %d in PCT version 1", CH_OFFSET, PCT_CH_OFFSET_V1); - else - proto_tree_add_text(tree, tvb, offset, 2, "CH_OFFSET: %d", CH_OFFSET); - offset += 2; - - CH_CIPHER_SPECS_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "CIPHER_SPECS Length: %d", CH_CIPHER_SPECS_LENGTH); - offset += 2; - - CH_HASH_SPECS_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "HASH_SPECS Length: %d", CH_HASH_SPECS_LENGTH); - offset += 2; - - CH_CERT_SPECS_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "CERT_SPECS Length: %d", CH_CERT_SPECS_LENGTH); - offset += 2; - - CH_EXCH_SPECS_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "EXCH_SPECS Length: %d", CH_EXCH_SPECS_LENGTH); - offset += 2; - - CH_KEY_ARG_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "IV Length: %d", CH_KEY_ARG_LENGTH); - offset += 2; - - if(CH_CIPHER_SPECS_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CH_CIPHER_SPECS_LENGTH); - CH_CIPHER_SPECS_ti = proto_tree_add_item(tree, hf_pct_handshake_cipher_spec, tvb, offset, CH_CIPHER_SPECS_LENGTH, FALSE); - CH_CIPHER_SPECS_tree = proto_item_add_subtree(CH_CIPHER_SPECS_ti, ett_pct_cipher_suites); - - for(i=0; i<(CH_CIPHER_SPECS_LENGTH/4); i++) { - proto_tree_add_item(CH_CIPHER_SPECS_tree, hf_pct_handshake_cipher, tvb, offset, 2, FALSE); - offset += 2; - proto_tree_add_text(CH_CIPHER_SPECS_tree, tvb, offset, 1, "Encryption key length: %d", tvb_get_guint8(tvb, offset)); - offset += 1; - proto_tree_add_text(CH_CIPHER_SPECS_tree, tvb, offset, 1, "MAC key length in bits: %d", tvb_get_guint8(tvb, offset) + 64); - offset += 1; - } - } - - if(CH_HASH_SPECS_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CH_HASH_SPECS_LENGTH); - CH_HASH_SPECS_ti = proto_tree_add_item(tree, hf_pct_handshake_hash_spec, tvb, offset, CH_HASH_SPECS_LENGTH, FALSE); - CH_HASH_SPECS_tree = proto_item_add_subtree(CH_HASH_SPECS_ti, ett_pct_hash_suites); - - for(i=0; i<(CH_HASH_SPECS_LENGTH/2); i++) { - proto_tree_add_item(CH_HASH_SPECS_tree, hf_pct_handshake_hash, tvb, offset, 2, FALSE); - offset += 2; - } - } - - if(CH_CERT_SPECS_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CH_CERT_SPECS_LENGTH); - CH_CERT_SPECS_ti = proto_tree_add_item(tree, hf_pct_handshake_cert_spec, tvb, offset, CH_CERT_SPECS_LENGTH, FALSE); - CH_CERT_SPECS_tree = proto_item_add_subtree(CH_CERT_SPECS_ti, ett_pct_cert_suites); - - for(i=0; i< (CH_CERT_SPECS_LENGTH/2); i++) { - proto_tree_add_item(CH_CERT_SPECS_tree, hf_pct_handshake_cert, tvb, offset, 2, FALSE); - offset += 2; - } - } - - if(CH_EXCH_SPECS_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CH_EXCH_SPECS_LENGTH); - CH_EXCH_SPECS_ti = proto_tree_add_item(tree, hf_pct_handshake_exch_spec, tvb, offset, CH_EXCH_SPECS_LENGTH, FALSE); - CH_EXCH_SPECS_tree = proto_item_add_subtree(CH_EXCH_SPECS_ti, ett_pct_exch_suites); - - for(i=0; i<(CH_EXCH_SPECS_LENGTH/2); i++) { - proto_tree_add_item(CH_EXCH_SPECS_tree, hf_pct_handshake_exch, tvb, offset, 2, FALSE); - offset += 2; - } - } - - if(CH_KEY_ARG_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CH_KEY_ARG_LENGTH); - proto_tree_add_text(tree, tvb, offset, CH_KEY_ARG_LENGTH, "IV data (%d bytes)", CH_KEY_ARG_LENGTH); - offset += CH_KEY_ARG_LENGTH; - } -} - -static void -dissect_pct_msg_server_hello(tvbuff_t *tvb, proto_tree *tree, guint32 offset, packet_info *pinfo) -{ -/* structure: -char SH_MSG_SERVER_HELLO -char SH_PAD -char SH_SERVER_VERSION_MSB -char SH_SERVER_VERSION_LSB -char SH_RESTART_SESSION_OK -char SH_CLIENT_AUTH_REQ -char SH_CIPHER_SPECS_DATA[4] -char SH_HASH_SPECS_DATA[2] -char SH_CERT_SPECS_DATA[2] -char SH_EXCH_SPECS_DATA[2] -char SH_CONNECTION_ID_DATA[32] -char SH_CERTIFICATE_LENGTH_MSB -char SH_CERTIFICATE_LENGTH_LSB -char SH_CLIENT_CERT_SPECS_LENGTH_MSB -char SH_CLIENT_CERT_SPECS_LENGTH_LSB -char SH_CLIENT_SIG_SPECS_LENGTH_MSB -char SH_CLIENT_SIG_SPECS_LENGTH_LSB -char SH_RESPONSE_LENGTH_MSB -char SH_RESPONSE_LENGTH_LSB -char SH_CERTIFICATE_DATA[MSB<<8|LSB] -char SH_CLIENT_CERT_SPECS_DATA[MSB<<8|LSB] -char SH_CLIENT_SIG_SPECS_DATA[MSB<<8|LSB] -char SH_RESPONSE_DATA[MSB<<8|LSB] - -*/ - - guint16 SH_SERVER_VERSION, SH_CERT_LENGTH, SH_CERT_SPECS_LENGTH, SH_CLIENT_SIG_LENGTH, SH_RESPONSE_LENGTH; - - proto_tree_add_text(tree, tvb, offset, 1, "PAD"); - offset += 1; - - SH_SERVER_VERSION = tvb_get_ntohs(tvb, offset); - if(SH_SERVER_VERSION != PCT_VERSION_1) - proto_tree_add_text(tree, tvb, offset, 2, "Server Version, should be %x in PCT version 1", PCT_VERSION_1); - else - proto_tree_add_text(tree, tvb, offset, 2, "Server Version (%x)", PCT_VERSION_1); - offset += 2; - - proto_tree_add_text(tree, tvb, offset, 1, "SH_RESTART_SESSION_OK flag"); - offset += 1; - - proto_tree_add_text(tree, tvb, offset, 1, "SH_CLIENT_AUTH_REQ flag"); - offset += 1; - - proto_tree_add_item(tree, hf_pct_handshake_cipher, tvb, offset, 2, FALSE); - offset += 2; - proto_tree_add_text(tree, tvb, offset, 1, "Encryption key length: %d", tvb_get_guint8(tvb, offset)); - offset += 1; - proto_tree_add_text(tree, tvb, offset, 1, "MAC key length in bits: %d", tvb_get_guint8(tvb, offset) + 64); - offset += 1; - - proto_tree_add_item(tree, hf_pct_handshake_hash, tvb, offset, 2, FALSE); - offset += 2; - - proto_tree_add_item(tree, hf_pct_handshake_cert, tvb, offset, 2, FALSE); - offset += 2; - - proto_tree_add_item(tree, hf_pct_handshake_exch, tvb, offset, 2, FALSE); - offset += 2; - - proto_tree_add_text(tree, tvb, offset, 32, "Connection ID Data (32 bytes)"); - offset += 32; - - SH_CERT_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Server Certificate Length: %d", SH_CERT_LENGTH); - offset += 2; - - SH_CERT_SPECS_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Client CERT_SPECS Length: %d", SH_CERT_SPECS_LENGTH); - offset += 2; - - SH_CLIENT_SIG_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Client SIG_SPECS Length: %d", SH_CLIENT_SIG_LENGTH); - offset += 2; - - SH_RESPONSE_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Response Length: %d", SH_RESPONSE_LENGTH); - offset += 2; - - if(SH_CERT_LENGTH) { - dissect_x509af_Certificate(FALSE, tvb, offset, pinfo, tree, hf_pct_handshake_server_cert); - offset += SH_CERT_LENGTH; - } - - if(SH_CERT_SPECS_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, SH_CERT_SPECS_LENGTH); - proto_tree_add_text(tree, tvb, offset, SH_CERT_SPECS_LENGTH, "Client CERT_SPECS (%d bytes)", SH_CERT_SPECS_LENGTH); - offset += SH_CERT_SPECS_LENGTH; - } - - if(SH_CLIENT_SIG_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, SH_CLIENT_SIG_LENGTH); - proto_tree_add_text(tree, tvb, offset, SH_CLIENT_SIG_LENGTH, "Client Signature (%d bytes)", SH_CLIENT_SIG_LENGTH); - offset += SH_CLIENT_SIG_LENGTH; - } - - if(SH_RESPONSE_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, SH_RESPONSE_LENGTH); - proto_tree_add_text(tree, tvb, offset, SH_RESPONSE_LENGTH, "Server Response (%d bytes)", SH_RESPONSE_LENGTH); - offset += SH_RESPONSE_LENGTH; - } - -} - -static void -dissect_pct_msg_client_master_key(tvbuff_t *tvb, proto_tree *tree, guint32 offset) -{ - guint16 CMK_CLEAR_KEY_LENGTH, CMK_ENCRYPTED_KEY_LENGTH, CMK_KEY_ARG_LENGTH, CMK_VERIFY_PRELUDE, CMK_CLIENT_CERT_LENGTH, CMK_RESPONSE_LENGTH; - - proto_tree_add_text(tree, tvb, offset, 1, "PAD"); - offset += 1; - - proto_tree_add_item(tree, hf_pct_handshake_cert, tvb, offset, 2, FALSE); - offset += 2; - - proto_tree_add_item(tree, hf_pct_handshake_sig, tvb, offset, 2, FALSE); - offset += 2; - - CMK_CLEAR_KEY_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Clear Key Length: %d",CMK_CLEAR_KEY_LENGTH); - offset += 2; - - CMK_ENCRYPTED_KEY_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Encrypted Key Length: %d",CMK_ENCRYPTED_KEY_LENGTH); - offset += 2; - - CMK_KEY_ARG_LENGTH= tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "IV Length: %d",CMK_KEY_ARG_LENGTH); - offset += 2; - - CMK_VERIFY_PRELUDE = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Verify Prelude Length: %d",CMK_VERIFY_PRELUDE); - offset += 2; - - CMK_CLIENT_CERT_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Client Cert Length: %d",CMK_CLIENT_CERT_LENGTH); - offset += 2; - - CMK_RESPONSE_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Response Length: %d",CMK_RESPONSE_LENGTH); - offset += 2; - - if(CMK_CLEAR_KEY_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CMK_CLEAR_KEY_LENGTH); - proto_tree_add_text(tree, tvb, offset, CMK_CLEAR_KEY_LENGTH, "Clear Key data (%d bytes)", CMK_CLEAR_KEY_LENGTH); - offset += CMK_CLEAR_KEY_LENGTH; - } - if(CMK_ENCRYPTED_KEY_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CMK_ENCRYPTED_KEY_LENGTH); - proto_tree_add_text(tree, tvb, offset, CMK_ENCRYPTED_KEY_LENGTH, "Encrypted Key data (%d bytes)", CMK_ENCRYPTED_KEY_LENGTH); - offset += CMK_ENCRYPTED_KEY_LENGTH; - } - if(CMK_KEY_ARG_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CMK_KEY_ARG_LENGTH); - proto_tree_add_text(tree, tvb, offset, CMK_KEY_ARG_LENGTH, "IV data (%d bytes)", CMK_KEY_ARG_LENGTH); - offset += CMK_KEY_ARG_LENGTH; - } - if(CMK_VERIFY_PRELUDE) { - tvb_ensure_bytes_exist(tvb, offset, CMK_VERIFY_PRELUDE); - proto_tree_add_text(tree, tvb, offset, CMK_VERIFY_PRELUDE, "Verify Prelude data (%d bytes)", CMK_VERIFY_PRELUDE); - offset += CMK_VERIFY_PRELUDE; - } - if(CMK_CLIENT_CERT_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CMK_CLIENT_CERT_LENGTH); - proto_tree_add_text(tree, tvb, offset, CMK_CLIENT_CERT_LENGTH, "Client Certificate data (%d bytes)", CMK_CLIENT_CERT_LENGTH); - offset += CMK_CLIENT_CERT_LENGTH; - } - if(CMK_RESPONSE_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, CMK_RESPONSE_LENGTH); - proto_tree_add_text(tree, tvb, offset, CMK_RESPONSE_LENGTH, "Response data (%d bytes)", CMK_RESPONSE_LENGTH); - offset += CMK_RESPONSE_LENGTH; - } -} - -static void -dissect_pct_msg_server_verify(tvbuff_t *tvb, - proto_tree *tree, guint32 offset) -{ - guint16 SV_RESPONSE_LENGTH; - - proto_tree_add_text(tree, tvb, offset, 1, "PAD"); - offset += 1; - - proto_tree_add_text(tree, tvb, offset, 32, "Server Session ID data (32 bytes)"); - offset += 32; - - SV_RESPONSE_LENGTH = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Server Response Length: %d", SV_RESPONSE_LENGTH); - offset += 2; - - if(SV_RESPONSE_LENGTH) { - tvb_ensure_bytes_exist(tvb, offset, SV_RESPONSE_LENGTH); - proto_tree_add_text(tree, tvb, offset, SV_RESPONSE_LENGTH, "Server Response (%d bytes)", SV_RESPONSE_LENGTH); - offset += SV_RESPONSE_LENGTH; - } -} - -static void -dissect_pct_msg_error(tvbuff_t *tvb, - proto_tree *tree, guint32 offset) -{ - guint16 ERROR_CODE, INFO_LEN; - - ERROR_CODE = tvb_get_ntohs(tvb, offset); - proto_tree_add_item(tree, hf_pct_msg_error_type, tvb, offset, 2, FALSE); - offset += 2; - - INFO_LEN = tvb_get_ntohs(tvb, offset); - proto_tree_add_text(tree, tvb, offset, 2, "Eror Information Length: %d", INFO_LEN); - offset += 2; - if (ERROR_CODE == PCT_ERR_SPECS_MISMATCH && INFO_LEN == 6) - { - proto_tree_add_text(tree, tvb, offset, 1, "SPECS_MISMATCH_CIPHER"); - offset += 1; - proto_tree_add_text(tree, tvb, offset, 1, "SPECS_MISMATCH_HASH"); - offset += 1; - proto_tree_add_text(tree, tvb, offset, 1, "SPECS_MISMATCH_CERT"); - offset += 1; - proto_tree_add_text(tree, tvb, offset, 1, "SPECS_MISMATCH_EXCH"); - offset += 1; - proto_tree_add_text(tree, tvb, offset, 1, "SPECS_MISMATCH_CLIENT_CERT"); - offset += 1; - proto_tree_add_text(tree, tvb, offset, 1, "SPECS_MISMATCH_CLIENT_SIG"); - offset += 1; - } - else if(INFO_LEN) { - proto_tree_add_text(tree, tvb, offset, INFO_LEN, "Error Information dta (%d bytes)", INFO_LEN); - offset += INFO_LEN; - } -} - -static void -dissect_ssl2_hnd_client_master_key(tvbuff_t *tvb, - proto_tree *tree, guint32 offset) -{ - /* struct { - * uint8 msg_type; - * V2Cipherspec cipher; - * uint16 clear_key_length; - * uint16 encrypted_key_length; - * uint16 key_arg_length; - * opaque clear_key_data[V2ClientMasterKey.clear_key_length]; - * opaque encrypted_key_data[V2ClientMasterKey.encrypted_key_length]; - * opaque key_arg_data[V2ClientMasterKey.key_arg_length]; - * } V2ClientMasterKey; - * - * Note: when we get here, offset's already pointing at cipher - */ - guint16 clear_key_length; - guint16 encrypted_key_length; - guint16 key_arg_length; - - /* at this point, everything we do involves the tree, - * so quit now if we don't have one ;-) - */ - if (!tree) - { - return; - } - - /* show the selected cipher */ - proto_tree_add_item(tree, hf_ssl2_handshake_cipher_spec, - tvb, offset, 3, FALSE); - offset += 3; - - /* get the fixed fields */ - clear_key_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_item(tree, hf_ssl2_handshake_clear_key_len, - tvb, offset, 2, FALSE); - offset += 2; - - encrypted_key_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_item(tree, hf_ssl2_handshake_enc_key_len, - tvb, offset, 2, FALSE); - offset += 2; - - key_arg_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_item(tree, hf_ssl2_handshake_key_arg_len, - tvb, offset, 2, FALSE); - offset += 2; - - /* show the variable length fields */ - if (clear_key_length > 0) - { - tvb_ensure_bytes_exist(tvb, offset, clear_key_length); - proto_tree_add_item(tree, hf_ssl2_handshake_clear_key, - tvb, offset, clear_key_length, FALSE); - offset += clear_key_length; - } - - if (encrypted_key_length > 0) - { - tvb_ensure_bytes_exist(tvb, offset, encrypted_key_length); - proto_tree_add_item(tree, hf_ssl2_handshake_enc_key, - tvb, offset, encrypted_key_length, FALSE); - offset += encrypted_key_length; - } - - if (key_arg_length > 0) - { - tvb_ensure_bytes_exist(tvb, offset, key_arg_length); - proto_tree_add_item(tree, hf_ssl2_handshake_key_arg, - tvb, offset, key_arg_length, FALSE); - offset += key_arg_length; - } - -} - -static void -dissect_ssl2_hnd_server_hello(tvbuff_t *tvb, - proto_tree *tree, guint32 offset, packet_info *pinfo) -{ - /* struct { - * uint8 msg_type; - * uint8 session_id_hit; - * uint8 certificate_type; - * uint16 server_version; - * uint16 certificate_length; - * uint16 cipher_specs_length; - * uint16 connection_id_length; - * opaque certificate_data[V2ServerHello.certificate_length]; - * opaque cipher_specs_data[V2ServerHello.cipher_specs_length]; - * opaque connection_id_data[V2ServerHello.connection_id_length]; - * } V2ServerHello; - * - * Note: when we get here, offset's already pointing at session_id_hit - */ - guint16 certificate_length; - guint16 cipher_spec_length; - guint16 connection_id_length; - guint16 version; - proto_tree *ti; - proto_tree *subtree; - - /* everything we do only makes sense with a tree, so - * quit now if we don't have one - */ - if (!tree) - { - return; - } - - version = tvb_get_ntohs(tvb, offset + 2); - if (!ssl_is_valid_ssl_version(version)) - { - /* invalid version; probably encrypted data */ - return; - } - - - /* is there a hit? */ - proto_tree_add_item(tree, hf_ssl2_handshake_session_id_hit, - tvb, offset, 1, FALSE); - offset++; - - /* what type of certificate is this? */ - proto_tree_add_item(tree, hf_ssl2_handshake_cert_type, - tvb, offset, 1, FALSE); - offset++; - - /* now the server version */ - proto_tree_add_item(tree, hf_dtls_handshake_server_version, - tvb, offset, 2, FALSE); - offset += 2; - - /* get the fixed fields */ - certificate_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_dtls_handshake_certificate_len, - tvb, offset, 2, certificate_length); - offset += 2; - - cipher_spec_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_ssl2_handshake_cipher_spec_len, - tvb, offset, 2, cipher_spec_length); - offset += 2; - - connection_id_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_ssl2_handshake_connection_id_len, - tvb, offset, 2, connection_id_length); - offset += 2; - - /* now the variable length fields */ - if (certificate_length > 0) - { - dissect_x509af_Certificate(FALSE, tvb, offset, pinfo, tree, hf_dtls_handshake_certificate); - offset += certificate_length; - } - - if (cipher_spec_length > 0) - { - /* provide a collapsing node for the cipher specs */ - tvb_ensure_bytes_exist(tvb, offset, cipher_spec_length); - ti = proto_tree_add_none_format(tree, - hf_dtls_handshake_cipher_suites, - tvb, offset, cipher_spec_length, - "Cipher Specs (%u spec%s)", - cipher_spec_length/3, - plurality(cipher_spec_length/3, "", "s")); - subtree = proto_item_add_subtree(ti, ett_dtls_cipher_suites); - if (!subtree) - { - subtree = tree; - } - - /* iterate through the cipher specs */ - while (cipher_spec_length > 0) - { - proto_tree_add_item(subtree, hf_ssl2_handshake_cipher_spec, - tvb, offset, 3, FALSE); - offset += 3; - cipher_spec_length -= 3; - } - } + /* + * struct { + * opaque verify_data[12]; + * } Finished; + */ - if (connection_id_length > 0) + /* this all needs a tree, so bail if we don't have one */ + if (!tree) { - tvb_ensure_bytes_exist(tvb, offset, connection_id_length); - proto_tree_add_item(tree, hf_ssl2_handshake_connection_id, - tvb, offset, connection_id_length, FALSE); - offset += connection_id_length; + return; } + switch(*conv_version) { + case SSL_VER_DTLS: + proto_tree_add_item(tree, hf_dtls_handshake_finished, + tvb, offset, 12, FALSE); + break; + } } - - - /********************************************************************* * * Support Functions @@ -3234,316 +1753,103 @@ dissect_ssl2_hnd_server_hello(tvbuff_t *tvb, static void ssl_set_conv_version(packet_info *pinfo, guint version) { - conversation_t *conversation; + conversation_t *conversation; - if (pinfo->fd->flags.visited) + if (pinfo->fd->flags.visited) { - /* We've already processed this frame; no need to do any more - * work on it. - */ - return; + /* We've already processed this frame; no need to do any more + * work on it. + */ + return; } - conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, - pinfo->srcport, pinfo->destport, 0); + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); - if (conversation == NULL) + if (conversation == NULL) { - /* create a new conversation */ - conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, - pinfo->srcport, pinfo->destport, 0); + /* create a new conversation */ + conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); } - if (conversation_get_proto_data(conversation, proto_dtls) != NULL) + if (conversation_get_proto_data(conversation, proto_dtls) != NULL) { - /* get rid of the current data */ - conversation_delete_proto_data(conversation, proto_dtls); + /* get rid of the current data */ + conversation_delete_proto_data(conversation, proto_dtls); } - conversation_add_proto_data(conversation, proto_dtls, GINT_TO_POINTER(version)); + conversation_add_proto_data(conversation, proto_dtls, GINT_TO_POINTER(version)); } #endif -static int -ssl_is_valid_handshake_type(guint8 type) -{ - - switch (type) { - case SSL_HND_HELLO_REQUEST: - case SSL_HND_CLIENT_HELLO: - case SSL_HND_SERVER_HELLO: - case SSL_HND_HELLO_VERIFY_REQUEST: - case SSL_HND_CERTIFICATE: - case SSL_HND_SERVER_KEY_EXCHG: - case SSL_HND_CERT_REQUEST: - case SSL_HND_SVR_HELLO_DONE: - case SSL_HND_CERT_VERIFY: - case SSL_HND_CLIENT_KEY_EXCHG: - case SSL_HND_FINISHED: - return 1; - } - return 0; -} - -static int -ssl_is_valid_content_type(guint8 type) -{ - if (type >= 0x14 && type <= 0x17) - { - return 1; - } - - return 0; -} - -static int -ssl_is_valid_ssl_version(guint16 version) -{ - const gchar *version_str = match_strval(version, ssl_versions); - return version_str != NULL; -} - -static int -ssl_is_authoritative_version_message(guint8 content_type, - guint8 next_byte) -{ - if (content_type == SSL_ID_HANDSHAKE - && ssl_is_valid_handshake_type(next_byte)) - { - return (next_byte != SSL_HND_CLIENT_HELLO); - } - else if (ssl_is_valid_content_type(content_type) - && content_type != SSL_ID_HANDSHAKE) - { - return 1; - } - return 0; -} - -static int -ssl_is_v2_client_hello(tvbuff_t *tvb, guint32 offset) +static gint +dtls_is_valid_handshake_type(guint8 type) { - guint8 byte; - - byte = tvb_get_guint8(tvb, offset); - if (byte != 0x80) /* v2 client hello should start this way */ - { - return 0; - } - byte = tvb_get_guint8(tvb, offset+2); - if (byte != 0x01) /* v2 client hello msg type */ - { - return 0; - } - - /* 1 in 2^16 of being right; improve later if necessary */ + switch (type) { + case SSL_HND_HELLO_REQUEST: + case SSL_HND_CLIENT_HELLO: + case SSL_HND_SERVER_HELLO: + case SSL_HND_HELLO_VERIFY_REQUEST: + case SSL_HND_CERTIFICATE: + case SSL_HND_SERVER_KEY_EXCHG: + case SSL_HND_CERT_REQUEST: + case SSL_HND_SVR_HELLO_DONE: + case SSL_HND_CERT_VERIFY: + case SSL_HND_CLIENT_KEY_EXCHG: + case SSL_HND_FINISHED: return 1; + } + return 0; } -/* this applies a heuristic to determine whether - * or not the data beginning at offset looks like a - * valid sslv2 record. this isn't really possible, - * but we'll try to do a reasonable job anyway. - */ -static int -ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset) +static gint +dtls_is_authoritative_version_message(guint8 content_type, + guint8 next_byte) { - /* here's the current approach: - * - * we only try to catch unencrypted handshake messages, so we can - * assume that there is not padding. This means that the - * first byte must be >= 0x80 and there must be a valid sslv2 - * msg_type in the third byte - */ - - /* get the first byte; must have high bit set */ - guint8 byte = tvb_get_guint8(tvb, offset); - if (byte < 0x80) + if (content_type == SSL_ID_HANDSHAKE + && dtls_is_valid_handshake_type(next_byte)) { - return 0; + return (next_byte != SSL_HND_CLIENT_HELLO); } - - /* get the supposed msg_type byte; since we only care about - * unencrypted handshake messages (we can't tell the type for - * encrypted messages), we just check against that list - */ - byte = tvb_get_guint8(tvb, offset + 2); - switch(byte) { - case SSL2_HND_ERROR: - case SSL2_HND_CLIENT_HELLO: - case SSL2_HND_CLIENT_MASTER_KEY: - case SSL2_HND_SERVER_HELLO: - case PCT_MSG_CLIENT_MASTER_KEY: - case PCT_MSG_ERROR: - return 1; + else if (ssl_is_valid_content_type(content_type) + && content_type != SSL_ID_HANDSHAKE) + { + return 1; } - return 0; + return 0; } /* this applies a heuristic to determine whether * or not the data beginning at offset looks like a - * valid sslv3 record. this is somewhat more reliable - * than sslv2 due to the structure of the v3 protocol + * valid dtls record. */ -static int -ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset) +static gint +looks_like_dtls(tvbuff_t *tvb, guint32 offset) { - /* have to have a valid content type followed by a valid - * protocol version - */ - guint8 byte; - guint16 version; + /* have to have a valid content type followed by a valid + * protocol version + */ + guint8 byte; + guint16 version; - /* see if the first byte is a valid content type */ - byte = tvb_get_guint8(tvb, offset); - if (!ssl_is_valid_content_type(byte)) + /* see if the first byte is a valid content type */ + byte = tvb_get_guint8(tvb, offset); + if (!ssl_is_valid_content_type(byte)) { - return 0; + return 0; } - /* now check to see if the version byte appears valid */ - version = tvb_get_ntohs(tvb, offset + 1); - if (version != DTLSV1DOT0_VERSION) + /* now check to see if the version byte appears valid */ + version = tvb_get_ntohs(tvb, offset + 1); + if (version != DTLSV1DOT0_VERSION) { - return 0; - } - - return 1; -} - -/* applies a heuristic to determine whether - * or not the data beginning at offset looks - * like a valid, unencrypted v2 handshake message. - * since it isn't possible to completely tell random - * data apart from a valid message without state, - * we try to help the odds. - */ -static int -ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, guint32 offset, - guint32 record_length) -{ - /* first byte should be a msg_type. - * - * - we know we only see client_hello, client_master_key, - * and server_hello in the clear, so check to see if - * msg_type is one of those (this gives us a 3 in 2^8 - * chance of saying yes with random payload) - * - * - for those three types that we know about, do some - * further validation to reduce the chance of an error - */ - guint8 msg_type; - guint16 version; - guint32 sum; - - /* fetch the msg_type */ - msg_type = tvb_get_guint8(tvb, offset); - - switch (msg_type) { - case SSL2_HND_CLIENT_HELLO: - /* version follows msg byte, so verify that this is valid */ - version = tvb_get_ntohs(tvb, offset+1); - return ssl_is_valid_ssl_version(version); - break; - - case SSL2_HND_SERVER_HELLO: - /* version is three bytes after msg_type */ - version = tvb_get_ntohs(tvb, offset+3); - return ssl_is_valid_ssl_version(version); - break; - - case SSL2_HND_CLIENT_MASTER_KEY: - /* sum of clear_key_length, encrypted_key_length, and key_arg_length - * must be less than record length - */ - sum = tvb_get_ntohs(tvb, offset + 4); /* clear_key_length */ - sum += tvb_get_ntohs(tvb, offset + 6); /* encrypted_key_length */ - sum += tvb_get_ntohs(tvb, offset + 8); /* key_arg_length */ - if (sum > record_length) - { - return 0; - } - return 1; - break; - - default: - return 0; + return 0; } - return 0; -} - -/* applies a heuristic to determine whether - * or not the data beginning at offset looks - * like a valid, unencrypted v2 handshake message. - * since it isn't possible to completely tell random - * data apart from a valid message without state, - * we try to help the odds. - */ -static int -ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, guint32 offset, - guint32 record_length) -{ - /* first byte should be a msg_type. - * - * - we know we only see client_hello, client_master_key, - * and server_hello in the clear, so check to see if - * msg_type is one of those (this gives us a 3 in 2^8 - * chance of saying yes with random payload) - * - * - for those three types that we know about, do some - * further validation to reduce the chance of an error - */ - guint8 msg_type; - guint16 version; - guint32 sum; - - /* fetch the msg_type */ - msg_type = tvb_get_guint8(tvb, offset); - - switch (msg_type) { - case PCT_MSG_CLIENT_HELLO: - /* version follows msg byte, so verify that this is valid */ - version = tvb_get_ntohs(tvb, offset+1); - return version == PCT_VERSION_1; - break; - - case PCT_MSG_SERVER_HELLO: - /* version is one byte after msg_type */ - version = tvb_get_ntohs(tvb, offset+2); - return version == PCT_VERSION_1; - break; - - case PCT_MSG_CLIENT_MASTER_KEY: - /* sum of various length fields must be less than record length */ - sum = tvb_get_ntohs(tvb, offset + 6); /* clear_key_length */ - sum += tvb_get_ntohs(tvb, offset + 8); /* encrypted_key_length */ - sum += tvb_get_ntohs(tvb, offset + 10); /* key_arg_length */ - sum += tvb_get_ntohs(tvb, offset + 12); /* verify_prelude_length */ - sum += tvb_get_ntohs(tvb, offset + 14); /* client_cert_length */ - sum += tvb_get_ntohs(tvb, offset + 16); /* response_length */ - if (sum > record_length) - { - return 0; - } - return 1; - break; - - case PCT_MSG_SERVER_VERIFY: - /* record is 36 bytes longer than response_length */ - sum = tvb_get_ntohs(tvb, offset + 34); /* response_length */ - if ((sum + 36) == record_length) - return 1; - else - return 0; - break; - default: - return 0; - } - return 0; + return 1; } - /********************************************************************* * * Standard Ethereal Protocol Registration and housekeeping @@ -3553,308 +1859,300 @@ void proto_register_dtls(void) { - /* Setup list of header fields See Section 1.6.1 for details*/ - static hf_register_info hf[] = { - { &hf_dtls_record, - { "Record Layer", "dtls.record", - FT_NONE, BASE_NONE, NULL, 0x0, - "Record layer", HFILL } - }, - { &hf_dtls_record_content_type, - { "Content Type", "dtls.record.content_type", - FT_UINT8, BASE_DEC, VALS(ssl_31_content_type), 0x0, - "Content type", HFILL} - }, - { &hf_dtls_record_version, - { "Version", "dtls.record.version", - FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0, - "Record layer version.", HFILL } - }, - { &hf_dtls_record_epoch, - { "Epoch", "dtls.record.epoch", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Epoch", HFILL } - }, - { &hf_dtls_record_sequence_number, - { "Sequence Number", "dtls.record.sequence_number", - FT_DOUBLE, BASE_DEC, NULL, 0x0, - "Sequence Number", HFILL } - }, - { &hf_dtls_record_length, - { "Length", "dtls.record.length", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of DTLS record data", HFILL } - }, - { &hf_dtls_record_appdata, - { "Application Data", "dtls.app_data", - FT_NONE, BASE_NONE, NULL, 0x0, - "Payload is application data", HFILL } - }, - { &hf_dtls_record_appdata_decrypted, - { "Application Data decrypted", "dtls.app_data_decrypted", - FT_STRING, BASE_NONE, NULL, 0x0, - "Payload is decrypted application data", HFILL } - }, - { &hf_dtls_change_cipher_spec, - { "Change Cipher Spec Message", "dtls.change_cipher_spec", - FT_NONE, BASE_NONE, NULL, 0x0, - "Signals a change in cipher specifications", HFILL } - }, - { & hf_dtls_alert_message, - { "Alert Message", "dtls.alert_message", - FT_NONE, BASE_NONE, NULL, 0x0, - "Alert message", HFILL } - }, - { & hf_dtls_alert_message_level, - { "Level", "dtls.alert_message.level", - FT_UINT8, BASE_DEC, VALS(ssl_31_alert_level), 0x0, - "Alert message level", HFILL } - }, - { &hf_dtls_alert_message_description, - { "Description", "dtls.alert_message.desc", - FT_UINT8, BASE_DEC, VALS(ssl_31_alert_description), 0x0, - "Alert message description", HFILL } - }, - { &hf_dtls_handshake_protocol, - { "Handshake Protocol", "dtls.handshake", - FT_NONE, BASE_NONE, NULL, 0x0, - "Handshake protocol message", HFILL} - }, - { &hf_dtls_handshake_type, - { "Handshake Type", "dtls.handshake.type", - FT_UINT8, BASE_DEC, VALS(ssl_31_handshake_type), 0x0, - "Type of handshake message", HFILL} - }, - { &hf_dtls_handshake_length, - { "Length", "dtls.handshake.length", - FT_UINT24, BASE_DEC, NULL, 0x0, - "Length of handshake message", HFILL } - }, - { &hf_dtls_handshake_message_seq, - { "Message Sequence", "dtls.handshake.message_seq", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Message sequence of handshake message", HFILL } - }, - { &hf_dtls_handshake_fragment_offset, - { "Fragment Offset", "dtls.handshake.fragment_offset", - FT_UINT24, BASE_DEC, NULL, 0x0, - "Fragment offset of handshake message", HFILL } - }, - { &hf_dtls_handshake_fragment_length, - { "Fragment Length", "dtls.handshake.fragment_length", - FT_UINT24, BASE_DEC, NULL, 0x0, - "Fragment length of handshake message", HFILL } - }, - { &hf_dtls_handshake_client_version, - { "Version", "dtls.handshake.version", - FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0, - "Maximum version supported by client", HFILL } - }, - { &hf_dtls_handshake_server_version, - { "Version", "dtls.handshake.version", - FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0, - "Version selected by server", HFILL } - }, - { &hf_dtls_handshake_random_time, - { "Random.gmt_unix_time", "dtls.handshake.random_time", - FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, - "Unix time field of random structure", HFILL } - }, - { &hf_dtls_handshake_random_bytes, - { "Random.bytes", "dtls.handshake.random", - FT_NONE, BASE_NONE, NULL, 0x0, - "Random challenge used to authenticate server", HFILL } - }, - { &hf_dtls_handshake_cipher_suites_len, - { "Cipher Suites Length", "dtls.handshake.cipher_suites_length", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of cipher suites field", HFILL } - }, - { &hf_dtls_handshake_cipher_suites, - { "Cipher Suites", "dtls.handshake.ciphersuites", - FT_NONE, BASE_NONE, NULL, 0x0, - "List of cipher suites supported by client", HFILL } - }, - { &hf_dtls_handshake_cipher_suite, - { "Cipher Suite", "dtls.handshake.ciphersuite", - FT_UINT16, BASE_HEX, VALS(ssl_31_ciphersuite), 0x0, - "Cipher suite", HFILL } - }, - { &hf_dtls_handshake_cookie_len, - { "Cookie Length", "dtls.handshake.cookie_length", - FT_UINT8, BASE_DEC, NULL, 0x0, - "Length of the cookie field", HFILL } - }, - { &hf_dtls_handshake_cookie, - { "Cookie", "dtls.handshake.cookie", - FT_NONE, BASE_NONE, NULL, 0x0, - "Cookie", HFILL } - }, - { &hf_dtls_handshake_session_id, - { "Session ID", "dtls.handshake.session_id", - FT_BYTES, BASE_NONE, NULL, 0x0, - "Identifies the DTLS session, allowing later resumption", HFILL } - }, - { &hf_dtls_handshake_comp_methods_len, - { "Compression Methods Length", "dtls.handshake.comp_methods_length", - FT_UINT8, BASE_DEC, NULL, 0x0, - "Length of compression methods field", HFILL } - }, - { &hf_dtls_handshake_comp_methods, - { "Compression Methods", "dtls.handshake.comp_methods", - FT_NONE, BASE_NONE, NULL, 0x0, - "List of compression methods supported by client", HFILL } - }, - { &hf_dtls_handshake_comp_method, - { "Compression Method", "dtls.handshake.comp_method", - FT_UINT8, BASE_DEC, VALS(ssl_31_compression_method), 0x0, - "Compression Method", HFILL } - }, - { &hf_dtls_handshake_extensions_len, - { "Extensions Length", "dtls.handshake.extensions_length", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of hello extensions", HFILL } - }, - { &hf_dtls_handshake_extension_type, - { "Type", "dtls.handshake.extension.type", - FT_UINT16, BASE_HEX, VALS(tls_hello_extension_types), 0x0, - "Hello extension type", HFILL } - }, - { &hf_dtls_handshake_extension_len, - { "Length", "dtls.handshake.extension.len", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of a hello extension", HFILL } - }, - { &hf_dtls_handshake_extension_data, - { "Data", "dtls.handshake.extension.data", - FT_BYTES, BASE_NONE, NULL, 0x0, - "Hello Extension data", HFILL } - }, - { &hf_dtls_handshake_certificates_len, - { "Certificates Length", "dtls.handshake.certificates_length", - FT_UINT24, BASE_DEC, NULL, 0x0, - "Length of certificates field", HFILL } - }, - { &hf_dtls_handshake_certificates, - { "Certificates", "dtls.handshake.certificates", - FT_NONE, BASE_NONE, NULL, 0x0, - "List of certificates", HFILL } - }, - { &hf_dtls_handshake_certificate, - { "Certificate", "dtls.handshake.certificate", - FT_BYTES, BASE_NONE, NULL, 0x0, - "Certificate", HFILL } - }, - { &hf_dtls_handshake_certificate_len, - { "Certificate Length", "dtls.handshake.certificate_length", - FT_UINT24, BASE_DEC, NULL, 0x0, - "Length of certificate", HFILL } - }, - { &hf_dtls_handshake_cert_types_count, - { "Certificate types count", "dtls.handshake.cert_types_count", - FT_UINT8, BASE_DEC, NULL, 0x0, - "Count of certificate types", HFILL } - }, - { &hf_dtls_handshake_cert_types, - { "Certificate types", "dtls.handshake.cert_types", - FT_NONE, BASE_NONE, NULL, 0x0, - "List of certificate types", HFILL } - }, - { &hf_dtls_handshake_cert_type, - { "Certificate type", "dtls.handshake.cert_type", - FT_UINT8, BASE_DEC, VALS(ssl_31_client_certificate_type), 0x0, - "Certificate type", HFILL } - }, - { &hf_dtls_handshake_finished, - { "Verify Data", "dtls.handshake.verify_data", - FT_NONE, BASE_NONE, NULL, 0x0, - "Opaque verification data", HFILL } - }, - { &hf_dtls_handshake_md5_hash, - { "MD5 Hash", "dtls.handshake.md5_hash", - FT_NONE, BASE_NONE, NULL, 0x0, - "Hash of messages, master_secret, etc.", HFILL } - }, - { &hf_dtls_handshake_sha_hash, - { "SHA-1 Hash", "dtls.handshake.sha_hash", - FT_NONE, BASE_NONE, NULL, 0x0, - "Hash of messages, master_secret, etc.", HFILL } - }, - { &hf_dtls_handshake_session_id_len, - { "Session ID Length", "dtls.handshake.session_id_length", - FT_UINT8, BASE_DEC, NULL, 0x0, - "Length of session ID field", HFILL } - }, - { &hf_dtls_handshake_dnames_len, - { "Distinguished Names Length", "dtls.handshake.dnames_len", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of list of CAs that server trusts", HFILL } - }, - { &hf_dtls_handshake_dnames, - { "Distinguished Names", "dtls.handshake.dnames", - FT_NONE, BASE_NONE, NULL, 0x0, - "List of CAs that server trusts", HFILL } - }, - { &hf_dtls_handshake_dname_len, - { "Distinguished Name Length", "dtls.handshake.dname_len", - FT_UINT16, BASE_DEC, NULL, 0x0, - "Length of distinguished name", HFILL } - }, - { &hf_dtls_handshake_dname, - { "Distinguished Name", "dtls.handshake.dname", - FT_BYTES, BASE_NONE, NULL, 0x0, - "Distinguished name of a CA that server trusts", HFILL } - }, - }; - - /* Setup protocol subtree array */ - static gint *ett[] = { - &ett_dtls, - &ett_dtls_record, - &ett_dtls_alert, - &ett_dtls_handshake, - &ett_dtls_cipher_suites, - &ett_dtls_comp_methods, - &ett_dtls_extension, - &ett_dtls_certs, - &ett_dtls_cert_types, - &ett_dtls_dnames, - }; - - /* Register the protocol name and description */ - proto_dtls = proto_register_protocol("Datagram Transport Layer Security", - "DTLS", "dtls"); - - /* Required function calls to register the header fields and - * subtrees used */ - proto_register_field_array(proto_dtls, hf, array_length(hf)); - proto_register_subtree_array(ett, array_length(ett)); - - { - module_t *dtls_module = prefs_register_protocol(proto_dtls, ssl_parse); - prefs_register_string_preference(dtls_module, "keys_list", "RSA keys list", - "comma separated list of private RSA keys used for DTLS decryption; " - "each list entry must be in the form of <ip>:<port>:<key_file_name>" - "<key_file_name> is the local file name of the RSA private key used by the specified server\n", - (const char **)&dtls_keys_list); - prefs_register_string_preference(dtls_module, "ports_list", "DTLS ports list", - "comma separated list of tcp ports numbers to be dissectes as DTLS; " - "each list entry must be in the form of <port>:<clear-text-port>" - "<clear-text-port> is the port numbert associated with the protocol tunneled over DTLS for this port\n", - (const char **)&dtls_ports_list); - 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 char **)&dtls_debug_file_name); - } + /* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + { &hf_dtls_record, + { "Record Layer", "dtls.record", + FT_NONE, BASE_NONE, NULL, 0x0, + "Record layer", HFILL } + }, + { &hf_dtls_record_content_type, + { "Content Type", "dtls.record.content_type", + FT_UINT8, BASE_DEC, VALS(ssl_31_content_type), 0x0, + "Content type", HFILL} + }, + { &hf_dtls_record_version, + { "Version", "dtls.record.version", + FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0, + "Record layer version.", HFILL } + }, + { &hf_dtls_record_epoch, + { "Epoch", "dtls.record.epoch", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Epoch", HFILL } + }, + { &hf_dtls_record_sequence_number, + { "Sequence Number", "dtls.record.sequence_number", + FT_DOUBLE, BASE_DEC, NULL, 0x0, + "Sequence Number", HFILL } + }, + { &hf_dtls_record_length, + { "Length", "dtls.record.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of DTLS record data", HFILL } + }, + { &hf_dtls_record_appdata, + { "Encrypted Application Data", "dtls.app_data", + FT_BYTES, BASE_HEX, NULL, 0x0, + "Payload is encrypted application data", HFILL } + }, + { &hf_dtls_change_cipher_spec, + { "Change Cipher Spec Message", "dtls.change_cipher_spec", + FT_NONE, BASE_NONE, NULL, 0x0, + "Signals a change in cipher specifications", HFILL } + }, + { & hf_dtls_alert_message, + { "Alert Message", "dtls.alert_message", + FT_NONE, BASE_NONE, NULL, 0x0, + "Alert message", HFILL } + }, + { & hf_dtls_alert_message_level, + { "Level", "dtls.alert_message.level", + FT_UINT8, BASE_DEC, VALS(ssl_31_alert_level), 0x0, + "Alert message level", HFILL } + }, + { &hf_dtls_alert_message_description, + { "Description", "dtls.alert_message.desc", + FT_UINT8, BASE_DEC, VALS(ssl_31_alert_description), 0x0, + "Alert message description", HFILL } + }, + { &hf_dtls_handshake_protocol, + { "Handshake Protocol", "dtls.handshake", + FT_NONE, BASE_NONE, NULL, 0x0, + "Handshake protocol message", HFILL} + }, + { &hf_dtls_handshake_type, + { "Handshake Type", "dtls.handshake.type", + FT_UINT8, BASE_DEC, VALS(ssl_31_handshake_type), 0x0, + "Type of handshake message", HFILL} + }, + { &hf_dtls_handshake_length, + { "Length", "dtls.handshake.length", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Length of handshake message", HFILL } + }, + { &hf_dtls_handshake_message_seq, + { "Message Sequence", "dtls.handshake.message_seq", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Message sequence of handshake message", HFILL } + }, + { &hf_dtls_handshake_fragment_offset, + { "Fragment Offset", "dtls.handshake.fragment_offset", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Fragment offset of handshake message", HFILL } + }, + { &hf_dtls_handshake_fragment_length, + { "Fragment Length", "dtls.handshake.fragment_length", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Fragment length of handshake message", HFILL } + }, + { &hf_dtls_handshake_client_version, + { "Version", "dtls.handshake.version", + FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0, + "Maximum version supported by client", HFILL } + }, + { &hf_dtls_handshake_server_version, + { "Version", "dtls.handshake.version", + FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0, + "Version selected by server", HFILL } + }, + { &hf_dtls_handshake_random_time, + { "Random.gmt_unix_time", "dtls.handshake.random_time", + FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, + "Unix time field of random structure", HFILL } + }, + { &hf_dtls_handshake_random_bytes, + { "Random.bytes", "dtls.handshake.random", + FT_NONE, BASE_NONE, NULL, 0x0, + "Random challenge used to authenticate server", HFILL } + }, + { &hf_dtls_handshake_cipher_suites_len, + { "Cipher Suites Length", "dtls.handshake.cipher_suites_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of cipher suites field", HFILL } + }, + { &hf_dtls_handshake_cipher_suites, + { "Cipher Suites", "dtls.handshake.ciphersuites", + FT_NONE, BASE_NONE, NULL, 0x0, + "List of cipher suites supported by client", HFILL } + }, + { &hf_dtls_handshake_cipher_suite, + { "Cipher Suite", "dtls.handshake.ciphersuite", + FT_UINT16, BASE_HEX, VALS(ssl_31_ciphersuite), 0x0, + "Cipher suite", HFILL } + }, + { &hf_dtls_handshake_cookie_len, + { "Cookie Length", "dtls.handshake.cookie_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of the cookie field", HFILL } + }, + { &hf_dtls_handshake_cookie, + { "Cookie", "dtls.handshake.cookie", + FT_NONE, BASE_NONE, NULL, 0x0, + "Cookie", HFILL } + }, + { &hf_dtls_handshake_session_id, + { "Session ID", "dtls.handshake.session_id", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Identifies the DTLS session, allowing later resumption", HFILL } + }, + { &hf_dtls_handshake_comp_methods_len, + { "Compression Methods Length", "dtls.handshake.comp_methods_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of compression methods field", HFILL } + }, + { &hf_dtls_handshake_comp_methods, + { "Compression Methods", "dtls.handshake.comp_methods", + FT_NONE, BASE_NONE, NULL, 0x0, + "List of compression methods supported by client", HFILL } + }, + { &hf_dtls_handshake_comp_method, + { "Compression Method", "dtls.handshake.comp_method", + FT_UINT8, BASE_DEC, VALS(ssl_31_compression_method), 0x0, + "Compression Method", HFILL } + }, + { &hf_dtls_handshake_extensions_len, + { "Extensions Length", "dtls.handshake.extensions_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of hello extensions", HFILL } + }, + { &hf_dtls_handshake_extension_type, + { "Type", "dtls.handshake.extension.type", + FT_UINT16, BASE_HEX, VALS(tls_hello_extension_types), 0x0, + "Hello extension type", HFILL } + }, + { &hf_dtls_handshake_extension_len, + { "Length", "dtls.handshake.extension.len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of a hello extension", HFILL } + }, + { &hf_dtls_handshake_extension_data, + { "Data", "dtls.handshake.extension.data", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Hello Extension data", HFILL } + }, + { &hf_dtls_handshake_certificates_len, + { "Certificates Length", "dtls.handshake.certificates_length", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Length of certificates field", HFILL } + }, + { &hf_dtls_handshake_certificates, + { "Certificates", "dtls.handshake.certificates", + FT_NONE, BASE_NONE, NULL, 0x0, + "List of certificates", HFILL } + }, + { &hf_dtls_handshake_certificate, + { "Certificate", "dtls.handshake.certificate", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Certificate", HFILL } + }, + { &hf_dtls_handshake_certificate_len, + { "Certificate Length", "dtls.handshake.certificate_length", + FT_UINT24, BASE_DEC, NULL, 0x0, + "Length of certificate", HFILL } + }, + { &hf_dtls_handshake_cert_types_count, + { "Certificate types count", "dtls.handshake.cert_types_count", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Count of certificate types", HFILL } + }, + { &hf_dtls_handshake_cert_types, + { "Certificate types", "dtls.handshake.cert_types", + FT_NONE, BASE_NONE, NULL, 0x0, + "List of certificate types", HFILL } + }, + { &hf_dtls_handshake_cert_type, + { "Certificate type", "dtls.handshake.cert_type", + FT_UINT8, BASE_DEC, VALS(ssl_31_client_certificate_type), 0x0, + "Certificate type", HFILL } + }, + { &hf_dtls_handshake_finished, + { "Verify Data", "dtls.handshake.verify_data", + FT_NONE, BASE_NONE, NULL, 0x0, + "Opaque verification data", HFILL } + }, + { &hf_dtls_handshake_md5_hash, + { "MD5 Hash", "dtls.handshake.md5_hash", + FT_NONE, BASE_NONE, NULL, 0x0, + "Hash of messages, master_secret, etc.", HFILL } + }, + { &hf_dtls_handshake_sha_hash, + { "SHA-1 Hash", "dtls.handshake.sha_hash", + FT_NONE, BASE_NONE, NULL, 0x0, + "Hash of messages, master_secret, etc.", HFILL } + }, + { &hf_dtls_handshake_session_id_len, + { "Session ID Length", "dtls.handshake.session_id_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of session ID field", HFILL } + }, + { &hf_dtls_handshake_dnames_len, + { "Distinguished Names Length", "dtls.handshake.dnames_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of list of CAs that server trusts", HFILL } + }, + { &hf_dtls_handshake_dnames, + { "Distinguished Names", "dtls.handshake.dnames", + FT_NONE, BASE_NONE, NULL, 0x0, + "List of CAs that server trusts", HFILL } + }, + { &hf_dtls_handshake_dname_len, + { "Distinguished Name Length", "dtls.handshake.dname_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of distinguished name", HFILL } + }, + { &hf_dtls_handshake_dname, + { "Distinguished Name", "dtls.handshake.dname", + FT_BYTES, BASE_NONE, NULL, 0x0, + "Distinguished name of a CA that server trusts", HFILL } + }, + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_dtls, + &ett_dtls_record, + &ett_dtls_alert, + &ett_dtls_handshake, + &ett_dtls_cipher_suites, + &ett_dtls_comp_methods, + &ett_dtls_extension, + &ett_dtls_certs, + &ett_dtls_cert_types, + &ett_dtls_dnames, + }; + + /* Register the protocol name and description */ + proto_dtls = proto_register_protocol("Datagram Transport Layer Security", + "DTLS", "dtls"); + + /* Required function calls to register the header fields and + * subtrees used */ + proto_register_field_array(proto_dtls, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + { + module_t *dtls_module = prefs_register_protocol(proto_dtls, dtls_parse); +#ifdef HAVE_LIBGNUTLS + 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); + 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); +#endif + } - register_dissector("dtls", dissect_dtls, proto_dtls); + register_dissector("dtls", dissect_dtls, proto_dtls); - register_init_routine(ssl_init); - ssl_lib_init(); - dtls_tap = register_tap("dtls"); - ssl_debug_printf("proto_register_dtls: registered tap %s:%d\n", - "dtls", dtls_tap); + register_init_routine(dtls_init); + ssl_lib_init(); + dtls_tap = register_tap("dtls"); + ssl_debug_printf("proto_register_dtls: registered tap %s:%d\n", + "dtls", dtls_tap); } /* If this dissector uses sub-dissector registration add a registration @@ -3864,8 +2162,8 @@ proto_register_dtls(void) void proto_reg_handoff_dtls(void) { - dtls_handle = find_dissector("dtls"); + dtls_handle = find_dissector("dtls"); - /* add now dissector to default ports.*/ - ssl_parse(); + /* add now dissector to default ports.*/ + dtls_parse(); } diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c index 35ceb11260..bc319b8a8b 100644 --- a/epan/dissectors/packet-ssl-utils.c +++ b/epan/dissectors/packet-ssl-utils.c @@ -29,8 +29,10 @@ #include <string.h> #include "packet-ssl-utils.h" +#include <epan/emem.h> + void -ssl_data_set(StringInfo* str, unsigned char* data, unsigned int len) +ssl_data_set(StringInfo* str, guchar* data, guint len) { memcpy(str->data, data, len); str->data_len = len; @@ -42,21 +44,23 @@ ssl_data_set(StringInfo* str, unsigned char* data, unsigned int len) #define SSL_HMAC gcry_md_hd_t static inline void -ssl_hmac_init(SSL_HMAC* md, const void * key, int len, int algo) +ssl_hmac_init(SSL_HMAC* md, const void * key, gint len, gint algo) { gcry_md_open(md,algo, GCRY_MD_FLAG_HMAC); gcry_md_setkey (*(md), key, len); } static inline void -ssl_hmac_update(SSL_HMAC* md, const void* data, int len) +ssl_hmac_update(SSL_HMAC* md, const void* data, gint len) { gcry_md_write(*(md), data, len); } static inline void -ssl_hmac_final(SSL_HMAC* md, unsigned char* data, unsigned int* datalen) +ssl_hmac_final(SSL_HMAC* md, guchar* data, guint* datalen) { - int algo = gcry_md_get_algo (*(md)); - unsigned int len = gcry_md_get_algo_dlen(algo); + gint algo; + guint len; + algo = gcry_md_get_algo (*(md)); + len = gcry_md_get_algo_dlen(algo); memcpy(data, gcry_md_read(*(md), algo), len); *datalen =len; } @@ -70,20 +74,22 @@ ssl_hmac_cleanup(SSL_HMAC* md) #define SSL_MD gcry_md_hd_t static inline void -ssl_md_init(SSL_MD* md, int algo) +ssl_md_init(SSL_MD* md, gint algo) { gcry_md_open(md,algo, 0); } static inline void -ssl_md_update(SSL_MD* md, unsigned char* data, int len) +ssl_md_update(SSL_MD* md, guchar* data, gint len) { gcry_md_write(*(md), data, len); } static inline void -ssl_md_final(SSL_MD* md, unsigned char* data, unsigned int* datalen) +ssl_md_final(SSL_MD* md, guchar* data, guint* datalen) { - int algo = gcry_md_get_algo (*(md)); - int len = gcry_md_get_algo_dlen (algo); + gint algo; + gint len; + algo = gcry_md_get_algo (*(md)); + len = gcry_md_get_algo_dlen (algo); memcpy(data, gcry_md_read(*(md), algo), len); *datalen = len; } @@ -103,12 +109,12 @@ ssl_sha_init(SSL_SHA_CTX* md) gcry_md_open(md,GCRY_MD_SHA1, 0); } static inline void -ssl_sha_update(SSL_SHA_CTX* md, unsigned char* data, int len) +ssl_sha_update(SSL_SHA_CTX* md, guchar* data, gint len) { gcry_md_write(*(md), data, len); } static inline void -ssl_sha_final(unsigned char* buf, SSL_SHA_CTX* md) +ssl_sha_final(guchar* buf, SSL_SHA_CTX* md) { memcpy(buf, gcry_md_read(*(md), GCRY_MD_SHA1), gcry_md_get_algo_dlen(GCRY_MD_SHA1)); @@ -119,18 +125,18 @@ ssl_sha_cleanup(SSL_SHA_CTX* md) gcry_md_close(*(md)); } -static inline int +static inline gint ssl_md5_init(SSL_MD5_CTX* md) { return gcry_md_open(md,GCRY_MD_MD5, 0); } static inline void -ssl_md5_update(SSL_MD5_CTX* md, unsigned char* data, int len) +ssl_md5_update(SSL_MD5_CTX* md, guchar* data, gint len) { gcry_md_write(*(md), data, len); } static inline void -ssl_md5_final(unsigned char* buf, SSL_MD5_CTX* md) +ssl_md5_final(guchar* buf, SSL_MD5_CTX* md) { memcpy(buf, gcry_md_read(*(md), GCRY_MD_MD5), gcry_md_get_algo_dlen(GCRY_MD_MD5)); @@ -141,13 +147,14 @@ ssl_md5_cleanup(SSL_MD5_CTX* md) gcry_md_close(*(md)); } -static int -ssl_cipher_setiv(gcry_cipher_hd_t *cipher,unsigned char* iv, int iv_len) +static gint +ssl_cipher_setiv(gcry_cipher_hd_t *cipher,guchar* iv, gint iv_len) { - unsigned char * ivp; - int ret=0; - int i; + /* guchar * ivp; */ + gint ret; + /* gint i; */ gcry_cipher_hd_t c; + ret=0; c=(gcry_cipher_hd_t)*cipher; ssl_debug_printf("--------------------------------------------------------------------"); @@ -169,15 +176,13 @@ ssl_cipher_setiv(gcry_cipher_hd_t *cipher,unsigned char* iv, int iv_len) return ret; } /* stream cipher abstraction layer*/ -static int -ssl_cipher_init(gcry_cipher_hd_t *cipher, int algo, unsigned char* sk, - unsigned char* iv, int mode) -{ - int gcry_modes[]={ - GCRY_CIPHER_MODE_STREAM, - GCRY_CIPHER_MODE_CBC - }; - int err = gcry_cipher_open(cipher, algo, gcry_modes[mode], 0); +static gint +ssl_cipher_init(gcry_cipher_hd_t *cipher, gint algo, guchar* sk, + guchar* iv, gint mode) +{ + gint gcry_modes[]={GCRY_CIPHER_MODE_STREAM,GCRY_CIPHER_MODE_CBC}; + gint err; + err = gcry_cipher_open(cipher, algo, gcry_modes[mode], 0); if (err !=0) return -1; err = gcry_cipher_setkey(*(cipher), sk, gcry_cipher_get_algo_keylen (algo)); @@ -188,19 +193,19 @@ ssl_cipher_init(gcry_cipher_hd_t *cipher, int algo, unsigned char* sk, return -1; return 0; } -static inline int -ssl_cipher_decrypt(gcry_cipher_hd_t *cipher, unsigned char * out, int outl, - const unsigned char * in,int inl) +static inline gint +ssl_cipher_decrypt(gcry_cipher_hd_t *cipher, guchar * out, gint outl, + const guchar * in, gint inl) { return gcry_cipher_decrypt ( *(cipher), out, outl, in, inl); } -static inline int -ssl_get_digest_by_name(const char*name) +static inline gint +ssl_get_digest_by_name(const gchar*name) { return gcry_md_map_name(name); } -static inline int -ssl_get_cipher_by_name(const char* name) +static inline gint +ssl_get_cipher_by_name(const gchar* name) { return gcry_cipher_map_name(name); } @@ -213,28 +218,30 @@ ssl_cipher_cleanup(gcry_cipher_hd_t *cipher) } /* private key abstraction layer */ -static inline int +static inline gint ssl_get_key_len(SSL_PRIVATE_KEY* pk) {return gcry_pk_get_nbits (pk); } gcry_err_code_t _gcry_rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags); + gcry_mpi_t *skey, gint flags); #define PUBKEY_FLAG_NO_BLINDING (1 << 0) /* decrypt data with private key. Store decrypted data directly into input * buffer */ int -ssl_private_decrypt(unsigned int len, unsigned char* encr_data, SSL_PRIVATE_KEY* pk) +ssl_private_decrypt(guint len, guchar* encr_data, SSL_PRIVATE_KEY* pk) { - int rc; - size_t decr_len = 0; + gint rc; + size_t decr_len; gcry_sexp_t s_data, s_plain; gcry_mpi_t encr_mpi; - size_t i, encr_len = len; - unsigned char* decr_data_ptr; - gcry_mpi_t text=NULL; - + size_t i, encr_len; + guchar* decr_data_ptr; + gcry_mpi_t text; + decr_len = 0; + encr_len = len; + text=NULL; /* build up a mpi rappresentation for encrypted data */ rc = gcry_mpi_scan(&encr_mpi, GCRYMPI_FMT_USG,encr_data, encr_len, &encr_len); if (rc != 0 ) { @@ -349,8 +356,8 @@ out: } /* stringinfo interface */ -static int -ssl_data_alloc(StringInfo* str, unsigned int len) +static gint +ssl_data_alloc(StringInfo* str, guint len) { str->data = g_malloc(len); if (!str->data) @@ -363,12 +370,12 @@ ssl_data_alloc(StringInfo* str, unsigned int len) ssl3_prf(secret,usage,rnd1,rnd2,out): \ tls_prf(secret,usage,rnd1,rnd2,out)) -static const char *digests[]={ +static const gchar *digests[]={ "MD5", "SHA1" }; -static const char *ciphers[]={ +static const gchar *ciphers[]={ "DES", "3DES", "ARCFOUR", /* gnutls does not support rc4, but this should be 100% compatible*/ @@ -438,17 +445,20 @@ ssl_find_cipher(int num,SslCipherSuite* cs) return -1; } -static int +static gint tls_hash(StringInfo* secret, - StringInfo* seed, int md, StringInfo* out) + StringInfo* seed, gint md, StringInfo* out) { - guint8 *ptr=out->data; - unsigned int left=out->data_len; - int tocpy; + guint8 *ptr; + guint left; + gint tocpy; guint8 *A; guint8 _A[20],tmp[20]; - unsigned int A_l,tmp_l; + guint A_l,tmp_l; SSL_HMAC hm; + ptr=out->data; + left=out->data_len; + ssl_print_string("tls_hash: hash secret", secret); ssl_print_string("tls_hash: hash seed", seed); @@ -478,16 +488,18 @@ tls_hash(StringInfo* secret, return (0); } -static int -tls_prf(StringInfo* secret, const char *usage, +static gint +tls_prf(StringInfo* secret, const gchar *usage, StringInfo* rnd1, StringInfo* rnd2, StringInfo* out) { StringInfo seed, sha_out, md5_out; guint8 *ptr; StringInfo s1, s2; - unsigned int i,s_l, r=-1; - int usage_len = strlen(usage); - + guint i,s_l, r; + gint usage_len; + r=-1; + usage_len = strlen(usage); + /* initalize buffer for sha, md5 random seed*/ if (ssl_data_alloc(&sha_out, MAX(out->data_len,20)) < 0) return -1; @@ -536,7 +548,7 @@ free_sha: return r; } -static int +static gint ssl3_generate_export_iv(StringInfo* r1, StringInfo* r2, StringInfo* out) { @@ -555,23 +567,23 @@ ssl3_generate_export_iv(StringInfo* r1, return(0); } -static int -ssl3_prf(StringInfo* secret, const char* usage, +static gint +ssl3_prf(StringInfo* secret, const gchar* usage, StringInfo* r1, StringInfo* r2,StringInfo* out) { SSL_MD5_CTX md5; SSL_SHA_CTX sha; StringInfo *rnd1,*rnd2; - unsigned int off; - int i=0,j; + guint off; + gint i=0,j; guint8 buf[20]; rnd1=r1; rnd2=r2; for(off=0;off<out->data_len;off+=16){ - unsigned char outbuf[16]; - int tocpy; + guchar outbuf[16]; + gint tocpy; i++; ssl_debug_printf("ssl3_prf: sha1_hash(%d)\n",i); @@ -611,12 +623,12 @@ ssl3_prf(StringInfo* secret, const char* usage, return(0); } -static int +static gint ssl_create_decoder(SslDecoder *dec, SslCipherSuite *cipher_suite, guint8 *mk, guint8 *sk, guint8 *iv) { - int ciph=0; - + gint ciph; + ciph=0; /* Find the SSLeay cipher */ if(cipher_suite->enc!=ENC_NULL) { ssl_debug_printf("ssl_create_decoder CIPHER: %s\n", ciphers[cipher_suite->enc-0x30]); @@ -654,7 +666,7 @@ ssl_generate_keyring_material(SslDecryptSession*ssl_session) StringInfo key_block; guint8 _iv_c[MAX_BLOCK_SIZE],_iv_s[MAX_BLOCK_SIZE]; guint8 _key_c[MAX_KEY_SIZE],_key_s[MAX_KEY_SIZE]; - int needed; + gint needed; guint8 *ptr,*c_wk,*s_wk,*c_mk,*s_mk,*c_iv = _iv_c,*s_iv = _iv_s; /* if master_key is not yet generate, create it now*/ @@ -864,7 +876,7 @@ int ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, StringInfo* entrypted_pre_master, SSL_PRIVATE_KEY *pk) { - int i; + gint i; if(ssl_session->cipher_suite.kex!=KEX_RSA) { ssl_debug_printf("ssl_decrypt_pre_master_secret key %d diferent from KEX_RSA(%d)\n", @@ -898,7 +910,7 @@ ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, /* convert network byte order 32 byte number to right-aligned host byte order * * 8 bytes buffer */ -static int fmt_seq(guint32 num, guint8* buf) +static gint fmt_seq(guint32 num, guint8* buf) { guint32 netnum; @@ -909,12 +921,12 @@ static int fmt_seq(guint32 num, guint8* buf) return(0); } -static int -tls_check_mac(SslDecoder*decoder, int ct,int ver, guint8* data, +static gint +tls_check_mac(SslDecoder*decoder, gint ct, gint ver, guint8* data, guint32 datalen, guint8* mac) { SSL_HMAC hm; - int md; + gint md; guint32 len; guint8 buf[20]; @@ -958,10 +970,10 @@ ssl3_check_mac(SslDecoder*decoder,int ct,guint8* data, guint32 datalen, guint8* mac) { SSL_MD mc; - int md; + gint md; guint32 len; guint8 buf[64],dgst[20]; - int pad_ct; + gint pad_ct; pad_ct=(decoder->cipher_suite->dig==DIG_SHA)?40:48; @@ -1014,12 +1026,12 @@ ssl3_check_mac(SslDecoder*decoder,int ct,guint8* data, } #if 0 -static int -dtls_check_mac(SslDecoder*decoder, int ct,int ver, guint8* data, +static gint +dtls_check_mac(SslDecoder*decoder, gint ct,int ver, guint8* data, guint32 datalen, guint8* mac) { SSL_HMAC hm; - int md; + gint md; guint32 len; guint8 buf[20]; guint32 netnum; @@ -1060,10 +1072,10 @@ dtls_check_mac(SslDecoder*decoder, int ct,int ver, guint8* data, int -ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, - const unsigned char* in, int inl,unsigned char*out,int* outl) +ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct, + const guchar* in, gint inl, guchar*out, gint* outl) { - int pad, worklen; + gint pad, worklen; guint8 *mac; @@ -1134,9 +1146,9 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, /* old relase of gnutls does not define the appropriate macros, so get * them from the string*/ static void -ssl_get_version(int* major, int* minor, int* patch) +ssl_get_version(gint* major, gint* minor, gint* patch) { - const char* str = gnutls_check_version(NULL); + const gchar* str = gnutls_check_version(NULL); ssl_debug_printf("ssl_get_version: %s\n", str); sscanf(str, "%d.%d.%d", major, minor, patch); @@ -1153,9 +1165,9 @@ ssl_load_key(FILE* fp) struct gnutls_x509_privkey_int* priv_key; gnutls_datum key; gnutls_datum m, e, d, p,q, u; - int size, major, minor, patch; - unsigned int bytes; - unsigned int tmp_size; + gint size, major, minor, patch; + guint bytes; + guint tmp_size; #ifdef SSL_FAST gcry_mpi_t* rsa_params = g_malloc(sizeof(gcry_mpi_t)*6); #else @@ -1260,7 +1272,7 @@ ssl_load_key(FILE* fp) return rsa_params; #else { - int i; + gint i; for (i=0; i< 6; i++) gcry_mpi_release(rsa_params[i]); } @@ -1271,7 +1283,7 @@ ssl_load_key(FILE* fp) void ssl_free_key(SSL_PRIVATE_KEY* key) { #if SSL_FAST - int i; + gint i; for (i=0; i< 6; i++) gcry_mpi_release(key[i]); #else @@ -1329,8 +1341,8 @@ ssl_decrypt_pre_master_secret(SslDecryptSession* ssl_session, } int -ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, - const unsigned char* in, int inl,unsigned char*out,int* outl) +ssl_decrypt_record(SslDecryptSession*ssl, SslDecoder* decoder, gint ct, + const guchar* in, gint inl, guchar*out, gint* outl) { ssl_debug_printf("ssl_decrypt_record: impossible without gnutls. ssl %p" "decoder %p ct %d, in %p inl %d out %p outl %p\n", ssl, decoder, ct, @@ -1345,7 +1357,7 @@ void ssl_session_init(SslDecryptSession* ssl_session) { ssl_debug_printf("ssl_session_init: initializing ptr %p size %lu\n", - ssl_session, (unsigned long)sizeof(SslDecryptSession)); + ssl_session, (gulong)sizeof(SslDecryptSession)); ssl_session->master_secret.data = ssl_session->_master_secret; ssl_session->session_id.data = ssl_session->_session_id; @@ -1356,6 +1368,359 @@ ssl_session_init(SslDecryptSession* ssl_session) ssl_session->app_data_segment.data_len=0; } +/* Hash Functions for TLS/DTLS sessions table and private keys table*/ +gint +ssl_equal (gconstpointer v, gconstpointer v2) +{ + const StringInfo *val1; + const StringInfo *val2; + val1 = (const StringInfo *)v; + val2 = (const StringInfo *)v2; + + if (val1->data_len == val2->data_len && + !memcmp(val1->data, val2->data, val2->data_len)) { + return 1; + } + return 0; +} + +guint +ssl_hash (gconstpointer v) +{ + guint l,hash; + StringInfo* id; + guint* cur; + hash = 0; + id = (StringInfo*) v; + cur = (guint*) id->data; + + for (l=4; (l<id->data_len); l+=4, cur++) + hash = hash ^ (*cur); + + return hash; +} + +gint +ssl_private_key_equal (gconstpointer v, gconstpointer v2) +{ + const SslService *val1; + const SslService *val2; + val1 = (const SslService *)v; + val2 = (const SslService *)v2; + + if ((val1->port == val2->port) && + ! CMP_ADDRESS(&val1->addr, &val2->addr)) { + return 1; + } + return 0; +} + +guint +ssl_private_key_hash (gconstpointer v) +{ + const SslService *key; + guint l, hash, len ; + guint* cur; + key = (const SslService *)v; + hash = key->port; + len = key->addr.len; + cur = (guint*) key->addr.data; + + for (l=4; (l<len); l+=4, cur++) + hash = hash ^ (*cur); + + return hash; +} + +/* private key table entries have a scope 'larger' then packet capture, + * so we can't relay on se_alloc** function */ +void +ssl_private_key_free(gpointer id, gpointer key, gpointer dummy _U_) +{ + g_free(id); + ssl_free_key((SSL_PRIVATE_KEY*) key); +} + +/* handling of association between tls/dtls ports and clear text protocol */ +void +ssl_association_add(GTree* associations, dissector_handle_t handle, guint port, gchar *protocol, gboolean tcp) +{ + + SslAssociation* assoc; + assoc = g_malloc(sizeof(SslAssociation)); + + assoc->info=g_malloc(strlen(protocol)+1); + strcpy(assoc->info, protocol); + assoc->ssl_port = port; + + assoc->handle = find_dissector(protocol); + + ssl_debug_printf("association_add port %d protocol %s handle %p\n", + port, protocol, assoc->handle); + + + if(!assoc->handle){ + fprintf(stderr, "association_add() could not find handle for protocol:%s\n",protocol); + } else { + if(tcp) + dissector_add("tcp.port", port, handle); + else + dissector_add("udp.port", port, handle); + g_tree_insert(associations, (gpointer)port, assoc); + } +} + + +gint +ssl_association_cmp(gconstpointer a, gconstpointer b) +{ + return (gint)a-(gint)b; +} + +SslAssociation* +ssl_association_find(GTree * associations, guint port) +{ + register SslAssociation* ret; + ret = g_tree_lookup(associations, (gpointer)port); + + ssl_debug_printf("association_find: port %d found %p\n", port, ret); + return ret; +} + +gint +ssl_association_remove_handle_tcp (gpointer key _U_, + gpointer data, gpointer user_data _U_) +{ + SslAssociation* assoc; + assoc = (SslAssociation*) data; + + ssl_debug_printf("association_remove_handle removing ptr %p handle %p\n", + data, assoc->handle); + if (assoc->handle) + dissector_delete("tcp.port", assoc->ssl_port, assoc->handle); + g_free(data); + return 0; +} + +gint +ssl_association_remove_handle_udp (gpointer key _U_, + gpointer data, gpointer user_data _U_) +{ + SslAssociation* assoc; + assoc = (SslAssociation*) data; + + ssl_debug_printf("association_remove_handle removing ptr %p handle %p\n", + data, assoc->handle); + if (assoc->handle) + dissector_delete("tcp.port", assoc->ssl_port, assoc->handle); + g_free(data); + return 0; +} + +int +ssl_packet_from_server(GTree* associations, guint port) +{ + register gint ret; + ret = ssl_association_find(associations, port) != 0; + + ssl_debug_printf("packet_from_server: is from server %d\n", ret); + return ret; +} + +/* add to packet data a newly allocated tvb with the specified real data*/ +void +ssl_add_record_info(gint proto, packet_info *pinfo, guchar* data, gint data_len, gint record_id) +{ + guchar* real_data; + SslRecordInfo* rec; + SslPacketInfo* pi; + real_data = se_alloc(data_len); + rec = se_alloc(sizeof(SslRecordInfo)); + pi = p_get_proto_data(pinfo->fd, proto); + + if (!pi) + { + pi = se_alloc0(sizeof(SslPacketInfo)); + p_add_proto_data(pinfo->fd, proto,pi); + } + + rec->id = record_id; + rec->tvb = tvb_new_real_data(real_data, data_len, data_len); + memcpy(real_data, data, data_len); + + /* head insertion */ + rec->next= pi->handshake_data; + pi->handshake_data = rec; +} + + +/* search in packet data the tvbuff associated to the specified id */ +tvbuff_t* +ssl_get_record_info(int proto, packet_info *pinfo, gint record_id) +{ + SslRecordInfo* rec; + SslPacketInfo* pi; + pi = p_get_proto_data(pinfo->fd, proto); + + if (!pi) + return NULL; + + for (rec = pi->handshake_data; rec; rec = rec->next) + if (rec->id == record_id) + return rec->tvb; + + return NULL; +} + +/* initialize/reset per capture state data (ssl sessions cache) */ +void +ssl_common_init(GHashTable **session_hash , StringInfo * decrypted_data) +{ + if (*session_hash) + g_hash_table_destroy(*session_hash); + *session_hash = g_hash_table_new(ssl_hash, ssl_equal); + if (decrypted_data->data) + g_free(decrypted_data->data); + decrypted_data->data = g_malloc0(32); + decrypted_data->data_len = 32; +} + +/* parse ssl related preferences (private keys and ports association strings) */ +void +ssl_parse_key_list(const gchar * keys_list, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp) +{ + gchar* end; + gchar* start; + gchar* tmp; + guchar* ip; + SslService* service; + SSL_PRIVATE_KEY * private_key; + FILE* fp; + + start = strdup(keys_list); + tmp = start; + ssl_debug_printf("ssl_init keys string %s\n", start); + do { + gchar* addr, *port, *protocol, *filename; + + addr = start; + /* split ip/file couple with ';' separator*/ + end = strchr(start, ';'); + if (end) { + *end = 0; + start = end+1; + } + + /* for each entry split ip, port, protocol, filename with ',' separator */ + ssl_debug_printf("ssl_init found host entry %s\n", addr); + port = strchr(addr, ','); + if (!port) + { + ssl_debug_printf("ssl_init entry malformed can't find port in %s\n", addr); + break; + } + *port = 0; + port++; + + protocol = strchr(port,','); + if (!protocol) + { + ssl_debug_printf("ssl_init entry malformed can't find protocol in %s\n", port); + break; + } + *protocol=0; + protocol++; + + filename = strchr(protocol,','); + if (!filename) + { + ssl_debug_printf("ssl_init entry malformed can't find filename in %s\n", port); + break; + } + *filename=0; + filename++; + + /* convert ip and port string to network rappresentation*/ + service = g_malloc(sizeof(SslService) + 4); + service->addr.type = AT_IPv4; + service->addr.len = 4; + service->addr.data = ip = ((guchar*)service) + sizeof(SslService); + sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &ip[0], &ip[1], &ip[2], &ip[3]); + service->port = atoi(port); + ssl_debug_printf("ssl_init addr %hhu.%hhu.%hhu.%hhu port %d filename %s\n", + ip[0], ip[1], ip[2], ip[3], service->port, filename); + + /* try to load pen file*/ + fp = fopen(filename, "rb"); + if (!fp) { + fprintf(stderr, "can't open file %s \n",filename); + break; + } + + private_key = ssl_load_key(fp); + if (!private_key) { + fprintf(stderr,"can't load private key from %s\n", + filename); + break; + } + fclose(fp); + + ssl_debug_printf("ssl_init private key file %s successfully loaded\n", + filename); + g_hash_table_insert(key_hash, service, private_key); + + ssl_association_add(associations, handle, atoi(port), protocol, tcp); + + } while (end != NULL); + free(tmp); +} + +/* store master secret into session data cache */ +void +ssl_save_session(SslDecryptSession* ssl, GHashTable *session_hash) +{ + /* allocate stringinfo chunks for session id and master secret data*/ + StringInfo* session_id; + StringInfo* master_secret; + session_id = se_alloc0(sizeof(StringInfo) + ssl->session_id.data_len); + master_secret = se_alloc0(48 + sizeof(StringInfo)); + + master_secret->data = ((guchar*)master_secret+sizeof(StringInfo)); + session_id->data = ((guchar*)session_id+sizeof(StringInfo)); + + ssl_data_set(session_id, ssl->session_id.data, ssl->session_id.data_len); + ssl_data_set(master_secret, ssl->master_secret.data, ssl->master_secret.data_len); + g_hash_table_insert(session_hash, session_id, master_secret); + ssl_print_string("ssl_save_session stored session id", session_id); + ssl_print_string("ssl_save_session stored master secret", master_secret); +} + +void +ssl_restore_session(SslDecryptSession* ssl, GHashTable *session_hash) +{ + StringInfo* ms; + ms = g_hash_table_lookup(session_hash, &ssl->session_id); + + if (!ms) { + ssl_debug_printf("ssl_restore_session can't find stored session\n"); + return; + } + ssl_data_set(&ssl->master_secret, ms->data, ms->data_len); + ssl->state |= SSL_MASTER_SECRET; + ssl_debug_printf("ssl_restore_session master key retrived\n"); +} + +int +ssl_is_valid_content_type(guint8 type) +{ + if (type >= 0x14 && type <= 0x17) + { + return 1; + } + + return 0; +} + #ifdef SSL_DECRYPT_DEBUG static FILE* ssl_debug_file=NULL; @@ -1363,9 +1728,11 @@ static FILE* ssl_debug_file=NULL; void ssl_set_debug(char* name) { - static int debug_file_must_be_closed = 0; - int use_stderr = name?(strcmp(name, SSL_DEBUG_USE_STDERR) == 0):0; - + static gint debug_file_must_be_closed; + gint use_stderr; + debug_file_must_be_closed = 0; + use_stderr = name?(strcmp(name, SSL_DEBUG_USE_STDERR) == 0):0; + if (debug_file_must_be_closed) fclose(ssl_debug_file); if (use_stderr) @@ -1380,10 +1747,12 @@ ssl_set_debug(char* name) void -ssl_debug_printf(const char* fmt, ...) +ssl_debug_printf(const gchar* fmt, ...) { va_list ap; - int ret=0; + gint ret; + ret=0; + if (!ssl_debug_file) return; @@ -1394,9 +1763,9 @@ ssl_debug_printf(const char* fmt, ...) } void -ssl_print_text_data(const char* name, const unsigned char* data, int len) +ssl_print_text_data(const gchar* name, const guchar* data, gint len) { - int i; + gint i; if (!ssl_debug_file) return; fprintf(ssl_debug_file,"%s: ",name); @@ -1408,9 +1777,9 @@ ssl_print_text_data(const char* name, const unsigned char* data, int len) } void -ssl_print_data(const char* name, const unsigned char* data, int len) +ssl_print_data(const gchar* name, const guchar* data, gint len) { - int i; + gint i; if (!ssl_debug_file) return; fprintf(ssl_debug_file,"%s[%d]:\n",name, len); @@ -1424,7 +1793,7 @@ ssl_print_data(const char* name, const unsigned char* data, int len) } void -ssl_print_string(const char* name, const StringInfo* data) +ssl_print_string(const gchar* name, const StringInfo* data) { ssl_print_data(name, data->data, data->data_len); } diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h index decd2f9be9..bc9cd47871 100644 --- a/epan/dissectors/packet-ssl-utils.h +++ b/epan/dissectors/packet-ssl-utils.h @@ -37,6 +37,8 @@ #include <gnutls/x509.h> #include <gnutls/openssl.h> +#include <epan/conversation.h> + /* #define SSL_FAST 1 */ #define SSL_DECRYPT_DEBUG @@ -552,8 +554,8 @@ static const value_string tls_hello_extension_types[] = { }; typedef struct _StringInfo { - unsigned char* data; - unsigned int data_len; + guchar* data; + guint data_len; } StringInfo; #define SSL_WRITE_KEY 1 @@ -576,22 +578,22 @@ typedef struct _StringInfo { #define SSL_DEBUG_USE_STDERR "-" typedef struct _SslCipherSuite { - int number; - int kex; - int sig; - int enc; - int block; - int bits; - int eff_bits; - int dig; - int dig_len; - int export; - int mode; + gint number; + gint kex; + gint sig; + gint enc; + gint block; + gint bits; + gint eff_bits; + gint dig; + gint dig_len; + gint export; + gint mode; } SslCipherSuite; typedef struct _SslDecoder { SslCipherSuite* cipher_suite; - unsigned char _mac_key[20]; + guchar _mac_key[20]; StringInfo mac_key; SSL_CIPHER_CTX evp; guint32 seq; @@ -621,7 +623,7 @@ struct tvbuff; typedef struct _SslRecordInfo { struct tvbuff* tvb; - int id; + gint id; struct _SslRecordInfo* next; } SslRecordInfo; @@ -631,18 +633,18 @@ typedef struct { } SslPacketInfo; typedef struct _SslDecryptSession { - unsigned char _master_secret[48]; - unsigned char _session_id[256]; - unsigned char _client_random[32]; - unsigned char _server_random[32]; + guchar _master_secret[48]; + guchar _session_id[256]; + guchar _client_random[32]; + guchar _server_random[32]; StringInfo session_id; StringInfo server_random; StringInfo client_random; StringInfo master_secret; StringInfo pre_master_secret; - int cipher; - int state; + gint cipher; + gint state; SslCipherSuite cipher_suite; SslDecoder server; SslDecoder client; @@ -653,6 +655,18 @@ typedef struct _SslDecryptSession { } SslDecryptSession; +typedef struct _SslAssociation { + guint ssl_port; + dissector_handle_t handle; + gchar* info; +} SslAssociation; + +typedef struct _SslService { + address addr; + guint port; +} SslService; + + /** Initialize decryption engine/ssl layer. To be called once per execution */ extern void ssl_lib_init(void); @@ -668,7 +682,7 @@ ssl_session_init(SslDecryptSession* ssl); @param src the data source @param len the source data len */ extern void -ssl_data_set(StringInfo* buf, unsigned char* src, unsigned int len); +ssl_data_set(StringInfo* buf, guchar* src, guint len); /** Load an RSA private key from specified file @param fp the file that contain the key data @@ -685,14 +699,14 @@ ssl_free_key(SSL_PRIVATE_KEY* key); @param num the id of the cipher suite to be searched @param cs pointer to the cipher suite struct to be filled @return 0 if the cipher suite is found, -1 elsewhere */ -extern int +extern gint ssl_find_cipher(int num,SslCipherSuite* cs); /* Expand the pre_master_secret to generate all the session information * (master secret, session keys, ivs) @param ssl_session the store for all the session data @return 0 on success */ -extern int +extern gint ssl_generate_keyring_material(SslDecryptSession*ssl_session); /* Try to decrypt in place the encrypted pre_master_secret @@ -700,7 +714,7 @@ ssl_generate_keyring_material(SslDecryptSession*ssl_session); @param entrypted_pre_master the rsa encrypted pre_master_secret @param pk the private key to be used for decryption @return 0 on success */ -extern int +extern gint ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, StringInfo* entrypted_pre_master, SSL_PRIVATE_KEY *pk); @@ -713,26 +727,93 @@ ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, @param out a pointer to the store for the decrypted data @param outl the decrypted data len @return 0 on success */ -extern int -ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, - const unsigned char* in, int inl,unsigned char*out,int* outl); +extern gint +ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct, + const guchar* in, gint inl,guchar*out,gint* outl); + + +/* Common part bitween SSL and DTLS dissectors */ +/* Hash Functions for TLS/DTLS sessions table and private keys table */ +extern gint +ssl_equal (gconstpointer v, gconstpointer v2); + +extern guint +ssl_hash (gconstpointer v); + +extern gint +ssl_private_key_equal (gconstpointer v, gconstpointer v2); + +extern guint +ssl_private_key_hash (gconstpointer v); + +/* private key table entries have a scope 'larger' then packet capture, + * so we can't relay on se_alloc** function */ +extern void +ssl_private_key_free(gpointer id, gpointer key, gpointer dummy _U_); + +/* handling of association between tls/dtls ports and clear text protocol */ +extern void +ssl_association_add(GTree* associations, dissector_handle_t handle, guint port, gchar *protocol, gboolean tcp); + +extern gint +ssl_association_cmp(gconstpointer a, gconstpointer b); + +extern SslAssociation* +ssl_association_find(GTree * associations, guint port); + +extern gint +ssl_association_remove_handle_tcp (gpointer key _U_, + gpointer data, gpointer user_data _U_); + +extern gint +ssl_association_remove_handle_udp (gpointer key _U_, + gpointer data, gpointer user_data _U_); + +extern gint +ssl_packet_from_server(GTree* associations, guint port); + +/* add to packet data a newly allocated tvb with the specified real data*/ +extern void +ssl_add_record_info(gint proto, packet_info *pinfo, guchar* data, gint data_len, gint record_id); + +/* search in packet data the tvbuff associated to the specified id */ +extern tvbuff_t* +ssl_get_record_info(gint proto, packet_info *pinfo, gint record_id); + +/* initialize/reset per capture state data (ssl sessions cache) */ +extern void +ssl_common_init(GHashTable **session_hash , StringInfo * decrypted_data); + +/* parse ssl related preferences (private keys and ports association strings) */ +extern void +ssl_parse_key_list(const gchar * keys_list, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp); + +/* store master secret into session data cache */ +extern void +ssl_save_session(SslDecryptSession* ssl, GHashTable *session_hash); + +extern void +ssl_restore_session(SslDecryptSession* ssl, GHashTable *session_hash); + +extern gint +ssl_is_valid_content_type(guint8 type); #ifdef SSL_DECRYPT_DEBUG extern void -ssl_debug_printf(const char* fmt,...) GNUC_FORMAT_CHECK(printf,1,2); +ssl_debug_printf(const gchar* fmt,...) GNUC_FORMAT_CHECK(printf,1,2); extern void -ssl_print_data(const char* name, const unsigned char* data, int len); +ssl_print_data(const gchar* name, const guchar* data, gint len); extern void -ssl_print_string(const char* name, const StringInfo* data); +ssl_print_string(const gchar* name, const StringInfo* data); extern void -ssl_print_text_data(const char* name, const unsigned char* data, int len); +ssl_print_text_data(const gchar* name, const guchar* data, gint len); extern void -ssl_set_debug(char* name); +ssl_set_debug(gchar* name); #else /* No debug: nullify debug operation*/ static inline void GNUC_FORMAT_CHECK(printf,1,2) -ssl_debug_printf(const char* fmt _U_,...) +ssl_debug_printf(const gchar* fmt _U_,...) { } #define ssl_print_data(a, b, c) diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c index f5af1f3d4c..9e1f382dc1 100644 --- a/epan/dissectors/packet-ssl.c +++ b/epan/dissectors/packet-ssl.c @@ -128,81 +128,81 @@ static proto_tree *top_tree; *********************************************************************/ /* Initialize the protocol and registered fields */ -static int ssl_tap = -1; -static int proto_ssl = -1; -static int hf_ssl_record = -1; -static int hf_ssl_record_content_type = -1; -static int hf_ssl_record_version = -1; -static int hf_ssl_record_length = -1; -static int hf_ssl_record_appdata = -1; -static int hf_ssl2_record = -1; -static int hf_ssl2_record_is_escape = -1; -static int hf_ssl2_record_padding_length = -1; -static int hf_ssl2_msg_type = -1; -static int hf_pct_msg_type = -1; -static int hf_ssl_change_cipher_spec = -1; -static int hf_ssl_alert_message = -1; -static int hf_ssl_alert_message_level = -1; -static int hf_ssl_alert_message_description = -1; -static int hf_ssl_handshake_protocol = -1; -static int hf_ssl_handshake_type = -1; -static int hf_ssl_handshake_length = -1; -static int hf_ssl_handshake_client_version = -1; -static int hf_ssl_handshake_server_version = -1; -static int hf_ssl_handshake_random_time = -1; -static int hf_ssl_handshake_random_bytes = -1; -static int hf_ssl_handshake_cipher_suites_len = -1; -static int hf_ssl_handshake_cipher_suites = -1; -static int hf_ssl_handshake_cipher_suite = -1; -static int hf_ssl_handshake_session_id = -1; -static int hf_ssl_handshake_comp_methods_len = -1; -static int hf_ssl_handshake_comp_methods = -1; -static int hf_ssl_handshake_comp_method = -1; -static int hf_ssl_handshake_extensions_len = -1; -static int hf_ssl_handshake_extension_type = -1; -static int hf_ssl_handshake_extension_len = -1; -static int hf_ssl_handshake_extension_data = -1; -static int hf_ssl_handshake_certificates_len = -1; -static int hf_ssl_handshake_certificates = -1; -static int hf_ssl_handshake_certificate = -1; -static int hf_ssl_handshake_certificate_len = -1; -static int hf_ssl_handshake_cert_types_count = -1; -static int hf_ssl_handshake_cert_types = -1; -static int hf_ssl_handshake_cert_type = -1; -static int hf_ssl_handshake_finished = -1; -static int hf_ssl_handshake_md5_hash = -1; -static int hf_ssl_handshake_sha_hash = -1; -static int hf_ssl_handshake_session_id_len = -1; -static int hf_ssl_handshake_dnames_len = -1; -static int hf_ssl_handshake_dnames = -1; -static int hf_ssl_handshake_dname_len = -1; -static int hf_ssl_handshake_dname = -1; -static int hf_ssl2_handshake_cipher_spec_len = -1; -static int hf_ssl2_handshake_session_id_len = -1; -static int hf_ssl2_handshake_challenge_len = -1; -static int hf_ssl2_handshake_cipher_spec = -1; -static int hf_ssl2_handshake_challenge = -1; -static int hf_ssl2_handshake_clear_key_len = -1; -static int hf_ssl2_handshake_enc_key_len = -1; -static int hf_ssl2_handshake_key_arg_len = -1; -static int hf_ssl2_handshake_clear_key = -1; -static int hf_ssl2_handshake_enc_key = -1; -static int hf_ssl2_handshake_key_arg = -1; -static int hf_ssl2_handshake_session_id_hit = -1; -static int hf_ssl2_handshake_cert_type = -1; -static int hf_ssl2_handshake_connection_id_len = -1; -static int hf_ssl2_handshake_connection_id = -1; -static int hf_pct_handshake_cipher_spec = -1; -static int hf_pct_handshake_hash_spec = -1; -static int hf_pct_handshake_cert_spec = -1; -static int hf_pct_handshake_cert = -1; -static int hf_pct_handshake_server_cert = -1; -static int hf_pct_handshake_exch_spec = -1; -static int hf_pct_handshake_hash = -1; -static int hf_pct_handshake_cipher = -1; -static int hf_pct_handshake_exch = -1; -static int hf_pct_handshake_sig = -1; -static int hf_pct_msg_error_type = -1; +static gint ssl_tap = -1; +static gint proto_ssl = -1; +static gint hf_ssl_record = -1; +static gint hf_ssl_record_content_type = -1; +static gint hf_ssl_record_version = -1; +static gint hf_ssl_record_length = -1; +static gint hf_ssl_record_appdata = -1; +static gint hf_ssl2_record = -1; +static gint hf_ssl2_record_is_escape = -1; +static gint hf_ssl2_record_padding_length = -1; +static gint hf_ssl2_msg_type = -1; +static gint hf_pct_msg_type = -1; +static gint hf_ssl_change_cipher_spec = -1; +static gint hf_ssl_alert_message = -1; +static gint hf_ssl_alert_message_level = -1; +static gint hf_ssl_alert_message_description = -1; +static gint hf_ssl_handshake_protocol = -1; +static gint hf_ssl_handshake_type = -1; +static gint hf_ssl_handshake_length = -1; +static gint hf_ssl_handshake_client_version = -1; +static gint hf_ssl_handshake_server_version = -1; +static gint hf_ssl_handshake_random_time = -1; +static gint hf_ssl_handshake_random_bytes = -1; +static gint hf_ssl_handshake_cipher_suites_len = -1; +static gint hf_ssl_handshake_cipher_suites = -1; +static gint hf_ssl_handshake_cipher_suite = -1; +static gint hf_ssl_handshake_session_id = -1; +static gint hf_ssl_handshake_comp_methods_len = -1; +static gint hf_ssl_handshake_comp_methods = -1; +static gint hf_ssl_handshake_comp_method = -1; +static gint hf_ssl_handshake_extensions_len = -1; +static gint hf_ssl_handshake_extension_type = -1; +static gint hf_ssl_handshake_extension_len = -1; +static gint hf_ssl_handshake_extension_data = -1; +static gint hf_ssl_handshake_certificates_len = -1; +static gint hf_ssl_handshake_certificates = -1; +static gint hf_ssl_handshake_certificate = -1; +static gint hf_ssl_handshake_certificate_len = -1; +static gint hf_ssl_handshake_cert_types_count = -1; +static gint hf_ssl_handshake_cert_types = -1; +static gint hf_ssl_handshake_cert_type = -1; +static gint hf_ssl_handshake_finished = -1; +static gint hf_ssl_handshake_md5_hash = -1; +static gint hf_ssl_handshake_sha_hash = -1; +static gint hf_ssl_handshake_session_id_len = -1; +static gint hf_ssl_handshake_dnames_len = -1; +static gint hf_ssl_handshake_dnames = -1; +static gint hf_ssl_handshake_dname_len = -1; +static gint hf_ssl_handshake_dname = -1; +static gint hf_ssl2_handshake_cipher_spec_len = -1; +static gint hf_ssl2_handshake_session_id_len = -1; +static gint hf_ssl2_handshake_challenge_len = -1; +static gint hf_ssl2_handshake_cipher_spec = -1; +static gint hf_ssl2_handshake_challenge = -1; +static gint hf_ssl2_handshake_clear_key_len = -1; +static gint hf_ssl2_handshake_enc_key_len = -1; +static gint hf_ssl2_handshake_key_arg_len = -1; +static gint hf_ssl2_handshake_clear_key = -1; +static gint hf_ssl2_handshake_enc_key = -1; +static gint hf_ssl2_handshake_key_arg = -1; +static gint hf_ssl2_handshake_session_id_hit = -1; +static gint hf_ssl2_handshake_cert_type = -1; +static gint hf_ssl2_handshake_connection_id_len = -1; +static gint hf_ssl2_handshake_connection_id = -1; +static gint hf_pct_handshake_cipher_spec = -1; +static gint hf_pct_handshake_hash_spec = -1; +static gint hf_pct_handshake_cert_spec = -1; +static gint hf_pct_handshake_cert = -1; +static gint hf_pct_handshake_server_cert = -1; +static gint hf_pct_handshake_exch_spec = -1; +static gint hf_pct_handshake_hash = -1; +static gint hf_pct_handshake_cipher = -1; +static gint hf_pct_handshake_exch = -1; +static gint hf_pct_handshake_sig = -1; +static gint hf_pct_msg_error_type = -1; /* Initialize the subtree pointers */ static gint ett_ssl = -1; @@ -220,194 +220,21 @@ static gint ett_pct_hash_suites = -1; static gint ett_pct_cert_suites = -1; static gint ett_pct_exch_suites = -1; -typedef struct { - unsigned int ssl_port; - dissector_handle_t handle; - char* info; -} SslAssociation; - -static char* ssl_keys_list = NULL; -static char* ssl_debug_file_name = NULL; - -typedef struct _SslService { - address addr; - guint port; -} SslService; - static GHashTable *ssl_session_hash = NULL; static GHashTable *ssl_key_hash = NULL; static GTree* ssl_associations = NULL; static dissector_handle_t ssl_handle = NULL; static StringInfo ssl_decrypted_data = {NULL, 0}; -static int ssl_decrypted_data_avail = 0; - -/* Hash Functions for ssl sessions table and private keys table*/ -static gint -ssl_equal (gconstpointer v, gconstpointer v2) -{ - const StringInfo *val1 = (const StringInfo *)v; - const StringInfo *val2 = (const StringInfo *)v2; - - if (val1->data_len == val2->data_len && - !memcmp(val1->data, val2->data, val2->data_len)) { - return 1; - } - return 0; -} - -static guint -ssl_hash (gconstpointer v) -{ - guint l,hash = 0; - StringInfo* id = (StringInfo*) v; - guint* cur = (guint*) id->data; - for (l=4; (l<id->data_len); l+=4, cur++) - hash = hash ^ (*cur); - - return hash; -} - -static gint -ssl_private_key_equal (gconstpointer v, gconstpointer v2) -{ - const SslService *val1 = (const SslService *)v; - const SslService *val2 = (const SslService *)v2; - - if ((val1->port == val2->port) && - ! CMP_ADDRESS(&val1->addr, &val2->addr)) { - return 1; - } - return 0; -} - -static guint -ssl_private_key_hash (gconstpointer v) -{ - const SslService *key = (const SslService *)v; - guint l,hash = key->port, len = key->addr.len; - - guint* cur = (guint*) key->addr.data; - for (l=4; (l<len); l+=4, cur++) - hash = hash ^ (*cur); - - return hash; -} +static gint ssl_decrypted_data_avail = 0; -/* private key table entries have a scope 'larger' then packet capture, - * so we can't relay on se_alloc** function */ -static void -ssl_private_key_free(gpointer id, gpointer key, gpointer dummy _U_) -{ - g_free(id); - ssl_free_key((SSL_PRIVATE_KEY*) key); -} - -/* handling of association between ssl ports and clear text protocol */ -static void -ssl_association_add(unsigned int port, char *protocol) -{ - SslAssociation* assoc = g_malloc(sizeof(SslAssociation)); - - assoc->info=g_malloc(strlen(protocol)+1); - strcpy(assoc->info, protocol); - assoc->ssl_port = port; - assoc->handle = find_dissector(protocol); - - ssl_debug_printf("ssl_association_add port %d protocol %s handle %p\n", - port, protocol, assoc->handle); - - if(!assoc->handle){ - fprintf(stderr, "ssl_association_add() could not find handle for protocol:%s\n",protocol); - } else { - dissector_add("tcp.port", port, ssl_handle); - g_tree_insert(ssl_associations, (gpointer)port, assoc); - } -} - -static gint -ssl_association_cmp(gconstpointer a, gconstpointer b) -{ - return (gint)a-(gint)b; -} - -static inline -SslAssociation* ssl_association_find(unsigned int port) -{ - register SslAssociation* ret = g_tree_lookup(ssl_associations, (gpointer)port); - ssl_debug_printf("ssl_association_find: port %d found %p\n", port, ret); - return ret; -} - -static gint -ssl_association_remove_handle (gpointer key _U_, - gpointer data, gpointer user_data _U_) -{ - SslAssociation* assoc = (SslAssociation*) data; - ssl_debug_printf("ssl_association_remove_handle removing ptr %p handle %p\n", - data, assoc->handle); - if (assoc->handle) - dissector_delete("tcp.port", assoc->ssl_port, assoc->handle); - g_free(data); - return 0; -} - -static inline int -ssl_packet_from_server(unsigned int port) -{ - register int ret = ssl_association_find(port) != 0; - ssl_debug_printf("ssl_packet_from_server: is from server %d\n", ret); - return ret; -} - -/* add to packet data a newly allocated tvb with the specified real data*/ -static void -ssl_add_record_info(packet_info *pinfo, unsigned char* data, int data_len, int record_id) -{ - unsigned char* real_data = se_alloc(data_len); - SslRecordInfo* rec = se_alloc(sizeof(SslRecordInfo)); - SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl); - if (!pi) - { - pi = se_alloc0(sizeof(SslPacketInfo)); - p_add_proto_data(pinfo->fd, proto_ssl,pi); - } - - rec->id = record_id; - rec->tvb = tvb_new_real_data(real_data, data_len, data_len); - memcpy(real_data, data, data_len); - - /* head insertion */ - rec->next= pi->handshake_data; - pi->handshake_data = rec; -} - -/* search in packet data the tvbuff associated to the specified id */ -static tvbuff_t* -ssl_get_record_info(packet_info *pinfo, int record_id) -{ - SslRecordInfo* rec; - SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl); - if (!pi) - return NULL; - - for (rec = pi->handshake_data; rec; rec = rec->next) - if (rec->id == record_id) - return rec->tvb; - - return NULL; -} +static gchar* ssl_keys_list = NULL; +static gchar* ssl_debug_file_name = NULL; /* initialize/reset per capture state data (ssl sessions cache) */ static void ssl_init(void) { - if (ssl_session_hash) - g_hash_table_destroy(ssl_session_hash); - ssl_session_hash = g_hash_table_new(ssl_hash, ssl_equal); - if (ssl_decrypted_data.data) - g_free(ssl_decrypted_data.data); - ssl_decrypted_data.data = g_malloc0(32); - ssl_decrypted_data.data_len = 32; + ssl_common_init(&ssl_session_hash, &ssl_decrypted_data); } /* parse ssl related preferences (private keys and ports association strings) */ @@ -421,7 +248,7 @@ ssl_parse(void) } if (ssl_associations) { - g_tree_traverse(ssl_associations, ssl_association_remove_handle, G_IN_ORDER, NULL); + g_tree_traverse(ssl_associations, ssl_association_remove_handle_tcp, G_IN_ORDER, NULL); g_tree_destroy(ssl_associations); } @@ -431,136 +258,29 @@ ssl_parse(void) if (ssl_keys_list && (ssl_keys_list[0] != 0)) { - char* end; - char* start = strdup(ssl_keys_list); - char* tmp = start; - - ssl_debug_printf("ssl_init keys string %s\n", start); - do { - char* addr, *port, *protocol, *filename; - unsigned char* ip; - SslService* service; - SSL_PRIVATE_KEY * private_key; - FILE* fp; - - addr = start; - /* split ip/file couple with ';' separator*/ - end = strchr(start, ';'); - if (end) { - *end = 0; - start = end+1; - } - - /* for each entry split ip, port, protocol, filename with ',' separator */ - ssl_debug_printf("ssl_init found host entry %s\n", addr); - port = strchr(addr, ','); - if (!port) - { - ssl_debug_printf("ssl_init entry malformed can't find port in %s\n", addr); - break; - } - *port = 0; - port++; - - protocol = strchr(port,','); - if (!protocol) - { - ssl_debug_printf("ssl_init entry malformed can't find protocol in %s\n", port); - break; - } - *protocol=0; - protocol++; - - filename = strchr(protocol,','); - if (!filename) - { - ssl_debug_printf("ssl_init entry malformed can't find filename in %s\n", port); - break; - } - *filename=0; - filename++; - - /* convert ip and port string to network rappresentation*/ - service = g_malloc(sizeof(SslService) + 4); - service->addr.type = AT_IPv4; - service->addr.len = 4; - service->addr.data = ip = ((unsigned char*)service) + sizeof(SslService); - sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &ip[0], &ip[1], &ip[2], &ip[3]); - service->port = atoi(port); - ssl_debug_printf("ssl_init addr %hhu.%hhu.%hhu.%hhu port %d filename %s\n", - ip[0], ip[1], ip[2], ip[3], service->port, filename); - - /* try to load pen file*/ - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "can't open file %s \n",filename); - break; - } - - private_key = ssl_load_key(fp); - if (!private_key) { - fprintf(stderr,"can't load private key from %s\n", - filename); - break; - } - fclose(fp); - - ssl_debug_printf("ssl_init private key file %s successfully loaded\n", - filename); - g_hash_table_insert(ssl_key_hash, service, private_key); - - ssl_association_add(atoi(port), protocol); - - } while (end != NULL); - free(tmp); + ssl_parse_key_list(ssl_keys_list,ssl_key_hash,ssl_associations,ssl_handle,TRUE); } ssl_set_debug(ssl_debug_file_name); /* [re] add ssl dissection to defaults ports */ - ssl_association_add(443, "http"); - ssl_association_add(636, "ldap"); - ssl_association_add(993, "imap"); - ssl_association_add(995, "pop"); + ssl_association_add(ssl_associations, ssl_handle, 443, "http", TRUE); + ssl_association_add(ssl_associations, ssl_handle, 636, "ldap", TRUE); + ssl_association_add(ssl_associations, ssl_handle, 993, "imap", TRUE); + ssl_association_add(ssl_associations, ssl_handle, 995, "pop", TRUE); } -/* store master secret into session data cache */ -static void -ssl_save_session(SslDecryptSession* ssl) -{ - /* allocate stringinfo chunks for session id and master secret data*/ - StringInfo* session_id = se_alloc0(sizeof(StringInfo) + ssl->session_id.data_len); - StringInfo* master_secret = se_alloc0(48 + sizeof(StringInfo)); - - master_secret->data = ((unsigned char*)master_secret+sizeof(StringInfo)); - session_id->data = ((unsigned char*)session_id+sizeof(StringInfo)); - - ssl_data_set(session_id, ssl->session_id.data, ssl->session_id.data_len); - ssl_data_set(master_secret, ssl->master_secret.data, ssl->master_secret.data_len); - g_hash_table_insert(ssl_session_hash, session_id, master_secret); - ssl_print_string("ssl_save_session stored session id", session_id); - ssl_print_string("ssl_save_session stored master secret", master_secret); -} - -static void -ssl_restore_session(SslDecryptSession* ssl) -{ - StringInfo* ms = g_hash_table_lookup(ssl_session_hash, &ssl->session_id); - if (!ms) { - ssl_debug_printf("ssl_restore_session can't find stored session\n"); - return; - } - ssl_data_set(&ssl->master_secret, ms->data, ms->data_len); - ssl->state |= SSL_MASTER_SECRET; - ssl_debug_printf("ssl_restore_session master key retrived\n"); -} /* function that save app_data during sub protocol reassembling */ static void -ssl_add_app_data(SslDecryptSession* ssl, unsigned char* data, int data_len){ - StringInfo * app=&ssl->app_data_segment; +ssl_add_app_data(SslDecryptSession* ssl, guchar* data, gint data_len){ + StringInfo * app; + app=&ssl->app_data_segment; + if(app->data_len!=0){ - unsigned char* tmp=g_malloc(app->data_len); - int tmp_len=app->data_len; + guchar* tmp; + gint tmp_len; + tmp=g_malloc(app->data_len); + tmp_len=app->data_len; memcpy(tmp,app->data,app->data_len); if(app->data!=NULL) g_free(app->data); @@ -572,7 +292,7 @@ ssl_add_app_data(SslDecryptSession* ssl, unsigned char* data, int data_len){ memcpy(app->data+tmp_len, data,data_len); } else{ - //it's new + /* it's new */ if(app->data!=NULL) g_free(app->data); app->data=g_malloc(data_len); @@ -592,8 +312,8 @@ ssl_desegment_ssl_app_data(SslDecryptSession * ssl, packet_info *pinfo){ tvbuff_t* new_tvb; packet_info * pp; /* find out a dissector using server port*/ - association = ssl_association_find(pinfo->srcport); - association = association ? association: ssl_association_find(pinfo->destport); + association = ssl_association_find(ssl_associations, pinfo->srcport); + association = association ? association: ssl_association_find(ssl_associations, pinfo->destport); /* create a copy of packet_info */ pp=g_malloc(sizeof(packet_info)); memcpy(pp, pinfo, sizeof(packet_info)); @@ -686,7 +406,7 @@ ssl_desegment_ssl_app_data(SslDecryptSession * ssl, packet_info *pinfo){ * */ /* record layer dissector */ -static int dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, +static gint dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint *conv_version, gboolean *need_desegmentation, @@ -740,7 +460,7 @@ static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, */ /* record layer dissector */ -static int dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, +static gint dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint *conv_version, gboolean *need_desegmentation, @@ -786,18 +506,17 @@ static void dissect_pct_msg_error(tvbuff_t *tvb, * */ /*static void ssl_set_conv_version(packet_info *pinfo, guint version);*/ -static int ssl_is_valid_handshake_type(guint8 type); -static int ssl_is_valid_content_type(guint8 type); -static int ssl_is_valid_ssl_version(guint16 version); -static int ssl_is_authoritative_version_message(guint8 content_type, +static gint ssl_is_valid_handshake_type(guint8 type); +static gint ssl_is_valid_ssl_version(guint16 version); +static gint ssl_is_authoritative_version_message(guint8 content_type, guint8 next_byte); -static int ssl_is_v2_client_hello(tvbuff_t *tvb, guint32 offset); -static int ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset); -static int ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset); -static int ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, +static gint ssl_is_v2_client_hello(tvbuff_t *tvb, guint32 offset); +static gint ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset); +static gint ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset); +static gint ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, guint32 offset, guint32 record_length); -static int ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, +static gint ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, guint32 offset, guint32 record_length); /********************************************************************* @@ -814,13 +533,18 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) conversation_t *conversation; void *conv_data; - proto_item *ti = NULL; - proto_tree *ssl_tree = NULL; - guint32 offset = 0; - gboolean first_record_in_frame = TRUE; + proto_item *ti; + proto_tree *ssl_tree; + guint32 offset; + gboolean first_record_in_frame; gboolean need_desegmentation; - SslDecryptSession* ssl_session = NULL; + SslDecryptSession* ssl_session; guint* conv_version; + ti = NULL; + ssl_tree = NULL; + offset = 0; + first_record_in_frame = TRUE; + ssl_session = NULL; top_tree=tree; @@ -838,6 +562,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + if (!conversation) { /* create a new conversation */ @@ -859,7 +584,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) conversation_add_proto_data(conversation, proto_ssl, ssl_session); /* we need to know witch side of conversation is speaking*/ - if (ssl_packet_from_server(pinfo->srcport)) { + if (ssl_packet_from_server(ssl_associations, pinfo->srcport)) { dummy.addr = pinfo->src; dummy.port = pinfo->srcport; } @@ -895,7 +620,6 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSL"); } - /* clear the the info column */ if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO); @@ -1022,15 +746,15 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tap_queue_packet(ssl_tap, pinfo, (gpointer)proto_ssl); } -static int +static gint decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, guint32 record_length, guint8 content_type, SslDecryptSession* ssl, gboolean save_plaintext) { - int ret = 0; - int direction; + gint ret; + gint direction; SslDecoder* decoder; - + ret = 0; /* if we can decrypt and decryption have success * add decrypted data to this packet info*/ ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl state %X\n", @@ -1041,7 +765,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, } /* retrive decoder for this packet direction*/ - if ((direction = ssl_packet_from_server(pinfo->srcport)) != 0) { + if ((direction = ssl_packet_from_server(ssl_associations, pinfo->srcport)) != 0) { ssl_debug_printf("decrypt_ssl3_record: using server decoder\n"); decoder = &ssl->server; } @@ -1070,7 +794,8 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, ret = 1; if (ret && save_plaintext) { - SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl); + SslPacketInfo* pi; + pi = p_get_proto_data(pinfo->fd, proto_ssl); if (!pi) { ssl_debug_printf("decrypt_ssl3_record: allocating app_data %d " @@ -1082,7 +807,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, memcpy(pi->app_data.data, ssl_decrypted_data.data, ssl_decrypted_data_avail); } else { - unsigned char* store; + guchar* store; /* update previus record*/ ssl_debug_printf("decrypt_ssl3_record: reallocating app_data " "%d bytes for app data (total %d appdata bytes)\n", @@ -1114,7 +839,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, * SSL version 3 and TLS Dissection Routines * *********************************************************************/ -static int +static gint dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint *conv_version, gboolean *need_desegmentation, @@ -1143,12 +868,14 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint16 version; guint8 content_type; guint8 next_byte; - proto_tree *ti = NULL; - proto_tree *ssl_record_tree = NULL; - guint32 available_bytes = 0; + proto_tree *ti; + proto_tree *ssl_record_tree; + guint32 available_bytes; SslPacketInfo* pi; SslAssociation* association; - + ti = NULL; + ssl_record_tree = NULL; + available_bytes = 0; available_bytes = tvb_length_remaining(tvb, offset); @@ -1319,14 +1046,15 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, break; case SSL_ID_ALERT: { - tvbuff_t* decrypted=0; + tvbuff_t* decrypted; + decrypted=0; if (ssl&&decrypt_ssl3_record(tvb, pinfo, offset, record_length, content_type, ssl, FALSE)) - ssl_add_record_info(pinfo, ssl_decrypted_data.data, + ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data, ssl_decrypted_data_avail, offset); /* try to retrive and use decrypted alert record, if any. */ - decrypted = ssl_get_record_info(pinfo, offset); + decrypted = ssl_get_record_info(proto_ssl, pinfo, offset); if (decrypted) dissect_ssl3_alert(decrypted, pinfo, ssl_record_tree, 0, conv_version); @@ -1337,18 +1065,19 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, } case SSL_ID_HANDSHAKE: { - tvbuff_t* decrypted=0; + tvbuff_t* decrypted; + decrypted=0; /* try to decrypt handshake record, if possible. Store decrypted * record for later usage. The offset is used as 'key' to itentify * this record into the packet (we can have multiple handshake records * in the same frame) */ if (ssl && decrypt_ssl3_record(tvb, pinfo, offset, record_length, content_type, ssl, FALSE)) - ssl_add_record_info(pinfo, ssl_decrypted_data.data, + ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data, ssl_decrypted_data_avail, offset); /* try to retrive and use decrypted handshake record, if any. */ - decrypted = ssl_get_record_info(pinfo, offset); + decrypted = ssl_get_record_info(proto_ssl, pinfo, offset); if (decrypted) dissect_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0, decrypted->length, conv_version, ssl, content_type); @@ -1378,8 +1107,8 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, /* we need dissector information when the selected packet is shown. * ssl session pointer is NULL at that time, so we can't access * info cached there*/ - association = ssl_association_find(pinfo->srcport); - association = association ? association: ssl_association_find(pinfo->destport); + association = ssl_association_find(ssl_associations, pinfo->srcport); + association = association ? association: ssl_association_find(ssl_associations, pinfo->destport); proto_item_set_text(ssl_record_tree, "%s Record Layer: %s Protocol: %s", @@ -1468,11 +1197,11 @@ dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, * } Alert; */ proto_tree *ti; - proto_tree *ssl_alert_tree = NULL; + proto_tree *ssl_alert_tree; const gchar *level; const gchar *desc; guint8 byte; - + ssl_alert_tree = NULL; if (tree) { ti = proto_tree_add_item(tree, hf_ssl_alert_message, tvb, @@ -1555,13 +1284,16 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, * } body; * } Handshake; */ - proto_tree *ti = NULL; - proto_tree *ssl_hand_tree = NULL; - const gchar *msg_type_str = NULL; + proto_tree *ti; + proto_tree *ssl_hand_tree; + const gchar *msg_type_str; guint8 msg_type; guint32 length; - gboolean first_iteration = TRUE; - + 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 @@ -1691,9 +1423,11 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, { /* PAOLO: here we can have all the data to build session key*/ StringInfo encrypted_pre_master; - int ret; - unsigned encrlen = length, skip = 0; - + gint ret; + guint encrlen, skip; + encrlen = length; + skip = 0; + if (!ssl) break; @@ -1742,7 +1476,7 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, break; } ssl->state |= SSL_HAVE_SESSION_KEY; - ssl_save_session(ssl); + ssl_save_session(ssl, ssl_session_hash); ssl_debug_printf("dissect_ssl3_handshake session keys succesfully generated\n"); } break; @@ -1762,13 +1496,14 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, } } -static int +static gint dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, guint32 offset, SslDecryptSession* ssl, gint from_server) { /* show the client's random challenge */ nstime_t gmt_unix_time; - guint8 session_id_length = 0; + guint8 session_id_length; + session_id_length = 0; if (ssl) { @@ -1795,7 +1530,7 @@ dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, (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); + ssl_restore_session(ssl, ssl_session_hash); } else { tvb_memcpy(tvb,ssl->session_id.data, offset+33, session_id_length); @@ -1839,7 +1574,7 @@ dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, return session_id_length+33; } -static int +static gint dissect_ssl3_hnd_hello_ext(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 left) { @@ -1909,10 +1644,13 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, */ proto_tree *ti; proto_tree *cs_tree; - guint16 cipher_suite_length = 0; - guint8 compression_methods_length = 0; + guint16 cipher_suite_length; + guint8 compression_methods_length; guint8 compression_method; - guint16 start_offset = offset; + guint16 start_offset; + cipher_suite_length = 0; + compression_methods_length = 0; + start_offset = offset; if (tree || ssl) { @@ -2024,7 +1762,8 @@ dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb, * Extension server_hello_extension_list<0..2^16-1>; * } ServerHello; */ - guint16 start_offset = offset; + guint16 start_offset; + start_offset = offset; if (tree || ssl) { @@ -2136,7 +1875,8 @@ dissect_ssl3_hnd_cert(tvbuff_t *tvb, while (certificate_list_length > 0) { /* get the length of the current certificate */ - guint32 cert_length = tvb_get_ntoh24(tvb, offset); + guint32 cert_length; + cert_length = tvb_get_ntoh24(tvb, offset); certificate_list_length -= 3 + cert_length; proto_tree_add_item(subtree, hf_ssl_handshake_certificate_len, @@ -2171,8 +1911,10 @@ dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, */ proto_tree *ti; proto_tree *subtree; - guint8 cert_types_count = 0; - int dnames_length = 0; + guint8 cert_types_count; + gint dnames_length; + cert_types_count = 0; + dnames_length = 0; if (tree) { @@ -2227,7 +1969,8 @@ dissect_ssl3_hnd_cert_req(tvbuff_t *tvb, while (dnames_length > 0) { /* get the length of the current certificate */ - guint16 name_length = tvb_get_ntohs(tvb, offset); + guint16 name_length; + name_length = tvb_get_ntohs(tvb, offset); dnames_length -= 2 + name_length; proto_tree_add_item(subtree, hf_ssl_handshake_dname_len, @@ -2298,24 +2041,34 @@ dissect_ssl3_hnd_finished(tvbuff_t *tvb, /* record layer dissector */ -static int +static gint dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint* conv_version, gboolean *need_desegmentation, SslDecryptSession* ssl) { - guint32 initial_offset = offset; - guint8 byte = 0; - guint8 record_length_length = 0; - guint32 record_length = 0; - gint is_escape = -1; - gint16 padding_length = -1; - guint8 msg_type = 0; - const gchar *msg_type_str = NULL; - guint32 available_bytes = 0; - + guint32 initial_offset; + guint8 byte; + guint8 record_length_length; + guint32 record_length; + gint is_escape; + gint16 padding_length; + guint8 msg_type; + const gchar *msg_type_str; + guint32 available_bytes; proto_tree *ti; - proto_tree *ssl_record_tree = NULL; + proto_tree *ssl_record_tree; + + initial_offset = offset; + byte = 0; + record_length_length = 0; + record_length = 0; + is_escape = -1; + padding_length = -1; + msg_type = 0; + msg_type_str = NULL; + available_bytes = 0; + ssl_record_tree = NULL; /* pull first byte; if high bit is set, then record * length is three bytes due to padding; otherwise @@ -2586,7 +2339,8 @@ dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, guint16 challenge_length; proto_tree *ti; - proto_tree *cs_tree=0; + proto_tree *cs_tree; + cs_tree=0; version = tvb_get_ntohs(tvb, offset); if (!ssl_is_valid_ssl_version(version)) @@ -2686,8 +2440,9 @@ dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, { /* PAOLO: get client random data; we get at most 32 bytes from challenge */ - int max = challenge_length > 32? 32: challenge_length; - + gint max; + max = challenge_length > 32? 32: challenge_length; + ssl_debug_printf("client random len: %d padded to 32\n", challenge_length); @@ -3279,7 +3034,7 @@ ssl_set_conv_version(packet_info *pinfo, guint version) } #endif -static int +static gint ssl_is_valid_handshake_type(guint8 type) { @@ -3299,25 +3054,15 @@ ssl_is_valid_handshake_type(guint8 type) return 0; } -static int -ssl_is_valid_content_type(guint8 type) -{ - if (type >= 0x14 && type <= 0x17) - { - return 1; - } - - return 0; -} - -static int +static gint ssl_is_valid_ssl_version(guint16 version) { - const gchar *version_str = match_strval(version, ssl_versions); + const gchar *version_str; + version_str = match_strval(version, ssl_versions); return version_str != NULL; } -static int +static gint ssl_is_authoritative_version_message(guint8 content_type, guint8 next_byte) { @@ -3334,7 +3079,7 @@ ssl_is_authoritative_version_message(guint8 content_type, return 0; } -static int +static gint ssl_is_v2_client_hello(tvbuff_t *tvb, guint32 offset) { guint8 byte; @@ -3360,7 +3105,7 @@ ssl_is_v2_client_hello(tvbuff_t *tvb, guint32 offset) * valid sslv2 record. this isn't really possible, * but we'll try to do a reasonable job anyway. */ -static int +static gint ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset) { /* here's the current approach: @@ -3372,7 +3117,9 @@ ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset) */ /* get the first byte; must have high bit set */ - guint8 byte = tvb_get_guint8(tvb, offset); + guint8 byte; + byte = tvb_get_guint8(tvb, offset); + if (byte < 0x80) { return 0; @@ -3400,7 +3147,7 @@ ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset) * valid sslv3 record. this is somewhat more reliable * than sslv2 due to the structure of the v3 protocol */ -static int +static gint ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset) { /* have to have a valid content type followed by a valid @@ -3433,7 +3180,7 @@ ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset) * data apart from a valid message without state, * we try to help the odds. */ -static int +static gint ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, guint32 offset, guint32 record_length) { @@ -3494,7 +3241,7 @@ ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, guint32 offset, * data apart from a valid message without state, * we try to help the odds. */ -static int +static gint ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, guint32 offset, guint32 record_length) { @@ -3983,11 +3730,11 @@ proto_register_ssl(void) "semicolon separated list of private RSA keys used for SSL 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 char **)&ssl_keys_list); + (const gchar **)&ssl_keys_list); prefs_register_string_preference(ssl_module, "debug_file", "SSL debug file", "redirect ssl debug to file name; leave empty to disable debug, " "use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n", - (const char **)&ssl_debug_file_name); + (const gchar **)&ssl_debug_file_name); #endif } |