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: Mon, 05 Dec 2005 10:18:16 +0100
On Mon, 2005-12-05 at 00:48 +0100, Joerg Mayer wrote:
> When the packages containing the libs are present, but the development
> stuff is missing, configure fails. The proper way to handle this should
> be to disable this feature and continue.

Well the idea was to implement ssl decryption. That is impossible
without the crypto libraries, and thus the patch is useless without
them :-). Anyway if there is any interest in the decryption
functionality I can rework the patch. 

> Also, the necessary changes to epan/dissctors/Makefile.common are
> missing.
> Compiling gives a lot of warnings, the list is attached.

I see... I posted a second version of the patch on November 28 with the
required changes to epan/dissctors/Makefile.common and some warning fix.
Anyway some issues where still present. The attached version should work
better and (at least on my machine) does not produce compilation warning

ciao,

Paolo Abeni








 
 
 --
 Email.it, the professional e-mail, gratis per te: http://www.email.it/f
 
 Sponsor:
 Natsabe.it la pi� grande erboristeria multimarca online.
* Solo prodotti di altissima qualit�. 
* 
 Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=1308&d=5-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-11-30 14:48:57.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/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-11-30 14:48:57.000000000 +0100
@@ -63,6 +63,12 @@
 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, , [
+	AC_MSG_ERROR([[gnuTLS not found; install gnuTLS-devel package for your system]])
+])        
+        
+
 # Check for xsltproc
 AC_PATH_PROG(XSLTPROC, xsltproc)
 AC_CHECK_PROG(HAVE_XSLTPROC, xsltproc, "yes", "no")
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-11-30 14:48:57.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-11-30 14:48:57.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,90 @@
 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;
+
+
+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 GHashTable *ssl_session_hash = NULL;
+static GHashTable *ssl_key_hash = NULL;
+
 /* The TCP port to associate with by default */
 #define TCP_PORT_SSL                    443
 #define TCP_PORT_SSL_LDAP               636
@@ -704,7 +795,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 +813,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 +837,7 @@
 static void dissect_ssl3_hnd_finished(tvbuff_t *tvb,
                                       proto_tree *tree,
                                       guint32 offset,
-                                      guint *conv_version);
+                                      guint* conv_version);
 
 
 /*
@@ -754,12 +849,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 +891,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 +906,9 @@
 static int  ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb,
                                                guint32 offset,
                                                guint32 record_length);
-
+static SslAssociation* ssl_find_association(packet_info* pinfo);
+static void ssl_save_session(SslDecryptSession* ssl);
+static void ssl_restore_session(SslDecryptSession* ssl);
 /*********************************************************************
  *
  * Main dissector
@@ -824,12 +923,15 @@
 
     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;
+    int from_server;
+    SslDecryptSession* ssl_session;
+    SslService dummy;
+    guint* conv_version;
 
     /* Track the version using conversations to reduce the
      * chance that a packet that simply *looks* like a v2 or
@@ -852,11 +954,47 @@
                                         pinfo->srcport, pinfo->destport, 0);
     }
     conv_data = conversation_get_proto_data(conversation, proto_ssl);
-    if (conv_data != NULL)
-    {
-        conv_version = GPOINTER_TO_UINT(conv_data);
+    
+    /* PAOLO: manage ssl decryption data */
+
+    /* we need to know witch side of conversation is speaking*/
+    if (ssl_packet_from_server(pinfo->srcport)) {
+        from_server = 1;
+        dummy.addr = pinfo->net_src;
+        dummy.port = pinfo->srcport;
+    }
+    else {
+        from_server = 0;
+        dummy.addr = pinfo->net_dst;
+        dummy.port = pinfo->destport;
     }
 
+    /*get a valid ssl session pointer*/ 
+    if (conv_data != NULL)
+        ssl_session = conv_data;
+    else {
+        ssl_session= ssl_alloc_session();
+        ssl_session->version = SSL_VER_UNKNOWN;
+        conversation_add_proto_data(conversation, proto_ssl, ssl_session);
+        
+        /* try to retrive private key for this service. Do it now 'cause pinfo
+         * is not always available*/
+        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
      * throw an exception before we get the chance to do so). */
@@ -910,12 +1048,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 +1068,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 +1089,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 +1115,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 +1124,84 @@
         /* 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 +1211,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 +1240,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 +1361,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 +1400,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 +1413,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 +1442,52 @@
             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)
+         {
+             /* 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 */
+             tvbuff_t* 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 +1505,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 +1528,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 +1572,7 @@
         if (check_col(pinfo->cinfo, COL_INFO))
             col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Alert");
     }
-
+    
     if (tree)
     {
         if (level && desc)
@@ -1325,7 +1603,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 +1646,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 +1706,22 @@
 
         /* 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)
         {
+            /* PAOLO: variables for session key creation*/
+            StringInfo encrypted_pre_master;
+            int ret;
+    
             /* 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 +1732,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 +1759,46 @@
                 /* 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*/
+                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 +1809,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 +1818,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 +1893,9 @@
         }
 
     }
-    return offset - initial_offset;
+    
+    // XXXX
+    return session_id_length+33;
 }
 
 static int
@@ -1591,7 +1953,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 +1973,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 +2072,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 +2085,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 +2311,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 +2358,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 +2459,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 +2568,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 +2621,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 +2644,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 +2653,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 +2709,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 +2736,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 +3304,7 @@
  * Support Functions
  *
  *********************************************************************/
-
+#if 0
 static void
 ssl_set_conv_version(packet_info *pinfo, guint version)
 {
@@ -2895,6 +3335,7 @@
     }
     conversation_add_proto_data(conversation, proto_ssl, GINT_TO_POINTER(version));
 }
+#endif
 
 static int
 ssl_is_valid_handshake_type(guint8 type)
@@ -3175,6 +3616,108 @@
     return 0;
 }
 
+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");
+}
 
 /*********************************************************************
  *
@@ -3222,6 +3765,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 +4046,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 +4138,31 @@
              "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
@@ -3605,8 +4175,22 @@
     dissector_handle_t ssl_handle;
 
     ssl_handle = find_dissector("ssl");
+    
+    dissector_table_t 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-11-30 14:48:57.000000000 +0100
@@ -0,0 +1,1110 @@
+/* packet-ss-utils.c
+ *
+ * $Id: ethereal_ssl_decrypt_0.10.13.patch,v 1.8 2005/11/30 12:47:40 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>
+
+#define SSL_DECRYPT_DEBUG
+
+#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_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;
+}
+
+void ssl_debug_printf(char* fmt,...)
+{
+#ifdef SSL_DECRYPT_DEBUG
+  va_list ap;
+  int ret=0;
+  va_start(ap, fmt);
+  ret += vfprintf(stderr, fmt, ap);
+  va_end(ap);
+#endif
+}
+
+
+void ssl_print_text_data(const char* name, const unsigned char* data, int len)
+{
+#ifdef SSL_DECRYPT_DEBUG    
+    int i;
+    fprintf(stderr,"%s: ",name);
+    for (i=0; i< len; i++) {
+      fprintf(stderr,"%c",data[i]);
+    }
+    fprintf(stderr,"\n");
+#endif    
+}
+
+void ssl_print_data(const char* name, const unsigned char* data, int len)
+{
+#ifdef SSL_DECRYPT_DEBUG    
+    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");
+#endif    
+}
+
+void ssl_print_string(const char* name, const StringInfo* data)
+{
+#ifdef SSL_DECRYPT_DEBUG    
+    ssl_print_data(name, data->data, data->data_len);
+#endif    
+}
+
+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;
+}
+
+/* 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;
+}
+
+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    
+}
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-11-30 14:48:57.000000000 +0100
@@ -0,0 +1,127 @@
+#ifndef __SSL_UTILS_H_
+#define __SSL_UTILS_H_
+
+#include <stdio.h>
+#include <gcrypt.h>
+#include <gnutls/x509.h>
+#include <gnutls/openssl.h>
+#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
+
+//#include <epan/address.h>
+#include <netinet/in.h>
+
+typedef struct _StringInfo {
+    unsigned char* data;
+    unsigned int data_len;
+} StringInfo;
+
+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);
+SSL_PRIVATE_KEY* ssl_load_key(FILE* fp);
+
+#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;
+
+
+int ssl_data_set(StringInfo* data, unsigned char* src, unsigned int len);
+int ssl_data_init(StringInfo* data, unsigned char* src, unsigned int len);
+
+SslDecryptSession* ssl_alloc_session(void);
+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);
+#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-11-30 14:48:57.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