Wireshark-dev: Re: [Wireshark-dev] [DTLS patch]
From: "authesserre samuel" <[email protected]>
Date: Thu, 6 Jul 2006 17:30:48 +0200
Hi,

Sorry for this mistake (first empty mail)

I have done the same corrections on DTLS dissector that you have done
on SSL one....

I have done more (because the dissector wasn't finished at all ;) ) :
- make code cleaner (removed SSL and pct code that was unuseful, add
comments, indentation corrections....)
- integration process


details :

make code cleaner :
In my first patch I had just made adaptation without taking care about
dead code so I have corrected this now
I have added a description in the start of the plugin that explain (I
wish ;) ) that plugin follow the only actual implementation of DTLS
It is smaller and easier to understand...


integration process :
I have moved identical code in the two dissectors in a file named
packet-ssl-dtls-common.h, I haven't touch packet-ssl or
packet-ssl-utils before your agreement...(I think others things in
packet-ssl could be moved but I make things in order....)
Actually code is ready to integration and dtls dissector works with
the code in packet-ssl-dtls-common.h. With your aggreement I will
integrate this code in packet-ssl-utils and modify ssl dissector to
use this functions (just code moving and functions names move, no
algorithm modification to limit problems)
I have for exemple unified parse of preference parameter (who is
strictly the same) and others....

enclosed the only file that could be sent on this mailing list (< 40
ko) that allows you to understand what I am saying (about ssl
interaction)

Are you agree with this modifications?
Can I start modifications on ssl one ? (I will not start if it isn't
accepted ....)
where can I send my patch without problem (it is bigger than 40 ko) ?

thanks,

regards,


On 7/6/06, authesserre samuel <[email protected]> wrote:
Hi,


--
Authesserre Samuel
12 rue de la défense passive
14000 CAEN
FRANCE
06-27-28-13-32
[email protected]


--
Authesserre Samuel
12 rue de la défense passive
14000 CAEN
FRANCE
06-27-28-13-32
[email protected]
/* packet-ssl-dtls-common.c
 * Common part bitween SSL and DTLS dissectors
 * Copyright (c) 2006, Authesserre Samuel <[email protected]>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <[email protected]>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * This fonction are prepared to integration in packet-ssl-utils file,
 * thay do the same job but allow use of them in TLS and DTLS dissections 
 * 
 */

#ifndef __SSL_DTLS_COMMON_H_
#define __SSL_DTLS_COMMON_H_


typedef struct {
  unsigned int ssl_port;
  dissector_handle_t handle;
  char* info;
} SslAssociation;

typedef struct _SslService {
  address addr;
  guint port;
} SslService;



/* Hash Functions for TLS/DTLS 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 tls/dtls ports and clear text protocol */
static void 
ssl_association_add(GTree* associations, dissector_handle_t handle, unsigned int port, char *protocol, gboolean tcp)
{

  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("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);
  }
}


static gint 
ssl_association_cmp(gconstpointer a, gconstpointer b)
{
  return (gint)a-(gint)b;
}

static inline 
SslAssociation* ssl_association_find(GTree * associations, unsigned int port)
{
  register SslAssociation* ret = g_tree_lookup(associations, (gpointer)port);
  ssl_debug_printf("association_find: port %d found %p\n", port, ret);
  return ret;
}

static gint 
ssl_association_remove_handle_tcp (gpointer key _U_, 
				   gpointer  data, gpointer  user_data _U_)
{
  SslAssociation* 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;
}

static gint 
ssl_association_remove_handle_udp (gpointer key _U_, 
				   gpointer  data, gpointer  user_data _U_)
{
  SslAssociation* 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;
}

static inline int 
ssl_packet_from_server(GTree* associations, unsigned int port)
{
  register int 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*/
static void
ssl_add_record_info(int proto, 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);
  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 */
static tvbuff_t* 
ssl_get_record_info(int proto, packet_info *pinfo, int record_id)
{
  SslRecordInfo* rec;
  SslPacketInfo* 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) */
static 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) */
static void 
ssl_parse_key_list(const char * keys_list, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp)
{
  char* end;
  char* start = strdup(keys_list);
  char* tmp = start;
        
  ssl_debug_printf("ssl_init keys string %s\n", start);
  do {
    char* addr, *port, *protocol, *filename;            
            
    addr = start;
    /* split ip/file couple with ';' separator*/
    end = strchr(start, ';');
    if (end) {
      *end = 0;
      start = end+1;
    }
    unsigned char* ip;
    SslService* service;
    SSL_PRIVATE_KEY * private_key;
    FILE* fp;
  
    /* 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(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 */
static void 
ssl_save_session(SslDecryptSession* ssl, GHashTable *session_hash)
{
  /* 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(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, GHashTable *session_hash)
{
  StringInfo* 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");
}

static int
ssl_is_valid_content_type(guint8 type)
{
  if (type >= 0x14 && type <= 0x17)
    {
      return 1;
    }

  return 0;
}

#endif