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





