Ethereal-dev: Re: [Ethereal-dev] SSL decryption patch for ethereal 0.10.13

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Paolo Abeni <paolo.abeni@xxxxxxxx>
Date: Wed, 07 Dec 2005 10:00:26 +0100
On Mon, 2005-12-05 at 12:46 +0100, Joerg Mayer wrote:
[...]
>  So the
> idea is to handle this like most other features requesting libs that may
> not be present on all systems (e.g. pcre): By default it should be used
> if a usable installation exists and it should be possible to require its
> existence (failing if isn't usable). Last it should be possible to build
> the package without checking or using the lib 

Ok the attached version of the patch should works as requested. The
relevant configure option is '--with-libgnutls-prefix'. Let me know if
there are any trouble.

Best regards,
Paolo

 
 
 --
 Email.it, the professional e-mail, gratis per te: http://www.email.it/f
 
 Sponsor:
 Natsabe.it la pi� grande erboristeria online italiana 
* prezzi bassi tutto l'anno !
 Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=1298&d=7-12
diff -uNr ethereal-0.10.13/acinclude.m4 ethereal-0.10.13-patch/acinclude.m4
--- ethereal-0.10.13/acinclude.m4	2005-10-10 15:23:13.000000000 +0200
+++ ethereal-0.10.13-patch/acinclude.m4	2005-12-07 09:51:53.000000000 +0100
@@ -1268,3 +1268,161 @@
 	fi
 	AC_SUBST(KRB5_LIBS)
 ])
+
+dnl Autoconf macros for libgnutls
+dnl $id$
+
+# Modified for LIBGNUTLS -- nmav
+# Configure paths for LIBGCRYPT
+# Shamelessly stolen from the one of XDELTA by Owen Taylor
+# Werner Koch   99-12-09
+
+dnl AM_PATH_LIBGNUTLS([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgnutls, and define LIBGNUTLS_CFLAGS and LIBGNUTLS_LIBS
+dnl
+AC_DEFUN([AM_PATH_LIBGNUTLS],
+[dnl
+dnl Get the cflags and libraries from the libgnutls-config script
+dnl
+AC_ARG_WITH(libgnutls-prefix,
+          [  --with-libgnutls-prefix=PFX   Prefix where libgnutls is installed (optional)],
+          libgnutls_config_prefix="$withval", libgnutls_config_prefix="")
+
+  if test x$libgnutls_config_prefix != x ; then
+     if test x${LIBGNUTLS_CONFIG+set} != xset ; then
+        LIBGNUTLS_CONFIG=$libgnutls_config_prefix/bin/libgnutls-config
+     fi
+  fi
+
+  AC_PATH_PROG(LIBGNUTLS_CONFIG, libgnutls-config, no)
+  min_libgnutls_version=ifelse([$1], ,0.1.0,$1)
+  AC_MSG_CHECKING(for libgnutls - version >= $min_libgnutls_version)
+  no_libgnutls=""
+  if test "$LIBGNUTLS_CONFIG" = "no" ; then
+    no_libgnutls=yes
+  else
+    LIBGNUTLS_CFLAGS=`$LIBGNUTLS_CONFIG $libgnutls_config_args --cflags`
+    LIBGNUTLS_LIBS=`$LIBGNUTLS_CONFIG $libgnutls_config_args --libs`
+    libgnutls_config_version=`$LIBGNUTLS_CONFIG $libgnutls_config_args --version`
+
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS"
+      LIBS="$LIBS $LIBGNUTLS_LIBS"
+dnl
+dnl Now check if the installed libgnutls is sufficiently new. Also sanity
+dnl checks the results of libgnutls-config to some extent
+dnl
+      rm -f conf.libgnutlstest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+
+int
+main ()
+{
+    system ("touch conf.libgnutlstest");
+
+    if( strcmp( gnutls_check_version(NULL), "$libgnutls_config_version" ) )
+    {
+      printf("\n*** 'libgnutls-config --version' returned %s, but LIBGNUTLS (%s)\n",
+             "$libgnutls_config_version", gnutls_check_version(NULL) );
+      printf("*** was found! If libgnutls-config was correct, then it is best\n");
+      printf("*** to remove the old version of LIBGNUTLS. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If libgnutls-config was wrong, set the environment variable LIBGNUTLS_CONFIG\n");
+      printf("*** to point to the correct copy of libgnutls-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    }
+    else if ( strcmp(gnutls_check_version(NULL), LIBGNUTLS_VERSION ) )
+    {
+      printf("\n*** LIBGNUTLS header file (version %s) does not match\n", LIBGNUTLS_VERSION);
+      printf("*** library (version %s)\n", gnutls_check_version(NULL) );
+    }
+    else
+    {
+      if ( gnutls_check_version( "$min_libgnutls_version" ) )
+      {
+        return 0;
+      }
+     else
+      {
+        printf("no\n*** An old version of LIBGNUTLS (%s) was found.\n",
+                gnutls_check_version(NULL) );
+        printf("*** You need a version of LIBGNUTLS newer than %s. The latest version of\n",
+               "$min_libgnutls_version" );
+        printf("*** LIBGNUTLS is always available from ftp://gnutls.hellug.gr/pub/gnutls.\n";);
+        printf("*** \n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the libgnutls-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of LIBGNUTLS, but you can also set the LIBGNUTLS_CONFIG environment to point to the\n");
+        printf("*** correct copy of libgnutls-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+],, no_libgnutls=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_libgnutls" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])
+  else
+     if test -f conf.libgnutlstest ; then
+        :
+     else
+        AC_MSG_RESULT(no)
+     fi
+     if test "$LIBGNUTLS_CONFIG" = "no" ; then
+       echo "*** The libgnutls-config script installed by LIBGNUTLS could not be found"
+       echo "*** If LIBGNUTLS was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the LIBGNUTLS_CONFIG environment variable to the"
+       echo "*** full path to libgnutls-config."
+     else
+       if test -f conf.libgnutlstest ; then
+        :
+       else
+          echo "*** Could not run libgnutls test program, checking why..."
+          CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS"
+          LIBS="$LIBS $LIBGNUTLS_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+],      [ return !!gnutls_check_version(NULL); ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding LIBGNUTLS or finding the wrong"
+          echo "*** version of LIBGNUTLS. If it is not finding LIBGNUTLS, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+          echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+          echo "***" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means LIBGNUTLS was incorrectly installed"
+          echo "*** or that you have moved LIBGNUTLS since it was installed. In the latter case, you"
+          echo "*** may want to edit the libgnutls-config script: $LIBGNUTLS_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     LIBGNUTLS_CFLAGS=""
+     LIBGNUTLS_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  rm -f conf.libgnutlstest
+  AC_SUBST(LIBGNUTLS_CFLAGS)
+  AC_SUBST(LIBGNUTLS_LIBS)
+])
diff -uNr ethereal-0.10.13/config.h.in ethereal-0.10.13-patch/config.h.in
--- ethereal-0.10.13/config.h.in	2005-10-14 21:18:33.000000000 +0200
+++ ethereal-0.10.13-patch/config.h.in	2005-12-07 09:51:53.000000000 +0100
@@ -55,6 +55,9 @@
 /* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */
 #undef HAVE_KEYTYPE_ARCFOUR_56
 
+/* Define to use gnutls library */
+#undef HAVE_LIBGNUTLS
+
 /* Define to use libpcap library */
 #undef HAVE_LIBPCAP
 
diff -uNr ethereal-0.10.13/configure.in ethereal-0.10.13-patch/configure.in
--- ethereal-0.10.13/configure.in	2005-10-14 21:10:13.000000000 +0200
+++ ethereal-0.10.13-patch/configure.in	2005-12-07 09:51:53.000000000 +0100
@@ -63,6 +63,24 @@
 AC_CHECK_PROG(HAVE_DOXYGEN, doxygen, "yes", "no")
 AM_CONDITIONAL(HAVE_DOXYGEN, test x$HAVE_DOXYGEN = xyes)
 
+# gnu tls
+AM_PATH_LIBGNUTLS(1.0.0, 
+        [
+                echo "gnuTLS found, enabling ssl decryption"
+                AC_DEFINE(HAVE_LIBGNUTLS, 1, [Define to use gnutls library])
+                tls_message="yes"
+        ]
+        , [
+                if test x$libgnutls_config_prefix != x ; then
+	                AC_MSG_ERROR([[gnuTLS not found; install gnuTLS-devel package for your system]])
+                else
+                        echo echo "gnuTLS not found, disabling ssl decryption"
+                        tls_message="no"
+                fi
+        ]
+)        
+        
+
 # Check for xsltproc
 AC_PATH_PROG(XSLTPROC, xsltproc)
 AC_CHECK_PROG(HAVE_XSLTPROC, xsltproc, "yes", "no")
@@ -1330,3 +1348,4 @@
 echo "            Use SSL crypto library : $ssl_message"
 echo "          Use IPv6 name resolution : $enable_ipv6"
 echo "     Use UCD SNMP/Net-SNMP library : $snmp_libs_message"
+echo "                Use gnutls library : $tls_message"
diff -uNr ethereal-0.10.13/epan/dissectors/Makefile.common ethereal-0.10.13-patch/epan/dissectors/Makefile.common
--- ethereal-0.10.13/epan/dissectors/Makefile.common	2005-10-10 15:23:00.000000000 +0200
+++ ethereal-0.10.13-patch/epan/dissectors/Makefile.common	2005-12-07 09:51:53.000000000 +0100
@@ -540,6 +540,7 @@
 	packet-skinny.c	\
 	packet-slimp3.c	\
 	packet-sll.c	\
+	packet-ssl-utils.c	\
 	packet-slowprotocols.c	\
 	packet-slsk.c	\
 	packet-smb-browse.c	\
diff -uNr ethereal-0.10.13/epan/dissectors/packet-ssl.c ethereal-0.10.13-patch/epan/dissectors/packet-ssl.c
--- ethereal-0.10.13/epan/dissectors/packet-ssl.c	2005-10-10 15:23:04.000000000 +0200
+++ ethereal-0.10.13-patch/epan/dissectors/packet-ssl.c	2005-12-07 09:51:53.000000000 +0100
@@ -56,14 +56,7 @@
  *
  * Notes:
  *
- *   - Uses conversations in a no-malloc fashion.  Since we just want to
- *     remember the version of the conversation, we store the version
- *     integer directly in the void *data member of the conversation
- *     structure.  This means that we don't have to manage any memory,
- *     but will cause problems if anyone assumes that all data pointers
- *     are actually pointers to memory allocated by g_mem_chunk_alloc.
- *
- *   - Does not support decryption of encrypted frames, nor dissection
+ *   - Does not support dissection
  *     of frames that would require state maintained between frames
  *     (e.g., single ssl records spread across multiple tcp frames)
  *
@@ -82,6 +75,17 @@
  *       - Request Certificate
  *       - Client Certificate
  *
+ *    - Decryption is supported only for session that use RSA key exchange,
+ *      if the host private key is provided via preference. 
+ *    
+ *    - Decryption need to be performed 'sequentially', so it's done
+ *      at packet reception time. This may cause a significative packet capture
+ *      slow down. This also cause do dissect some ssl info that in previous
+ *      dissector version were dissected only when a proto_tree context was 
+ *      available
+ *
+ *     We are at Packet reception if time pinfo->fd->flags.visited == 0 
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -97,6 +101,8 @@
 #include <epan/conversation.h>
 #include <epan/prefs.h>
 #include <epan/dissectors/packet-x509af.h>
+#include <epan/dissectors/packet-ssl-utils.h>
+
 
 static gboolean ssl_desegment = TRUE;
 
@@ -114,6 +120,7 @@
 static int hf_ssl_record_version             = -1;
 static int hf_ssl_record_length              = -1;
 static int hf_ssl_record_appdata             = -1;
+static int hf_ssl_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;
@@ -199,6 +206,191 @@
 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* ssl_keys_list = "127.0.0.1:443:/etc/ssl/apache/server.key";
+static SslAssociation ssl_associations[] =  {
+    {443, 80, 0, "Hypertext transfer protocol"}, /* https */
+    {636, 389, 0, "Lightweight directory access protocol"}, /* ldap */
+    {993, 143, 0, "Interactive mail access protocol"}, /* imap */
+    {995, 110, 0, "Post office protocol"}, /* pop3 */
+    {4433, 80, 0, "Hypertext transfer protocol"}, /* https */
+    {0, 0, 0, 0}};    
+
+typedef struct _SslService {
+    address addr;
+    guint port;
+} SslService;
+
+static GHashTable *ssl_session_hash = NULL;
+static GHashTable *ssl_key_hash = NULL;
+
+int ssl_packet_from_server(unsigned int port)
+{
+    SslAssociation* current;
+    for (current = ssl_associations; current->ssl_port != 0; current++)
+    {
+        if (current->ssl_port == port)
+            return 1;
+    }
+    return 0;
+}    
+
+/* Hash Functions */
+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 void ssl_init(void)
+{
+    if (ssl_session_hash)
+            g_hash_table_destroy(ssl_session_hash);
+    if (ssl_key_hash)
+            g_hash_table_destroy(ssl_key_hash);
+
+    ssl_key_hash = g_hash_table_new(ssl_private_key_hash,ssl_private_key_equal);
+    ssl_session_hash = g_hash_table_new(ssl_hash, ssl_equal);
+    if (ssl_keys_list) 
+    {
+        char* end;
+        char* start = strdup(ssl_keys_list);
+        char* tmp = 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 and filename with ':' separator */
+            ssl_debug_printf("ssl_init found host entry %s\n", addr);
+            port = strchr(addr, ':');
+            if (!port)
+                return;
+            *port = 0;
+            port++;
+            
+            filename = strchr(port,':');
+            if (!filename)
+                return;
+            *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);
+                return;
+            }        
+            
+            private_key = ssl_load_key(fp);
+            if (!private_key) {
+                fprintf(stderr,"can't load private key from %s\n",
+                    filename);
+                return;
+            }
+            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);
+    }
+}
+
+static void ssl_save_session(SslDecryptSession* ssl)
+{
+    StringInfo* session_id = g_malloc0(sizeof(StringInfo) + ssl->session_id.data_len);
+    StringInfo* master_secret = g_malloc0(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");
+}
+
 /* The TCP port to associate with by default */
 #define TCP_PORT_SSL                    443
 #define TCP_PORT_SSL_LDAP               636
@@ -704,7 +896,8 @@
 static int dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
                                proto_tree *tree, guint32 offset,
                                guint *conv_version,
-                               gboolean *need_desegmentation);
+                               gboolean *need_desegmentation,
+                               SslDecryptSession *conv_data);
 
 /* change cipher spec dissector */
 static void dissect_ssl3_change_cipher_spec(tvbuff_t *tvb,
@@ -721,16 +914,19 @@
 static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
                                    proto_tree *tree, guint32 offset,
                                    guint32 record_length,
-                                   guint *conv_version, guint8 content_type);
+                                   guint *conv_version,
+                                   SslDecryptSession *conv_data, guint8 content_type);
 
 
 static void dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb,
                                        proto_tree *tree,
-                                       guint32 offset, guint32 length);
+                                       guint32 offset, guint32 length, 
+                                       SslDecryptSession* ssl);
 
 static void dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb,
                                        proto_tree *tree,
-                                       guint32 offset, guint32 length);
+                                       guint32 offset, guint32 length, 
+                                       SslDecryptSession* ssl);
 
 static void dissect_ssl3_hnd_cert(tvbuff_t *tvb,
                                   proto_tree *tree, guint32 offset, packet_info *pinfo);
@@ -742,7 +938,7 @@
 static void dissect_ssl3_hnd_finished(tvbuff_t *tvb,
                                       proto_tree *tree,
                                       guint32 offset,
-                                      guint *conv_version);
+                                      guint* conv_version);
 
 
 /*
@@ -754,12 +950,14 @@
 static int dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo,
                                proto_tree *tree, guint32 offset,
                                guint *conv_version,
-                               gboolean *need_desegmentation);
+                               gboolean *need_desegmentation,
+                               SslDecryptSession* ssl);
 
 /* client hello dissector */
 static void dissect_ssl2_hnd_client_hello(tvbuff_t *tvb,
                                           proto_tree *tree,
-                                          guint32 offset);
+                                          guint32 offset,
+                                          SslDecryptSession* ssl);
 
 static void dissect_pct_msg_client_hello(tvbuff_t *tvb,
                                           proto_tree *tree,
@@ -794,7 +992,7 @@
  * Support Functions
  *
  */
-static void ssl_set_conv_version(packet_info *pinfo, guint version);
+/*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);
@@ -809,7 +1007,7 @@
 static int  ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb,
                                                guint32 offset,
                                                guint32 record_length);
-
+static SslAssociation* ssl_find_association(packet_info* pinfo);
 /*********************************************************************
  *
  * Main dissector
@@ -824,12 +1022,13 @@
 
     conversation_t *conversation;
     void *conv_data;
-    guint conv_version     = SSL_VER_UNKNOWN;
     proto_item *ti         = NULL;
     proto_tree *ssl_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
@@ -852,10 +1051,48 @@
                                         pinfo->srcport, pinfo->destport, 0);
     }
     conv_data = conversation_get_proto_data(conversation, proto_ssl);
+    
+    /* PAOLO: manage ssl decryption data */
+    /*get a valid ssl session pointer*/ 
     if (conv_data != NULL)
-    {
-        conv_version = GPOINTER_TO_UINT(conv_data);
-    }
+        ssl_session = conv_data;
+    else {
+        SslService dummy;
+
+        ssl_session= ssl_alloc_session();
+        ssl_session->version = SSL_VER_UNKNOWN;
+        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)) {
+            dummy.addr = pinfo->net_src;
+            dummy.port = pinfo->srcport;
+        }
+        else {
+            dummy.addr = pinfo->net_dst;
+            dummy.port = pinfo->destport;
+        }
+
+        /* 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 "
+                "%hhd.%hhd.%hhd.%hhd:%d\n", dummy.addr.data[0],
+                dummy.addr.data[1],dummy.addr.data[2],
+                dummy.addr.data[3],dummy.port);
+        }
+    }
+    conv_version= & ssl_session->version;
+
+    /* 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 SSL it is (assuming we don't
@@ -910,12 +1147,13 @@
         /* first try to dispatch off the cached version
          * known to be associated with the conversation
          */
-        switch(conv_version) {
+        switch(*conv_version) {
         case SSL_VER_SSLv2:
         case SSL_VER_PCT:
             offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
-                                         offset, &conv_version,
-                                         &need_desegmentation);
+                                         offset, conv_version,
+                                         &need_desegmentation, 
+                                         ssl_session);
             break;
 
         case SSL_VER_SSLv3:
@@ -929,14 +1167,16 @@
             if (ssl_is_v2_client_hello(tvb, offset))
             {
                 offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
-                                             offset, &conv_version,
-                                             &need_desegmentation);
+                                             offset, conv_version,
+                                             &need_desegmentation,
+                                             ssl_session);
             }
             else
             {
                 offset = dissect_ssl3_record(tvb, pinfo, ssl_tree,
-                                             offset, &conv_version,
-                                             &need_desegmentation);
+                                             offset, conv_version,
+                                             &need_desegmentation,
+                                             ssl_session);
             }
             break;
 
@@ -948,15 +1188,17 @@
             {
                 /* looks like sslv2 or pct client hello */
                 offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
-                                             offset, &conv_version,
-                                             &need_desegmentation);
+                                             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, ssl_tree,
-                                             offset, &conv_version,
-                                             &need_desegmentation);
+                                             offset, conv_version,
+                                             &need_desegmentation,
+                                             ssl_session);
             }
             else
             {
@@ -972,7 +1214,7 @@
                 if (check_col(pinfo->cinfo, COL_PROTOCOL))
                 {
                     col_set_str(pinfo->cinfo, COL_PROTOCOL,
-                         ssl_version_short_names[conv_version]);
+                         ssl_version_short_names[*conv_version]);
                 }
             }
             break;
@@ -981,21 +1223,85 @@
         /* Desegmentation return check */
         if (need_desegmentation)
           return;
-
-        /* If we haven't already set the version information for
-         * this conversation, do so. */
-        if (conv_data == NULL)
-        {
-            conv_data = GINT_TO_POINTER(conv_version);
-            conversation_add_proto_data(conversation, proto_ssl, conv_data);
-        }
-
         /* set up for next record in frame, if any */
         first_record_in_frame = FALSE;
     }
 
 }
 
+static void 
+decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, 
+        guint32 record_length, guint8 content_type, SslDecryptSession* ssl,
+        gboolean save_plaintext)
+{
+     int len;
+     SslDecoder* decoder;
+     StringInfo* data;
+ 
+     /* retrive decoder for this packet direction*/
+     if (ssl_packet_from_server(pinfo->srcport)) {
+         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;
+     }
+     ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl state %X\n", 
+         record_length, ssl->state);
+
+     /* if we can decrypt and decryption have success
+      * add decrypted data to this packet info*/
+     if (!(ssl->state & SSL_HAVE_SESSION_KEY)) {
+         return ;
+     }
+
+     /* ensure we have enough storage space for decrypted data */
+     if (record_length > decoder->decrypted_data.data_len)
+     {
+         ssl_debug_printf("decrypt_ssl3_record: allocating decrypt %d bytes for decrypt data\n", record_length + 32);
+         ssl_data_init(&decoder->decrypted_data, NULL, record_length + 32);
+     }
+
+     /* run decryption and add decrypted payload to protocol data, if decryption 
+      * is successful*/
+     len = decoder->decrypted_data.data_len; 
+     if ((ssl_decrypt_record(ssl, decoder, 
+            content_type, tvb_get_ptr(tvb, offset, record_length),
+            record_length,  decoder->decrypted_data.data, &len) == 0) && 
+            save_plaintext)
+     {
+         data = p_get_proto_data(pinfo->fd, proto_ssl);
+         
+         if (!data) 
+         {
+             ssl_debug_printf("decrypt_ssl3_record: allocating app_data %d bytes for app data\n", len);
+             /* first app data record: allocate and put packet data*/
+             data = g_malloc0(sizeof(StringInfo)+ len);
+             data->data = ((unsigned char*)data) + sizeof(StringInfo);                            
+             ssl_data_set(data, decoder->decrypted_data.data, len);
+         }
+         else { 
+             /* update previus record*/
+             ssl_debug_printf("decrypt_ssl3_record: reallocating app_data "
+                 "%d bytes for app data (total %d appdata bytes)\n", 
+                 len, data->data_len + len+sizeof(StringInfo));
+             data = g_realloc(data, data->data_len + len+sizeof(StringInfo));
+             data->data= ((unsigned char*)data) + sizeof(StringInfo);
+             memcpy(&data->data[data->data_len], decoder->decrypted_data.data, len);
+             data->data_len += len;
+             
+             /* realloc can change ptr so remove old one and readd the new one*/
+             ssl_debug_printf("decrypt_ssl3_record: removing old app_data ptr\n");
+             p_rem_proto_data(pinfo->fd, proto_ssl);
+         }
+         
+         ssl_debug_printf("decrypt_ssl3_record: setting decrypted app_data ptr %p\n",data);
+         p_add_proto_data(pinfo->fd, proto_ssl, data);
+     }
+}
+
+
 
 /*********************************************************************
  *
@@ -1005,7 +1311,8 @@
 static int
 dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
                     proto_tree *tree, guint32 offset,
-                    guint *conv_version, gboolean *need_desegmentation)
+                    guint *conv_version, gboolean *need_desegmentation,
+                    SslDecryptSession* ssl)
 {
 
     /*
@@ -1033,6 +1340,8 @@
     proto_tree *ti              = NULL;
     proto_tree *ssl_record_tree = NULL;
     guint32 available_bytes     = 0;
+    StringInfo* decrypted;
+    SslAssociation* association;
 
     available_bytes = tvb_length_remaining(tvb, offset);
 
@@ -1152,12 +1461,21 @@
         if (version == 0x0300)
         {
             *conv_version = SSL_VER_SSLv3;
-            ssl_set_conv_version(pinfo, *conv_version);
+            if (ssl) {
+                ssl->version_netorder = version;
+                ssl->state |= SSL_VERSION;
+            }
+            /*ssl_set_conv_version(pinfo, ssl->version);*/
         }
         else if (version == 0x0301)
         {
+            
             *conv_version = SSL_VER_TLS;
-            ssl_set_conv_version(pinfo, *conv_version);
+            if (ssl) {
+                ssl->version_netorder = version;
+                ssl->state |= SSL_VERSION;
+            }
+            /*ssl_set_conv_version(pinfo, ssl->version);*/
         }
     }
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -1182,6 +1500,11 @@
     /*
      * now dissect the next layer
      */
+    ssl_debug_printf("dissect_ssl3_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))
@@ -1190,18 +1513,28 @@
                                         offset, conv_version, content_type);
         break;
     case SSL_ID_ALERT:
+        if (ssl)
+            decrypt_ssl3_record(tvb, pinfo, offset, 
+                record_length, content_type, ssl, FALSE);
         dissect_ssl3_alert(tvb, pinfo, ssl_record_tree, offset,
                            conv_version);
         break;
     case SSL_ID_HANDSHAKE:
+        if (ssl)
+            decrypt_ssl3_record(tvb, pinfo, offset, 
+                record_length, content_type, ssl, FALSE);
         dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset,
-                               record_length, conv_version, content_type);
+                               record_length, conv_version, ssl, content_type);
         break;
     case SSL_ID_APP_DATA:
+        if (ssl)
+            decrypt_ssl3_record(tvb, pinfo, offset, 
+                record_length, content_type, ssl, TRUE);
         if (check_col(pinfo->cinfo, COL_INFO))
             col_append_str(pinfo->cinfo, COL_INFO, "Application Data");
         if (ssl_record_tree)
         {
+            //proto_name_str = match_strval(content_type, ssl_31_content_type);
             proto_item_set_text(ssl_record_tree,
                                 "%s Record Layer: %s Protocol: Application Data",
                                 ssl_version_short_names[*conv_version],
@@ -1209,7 +1542,54 @@
             tvb_ensure_bytes_exist(tvb, offset, record_length);
             proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb,
                                 offset, record_length, 0);
-        }
+        }        
+         
+         /* we need dissector information when the selected packet is shown
+          * and ssl session pointer is NULL at that time, so we can't access
+          * info cached there*/         
+         association = ssl_find_association(pinfo);
+         
+         /* show on info colum what we are decoding */
+         if (check_col(pinfo->cinfo, COL_INFO) && association)
+         {
+             ssl_debug_printf("adding COL_INFO %s\n",association->info);
+             col_clear(pinfo->cinfo, COL_INFO);
+             col_append_str(pinfo->cinfo, COL_INFO, association->info);
+         }
+
+         /* show decrypted data info, if available */         
+         decrypted = p_get_proto_data(pinfo->fd, proto_ssl);
+         if (decrypted && ssl_record_tree)
+         {
+             tvbuff_t* new_tvb;
+             
+             /* try to dissect decrypted data*/
+             ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", decrypted->data_len);
+             
+             /* create new tvbuff for the decrypted data */
+             new_tvb = tvb_new_real_data(decrypted->data, 
+                 decrypted->data_len, decrypted->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) {
+                 ssl_debug_printf("dissect_ssl3_record found association %p\n", association);
+                 ssl_print_text_data("decrypted app data",decrypted->data, 
+                     decrypted->data_len);
+                 
+                 call_dissector(association->handle, new_tvb, pinfo, ssl_record_tree);
+             }
+             /* add raw decrypted data only if a decoder is not found*/
+             else 
+                 proto_tree_add_string(ssl_record_tree, hf_ssl_record_appdata_decrypted, tvb,
+                         offset, decrypted->data_len, (char*) decrypted->data);
+         }
+         else 
+             if (ssl_record_tree)
+                 proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb,
+                            offset, record_length, 0);
+        
         break;
 
     default:
@@ -1227,7 +1607,7 @@
 static void
 dissect_ssl3_change_cipher_spec(tvbuff_t *tvb,
                                 proto_tree *tree, guint32 offset,
-                                guint *conv_version, guint8 content_type)
+                                guint* conv_version, guint8 content_type)
 {
     /*
      * struct {
@@ -1250,7 +1630,7 @@
 static void
 dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo,
                    proto_tree *tree, guint32 offset,
-                   guint *conv_version)
+                   guint* conv_version)
 {
     /*     struct {
      *         AlertLevel level;
@@ -1294,7 +1674,7 @@
         if (check_col(pinfo->cinfo, COL_INFO))
             col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Alert");
     }
-
+    
     if (tree)
     {
         if (level && desc)
@@ -1325,7 +1705,8 @@
 static void
 dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
                        proto_tree *tree, guint32 offset,
-                       guint32 record_length, guint *conv_version, guint8 content_type)
+                       guint32 record_length, guint *conv_version,
+                       SslDecryptSession* ssl, guint8 content_type)
 {
     /*     struct {
      *         HandshakeType msg_type;
@@ -1367,6 +1748,8 @@
         msg_type_str = match_strval(msg_type, ssl_31_handshake_type);
         length   = tvb_get_ntoh24(tvb, offset + 1);
 
+        ssl_debug_printf("dissect_ssl3_handshake iteration %d type %d offset %d lenght %d "
+            "bytes, remaning %d \n", first_iteration, msg_type, offset, length, record_length);
         if (!msg_type_str && !first_iteration)
         {
             /* only dissect / report messages if they're
@@ -1425,17 +1808,18 @@
 
         /* if we don't have a valid handshake type, just quit dissecting */
         if (!msg_type_str)
-        {
             return;
-        }
-
-        if (ssl_hand_tree)
+                
+        /* PAOLO: 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 */
-            proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type,
-                                tvb, offset, 1, msg_type);
+            if (ssl_hand_tree)
+                proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type,
+                                    tvb, offset, 1, msg_type);
             offset++;
-            proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length,
+            if (ssl_hand_tree)
+                proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length,
                                 tvb, offset, 3, length);
             offset += 3;
 
@@ -1446,11 +1830,11 @@
                 break;
 
             case SSL_HND_CLIENT_HELLO:
-                dissect_ssl3_hnd_cli_hello(tvb, ssl_hand_tree, offset, length);
+                dissect_ssl3_hnd_cli_hello(tvb, ssl_hand_tree, offset, length, ssl);
             break;
 
             case SSL_HND_SERVER_HELLO:
-                dissect_ssl3_hnd_srv_hello(tvb, ssl_hand_tree, offset, length);
+                dissect_ssl3_hnd_srv_hello(tvb, ssl_hand_tree, offset, length, ssl);
                 break;
 
             case SSL_HND_CERTIFICATE:
@@ -1473,8 +1857,51 @@
                 /* unimplemented */
                 break;
 
-            case SSL_HND_CLIENT_KEY_EXCHG:
-                /* unimplemented */
+            case SSL_HND_CLIENT_KEY_EXCHG: 
+                {
+                    /* PAOLO: here we can have all the data to build session key*/
+                    StringInfo encrypted_pre_master;
+                    int ret;
+    
+                    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;
+                    }
+                                
+                    /* get encrypted data, we must skip tls record len && version and
+                     * 2 bytes of record data */
+                    encrypted_pre_master.data = g_malloc(length - 2);
+                    encrypted_pre_master.data_len = length-2;
+                    tvb_memcpy(tvb, encrypted_pre_master.data, offset+2, length-2);
+                    
+                    if (!ssl->private_key) {
+                        ssl_debug_printf("dissect_ssl3_handshake can't find private key\n");
+                        break;
+                    }
+                                
+                    /* go with ssl key processessing*/
+                    ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key);
+                    g_free(encrypted_pre_master.data);
+                    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:
@@ -1485,9 +1912,8 @@
 
         }
         else
-        {
-            offset += 4;        /* skip the handshake header */
-        }
+            offset += 4;        /* skip the handshake header when handshake is not processed*/
+
         offset += length;
         first_iteration = FALSE; /* set up for next pass, if any */
     }
@@ -1495,13 +1921,50 @@
 
 static int
 dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
-                              guint32 offset)
+                              guint32 offset, SslDecryptSession* ssl, gint from_server)
 {
     /* show the client's random challenge */
-    guint32 initial_offset = offset;
     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;
+        
+        /* 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);
+        
+        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); 
+        }
+        else {
+            /* reset state on renegotiation*/
+            if (!from_server)
+                ssl->state &= ~(SSL_HAVE_SESSION_KEY|SSL_MASTER_SECRET|
+                    SSL_CIPHER|SSL_SERVER_RANDOM);
+            
+            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 */
@@ -1533,7 +1996,9 @@
         }
 
     }
-    return offset - initial_offset;
+    
+    // XXXX
+    return session_id_length+33;
 }
 
 static int
@@ -1591,7 +2056,8 @@
 
 static void
 dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb,
-                           proto_tree *tree, guint32 offset, guint32 length)
+       proto_tree *tree, guint32 offset, guint32 length,
+       SslDecryptSession*ssl)
 {
     /* struct {
      *     ProtocolVersion client_version;
@@ -1610,20 +2076,23 @@
     guint8  compression_method;
     guint16 start_offset = offset;
 
-    if (tree)
+    if (tree || ssl)
     {
         /* show the client version */
-        proto_tree_add_item(tree, hf_ssl_handshake_client_version, tvb,
+        if (tree)
+            proto_tree_add_item(tree, hf_ssl_handshake_client_version, tvb,
                             offset, 2, FALSE);
         offset += 2;
 
         /* show the fields in common with server hello */
-        offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset);
+        offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 0);
 
         /* tell the user how many cipher suites there are */
         cipher_suite_length = tvb_get_ntohs(tvb, offset);
+        if (!tree)
+            return;
         proto_tree_add_uint(tree, hf_ssl_handshake_cipher_suites_len,
-                            tvb, offset, 2, cipher_suite_length);
+                        tvb, offset, 2, cipher_suite_length);
         offset += 2;            /* skip opaque length */
 
         if (cipher_suite_length > 0)
@@ -1706,7 +2175,7 @@
 
 static void
 dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb,
-                           proto_tree *tree, guint32 offset, guint32 length)
+                           proto_tree *tree, guint32 offset, guint32 length, SslDecryptSession* ssl)
 {
     /* struct {
      *     ProtocolVersion server_version;
@@ -1719,21 +2188,56 @@
      */
     guint16 start_offset = offset;
 
-    if (tree)
+    if (tree || ssl)
     {
         /* show the server version */
-        proto_tree_add_item(tree, hf_ssl_handshake_server_version, tvb,
+        if (tree)
+                proto_tree_add_item(tree, hf_ssl_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);
+        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;
+            }
+
+            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;
+            }
+            
+            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;
 
         /* now the server-selected cipher suite */
         proto_tree_add_item(tree, hf_ssl_handshake_cipher_suite,
-                            tvb, offset, 2, FALSE);
+                    tvb, offset, 2, FALSE);
         offset += 2;
 
         /* and the server-selected compression method */
@@ -1910,7 +2414,7 @@
 static void
 dissect_ssl3_hnd_finished(tvbuff_t *tvb,
                           proto_tree *tree, guint32 offset,
-                          guint *conv_version)
+                          guint* conv_version)
 {
     /* For TLS:
      *     struct {
@@ -1957,8 +2461,9 @@
 /* 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)
+                    guint32 offset, guint* conv_version,
+                    gboolean *need_desegmentation,
+                    SslDecryptSession* ssl)
 {
     guint32 initial_offset       = offset;
     guint8  byte                 = 0;
@@ -2057,13 +2562,13 @@
                                                (initial_offset +
                                                 record_length_length),
                                                record_length)) {
-            *conv_version = SSL_VER_PCT;
-            ssl_set_conv_version(pinfo, *conv_version);
+            *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, *conv_version);
+            /*ssl_set_conv_version(pinfo, ssl->version);*/
         }
     }
 
@@ -2166,7 +2671,7 @@
         /* dissect the message (only handle client hello right now) */
         switch (msg_type) {
         case SSL2_HND_CLIENT_HELLO:
-            dissect_ssl2_hnd_client_hello(tvb, ssl_record_tree, offset);
+            dissect_ssl2_hnd_client_hello(tvb, ssl_record_tree, offset, ssl);
             break;
 
         case SSL2_HND_CLIENT_MASTER_KEY:
@@ -2219,7 +2724,8 @@
 
 static void
 dissect_ssl2_hnd_client_hello(tvbuff_t *tvb,
-                              proto_tree *tree, guint32 offset)
+                              proto_tree *tree, guint32 offset,
+                              SslDecryptSession* ssl)
 {
     /* struct {
      *    uint8 msg_type;
@@ -2241,7 +2747,7 @@
     guint16 challenge_length;
 
     proto_tree *ti;
-    proto_tree *cs_tree;
+    proto_tree *cs_tree=0;
 
     version = tvb_get_ntohs(tvb, offset);
     if (!ssl_is_valid_ssl_version(version))
@@ -2250,46 +2756,54 @@
         return;
     }
 
-    if (tree)
+    if (tree || ssl)
     {
         /* show the version */
-        proto_tree_add_item(tree, hf_ssl_record_version, tvb,
+        if (tree)
+            proto_tree_add_item(tree, hf_ssl_record_version, tvb,
                             offset, 2, FALSE);
         offset += 2;
 
         cipher_spec_length = tvb_get_ntohs(tvb, offset);
-        proto_tree_add_item(tree, hf_ssl2_handshake_cipher_spec_len,
+        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);
-        proto_tree_add_item(tree, hf_ssl2_handshake_session_id_len,
+        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);
-        proto_tree_add_item(tree, hf_ssl2_handshake_challenge_len,
+        if (tree)
+            proto_tree_add_item(tree, hf_ssl2_handshake_challenge_len,
                             tvb, offset, 2, FALSE);
         offset += 2;
 
-        /* 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_ssl_handshake_cipher_suites,
+        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_ssl_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_ssl_cipher_suites);
-        if (!cs_tree)
-        {
-            cs_tree = tree;     /* failsafe */
+            /* make this a subtree and expand the actual specs below */
+            cs_tree = proto_item_add_subtree(ti, ett_ssl_cipher_suites);
+            if (!cs_tree)
+            {
+                cs_tree = tree;     /* failsafe */
+            }
         }
 
         /* iterate through the cipher specs, showing them */
         while (cipher_spec_length > 0)
         {
-            proto_tree_add_item(cs_tree, hf_ssl2_handshake_cipher_spec,
+            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;
@@ -2298,15 +2812,26 @@
         /* if there's a session id, show it */
         if (session_id_length > 0)
         {
-            tvb_ensure_bytes_exist(tvb, offset, session_id_length);
-            proto_tree_add_bytes_format(tree,
-                                         hf_ssl_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"));
-
+            if (tree)
+            {
+                tvb_ensure_bytes_exist(tvb, offset, session_id_length);
+                proto_tree_add_bytes_format(tree,
+                                             hf_ssl_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;
         }
 
@@ -2314,8 +2839,26 @@
         if (challenge_length > 0)
         {
             tvb_ensure_bytes_exist(tvb, offset, challenge_length);
-            proto_tree_add_item(tree, hf_ssl2_handshake_challenge,
+            
+            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;
         }
     }
@@ -2864,7 +3407,7 @@
  * Support Functions
  *
  *********************************************************************/
-
+#if 0
 static void
 ssl_set_conv_version(packet_info *pinfo, guint version)
 {
@@ -2895,6 +3438,7 @@
     }
     conversation_add_proto_data(conversation, proto_ssl, GINT_TO_POINTER(version));
 }
+#endif
 
 static int
 ssl_is_valid_handshake_type(guint8 type)
@@ -3222,6 +3766,12 @@
             FT_NONE, BASE_NONE, NULL, 0x0,
             "Payload is application data", HFILL }
         },
+        { &hf_ssl_record_appdata_decrypted,
+          { "Application Data decrypted", "ssl.app_data_decrypted",
+            FT_STRING, BASE_NONE, NULL, 0x0,
+            "Payload is decrypted application data", HFILL }
+        },
+
         { & hf_ssl2_record,
           { "SSLv2/PCT Record Header", "ssl.record",
             FT_NONE, BASE_DEC, NULL, 0x0,
@@ -3497,61 +4047,61 @@
             FT_NONE, BASE_NONE, NULL, 0x0,
             "Server's challenge to client", HFILL }
         },
-		{ &hf_pct_handshake_cipher_spec,
-		  { "Cipher Spec", "pct.handshake.cipherspec",
-			FT_NONE, BASE_NONE, NULL, 0x0,
-			"PCT Cipher specification", HFILL }
-		},
-		{ &hf_pct_handshake_cipher,
-		  { "Cipher", "pct.handshake.cipher",
-			FT_UINT16, BASE_HEX, VALS(pct_cipher_type), 0x0, 
-			"PCT Ciper", HFILL }
+        { &hf_pct_handshake_cipher_spec,
+          { "Cipher Spec", "pct.handshake.cipherspec",
+                FT_NONE, BASE_NONE, NULL, 0x0,
+                "PCT Cipher specification", HFILL }
+        },
+        { &hf_pct_handshake_cipher,
+          { "Cipher", "pct.handshake.cipher",
+                FT_UINT16, BASE_HEX, VALS(pct_cipher_type), 0x0, 
+                "PCT Ciper", HFILL }
 	},
-		{ &hf_pct_handshake_hash_spec,
-		  { "Hash Spec", "pct.handshake.hashspec",
-			FT_NONE, BASE_NONE, NULL, 0x0,
-			"PCT Hash specification", HFILL }
-		},
-		{ &hf_pct_handshake_hash,
-		  { "Hash", "pct.handshake.hash",
-			FT_UINT16, BASE_HEX, VALS(pct_hash_type), 0x0,
-			"PCT Hash", HFILL }
-		},
-		{ &hf_pct_handshake_cert_spec,
-		  { "Cert Spec", "pct.handshake.certspec",
-			FT_NONE, BASE_NONE, NULL, 0x0,
-			"PCT Certificate specification", HFILL }
-		},
-		{ &hf_pct_handshake_cert,
-		  { "Cert", "pct.handshake.cert",
-			FT_UINT16, BASE_HEX, VALS(pct_cert_type), 0x0,
-			"PCT Certificate", HFILL }
-		},
-		{ &hf_pct_handshake_exch_spec,
-		  { "Exchange Spec", "pct.handshake.exchspec",
-			FT_NONE, BASE_NONE, NULL, 0x0,
-			"PCT Exchange specification", HFILL }
-		},
-		{ &hf_pct_handshake_exch,
-		  { "Exchange", "pct.handshake.exch",
-			FT_UINT16, BASE_HEX, VALS(pct_exch_type), 0x0,
-			"PCT Exchange", HFILL }
-		},
-		{ &hf_pct_handshake_sig,
-		  { "Sig Spec", "pct.handshake.sig",
-			FT_UINT16, BASE_HEX, VALS(pct_sig_type), 0x0,
-			"PCT Signature", HFILL }
-		},
-		{ &hf_pct_msg_error_type,
-		  { "PCT Error Code", "pct.msg_error_code",
-			FT_UINT16, BASE_HEX, VALS(pct_error_code), 0x0,
-			"PCT Error Code", HFILL }
-		},
-		{ &hf_pct_handshake_server_cert,
-		  { "Server Cert", "pct.handshake.server_cert",
-			FT_NONE, BASE_NONE, NULL , 0x0,
-			"PCT Server Certificate", HFILL }
-		},
+        { &hf_pct_handshake_hash_spec,
+          { "Hash Spec", "pct.handshake.hashspec",
+                FT_NONE, BASE_NONE, NULL, 0x0,
+                "PCT Hash specification", HFILL }
+        },
+        { &hf_pct_handshake_hash,
+          { "Hash", "pct.handshake.hash",
+                FT_UINT16, BASE_HEX, VALS(pct_hash_type), 0x0,
+                "PCT Hash", HFILL }
+        },
+        { &hf_pct_handshake_cert_spec,
+          { "Cert Spec", "pct.handshake.certspec",
+                FT_NONE, BASE_NONE, NULL, 0x0,
+                "PCT Certificate specification", HFILL }
+        },
+        { &hf_pct_handshake_cert,
+          { "Cert", "pct.handshake.cert",
+                FT_UINT16, BASE_HEX, VALS(pct_cert_type), 0x0,
+                "PCT Certificate", HFILL }
+        },
+        { &hf_pct_handshake_exch_spec,
+          { "Exchange Spec", "pct.handshake.exchspec",
+                FT_NONE, BASE_NONE, NULL, 0x0,
+                "PCT Exchange specification", HFILL }
+        },
+        { &hf_pct_handshake_exch,
+          { "Exchange", "pct.handshake.exch",
+                FT_UINT16, BASE_HEX, VALS(pct_exch_type), 0x0,
+                "PCT Exchange", HFILL }
+        },
+        { &hf_pct_handshake_sig,
+          { "Sig Spec", "pct.handshake.sig",
+                FT_UINT16, BASE_HEX, VALS(pct_sig_type), 0x0,
+                "PCT Signature", HFILL }
+        },
+        { &hf_pct_msg_error_type,
+          { "PCT Error Code", "pct.msg_error_code",
+                FT_UINT16, BASE_HEX, VALS(pct_error_code), 0x0,
+                "PCT Error Code", HFILL }
+        },
+        { &hf_pct_handshake_server_cert,
+          { "Server Cert", "pct.handshake.server_cert",
+                FT_NONE, BASE_NONE, NULL , 0x0,
+                "PCT Server Certificate", HFILL }
+        },
     };
 
     /* Setup protocol subtree array */
@@ -3589,10 +4139,32 @@
              "Whether the SSL dissector should reassemble SSL records spanning multiple TCP segments. "
              "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
              &ssl_desegment);
+       prefs_register_string_preference(ssl_module, "rsa_private_key", "RSA private keys list",
+             "comma separated list of RSA private key to be used for decryption; "
+             "each list entry must be in the form of <ip>:<port>:<key_file_name>",
+             (const char **)&ssl_keys_list);
+
+
     }
 
     register_dissector("ssl", dissect_ssl, proto_ssl);
+    
+    register_init_routine(ssl_init);
+    SSL_LIB_INIT();
+}
 
+SslAssociation* ssl_find_association(packet_info* pinfo)
+{
+    SslAssociation* cur;
+    for (cur = ssl_associations; cur->ssl_port != 0; cur++) {
+        ssl_debug_printf("ssl_find_dissector cur port %d src port %d dest port %d\n",
+            cur->ssl_port, pinfo->srcport, pinfo->destport);
+        if (((cur->ssl_port == pinfo->srcport) || (cur->ssl_port == pinfo->destport)) && cur->handle) {
+            ssl_debug_printf("ssl_find_dissector found %p\n", cur->handle);
+            return cur;
+        }
+    }
+    return 0;
 }
 
 /* If this dissector uses sub-dissector registration add a registration
@@ -3603,10 +4175,25 @@
 proto_reg_handoff_ssl(void)
 {
     dissector_handle_t ssl_handle;
+    dissector_table_t tcp_dissectors;
 
     ssl_handle = find_dissector("ssl");
+    
+    tcp_dissectors = find_dissector_table( "tcp.port");
+    if (tcp_dissectors)
+    {
+        ssl_associations[0].handle = dissector_get_port_handle(tcp_dissectors, 80);
+        ssl_associations[1].handle = dissector_get_port_handle(tcp_dissectors, 389);
+        ssl_associations[2].handle = dissector_get_port_handle(tcp_dissectors, 143);
+        ssl_associations[3].handle = dissector_get_port_handle(tcp_dissectors, 110);
+        ssl_associations[4].handle = dissector_get_port_handle(tcp_dissectors, 80);
+    }
+    ssl_debug_printf("http: %p ldap %p imap %p pop %p\n", 
+        ssl_associations[0].handle, ssl_associations[1].handle, 
+        ssl_associations[2].handle, ssl_associations[3].handle);
     dissector_add("tcp.port", TCP_PORT_SSL, ssl_handle);
     dissector_add("tcp.port", TCP_PORT_SSL_LDAP, ssl_handle);
     dissector_add("tcp.port", TCP_PORT_SSL_IMAP, ssl_handle);
     dissector_add("tcp.port", TCP_PORT_SSL_POP, ssl_handle);
+    dissector_add("tcp.port", 4433, ssl_handle);
 }
diff -uNr ethereal-0.10.13/epan/dissectors/packet-ssl-utils.c ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.c
--- ethereal-0.10.13/epan/dissectors/packet-ssl-utils.c	1970-01-01 01:00:00.000000000 +0100
+++ ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.c	2005-12-07 09:51:53.000000000 +0100
@@ -0,0 +1,1143 @@
+/* packet-ss-utils.c
+ *
+ * $Id: ethereal_ssl_decrypt_0.10.13.patch,v 1.10 2005/12/07 07:47:00 cvs Exp $
+ *
+ * ssl manipulation functions
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * 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.
+ */
+ 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "packet-ssl-utils.h"
+
+#include <glib.h>
+
+#ifdef HAVE_LIBGNUTLS
+
+#define SSL_HMAC gcry_md_hd_t
+#define SSL_HMAC_INIT(md,key,len,algo) if (*(md)) gcry_md_close(*(md)); \
+    gcry_md_open(md,algo, GCRY_MD_FLAG_HMAC); \
+        gcry_md_setkey (*(md), key, len)
+#define SSL_HMAC_UPDATE(md, data, len) gcry_md_write(*(md), data, len)
+#define SSL_HMAC_FINAL(md, data, len) ({ int __algo = gcry_md_get_algo (*(md)); \
+        int __len = gcry_md_get_algo_dlen (__algo);\
+        memcpy(data, gcry_md_read(*(md),  __algo), __len); \
+        *len =__len;})
+#define SSL_HMAC_CLEANUP(md) gcry_md_close(*(md))
+
+#define SSL_MD gcry_md_hd_t        
+#define SSL_MD_INIT(md,algo) if (*(md)) gcry_md_close(*(md)); \
+    gcry_md_open(md,algo, 0); 
+#define SSL_MD_UPDATE(md, data, len) gcry_md_write(*(md), data, len)
+#define SSL_MD_FINAL(md, data, len) ({ int __algo = gcry_md_get_algo (*(md)); \
+        int __len = gcry_md_get_algo_dlen (__algo);\
+        memcpy(data, gcry_md_read(*(md),  __algo), __len); \
+        *len =__len;})
+#define SSL_MD_CLEANUP(md) gcry_md_close(*(md))
+
+#define SSL_SHA_CTX gcry_md_hd_t
+#define SSL_SHA_INIT(md) if (*(md)) gcry_md_close(*(md)); \
+    gcry_md_open(md,GCRY_MD_SHA1, 0); 
+#define SSL_SHA_UPDATE(md, data, len) gcry_md_write(*(md), data, len)
+#define SSL_SHA_FINAL(buf, md) memcpy(buf, gcry_md_read(*(md),  GCRY_MD_SHA1), \
+    gcry_md_get_algo_dlen(GCRY_MD_SHA1))
+
+#define SSL_MD5_CTX gcry_md_hd_t
+#define SSL_MD5_INIT(md) if (*(md)) gcry_md_close(*(md)); \
+    gcry_md_open(md,GCRY_MD_MD5, 0); 
+#define SSL_MD5_UPDATE(md, data, len) gcry_md_write(*(md), data, len)
+#define SSL_MD5_FINAL(buf, md) memcpy(buf, gcry_md_read(*(md),  GCRY_MD_MD5), \
+    gcry_md_get_algo_dlen(GCRY_MD_MD5))
+
+#define SSL_CIPHER_INIT(cipher, algo,sk,iv, mode) gcry_cipher_init(cipher, algo, sk, iv, mode)
+
+#define SSL_CIPHER_DECRYPT(chiper, out, outl, in, inl) \
+        gcry_cipher_decrypt ( *(chiper), out, outl, in, inl);
+        
+#define SSL_GET_DIGEST_BY_NAME(name) gcry_md_map_name(name)       
+#define SSL_GET_CIPHER_BY_NAME(name) gcry_cipher_map_name(name)
+
+#define SSL_GET_KEY_LEN(pk) gcry_pk_get_nbits (pk)
+#define SSL_PRIVATE_DECYPT(len, encr_data, decryped_data, pk) \
+    pcry_private_decrypt(len, encr_data, decryped_data, pk)
+
+gcry_err_code_t
+_gcry_rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
+                   gcry_mpi_t *skey, int flags);
+                   
+#define PUBKEY_FLAG_NO_BLINDING (1 << 0) 
+
+int pcry_private_decrypt(int len, unsigned char* encr_data, unsigned char** decrypted_data, SSL_PRIVATE_KEY* pk)
+{
+    int rc, i;
+    int decr_len = 0;
+    gcry_sexp_t  s_data, s_plain;
+    gcry_mpi_t encr_mpi;
+    int encr_len = len;
+    unsigned char* decr_data_ptr;
+    gcry_mpi_t text;
+
+    /* 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 ) {
+        ssl_debug_printf("pcry_private_decrypt: can't convert encr_data to mpi (size %d):%s\n", 
+            len, gcry_strerror(rc));
+        return 0;
+    }
+
+#ifndef SSL_FAST    
+    /* put the data into a simple list */
+    rc = gcry_sexp_build(&s_data, NULL, "(enc-val(rsa(a%m)))", encr_mpi);
+    if (rc != 0) {
+        ssl_debug_printf("pcry_private_decrypt: can't build encr_sexp:%s \n",
+             gcry_strerror(rc));
+        return 0;
+    }
+
+    /* pass it to libgcrypt */
+    rc = gcry_pk_decrypt(&s_plain, s_data, pk);
+    gcry_sexp_release(s_data);
+    if (rc != 0)
+    {
+        ssl_debug_printf("pcry_private_decrypt: can't decrypt key:%s\n", 
+            len, gcry_strerror(rc));
+        goto out;
+    }    
+    
+    /* convert plain text sexp to mpi format */
+    text = gcry_sexp_nth_mpi(s_plain, 0, 0);
+    
+    /* compute size requested for plaintext buffer */
+    decr_len = len;
+    if (gcry_mpi_print(GCRYMPI_FMT_USG, NULL, decr_len, &decr_len, text) != 0) {
+        ssl_debug_printf("pcry_private_decrypt: can't compute decr size:%s\n",
+            gcry_strerror(rc));
+        decr_len = 0;
+        goto out;
+    }
+
+    /* write plain text to newly allocated buffer */
+    *decrypted_data = decr_data_ptr = g_malloc(decr_len);
+    if (gcry_mpi_print( GCRYMPI_FMT_USG, decr_data_ptr, decr_len, &decr_len, 
+            text) != 0) {
+        ssl_debug_printf("pcry_private_decrypt: can't print decr data to mpi (size %d):%s\n", 
+            decr_len, gcry_strerror(rc));
+        g_free(decr_data_ptr);
+        decr_len = 0;
+        goto out;
+    }
+    
+    /* strip the padding*/
+    rc = 0;
+    for (i = 1; i < decr_len; i++) {
+        if (decr_data_ptr[i] == 0) {
+            rc = i+1;
+            break;
+        }
+    }
+    
+    ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %d\n", 
+        rc, decr_len);
+    ssl_print_data("decypted_unstrip_pre_master", decr_data_ptr, decr_len);
+    memcpy(decr_data_ptr, &decr_data_ptr[rc], decr_len - rc);
+    decr_len -= rc;
+
+out:        
+    gcry_sexp_release(s_plain);
+#else    
+    rc = _gcry_rsa_decrypt(0, &text,  &encr_mpi, pk,0);
+    gcry_mpi_print( GCRYMPI_FMT_USG, 0, 0, &decr_len, text);
+    
+    /* write plain text to newly allocated buffer */
+    *decrypted_data = decr_data_ptr = g_malloc(decr_len);
+    if (gcry_mpi_print( GCRYMPI_FMT_USG, decr_data_ptr, decr_len, &decr_len, 
+            text) != 0) {
+        ssl_debug_printf("pcry_private_decrypt: can't print decr data to mpi (size %d):%s\n", 
+            decr_len, gcry_strerror(rc));
+        g_free(decr_data_ptr);
+        return 0;
+    }
+    
+    /* strip the padding*/
+    rc = 0;
+    for (i = 1; i < decr_len; i++) {
+        if (decr_data_ptr[i] == 0) {
+            rc = i+1;
+            break;
+        }
+    }
+    
+    ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %d\n", 
+        rc, decr_len);
+    ssl_print_data("decypted_unstrip_pre_master", decr_data_ptr, decr_len);
+    memcpy(decr_data_ptr, &decr_data_ptr[rc], decr_len - rc);
+    decr_len -= rc;
+#endif    
+    return decr_len;
+}
+
+int gcry_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); 
+    if (err !=0)
+        return  -1;
+    err = gcry_cipher_setkey(*(cipher), sk, gcry_cipher_get_algo_keylen (algo)); 
+    if (err != 0)
+        return -1;
+    err = gcry_cipher_setiv(*(cipher), iv, gcry_cipher_get_algo_blklen (algo));
+    if (err != 0)
+        return -1;
+    return 0;
+}
+
+#define PRF(ssl,secret,usage,rnd1,rnd2,out) ((ssl->version_netorder==SSLV3_VERSION)? \
+        ssl3_prf(secret,usage,rnd1,rnd2,out): \
+        tls_prf(secret,usage,rnd1,rnd2,out))
+
+static char *digests[]={
+     "MD5",
+     "SHA1"
+};
+
+static char *ciphers[]={
+     "DES",
+     "DES3",
+     "ARCFOUR", /* gnutls does not support rc4, but this should be 100% compatible*/
+     "RC2",
+     "IDEA",
+     "AES",
+     "AES256"
+};
+
+/* look in openssl/ssl/ssl_lib.c for a complete list of available cipersuite*/
+static SslCipherSuite cipher_suites[]={
+     {1,KEX_RSA,SIG_RSA,ENC_NULL,0,0,0,DIG_MD5,16,0, SSL_CIPHER_MODE_STREAM},
+     {2,KEX_RSA,SIG_RSA,ENC_NULL,0,0,0,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {3,KEX_RSA,SIG_RSA,ENC_RC4,1,128,40,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM},
+     {4,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_MD5,16,0, SSL_CIPHER_MODE_STREAM},
+     {5,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {6,KEX_RSA,SIG_RSA,ENC_RC2,8,128,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {7,KEX_RSA,SIG_RSA,ENC_IDEA,8,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {8,KEX_RSA,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {9,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {10,KEX_RSA,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {11,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {12,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {13,KEX_DH,SIG_DSS,ENC_3DES,8,192,192,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {14,KEX_DH,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {15,KEX_DH,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {16,KEX_DH,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {17,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {18,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {19,KEX_DH,SIG_DSS,ENC_3DES,8,192,192,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {20,KEX_DH,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {21,KEX_DH,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {22,KEX_DH,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {23,KEX_DH,SIG_NONE,ENC_RC4,1,128,40,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM},
+     {24,KEX_DH,SIG_NONE,ENC_RC4,1,128,128,DIG_MD5,16,0, SSL_CIPHER_MODE_STREAM},
+     {25,KEX_DH,SIG_NONE,ENC_DES,8,64,40,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM},
+     {26,KEX_DH,SIG_NONE,ENC_DES,8,64,64,DIG_MD5,16,0, SSL_CIPHER_MODE_STREAM},
+     {27,KEX_DH,SIG_NONE,ENC_3DES,8,192,192,DIG_MD5,16,0, SSL_CIPHER_MODE_STREAM},
+     {47,KEX_RSA,SIG_RSA,ENC_AES,16,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC},
+     {53,KEX_RSA,SIG_RSA,ENC_AES256,16,256,256,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC},
+     {96,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM},
+     {97,KEX_RSA,SIG_RSA,ENC_RC2,1,128,56,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM},
+     {98,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {99,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,16,1, SSL_CIPHER_MODE_STREAM},
+     {100,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {101,KEX_DH,SIG_DSS,ENC_RC4,1,128,56,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
+     {102,KEX_DH,SIG_DSS,ENC_RC4,1,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+     {-1, 0,0,0,0,0,0,0,0,0, 0}
+};
+
+#define MAX_BLOCK_SIZE 16
+#define MAX_KEY_SIZE 32
+
+int ssl_find_cipher(int num,SslCipherSuite* cs)
+{
+    SslCipherSuite *c;
+    
+    for(c=cipher_suites;c->number!=-1;c++){
+        if(c->number==num){
+            *cs=*c;
+            return 0;
+        }
+    }
+    
+    return -1;
+}
+
+static int tls_hash(StringInfo* secret,
+        StringInfo* seed, int md, StringInfo* out)
+{
+    u_int8_t *ptr=out->data;
+    unsigned int left=out->data_len;
+    int tocpy;
+    u_int8_t *A;
+    u_int8_t _A[20],tmp[20];
+    unsigned int A_l,tmp_l;
+    SSL_HMAC hm;
+    
+    memset(&hm, 0, sizeof(hm));
+    ssl_print_string("tls_hash: hash secret", secret);
+    ssl_print_string("tls_hash: hash seed", seed);
+    A=seed->data;
+    A_l=seed->data_len;
+    
+    while(left){
+        SSL_HMAC_INIT(&hm,secret->data,secret->data_len,md);
+        SSL_HMAC_UPDATE(&hm,A,A_l);
+        SSL_HMAC_FINAL(&hm,_A,&A_l);
+        A=_A;
+        
+        SSL_HMAC_INIT(&hm,secret->data,secret->data_len,md);
+        SSL_HMAC_UPDATE(&hm,A,A_l);
+        SSL_HMAC_UPDATE(&hm,seed->data,seed->data_len);
+        SSL_HMAC_FINAL(&hm,tmp,&tmp_l);
+        
+        tocpy=MIN(left,tmp_l);
+        memcpy(ptr,tmp,tocpy);
+        ptr+=tocpy;
+        left-=tocpy;
+    }
+    
+    SSL_HMAC_CLEANUP(&hm);
+    ssl_print_string("hash out", out);
+    return (0);
+}    
+
+static int tls_prf(StringInfo* secret,char *usage,
+        StringInfo* rnd1, StringInfo* rnd2, StringInfo* out)
+{
+    StringInfo seed, sha_out, md5_out;
+    u_int8_t *ptr;
+    StringInfo s1, s2;
+    unsigned int i,s_l, r=-1;
+    int 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;
+    if (ssl_data_alloc(&md5_out, MAX(out->data_len,16)) < 0)
+        goto free_sha;
+    if (ssl_data_alloc(&seed, usage_len+rnd1->data_len+rnd2->data_len) < 0)
+        goto free_md5;
+
+    ptr=seed.data;
+    memcpy(ptr,usage,usage_len); ptr+=usage_len;
+    memcpy(ptr,rnd1->data,rnd1->data_len); ptr+=rnd1->data_len;
+    memcpy(ptr,rnd2->data,rnd2->data_len); ptr+=rnd2->data_len;    
+    
+    /* initalize buffer for client/server seeds*/
+    s_l=secret->data_len/2 + secret->data_len%2;
+    if (ssl_data_alloc(&s1, s_l) < 0)
+        goto free_seed;
+    if (ssl_data_alloc(&s2, s_l) < 0)
+        goto free_s1;
+    
+    memcpy(s1.data,secret->data,s_l);
+    memcpy(s2.data,secret->data + (secret->data_len - s_l),s_l);
+
+    ssl_debug_printf("tls_prf: tls_hash(md5 secret_len %d seed_len %d )\n", s1.data_len, seed.data_len);
+    if(tls_hash(&s1,&seed,SSL_GET_DIGEST_BY_NAME("MD5"),&md5_out) != 0)
+        goto free_all;
+    ssl_debug_printf("tls_prf: tls_hash(sha)\n");
+    if(tls_hash(&s2,&seed,SSL_GET_DIGEST_BY_NAME("SHA1"),&sha_out) != 0)
+        goto free_all;
+    
+    for(i=0;i<out->data_len;i++)
+      out->data[i]=md5_out.data[i] ^ sha_out.data[i];
+    r =0;
+    
+    ssl_print_string("PRF out",out);
+free_all:    
+    free(s2.data);
+free_s1:    
+    free(s1.data);
+free_seed:    
+    free(seed.data);
+free_md5:
+    free(md5_out.data);    
+free_sha:
+    free(sha_out.data);
+    return r;    
+}
+
+static int ssl3_generate_export_iv(StringInfo* r1,
+        StringInfo* r2, StringInfo* out)
+{
+    SSL_MD5_CTX md5;
+    u_int8_t tmp[16];
+    
+    SSL_MD5_INIT(&md5);
+    SSL_MD5_UPDATE(&md5,r1->data,r1->data_len);
+    SSL_MD5_UPDATE(&md5,r2->data,r2->data_len);
+    SSL_MD5_FINAL(tmp,&md5);
+    
+    memcpy(out->data,tmp,out->data_len);
+    ssl_print_string("export iv", out);
+    
+    return(0);
+}
+
+static int ssl3_prf(StringInfo* secret, char* 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;
+    u_int8_t buf[20];
+    
+    rnd1=r1; rnd2=r2;
+        
+    SSL_MD5_INIT(&md5);
+    memset(&sha,0,sizeof(sha));
+    SSL_SHA_INIT(&sha);
+    
+    for(off=0;off<out->data_len;off+=16){
+        char outbuf[16];
+        int tocpy;
+        i++;
+        
+        ssl_debug_printf("ssl3_prf: sha1_update(%d)\n",i);
+        /* A, BB, CCC,  ... */
+        for(j=0;j<i;j++){
+            buf[j]=64+i;
+        }
+        
+        SSL_SHA_UPDATE(&sha,buf,i);
+        if (secret) 
+            SSL_SHA_UPDATE(&sha,secret->data,secret->data_len);
+        
+        if(!strcmp(usage,"client write key") || !strcmp(usage,"server write key")){
+            SSL_SHA_UPDATE(&sha,rnd2->data,rnd2->data_len);
+            SSL_SHA_UPDATE(&sha,rnd1->data,rnd1->data_len);
+        }
+        else{
+            SSL_SHA_UPDATE(&sha,rnd1->data,rnd1->data_len);
+            SSL_SHA_UPDATE(&sha,rnd2->data,rnd2->data_len);
+        }
+        
+        SSL_SHA_FINAL(buf,&sha);
+        
+        SSL_SHA_INIT(&sha);
+        
+        ssl_debug_printf("ssl3_prf: md5_update(%d)\n",i);
+        SSL_MD5_UPDATE(&md5,secret->data,secret->data_len);
+        SSL_MD5_UPDATE(&md5,buf,20);
+        SSL_MD5_FINAL(outbuf,&md5);
+        tocpy=MIN(out->data_len-off,16);
+        memcpy(out->data+off,outbuf,tocpy);
+        
+        SSL_MD5_INIT(&md5);
+    }
+    
+    return(0);
+}
+
+int ssl_create_decoder(SslDecoder *dec, SslCipherSuite *cipher_suite, 
+        u_int8_t *mk, u_int8_t *sk, u_int8_t *iv)
+{
+    int 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]);
+        ciph=SSL_GET_CIPHER_BY_NAME(ciphers[cipher_suite->enc-0x30]);
+    }
+    if (ciph == 0) {
+        ssl_debug_printf("ssl_create_decoder can't find cipher %s\n", 
+            ciphers[cipher_suite->enc-0x30]);
+        return -1;
+    }
+    
+    /* init mac buffer: mac storage is embedded into decoder struct to save a
+     memory allocation and waste samo more memory*/
+    dec->cipher_suite=cipher_suite;
+    dec->mac_key.data = dec->_mac_key;
+    ssl_data_set(&dec->mac_key, mk, cipher_suite->dig_len);
+
+    if (SSL_CIPHER_INIT(&dec->evp,ciph,sk,iv,cipher_suite->mode) < 0) {
+        ssl_debug_printf("ssl_create_decoder: can't create cipher id:%d mode:%d\n",
+            ciph, cipher_suite->mode);
+        return -1;
+    }
+
+    ssl_debug_printf("decoder initialized (digest len %d)\n", cipher_suite->dig_len);
+    return 0;    
+}
+
+int ssl_generate_keyring_material(SslDecryptSession*ssl_session)
+{
+    StringInfo key_block;
+    u_int8_t _iv_c[MAX_BLOCK_SIZE],_iv_s[MAX_BLOCK_SIZE];
+    u_int8_t _key_c[MAX_KEY_SIZE],_key_s[MAX_KEY_SIZE];
+    int needed;
+    u_int8_t *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*/    
+    if (!(ssl_session->state & SSL_MASTER_SECRET)) {
+        ssl_debug_printf("ssl_generate_keyring_material:PRF(pre_master_secret)\n");
+        if (PRF(ssl_session,&ssl_session->pre_master_secret,"master secret",
+                &ssl_session->client_random,
+                &ssl_session->server_random, &ssl_session->master_secret)) {
+            ssl_debug_printf("ssl_generate_keyring_material can't generate master_secret\n");
+            return -1;
+        }
+        ssl_print_string("master secret",&ssl_session->master_secret);
+    }
+    
+    /* Compute the key block. First figure out how much data we need*/
+    needed=ssl_session->cipher_suite.dig_len*2;
+    needed+=ssl_session->cipher_suite.bits / 4;
+    if(ssl_session->cipher_suite.block>1) 
+        needed+=ssl_session->cipher_suite.block*2;
+    
+    key_block.data_len = needed;
+    key_block.data = malloc(needed);
+    if (!key_block.data) {
+        ssl_debug_printf("ssl_generate_keyring_material can't allacate key_block\n");
+        return -1;
+    }
+    ssl_debug_printf("ssl_generate_keyring_material sess key generation\n");
+    if (PRF(ssl_session,&ssl_session->master_secret,"key expansion",
+            &ssl_session->server_random,&ssl_session->client_random,
+            &key_block)) {
+        ssl_debug_printf("ssl_generate_keyring_material can't generate key_block\n");
+        goto fail;
+    }
+    ssl_print_string("key expansion", &key_block);
+    
+    ptr=key_block.data;
+    c_mk=ptr; ptr+=ssl_session->cipher_suite.dig_len;
+    s_mk=ptr; ptr+=ssl_session->cipher_suite.dig_len;
+    
+    c_wk=ptr; ptr+=ssl_session->cipher_suite.eff_bits/8;
+    s_wk=ptr; ptr+=ssl_session->cipher_suite.eff_bits/8;
+    
+    if(ssl_session->cipher_suite.block>1){
+        c_iv=ptr; ptr+=ssl_session->cipher_suite.block;
+        s_iv=ptr; ptr+=ssl_session->cipher_suite.block;
+    }
+    
+    if(ssl_session->cipher_suite.export){
+        StringInfo iv_c,iv_s;
+        StringInfo key_c,key_s;
+        StringInfo k;
+        
+        if(ssl_session->cipher_suite.block>1){
+            
+            /* We only have room for MAX_BLOCK_SIZE bytes IVs, but that's
+             all we should need. This is a sanity check */
+            if(ssl_session->cipher_suite.block>MAX_BLOCK_SIZE) {
+                ssl_debug_printf("ssl_generate_keyring_material cipher suite block must be at most %d nut is %d\n", 
+                    MAX_BLOCK_SIZE, ssl_session->cipher_suite.block);
+                goto fail;
+            }
+        
+            iv_c.data = _iv_c;
+            iv_c.data_len = ssl_session->cipher_suite.block;
+            iv_s.data = _iv_s;
+            iv_s.data_len = ssl_session->cipher_suite.block;
+            
+            if(ssl_session->version_netorder==SSLV3_VERSION){
+                ssl_debug_printf("ssl_generate_keyring_material ssl3_generate_export_iv\n");
+                if (ssl3_generate_export_iv(&ssl_session->client_random,
+                        &ssl_session->server_random,&iv_c)) {
+                    ssl_debug_printf("ssl_generate_keyring_material can't generate sslv3 client iv\n");
+                    goto fail;
+                }
+                ssl_debug_printf("ssl_generate_keyring_material ssl3_generate_export_iv(2)\n");
+                if (ssl3_generate_export_iv(&ssl_session->server_random,
+                        &ssl_session->client_random,&iv_s)) {
+                    ssl_debug_printf("ssl_generate_keyring_material can't generate sslv3 server iv\n");
+                    goto fail;
+                }            
+            }
+            else{
+                u_int8_t _iv_block[MAX_BLOCK_SIZE * 2];
+                StringInfo iv_block;
+                StringInfo key_null;
+                u_int8_t _key_null;
+                
+                key_null.data = &_key_null;
+                key_null.data_len = 0;
+                                
+                iv_block.data = _iv_block;
+                iv_block.data_len = ssl_session->cipher_suite.block*2;
+                
+                ssl_debug_printf("ssl_generate_keyring_material prf(iv_block)\n");
+                if(PRF(ssl_session,&key_null, "IV block",
+                        &ssl_session->client_random,
+                        &ssl_session->server_random,&iv_block)) {
+                    ssl_debug_printf("ssl_generate_keyring_material can't generate tls31 iv block\n");
+                    goto fail;
+                }
+                
+                memcpy(_iv_c,iv_block.data,ssl_session->cipher_suite.block);
+                memcpy(_iv_s,iv_block.data+ssl_session->cipher_suite.block,
+                    ssl_session->cipher_suite.block);
+            }
+            
+            c_iv=_iv_c;
+            s_iv=_iv_s;
+        }
+        
+        if (ssl_session->version_netorder==SSLV3_VERSION){
+            
+            SSL_MD5_CTX md5;
+            ssl_debug_printf("ssl_generate_keyring_material MD5(client_random)\n");
+            SSL_MD5_INIT(&md5);
+            SSL_MD5_UPDATE(&md5,c_wk,ssl_session->cipher_suite.eff_bits/8);
+            SSL_MD5_UPDATE(&md5,ssl_session->client_random.data,
+                ssl_session->client_random.data_len);
+            SSL_MD5_UPDATE(&md5,ssl_session->server_random.data,
+                ssl_session->server_random.data_len);        
+            SSL_MD5_FINAL(_key_c,&md5);
+            c_wk=_key_c;
+            
+            SSL_MD5_INIT(&md5);
+            ssl_debug_printf("ssl_generate_keyring_material MD5(server_random)\n");
+            SSL_MD5_UPDATE(&md5,s_wk,ssl_session->cipher_suite.eff_bits/8);
+            SSL_MD5_UPDATE(&md5,ssl_session->server_random.data,
+                ssl_session->server_random.data_len);
+            SSL_MD5_UPDATE(&md5,ssl_session->client_random.data,
+                ssl_session->client_random.data_len);
+            SSL_MD5_FINAL(_key_s,&md5);
+            s_wk=_key_s;
+        }
+        else{
+            key_c.data = _key_c;
+            key_c.data_len = sizeof(_key_c);
+            key_s.data = _key_s;
+            key_s.data_len = sizeof(_key_s);
+            
+            k.data = c_wk;
+            k.data_len = ssl_session->cipher_suite.eff_bits/8;
+            ssl_debug_printf("ssl_generate_keyring_material PRF(key_c)\n");
+            if (PRF(ssl_session,&k,"client write key",
+                    &ssl_session->client_random,
+                    &ssl_session->server_random, &key_c)) {
+                ssl_debug_printf("ssl_generate_keyring_material can't generate tll31 server key \n");        
+                goto fail;
+            }
+            c_wk=_key_c;
+            
+            k.data = s_wk;
+            k.data_len = ssl_session->cipher_suite.eff_bits/8;
+            ssl_debug_printf("ssl_generate_keyring_material PRF(key_s)\n");
+            if(PRF(ssl_session,&k,"server write key",
+                    &ssl_session->client_random,
+                    &ssl_session->server_random, &key_s)) {
+                ssl_debug_printf("ssl_generate_keyring_material can't generate tll31 client key \n");
+                goto fail;
+            }
+            s_wk=_key_s;
+        }
+    }
+    
+    /* show key material info */
+    ssl_print_data("Client MAC key",c_mk,ssl_session->cipher_suite.dig_len);
+    ssl_print_data("Server MAC key",s_mk,ssl_session->cipher_suite.dig_len);    
+    ssl_print_data("Client Write key",c_wk,ssl_session->cipher_suite.bits/8);
+    ssl_print_data("Server Write key",s_wk,ssl_session->cipher_suite.bits/8);    
+        
+    if(ssl_session->cipher_suite.block>1) {
+        ssl_print_data("Client Write IV",c_iv,ssl_session->cipher_suite.block);
+        ssl_print_data("Server Write IV",s_iv,ssl_session->cipher_suite.block);
+    }
+    else {
+        ssl_print_data("Client Write IV",c_iv,8);
+        ssl_print_data("Server Write IV",s_iv,8);
+    }
+    
+    /* create both client and server ciphers*/
+    ssl_debug_printf("ssl_generate_keyring_material ssl_create_decoder(client)\n");
+    if (ssl_create_decoder(&ssl_session->client,
+            &ssl_session->cipher_suite,c_mk,c_wk,c_iv)) {
+        ssl_debug_printf("ssl_generate_keyring_material can't init client decoder\n");        
+        goto fail;
+    }
+    ssl_debug_printf("ssl_generate_keyring_material ssl_create_decoder(server)\n");
+    if (ssl_create_decoder(&ssl_session->server,
+            &ssl_session->cipher_suite,s_mk,s_wk,s_iv)) {
+        ssl_debug_printf("ssl_generate_keyring_material can't init client decoder\n");        
+        goto fail;
+    }
+        
+    free(key_block.data);
+    return 0;
+    
+fail:
+    free(key_block.data);
+    return -1;
+}
+
+int ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, 
+    StringInfo* entrypted_pre_master, SSL_PRIVATE_KEY *pk)
+{
+    int 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",
+            ssl_session->cipher_suite.kex, KEX_RSA);
+        return(-1);
+    }
+
+#if 0 
+    /* can't find any place where ephemeral_rsa is set ...*/
+    if(d->ephemeral_rsa) {
+        ssl_debug_printf("ssl_decrypt_pre_master_secret ephimeral RSA\n");
+        return(-1);
+    }
+#endif    
+ 
+    /* with tls key loading will fail if not rsa type, so no need to check*/
+    ssl_print_string("pre master encrypted",entrypted_pre_master);
+    ssl_debug_printf("ssl_decrypt_pre_master_secret:RSA_private_decrypt\n");
+    i=SSL_PRIVATE_DECYPT(entrypted_pre_master->data_len,
+        entrypted_pre_master->data,&ssl_session->pre_master_secret.data, 
+        pk);
+
+    ssl_debug_printf("ssl_decrypt_pre_master_secret private decrypt(%d) %d\n", 
+        entrypted_pre_master->data_len,i);
+    if(i!=48)  {
+        return -1;
+    }
+
+    ssl_session->pre_master_secret.data_len=48;
+      
+    ssl_print_string("pre master secret",&ssl_session->pre_master_secret);
+
+    /* Remove the master secret if it was there
+       to force keying material regeneration in
+       case we're renegotiating */
+    ssl_session->state &= ~SSL_MASTER_SECRET;
+    return 0;
+}
+ 
+#define MSB(a) ((a>>8)&0xff)
+#define LSB(a) (a&0xff)
+
+/* This should go to 2^128, but we're never really going to see
+   more than 2^64, so we cheat*/
+static int fmt_seq(u_int32_t num, u_int8_t* buf)
+{
+    u_int32_t netnum;
+
+    memset(buf,0,8);
+    netnum=htonl(num);
+    memcpy(buf+4,&netnum,4);
+
+    return(0);
+}
+
+static int tls_check_mac(SslDecoder*decoder, int ct,int ver, u_int8_t* data,
+        u_int32_t datalen, u_int8_t* mac)
+{
+    SSL_HMAC hm;
+    int md;
+    u_int32_t l;
+    u_int8_t buf[20];
+
+    memset(&hm, 0, sizeof(hm));
+    md=SSL_GET_DIGEST_BY_NAME(digests[decoder->cipher_suite->dig-0x40]);
+    ssl_debug_printf("tls_check_mac mac:%s md %d\n",
+        digests[decoder->cipher_suite->dig-0x40], md);
+    SSL_HMAC_INIT(&hm,decoder->mac_key.data,decoder->mac_key.data_len,md);
+    ssl_debug_printf("tls_check_mac hmac %p\n",hm);
+    
+    fmt_seq(decoder->seq,buf);
+    decoder->seq++;
+    SSL_HMAC_UPDATE(&hm,buf,8);
+    buf[0]=ct;
+    SSL_HMAC_UPDATE(&hm,buf,1);
+
+    buf[0]=MSB(ver);
+    buf[1]=LSB(ver);
+    SSL_HMAC_UPDATE(&hm,buf,2); 
+    
+    buf[0]=MSB(datalen);
+    buf[1]=LSB(datalen);
+    SSL_HMAC_UPDATE(&hm,buf,2);
+
+    SSL_HMAC_UPDATE(&hm,data,datalen);
+
+    SSL_HMAC_FINAL(&hm,buf,&l);
+    if(memcmp(mac,buf,l))
+        return -1;
+
+    SSL_HMAC_CLEANUP(&hm);
+    return(0);
+}
+
+int ssl3_check_mac(SslDecoder*decoder,int ct,u_int8_t* data,
+        u_int32_t datalen, u_int8_t* mac)
+{
+    SSL_MD mc;
+    int md;
+    u_int32_t l;
+    u_int8_t buf[64],dgst[20];
+    int pad_ct;
+    
+    pad_ct=(decoder->cipher_suite->dig==DIG_SHA)?40:48;
+
+    /* get cipher used for digest comptuation */
+    md=SSL_GET_DIGEST_BY_NAME(digests[decoder->cipher_suite->dig-0x40]);
+    ssl_debug_printf("ssl3_check_mac digest%s md %d\n",
+        digests[decoder->cipher_suite->dig-0x40], md);
+    memset(&mc, 0, sizeof(mc));
+    SSL_MD_INIT(&mc,md);
+    ssl_debug_printf("ssl3_check_mac memory digest %p\n",mc);
+
+    /* do hash computation on data && padding */
+    SSL_MD_UPDATE(&mc,decoder->mac_key.data,decoder->mac_key.data_len);
+
+    memset(buf,0x36,pad_ct);
+    SSL_MD_UPDATE(&mc,buf,pad_ct);
+
+    fmt_seq(decoder->seq,buf);
+    decoder->seq++;
+    SSL_MD_UPDATE(&mc,buf,8);
+
+    buf[0]=ct;
+    SSL_MD_UPDATE(&mc,buf,1);
+
+    buf[0]=MSB(datalen);
+    buf[1]=LSB(datalen);
+    SSL_MD_UPDATE(&mc,buf,2);
+    SSL_MD_UPDATE(&mc,data,datalen);
+
+    SSL_MD_FINAL(&mc,dgst,&l);
+
+    SSL_MD_INIT(&mc,md);
+
+    SSL_MD_UPDATE(&mc,decoder->mac_key.data,decoder->mac_key.data_len);
+
+    memset(buf,0x5c,pad_ct);
+    SSL_MD_UPDATE(&mc,buf,pad_ct);
+    SSL_MD_UPDATE(&mc,dgst,l);
+
+    SSL_MD_FINAL(&mc,dgst,&l);
+
+    if(memcmp(mac,dgst,l))
+        return -1;
+
+    return(0);
+}
+  
+int ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct,
+        const unsigned char* in, int inl,unsigned char*out,int* outl)
+{
+    int pad, worklen;
+    u_int8_t *mac;
+    
+    ssl_debug_printf("ssl_decrypt_record ciphertext len %d\n", inl);
+    ssl_print_data("Ciphertext",in, inl);
+    
+    /* First decrypt*/
+    SSL_CIPHER_DECRYPT(&decoder->evp,out,*outl,in,inl);
+
+    ssl_print_data("Plaintext",out,inl);
+    worklen=inl;
+
+    /* Now strip off the padding*/
+    if(decoder->cipher_suite->block!=1){
+        pad=out[inl-1];
+        worklen-=(pad+1);
+        ssl_debug_printf("ssl_decrypt_record found padding %d final len %d\n", 
+            pad, *outl);
+    }
+
+    /* And the MAC */
+    worklen-=decoder->cipher_suite->dig_len;
+    if (worklen < 0)
+    {
+        ssl_debug_printf("ssl_decrypt_record wrong record len/padding outlen %d\n work %d\n",*outl, worklen);
+        return -1;
+    }
+    mac=out+worklen;
+    /*ssl_print_data("Record data",out,*outl);*/
+
+    /* Now check the MAC */
+    ssl_debug_printf("checking mac (len %d, version %X, ct %d)\n", worklen,ssl->version_netorder, ct);
+    if(ssl->version_netorder==0x300){
+        if(ssl3_check_mac(decoder,ct,out,worklen,mac) < 0) {
+            ssl_debug_printf("ssl_decrypt_record: mac falied\n");
+            return -1;
+        }
+    }
+    else{
+        if(tls_check_mac(decoder,ct,ssl->version_netorder,out,worklen,mac)< 0) {
+            ssl_debug_printf("ssl_decrypt_record: mac falied\n");
+            return -1;
+        }
+    }
+    ssl_debug_printf("ssl_decrypt_record: mac ok\n");
+    *outl = worklen;
+    return(0);
+}
+
+
+SSL_PRIVATE_KEY* ssl_load_key(FILE* fp)
+{    
+    /* gnutls make our work much harded, since we have to work internally with
+     * s-exp formatted data, but PEM loader export only in "gnutls_datum" 
+     * format, and a datum -> s-exp convertion function does not exist.
+     */
+    struct gnutls_x509_privkey_int* priv_key;
+    gnutls_datum key;
+    gnutls_datum m, e, d, p,q, u;
+    int size;
+    unsigned int bytes;
+    unsigned int tmp_size;
+#ifdef SSL_FAST
+    gcry_mpi_t* rsa_params = g_malloc(sizeof(gcry_mpi_t)*6);
+#else    
+    gcry_mpi_t rsa_params[6];
+#endif    
+    gcry_sexp_t rsa_priv_key;
+    
+    /* init private key data*/
+    gnutls_x509_privkey_init(&priv_key);
+    
+    /* compute file size and load all file contents into a datum buffer*/
+    if (fseek(fp, 0, SEEK_END) < 0) {
+        ssl_debug_printf("ssl_load_key: can't fseek file\n");
+        return NULL;
+    }
+    if ((size = ftell(fp)) < 0) {
+        ssl_debug_printf("ssl_load_key: can't ftell file\n");
+        return NULL;
+    }
+    if (fseek(fp, 0, SEEK_SET) < 0) {
+        ssl_debug_printf("ssl_load_key: can't refseek file\n");
+        return NULL;
+    }
+    key.data = g_malloc(size);
+    key.size = size;
+    bytes = fread(key.data, 1, key.size, fp);
+    if (bytes < key.size) {
+        ssl_debug_printf("ssl_load_key: can't read from file %d bytes, got %d\n", 
+            key.size, bytes);
+        return NULL;
+    }
+    
+    /* import PEM data*/
+    if (gnutls_x509_privkey_import(priv_key, &key, GNUTLS_X509_FMT_PEM)!=0) {
+        ssl_debug_printf("ssl_load_key: can't import pem data\n");
+        return NULL;
+    }
+    free(key.data);
+    //rsa_params = priv_key->params;
+    
+    /* RSA get parameter */
+    if (gnutls_x509_privkey_export_rsa_raw(priv_key, &m, &e, &d, &p, &q, &u) != 0) {
+        ssl_debug_printf("ssl_load_key: can't export rsa param (is a rsa private key file ?!?)\n");
+        return NULL;
+    }
+    
+    /* convert each rsa parameter to mpi format*/
+    if (gcry_mpi_scan( &rsa_params[0], GCRYMPI_FMT_USG, m.data,  m.size, &tmp_size) !=0) {
+        ssl_debug_printf("ssl_load_key: can't convert m rsa param to int (size %d)\n", m.size);
+        return NULL;
+    }
+    ssl_debug_printf("ssl_load_key: got rsa param m size %d (%d)\n", m.size, tmp_size);
+    
+    if (gcry_mpi_scan( &rsa_params[1], GCRYMPI_FMT_USG, e.data,  e.size, &tmp_size) != 0) {
+        ssl_debug_printf("ssl_load_key: can't convert e rsa param to int (size %d)\n", e.size);
+        return NULL;
+    }
+    ssl_debug_printf("ssl_load_key: got rsa param e size %d (%d)\n", e.size, tmp_size);
+
+    // note: openssl and gnutls use 'p' and 'q' with opposite meaning:
+    // our 'p' must be equal to 'q' as provided from openssl and viceversa
+    if (gcry_mpi_scan( &rsa_params[2], GCRYMPI_FMT_USG, d.data,  d.size, &tmp_size) !=0) {
+        ssl_debug_printf("ssl_load_key: can't convert d rsa param to int (size %d)\n", d.size);
+        return NULL;
+    }
+    ssl_debug_printf("ssl_load_key: got rsa param d size %d (%d)\n", d.size, tmp_size);
+    
+    if (gcry_mpi_scan( &rsa_params[3], GCRYMPI_FMT_USG, q.data,  q.size, &tmp_size) !=0) {
+        ssl_debug_printf("ssl_load_key: can't convert q rsa param to int (size %d)\n", q.size);
+        return NULL;
+    }
+    ssl_debug_printf("ssl_load_key: got rsa param q size %d (%d)\n", q.size, tmp_size);
+
+    if (gcry_mpi_scan( &rsa_params[4], GCRYMPI_FMT_USG, p.data,  p.size, &tmp_size) !=0) {
+        ssl_debug_printf("ssl_load_key: can't convert p rsa param to int (size %d)\n", p.size);
+        return NULL;
+    }
+    ssl_debug_printf("ssl_load_key: got rsa param p size %d (%d)\n", q.size, tmp_size);
+        
+    if (gcry_mpi_scan( &rsa_params[5], GCRYMPI_FMT_USG, u.data,  u.size, &tmp_size) !=0) {
+        ssl_debug_printf("ssl_load_key: can't convert u rsa param to int (size %d)\n", m.size);
+        return NULL; 
+    }
+    ssl_debug_printf("ssl_load_key: got rsa param u size %d (%d)\n", u.size, tmp_size);
+    
+    if  (gcry_sexp_build( &rsa_priv_key, NULL,
+            "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", rsa_params[0], 
+            rsa_params[1], rsa_params[2], rsa_params[3], rsa_params[4], 
+            rsa_params[5]) != 0) {
+        ssl_debug_printf("ssl_load_key: can't built rsa private key s-exp\n");
+        return NULL;
+    }
+
+#if SSL_FAST    
+    return rsa_params;
+#else
+    return rsa_priv_key;
+#endif    
+}
+
+#else
+/* no libgnutl: dummy operation to keep interface consistent*/
+SSL_PRIVATE_KEY* ssl_load_key(FILE* fp) 
+{
+    ssl_debug_printf("ssl_load_key: impossible without glutls. fp %p\n",fp);
+    return NULL;
+}
+int ssl_find_cipher(int num,SslCipherSuite* cs) 
+{
+    ssl_debug_printf("ssl_find_cipher: dummy without glutls. num %d cs %p\n",
+        num,cs);
+    return 0; 
+}
+int ssl_generate_keyring_material(SslDecryptSession*ssl) 
+{
+    ssl_debug_printf("ssl_generate_keyring_material: impossible without glutls. ssl %p\n",
+        ssl);
+    return 0; 
+}
+int ssl_decrypt_pre_master_secret(SslDecryptSession* ssl_session, 
+    StringInfo* entrypted_pre_master, SSL_PRIVATE_KEY *pk)
+{
+    ssl_debug_printf("ssl_decrypt_pre_master_secret: impossible without glutls."
+        " ssl %p entrypted_pre_master %p pk %p\n", ssl_session,
+        entrypted_pre_master, pk);
+    return 0;
+}
+
+int ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, 
+        const unsigned char* in, int inl,unsigned char*out,int* outl)
+{
+    ssl_debug_printf("ssl_decrypt_record: impossible without gnutls. ssl %p"
+        "decoder %p ct %d, in %p inl %d out %p outl %d\n", ssl, decoder, ct,
+        in, inl, out, outl);
+    return 0;
+}
+
+#endif
+
+/* get ssl data for this session. if no ssl data is found allocate a new one*/
+SslDecryptSession* ssl_alloc_session(void)
+{
+    SslDecryptSession*ssl_session = g_malloc0(sizeof(SslDecryptSession));
+    if (!ssl_session) 
+        return NULL;
+
+    ssl_debug_printf("ssl_alloc_session ptr %p size %d\n", 
+        ssl_session, sizeof(SslDecryptSession));
+
+    ssl_session->master_secret.data = ssl_session->_master_secret;
+    ssl_session->session_id.data = ssl_session->_session_id;
+    ssl_session->client_random.data = ssl_session->_client_random;
+    ssl_session->server_random.data = ssl_session->_server_random;
+    ssl_session->master_secret.data_len = 48;
+    return ssl_session;
+}
+
+int ssl_data_init(StringInfo* str, unsigned char* src, unsigned int len)
+{
+    str->data = g_realloc(str->data,len);
+    if (!str->data)
+        return -1;
+    if (src)
+        memcpy(str->data, src,len);
+    str->data_len = len;
+    return 0;
+}
+
+int ssl_data_alloc(StringInfo* str, unsigned int len)
+{
+    str->data = g_malloc(len);
+    if (!str->data)
+        return -1;
+    str->data_len = len;
+    return 0;
+}
+
+int ssl_data_set(StringInfo* str, unsigned char* data, unsigned int len)
+{
+    memcpy(str->data, data, len);
+    str->data_len = len;
+    return 0;
+}
+
+#ifdef SSL_DECRYPT_DEBUG
+void ssl_debug_printf(char* fmt, ...)
+{
+  va_list ap;
+  int ret=0;
+  va_start(ap, fmt);
+  ret += vfprintf(stderr, fmt, ap);
+  va_end(ap);
+}
+
+
+void ssl_print_text_data(const char* name, const unsigned char* data, int len)
+{
+    int i;
+    fprintf(stderr,"%s: ",name);
+    for (i=0; i< len; i++) {
+      fprintf(stderr,"%c",data[i]);
+    }
+    fprintf(stderr,"\n");
+}
+
+void ssl_print_data(const char* name, const unsigned char* data, int len)
+{
+    int i;
+    fprintf(stderr,"%s[%d]:\n",name, len);
+    for (i=0; i< len; i++) {
+        if ((i>0) && (i%16 == 0))
+            fprintf(stderr,"\n");
+        fprintf(stderr,"%.2x ",data[i]&255);
+    }
+    fprintf(stderr,"\n");
+}
+
+void ssl_print_string(const char* name, const StringInfo* data)
+{
+    ssl_print_data(name, data->data, data->data_len);
+}
+#endif
diff -uNr ethereal-0.10.13/epan/dissectors/packet-ssl-utils.h ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.h
--- ethereal-0.10.13/epan/dissectors/packet-ssl-utils.h	1970-01-01 01:00:00.000000000 +0100
+++ ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.h	2005-12-07 09:51:53.000000000 +0100
@@ -0,0 +1,145 @@
+#ifndef __SSL_UTILS_H_
+#define __SSL_UTILS_H_
+
+#ifdef HAVE_LIBGNUTLS
+#include <stdio.h>
+#include <gcrypt.h>
+#include <gnutls/x509.h>
+#include <gnutls/openssl.h>
+
+#define SSL_DECRYPT_DEBUG
+
+#define SSL_CIPHER_CTX gcry_cipher_hd_t
+#ifdef SSL_FAST
+#define SSL_PRIVATE_KEY gcry_mpi_t
+#else
+#define SSL_PRIVATE_KEY struct gcry_sexp
+#endif
+#define SSL_LIB_INIT gnutls_global_init
+#else 
+#define SSL_CIPHER_CTX void*
+#define SSL_PRIVATE_KEY void
+#define SSL_LIB_INIT()
+#endif
+
+#include <netinet/in.h>
+
+typedef struct _StringInfo {
+    unsigned char* data;
+    unsigned int data_len;
+} StringInfo;
+
+#define SSL_WRITE_KEY           1
+
+#define SSLV3_VERSION          0x300
+#define TLSV1_VERSION          0x301
+
+#define SSL_CLIENT_RANDOM       1
+#define SSL_SERVER_RANDOM       2
+#define SSL_CIPHER              4
+#define SSL_HAVE_SESSION_KEY    8    
+#define SSL_VERSION             0x10
+#define SSL_MASTER_SECRET       0x20
+
+#define SSL_CIPHER_MODE_STREAM  0
+#define SSL_CIPHER_MODE_CBC     1
+
+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;
+} SslCipherSuite;
+
+typedef struct _SslDecoder {
+    SslCipherSuite* cipher_suite;
+    unsigned char _mac_key[20];
+    StringInfo decrypted_data;
+    StringInfo mac_key;
+    SSL_CIPHER_CTX evp;    
+    u_int32_t seq;
+} SslDecoder;
+
+#define KEX_RSA         0x10
+#define KEX_DH          0x11
+
+#define SIG_RSA         0x20
+#define SIG_DSS         0x21
+#define SIG_NONE        0x22
+
+#define ENC_DES         0x30
+#define ENC_3DES        0x31
+#define ENC_RC4         0x32
+#define ENC_RC2         0x33
+#define ENC_IDEA        0x34
+#define ENC_AES         0x35
+#define ENC_AES256      0x36
+#define ENC_NULL        0x37
+
+#define DIG_MD5         0x40
+#define DIG_SHA         0x41
+
+/*typedef struct _SslService {
+    address addr;
+    guint port;
+} SslService;*/
+
+typedef struct _SslDecryptSession {
+    unsigned char _master_secret[48];
+    unsigned char _session_id[256];
+    unsigned char _client_random[32];
+    unsigned char _server_random[32];
+    StringInfo session_id;
+    StringInfo server_random;
+    StringInfo client_random;
+    StringInfo master_secret;
+    StringInfo pre_master_secret;
+    
+    int cipher;
+    int state;
+    SslCipherSuite cipher_suite;
+    SslDecoder server;
+    SslDecoder client;
+    SSL_PRIVATE_KEY* private_key;
+    u_int32_t version;
+    u_int16_t version_netorder;  
+} SslDecryptSession;
+
+SslDecryptSession* ssl_alloc_session(void);
+int ssl_data_alloc(StringInfo* str, unsigned int len);
+int ssl_data_set(StringInfo* data, unsigned char* src, unsigned int len);
+int ssl_data_init(StringInfo* data, unsigned char* src, unsigned int len);
+
+
+SSL_PRIVATE_KEY* ssl_load_key(FILE* fp);
+
+int ssl_find_cipher(int num,SslCipherSuite* cs);
+
+int ssl_generate_keyring_material(SslDecryptSession*ssl_session);
+
+int ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, 
+    StringInfo* entrypted_pre_master, SSL_PRIVATE_KEY *pk);
+
+int ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, 
+        const unsigned char* in, int inl,unsigned char*out,int* outl);
+
+#ifdef SSL_DECRYPT_DEBUG
+void ssl_debug_printf(char* fmt,...);
+void ssl_print_data(const char* name, const unsigned char* data, int len);
+void ssl_print_string(const char* name, const StringInfo* data);
+void ssl_print_text_data(const char* name, const unsigned char* data, int len);
+#else
+static inline char* ssl_debug_printf(char* fmt,...) { return fmt; }
+#define ssl_print_data(a, b, c)
+#define ssl_print_string(a, b)
+#define ssl_print_text_data(a, b, c)
+#endif
+
+#endif
diff -uNr ethereal-0.10.13/Makefile.am ethereal-0.10.13-patch/Makefile.am
--- ethereal-0.10.13/Makefile.am	2005-10-10 15:23:13.000000000 +0200
+++ ethereal-0.10.13-patch/Makefile.am	2005-12-07 09:51:53.000000000 +0100
@@ -281,7 +281,8 @@
 	@SNMP_LIBS@ @SSL_LIBS@ 		\
 	$(plugin_ldadd)			\
 	@PCRE_LIBS@			\
-	@PCAP_LIBS@ @GTK_LIBS@ @ADNS_LIBS@ @KRB5_LIBS@ @FRAMEWORKS@
+	@PCAP_LIBS@ @GTK_LIBS@ @ADNS_LIBS@ @KRB5_LIBS@ @FRAMEWORKS@ \
+	@LIBGNUTLS_LIBS@
 
 # Additional libs that I know how to build. These will be
 # linked into the tethereal executable.
@@ -303,7 +304,8 @@
 	$(plugin_ldadd)			\
 	@PCRE_LIBS@			\
 	@GLIB_LIBS@ -lm			\
-	@PCAP_LIBS@ @SOCKET_LIBS@ @NSL_LIBS@ @ADNS_LIBS@ @KRB5_LIBS@
+	@PCAP_LIBS@ @SOCKET_LIBS@ @NSL_LIBS@ @ADNS_LIBS@ @KRB5_LIBS@ \
+	@LIBGNUTLS_LIBS@
 
 if ENABLE_STATIC
 tethereal_LDFLAGS = -Wl,-static -all-static
@@ -419,7 +421,8 @@
 	$(plugin_ldadd)			\
 	@PCRE_LIBS@			\
 	@GLIB_LIBS@ -lm			\
-	@PCAP_LIBS@ @SOCKET_LIBS@ @NSL_LIBS@ @ADNS_LIBS@ @KRB5_LIBS@
+	@PCAP_LIBS@ @SOCKET_LIBS@ @NSL_LIBS@ @ADNS_LIBS@ @KRB5_LIBS@ \
+	@LIBGNUTLS_LIBS@
 
 dftest_LDFLAGS = -export-dynamic