Ethereal-dev: [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: Thu, 24 Nov 2005 17:02:29 +0100
hi all, The attached patch is an updated version of the previous one I posted some time ago. I reworked a large part of the code. It links against gnutls and support also the AES encryption algorithm. The patch modify some autoconf related files, so you need to invoke 'autogen.sh' after applying the patch. A few notes: You need the gnutls and libgcrypt devel package to compile the patched version of ethereal. To activate the decryption: - start ethereal - edit the preference - search and select the SSL item in the Protocol list - put into the 'RSA private keys list' field the private key information in the following format: <1# host IP>:<port>:<RSA private key file used from ssl>[, <IP>:KEY] - start the capture Even with the private key, only RSA key exchange can 'opened'/decrypted. To be sure that your apache web server use only RSA Key Exchange, find the SSLCipherSuite diirective in the configuration file and add at the end of that line: ':!DH:!EDH:!ADH' (without the quote '). If your configuration does not contain the SSLCiperSuite directive (and thus you are using the default value), simply add the following line to your config file: SSLCipherSuite ALL:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:!DH:! EDH:!ADH This will disable all non RSA key exchange. Find the SSLCertificateKeyFile directive. That will tell you the path of the RSA private key. Copy it on the host where ethereal is installed. If you can't find the SSLCertificateKeyFile directive, look for the SSLCertificateFile directive. The full path of the key file on the host running ethereal is what you need to put into the 'RSA private keys list' in SSL protocol preference (see above). SSLv2 record are just ignored by the decryption code: it's possible to decrypt only SSLv3/TLS1 sessions. best regards, Paolo Abeni -- Email.it, the professional e-mail, gratis per te: http://www.email.it/f Sponsor: Vuoi bere tanta acqua pura e risparmiare ben 495 euro all'anno? * Con BeviSano avrai finito di comprare acqua in bottiglia - clicca qui Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=3628&d=24-11
diff -uNr ethereal-0.10.13/acinclude.m4 ethereal-0.10.13-patch/acinclude.m4 --- ethereal-0.10.13/acinclude.m4 2005-10-10 15:23:13.000000000 +0200 +++ ethereal-0.10.13-patch/acinclude.m4 2005-11-08 10:28:21.000000000 +0100 @@ -1268,3 +1268,161 @@ fi AC_SUBST(KRB5_LIBS) ]) + +dnl Autoconf macros for libgnutls +dnl $id$ + +# Modified for LIBGNUTLS -- nmav +# Configure paths for LIBGCRYPT +# Shamelessly stolen from the one of XDELTA by Owen Taylor +# Werner Koch 99-12-09 + +dnl AM_PATH_LIBGNUTLS([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgnutls, and define LIBGNUTLS_CFLAGS and LIBGNUTLS_LIBS +dnl +AC_DEFUN([AM_PATH_LIBGNUTLS], +[dnl +dnl Get the cflags and libraries from the libgnutls-config script +dnl +AC_ARG_WITH(libgnutls-prefix, + [ --with-libgnutls-prefix=PFX Prefix where libgnutls is installed (optional)], + libgnutls_config_prefix="$withval", libgnutls_config_prefix="") + + if test x$libgnutls_config_prefix != x ; then + if test x${LIBGNUTLS_CONFIG+set} != xset ; then + LIBGNUTLS_CONFIG=$libgnutls_config_prefix/bin/libgnutls-config + fi + fi + + AC_PATH_PROG(LIBGNUTLS_CONFIG, libgnutls-config, no) + min_libgnutls_version=ifelse([$1], ,0.1.0,$1) + AC_MSG_CHECKING(for libgnutls - version >= $min_libgnutls_version) + no_libgnutls="" + if test "$LIBGNUTLS_CONFIG" = "no" ; then + no_libgnutls=yes + else + LIBGNUTLS_CFLAGS=`$LIBGNUTLS_CONFIG $libgnutls_config_args --cflags` + LIBGNUTLS_LIBS=`$LIBGNUTLS_CONFIG $libgnutls_config_args --libs` + libgnutls_config_version=`$LIBGNUTLS_CONFIG $libgnutls_config_args --version` + + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS" + LIBS="$LIBS $LIBGNUTLS_LIBS" +dnl +dnl Now check if the installed libgnutls is sufficiently new. Also sanity +dnl checks the results of libgnutls-config to some extent +dnl + rm -f conf.libgnutlstest + AC_TRY_RUN([ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <gnutls/gnutls.h> + +int +main () +{ + system ("touch conf.libgnutlstest"); + + if( strcmp( gnutls_check_version(NULL), "$libgnutls_config_version" ) ) + { + printf("\n*** 'libgnutls-config --version' returned %s, but LIBGNUTLS (%s)\n", + "$libgnutls_config_version", gnutls_check_version(NULL) ); + printf("*** was found! If libgnutls-config was correct, then it is best\n"); + printf("*** to remove the old version of LIBGNUTLS. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If libgnutls-config was wrong, set the environment variable LIBGNUTLS_CONFIG\n"); + printf("*** to point to the correct copy of libgnutls-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } + else if ( strcmp(gnutls_check_version(NULL), LIBGNUTLS_VERSION ) ) + { + printf("\n*** LIBGNUTLS header file (version %s) does not match\n", LIBGNUTLS_VERSION); + printf("*** library (version %s)\n", gnutls_check_version(NULL) ); + } + else + { + if ( gnutls_check_version( "$min_libgnutls_version" ) ) + { + return 0; + } + else + { + printf("no\n*** An old version of LIBGNUTLS (%s) was found.\n", + gnutls_check_version(NULL) ); + printf("*** You need a version of LIBGNUTLS newer than %s. The latest version of\n", + "$min_libgnutls_version" ); + printf("*** LIBGNUTLS is always available from ftp://gnutls.hellug.gr/pub/gnutls.\n"); + printf("*** \n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the libgnutls-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of LIBGNUTLS, but you can also set the LIBGNUTLS_CONFIG environment to point to the\n"); + printf("*** correct copy of libgnutls-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_libgnutls=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_libgnutls" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + if test -f conf.libgnutlstest ; then + : + else + AC_MSG_RESULT(no) + fi + if test "$LIBGNUTLS_CONFIG" = "no" ; then + echo "*** The libgnutls-config script installed by LIBGNUTLS could not be found" + echo "*** If LIBGNUTLS was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the LIBGNUTLS_CONFIG environment variable to the" + echo "*** full path to libgnutls-config." + else + if test -f conf.libgnutlstest ; then + : + else + echo "*** Could not run libgnutls test program, checking why..." + CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS" + LIBS="$LIBS $LIBGNUTLS_LIBS" + AC_TRY_LINK([ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <gnutls/gnutls.h> +], [ return !!gnutls_check_version(NULL); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding LIBGNUTLS or finding the wrong" + echo "*** version of LIBGNUTLS. If it is not finding LIBGNUTLS, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means LIBGNUTLS was incorrectly installed" + echo "*** or that you have moved LIBGNUTLS since it was installed. In the latter case, you" + echo "*** may want to edit the libgnutls-config script: $LIBGNUTLS_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + LIBGNUTLS_CFLAGS="" + LIBGNUTLS_LIBS="" + ifelse([$3], , :, [$3]) + fi + rm -f conf.libgnutlstest + AC_SUBST(LIBGNUTLS_CFLAGS) + AC_SUBST(LIBGNUTLS_LIBS) +]) diff -uNr ethereal-0.10.13/configure.in ethereal-0.10.13-patch/configure.in --- ethereal-0.10.13/configure.in 2005-10-14 21:10:13.000000000 +0200 +++ ethereal-0.10.13-patch/configure.in 2005-11-08 10:28:21.000000000 +0100 @@ -63,6 +63,12 @@ AC_CHECK_PROG(HAVE_DOXYGEN, doxygen, "yes", "no") AM_CONDITIONAL(HAVE_DOXYGEN, test x$HAVE_DOXYGEN = xyes) +# gnu tls +AM_PATH_LIBGNUTLS(1.0.0, , [ + AC_MSG_ERROR([[gnuTLS not found; install gnuTLS-devel package for your system]]) +]) + + # Check for xsltproc AC_PATH_PROG(XSLTPROC, xsltproc) AC_CHECK_PROG(HAVE_XSLTPROC, xsltproc, "yes", "no") diff -uNr ethereal-0.10.13/epan/dissectors/packet-ssl.c ethereal-0.10.13-patch/epan/dissectors/packet-ssl.c --- ethereal-0.10.13/epan/dissectors/packet-ssl.c 2005-10-10 15:23:04.000000000 +0200 +++ ethereal-0.10.13-patch/epan/dissectors/packet-ssl.c 2005-11-08 10:28:21.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,75 @@ static gint ett_pct_cert_suites = -1; static gint ett_pct_exch_suites = -1; +typedef struct { + unsigned int ssl_port; + dissector_handle_t handle; + char* info; +} SslDissector; + +static char* ssl_keys_list = "127.0.0.1:443:/etc/ssl/apache2/server.key"; +static SslDissector ssl_dissectors[] = { + {443, 0, "Hypertext transfer protocol"}, /* https */ + {636, 0, "Lightweight directory access protocol"}, /* ldap */ + {993, 0, "Interactive mail access protocol"}, /* imap */ + {995, 0, "Post office protocol"}, /* pop3 */ + {0, 0, 0}}; + +typedef struct _SslService { + address addr; + guint port; +} SslService; + +/* Hash Functions */ +static gint ssl_equal (gconstpointer v, gconstpointer v2) +{ + const StringInfo *val1 = (const StringInfo *)v; + const StringInfo *val2 = (const StringInfo *)v2; + + if (val1->data_len == val2->data_len && + !memcmp(val1->data, val2->data, val2->data_len)) { + return 1; + } + return 0; +} + +static guint ssl_hash (gconstpointer v) +{ + guint l,hash = 0; + StringInfo* id = (StringInfo*) v; + guint* cur = (guint*) id->data; + for (l=4; (l<id->data_len); l+=4, cur++) + hash = hash ^ (*cur); + + return hash; +} +static gint ssl_private_key_equal (gconstpointer v, gconstpointer v2) +{ + const SslService *val1 = (const SslService *)v; + const SslService *val2 = (const SslService *)v2; + + if ((val1->port == val2->port) && + ! CMP_ADDRESS(&val1->addr, &val2->addr)) { + return 1; + } + return 0; +} + +static guint ssl_private_key_hash (gconstpointer v) +{ + const SslService *key = (const SslService *)v; + guint l,hash = key->port, len = key->addr.len; + + guint* cur = (guint*) key->addr.data; + for (l=4; (l<len); l+=4, cur++) + hash = hash ^ (*cur); + + return hash; +} + +static GHashTable *ssl_session_hash = NULL; +static GHashTable *ssl_key_hash = NULL; + /* The TCP port to associate with by default */ #define TCP_PORT_SSL 443 #define TCP_PORT_SSL_LDAP 636 @@ -704,7 +780,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, @@ -715,22 +792,26 @@ /* alert message dissector */ static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version); + guint *conv_version, + SslDecryptSession *conv_data); /* handshake protocol dissector */ 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 +823,7 @@ static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, proto_tree *tree, guint32 offset, - guint *conv_version); + guint* conv_version); /* @@ -754,12 +835,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 +877,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 +892,9 @@ static int ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, guint32 offset, guint32 record_length); - +static SslDissector* ssl_find_dissector(packet_info* pinfo); +static void ssl_save_session(SslDecryptSession* ssl); +static void ssl_restore_session(SslDecryptSession* ssl); /********************************************************************* * * Main dissector @@ -824,12 +909,15 @@ conversation_t *conversation; void *conv_data; - guint conv_version = SSL_VER_UNKNOWN; proto_item *ti = NULL; proto_tree *ssl_tree = NULL; guint32 offset = 0; gboolean first_record_in_frame = TRUE; gboolean need_desegmentation; + int from_server; + SslDecryptSession* ssl_session; + SslService dummy; + guint* conv_version; /* Track the version using conversations to reduce the * chance that a packet that simply *looks* like a v2 or @@ -852,11 +940,46 @@ pinfo->srcport, pinfo->destport, 0); } conv_data = conversation_get_proto_data(conversation, proto_ssl); - if (conv_data != NULL) - { - conv_version = GPOINTER_TO_UINT(conv_data); + + /* PAOLO: manage ssl decryption data */ + + /* we need to know witch side of conversation is speaking*/ + if (ssl_packet_from_server(pinfo->srcport)) { + from_server = 1; + dummy.addr = pinfo->net_src; + dummy.port = pinfo->srcport; + } + else { + from_server = 0; + dummy.addr = pinfo->net_dst; + dummy.port = pinfo->destport; } + /*get a valid ssl session pointer*/ + if (conv_data != NULL) + ssl_session = conv_data; + else { + ssl_session= ssl_alloc_session(); + ssl_session->version = SSL_VER_UNKNOWN; + conversation_add_proto_data(conversation, proto_ssl, ssl_session); + + /* try to retrive private key for this service. Do it now 'cause pinfo + * is not always available*/ + ssl_session->private_key = g_hash_table_lookup(ssl_key_hash, &dummy); + if (!ssl_session->private_key) { + ssl_debug_printf("dissect_ssl can't find private key for " + "%hhd.%hhd.%hhd.%hhd:%d\n", dummy.addr.data[0], + dummy.addr.data[1],dummy.addr.data[2], + dummy.addr.data[3],dummy.port); + } + } + conv_version= & ssl_session->version; + + /* try do decryption only the first time we see this packet and if we have + * the server private key*/ + if (!ssl_session->private_key || pinfo->fd->flags.visited) + ssl_session = NULL; + /* Initialize the protocol column; we'll set it later when we * figure out what flavor of SSL it is (assuming we don't * throw an exception before we get the chance to do so). */ @@ -910,12 +1033,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 +1053,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 +1074,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 +1100,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,15 +1109,6 @@ /* 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; } @@ -1005,7 +1124,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 +1153,7 @@ proto_tree *ti = NULL; proto_tree *ssl_record_tree = NULL; guint32 available_bytes = 0; + StringInfo* decrypted; available_bytes = tvb_length_remaining(tvb, offset); @@ -1152,12 +1273,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 +1312,7 @@ /* * now dissect the next layer */ + ssl_debug_printf("dissect_ssl3_record: content_type %d\n",content_type); switch (content_type) { case SSL_ID_CHG_CIPHER_SPEC: if (check_col(pinfo->cinfo, COL_INFO)) @@ -1191,17 +1322,18 @@ break; case SSL_ID_ALERT: dissect_ssl3_alert(tvb, pinfo, ssl_record_tree, offset, - conv_version); + conv_version, ssl); break; case SSL_ID_HANDSHAKE: 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 (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 +1341,113 @@ tvb_ensure_bytes_exist(tvb, offset, record_length); proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb, offset, record_length, 0); - } + } + + /* PAOLO: test if any decrypted data is attached to this packet*/ + if (ssl) + { + /* first time we visit this packet: try to decrypt appdata */ + int len; + SslDecoder* decoder; + StringInfo* data; + + /* retrive decoder for this packet direction*/ + if (ssl_packet_from_server(pinfo->srcport)) + decoder = &ssl->server; + else + decoder = &ssl->client; + ssl_debug_printf("dissect_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) { + if (record_length > decoder->decrypted_data.data_len) + { + ssl_debug_printf("dissect_ssl3_record allocating decrypt %d bytes for decrypt data\n", record_length + 32); + ssl_data_init(&decoder->decrypted_data, NULL, record_length + 32); + } + 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) { + data = p_get_proto_data(pinfo->fd, proto_ssl); + + if (!data) + { + ssl_debug_printf("dissect_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 = ((char*)data) + sizeof(StringInfo); + ssl_data_set(data, decoder->decrypted_data.data, len); + } + else { + /* update previus record*/ + ssl_debug_printf("dissect_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= ((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("dissect_ssl3_record removing old app_data ptr\n"); + p_rem_proto_data(pinfo->fd, proto_ssl); + } + + ssl_debug_printf("dissect_ssl3_record setting decrypted app_data ptr %p\n",data); + p_add_proto_data(pinfo->fd, proto_ssl, data); + } + } + } + + /* 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*/ + SslDissector* dissector = ssl_find_dissector(pinfo); + + /* show on info colum what we are decoding */ + if (check_col(pinfo->cinfo, COL_INFO) && dissector) + { + ssl_debug_printf("adding COL_INFO %s\n",dissector->info); + col_clear(pinfo->cinfo, COL_INFO); + col_append_str(pinfo->cinfo, COL_INFO, dissector->info); + } + + /* show decrypted data info, if available */ + decrypted = p_get_proto_data(pinfo->fd, proto_ssl); + if (decrypted && ssl_record_tree) + { + /* try to dissect decrypted data*/ + ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", decrypted->data_len); + + /* create new tvbuff for the decrypted data */ + tvbuff_t* new_tvb = tvb_new_real_data(decrypted->data, + decrypted->data_len, decrypted->data_len); + + /* XXXX is this correct ?!? */ + 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 (dissector) { + ssl_debug_printf("dissect_ssl3_record found dissector %p\n", dissector); + ssl_print_text_data("decrypted app data",decrypted->data, + decrypted->data_len); + + call_dissector(dissector->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, 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 +1465,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 +1488,8 @@ static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version) + guint* conv_version, + SslDecryptSession* ssl) { /* struct { * AlertLevel level; @@ -1294,6 +1533,10 @@ if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Alert"); } + + /*PAOLO XXX must i decrypt encrypted alert ?!? */ + if (ssl) + ssl_debug_printf("XXXX alert decryption unhandled\n"); if (tree) { @@ -1325,7 +1568,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 +1611,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 @@ -1426,16 +1672,48 @@ /* if we don't have a valid handshake type, just quit dissecting */ if (!msg_type_str) { + /*PAOLO: this is (shold be) an encrypted message. we must + * try to decrypt it to keep decoder state 'aligned'*/ + SslDecoder* decoder; + int len = record_length - offset; + int outlen; + + /* can we try do to decryption ?!?*/ + if (!ssl) + return; + + /* retrive the decoder for this direction*/ + if (ssl_packet_from_server(pinfo->srcport)) + decoder = &ssl->server; + else + decoder = &ssl->client; + + /* run the decoder if we have the session key*/ + ssl_debug_printf("dissect_ssl3_handshake encrypted handshake msg len %d ssl state %X\n", + len, ssl->state); + if (abs(len) > decoder->decrypted_data.data_len) + ssl_data_init(&decoder->decrypted_data, 0, len+32); + outlen = decoder->decrypted_data.data_len; + if (ssl->state & SSL_HAVE_SESSION_KEY) + ssl_decrypt_record(ssl, decoder, content_type, tvb_get_ptr(tvb, offset, len), + len, decoder->decrypted_data.data, &outlen); return; } - - if (ssl_hand_tree) - { + + /* PAOLO: if we are doing ssl decryption we must dissect some requests type */ + if (ssl_hand_tree || ssl) + { + /* PAOLO: variables for session key creation*/ + StringInfo encrypted_pre_master; + int ret; + /* add nodes for the message type and message length */ - proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type, - tvb, offset, 1, msg_type); + if (ssl_hand_tree) + proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type, + tvb, offset, 1, msg_type); offset++; - proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length, + if (ssl_hand_tree) + proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length, tvb, offset, 3, length); offset += 3; @@ -1446,11 +1724,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 +1751,46 @@ /* unimplemented */ break; - case SSL_HND_CLIENT_KEY_EXCHG: - /* unimplemented */ + case SSL_HND_CLIENT_KEY_EXCHG: + /* PAOLO: here we can have all the data to build session key*/ + if (!ssl) + break; + + /* check for required session data */ + ssl_debug_printf("dissect_ssl3_handshake found SSL_HND_CLIENT_KEY_EXCHG state %X\n", + ssl->state); + if ((ssl->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) != + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) { + ssl_debug_printf("dissect_ssl3_handshake not enough data to generate key (required %X)\n", + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)); + break; + } + + /* get encrypted data, we must skip tls record len && version and + * 2 bytes of record data */ + encrypted_pre_master.data = g_malloc(length - 2); + encrypted_pre_master.data_len = length-2; + tvb_memcpy(tvb, encrypted_pre_master.data, offset+2, length-2); + + if (!ssl->private_key) { + ssl_debug_printf("dissect_ssl3_handshake can't find private key\n"); + break; + } + + /* go with ssl key processessing*/ + ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key); + g_free(encrypted_pre_master.data); + if (ret < 0) { + ssl_debug_printf("dissect_ssl3_handshake can't decrypt pre master secret\n"); + break; + } + if (ssl_generate_keyring_material(ssl)<0) { + ssl_debug_printf("dissect_ssl3_handshake can't generate keyring material\n"); + break; + } + ssl->state |= SSL_HAVE_SESSION_KEY; + ssl_save_session(ssl); + ssl_debug_printf("dissect_ssl3_handshake session keys succesfully generated\n"); break; case SSL_HND_FINISHED: @@ -1485,9 +1801,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 +1810,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 +1885,9 @@ } } - return offset - initial_offset; + + // XXXX + return session_id_length+33; } static int @@ -1591,7 +1945,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 +1965,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 +2064,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 +2077,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 +2303,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 +2350,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 +2451,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 +2560,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 +2613,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; @@ -2864,7 +3259,7 @@ * Support Functions * *********************************************************************/ - +#if 0 static void ssl_set_conv_version(packet_info *pinfo, guint version) { @@ -2895,6 +3290,7 @@ } conversation_add_proto_data(conversation, proto_ssl, GINT_TO_POINTER(version)); } +#endif static int ssl_is_valid_handshake_type(guint8 type) @@ -3175,6 +3571,108 @@ return 0; } +static void ssl_init(void) +{ + if (ssl_session_hash) + g_hash_table_destroy(ssl_session_hash); + if (ssl_key_hash) + g_hash_table_destroy(ssl_key_hash); + + ssl_key_hash = g_hash_table_new(ssl_private_key_hash,ssl_private_key_equal); + ssl_session_hash = g_hash_table_new(ssl_hash, ssl_equal); + if (ssl_keys_list) + { + char* end; + char* start = strdup(ssl_keys_list); + char* tmp = start; + do { + char* addr, *port, *filename, *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 = ((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 = ((char*)master_secret+sizeof(StringInfo)); + session_id->data = ((char*)session_id+sizeof(StringInfo)); + ssl_data_set(session_id, ssl->session_id.data, ssl->session_id.data_len); + ssl_data_set(master_secret, ssl->master_secret.data, ssl->master_secret.data_len); + g_hash_table_insert(ssl_session_hash, session_id, master_secret); + ssl_print_string("ssl_save_session stored session id", session_id); + ssl_print_string("ssl_save_session stored master secret", master_secret); +} + +static void ssl_restore_session(SslDecryptSession* ssl) +{ + StringInfo* ms = g_hash_table_lookup(ssl_session_hash, &ssl->session_id); + if (!ms) { + ssl_debug_printf("ssl_restore_session can't find stored session\n"); + return; + } + ssl_data_set(&ssl->master_secret, ms->data, ms->data_len); + ssl->state |= SSL_MASTER_SECRET; + ssl_debug_printf("ssl_restore_session master key retrived\n"); +} /********************************************************************* * @@ -3222,6 +3720,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 +4001,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 +4093,31 @@ "Whether the SSL dissector should reassemble SSL records spanning multiple TCP segments. " "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", &ssl_desegment); + prefs_register_string_preference(ssl_module, "rsa_private_key", "RSA private keys list", + "comma separated list of RSA private key to be used for decryption; " + "each list entry must be in the form of <ip>:<port>:<key_file_name>", + &ssl_keys_list); + + } register_dissector("ssl", dissect_ssl, proto_ssl); + register_init_routine(ssl_init); + SSL_LIB_INIT(); +} +SslDissector* ssl_find_dissector(packet_info* pinfo) +{ + SslDissector* cur; + for (cur = ssl_dissectors; cur->ssl_port != 0; cur++) { + ssl_debug_printf("ssl_find_dissector cur port %d src port %d dest port %d\n", + cur->ssl_port, pinfo->srcport, pinfo->destport); + if (((cur->ssl_port == pinfo->srcport) || (cur->ssl_port == pinfo->destport)) && cur->handle) { + ssl_debug_printf("ssl_find_dissector found %p\n", cur->handle); + return cur; + } + } + return 0; } /* If this dissector uses sub-dissector registration add a registration @@ -3605,6 +4130,18 @@ dissector_handle_t ssl_handle; ssl_handle = find_dissector("ssl"); + + dissector_table_t tcp_dissectors = find_dissector_table( "tcp.port"); + if (tcp_dissectors) + { + ssl_dissectors[0].handle = dissector_get_port_handle(tcp_dissectors, 80); + ssl_dissectors[1].handle = dissector_get_port_handle(tcp_dissectors, 389); + ssl_dissectors[2].handle = dissector_get_port_handle(tcp_dissectors, 143); + ssl_dissectors[3].handle = dissector_get_port_handle(tcp_dissectors, 110); + } + ssl_debug_printf("http: %p ldap %p imap %p pop %p\n", ssl_dissectors[0].handle, + ssl_dissectors[1].handle, ssl_dissectors[2].handle, + ssl_dissectors[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); diff -uNr ethereal-0.10.13/epan/dissectors/packet-ssl-utils.c ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.c --- ethereal-0.10.13/epan/dissectors/packet-ssl-utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.c 2005-11-08 10:28:21.000000000 +0100 @@ -0,0 +1,1093 @@ +/* packet-ss-utils.c + * + * $Id: ethereal_ssl_decrypt_0.10.13.patch,v 1.5 2005/11/08 08:28:13 cvs Exp $ + * + * ssl manipulation functions + * By Paolo Abeni <paolo.abeni@xxxxxxxxx> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "packet-ssl-utils.h" + +#include <glib.h> + +#define SSL_DECRYPT_DEBUG + +#define SSL_HMAC gcry_md_hd_t +#define SSL_HMAC_INIT(md,key,len,algo) if (*(md)) gcry_md_close(*(md)); \ + gcry_md_open(md,algo, GCRY_MD_FLAG_HMAC); \ + gcry_md_setkey (*(md), key, len) +#define SSL_HMAC_UPDATE(md, data, len) gcry_md_write(*(md), data, len) +#define SSL_HMAC_FINAL(md, data, len) ({ int __algo = gcry_md_get_algo (*(md)); \ + int __len = gcry_md_get_algo_dlen (__algo);\ + memcpy(data, gcry_md_read(*(md), __algo), __len); \ + *len =__len;}) +#define SSL_HMAC_CLEANUP(md) gcry_md_close(*(md)) + +#define SSL_MD gcry_md_hd_t +#define SSL_MD_INIT(md,algo) if (*(md)) gcry_md_close(*(md)); \ + gcry_md_open(md,algo, 0); +#define SSL_MD_UPDATE(md, data, len) gcry_md_write(*(md), data, len) +#define SSL_MD_FINAL(md, data, len) ({ int __algo = gcry_md_get_algo (*(md)); \ + int __len = gcry_md_get_algo_dlen (__algo);\ + memcpy(data, gcry_md_read(*(md), __algo), __len); \ + *len =__len;}) +#define SSL_MD_CLEANUP(md) gcry_md_close(*(md)) + +#define SSL_SHA_CTX gcry_md_hd_t +#define SSL_SHA_INIT(md) if (*(md)) gcry_md_close(*(md)); \ + gcry_md_open(md,GCRY_MD_SHA1, 0); +#define SSL_SHA_UPDATE(md, data, len) gcry_md_write(*(md), data, len) +#define SSL_SHA_FINAL(buf, md) memcpy(buf, gcry_md_read(*(md), GCRY_MD_SHA1), \ + gcry_md_get_algo_dlen(GCRY_MD_SHA1)) + +#define SSL_MD5_CTX gcry_md_hd_t +#define SSL_MD5_INIT(md) if (*(md)) gcry_md_close(*(md)); \ + gcry_md_open(md,GCRY_MD_MD5, 0); +#define SSL_MD5_UPDATE(md, data, len) gcry_md_write(*(md), data, len) +#define SSL_MD5_FINAL(buf, md) memcpy(buf, gcry_md_read(*(md), GCRY_MD_MD5), \ + gcry_md_get_algo_dlen(GCRY_MD_MD5)) + +#define SSL_CIPHER_INIT(chiper, algo,sk,iv,enc) gcry_cipher_open(chiper, algo, \ + GCRY_CIPHER_MODE_STREAM, 0); \ + gcry_cipher_setkey(*(chiper), sk, gcry_cipher_get_algo_keylen (algo)); \ + gcry_cipher_setiv(*(chiper), iv, gcry_cipher_get_algo_blklen (algo)) +#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, char* encr_data, 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; + 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; +} + + +#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" +}; + +/* 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}, + {2,KEX_RSA,SIG_RSA,ENC_NULL,0,0,0,DIG_SHA,20,0}, + {3,KEX_RSA,SIG_RSA,ENC_RC4,1,128,40,DIG_MD5,16,1}, + {4,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_MD5,16,0}, + {5,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_SHA,20,0}, + {6,KEX_RSA,SIG_RSA,ENC_RC2,8,128,40,DIG_SHA,20,1}, + {7,KEX_RSA,SIG_RSA,ENC_IDEA,8,128,128,DIG_SHA,20,0}, + {8,KEX_RSA,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1}, + {9,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0}, + {10,KEX_RSA,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0}, + {11,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1}, + {12,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0}, + {13,KEX_DH,SIG_DSS,ENC_3DES,8,192,192,DIG_SHA,20,0}, + {14,KEX_DH,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1}, + {15,KEX_DH,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0}, + {16,KEX_DH,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0}, + {17,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1}, + {18,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0}, + {19,KEX_DH,SIG_DSS,ENC_3DES,8,192,192,DIG_SHA,20,0}, + {20,KEX_DH,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1}, + {21,KEX_DH,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0}, + {22,KEX_DH,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0}, + {23,KEX_DH,SIG_NONE,ENC_RC4,1,128,40,DIG_MD5,16,1}, + {24,KEX_DH,SIG_NONE,ENC_RC4,1,128,128,DIG_MD5,16,0}, + {25,KEX_DH,SIG_NONE,ENC_DES,8,64,40,DIG_MD5,16,1}, + {26,KEX_DH,SIG_NONE,ENC_DES,8,64,64,DIG_MD5,16,0}, + {27,KEX_DH,SIG_NONE,ENC_3DES,8,192,192,DIG_MD5,16,0}, + {47,KEX_RSA,SIG_RSA,ENC_AES,8,128,128,DIG_SHA,20,0}, + {53,KEX_RSA,SIG_RSA,ENC_AES,8,256,256,DIG_SHA,20,0}, + {96,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_MD5,16,1}, + {97,KEX_RSA,SIG_RSA,ENC_RC2,1,128,56,DIG_MD5,16,1}, + {98,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,1}, + {99,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,16,1}, + {100,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_SHA,20,1}, + {101,KEX_DH,SIG_DSS,ENC_RC4,1,128,56,DIG_SHA,20,1}, + {102,KEX_DH,SIG_DSS,ENC_RC4,1,128,128,DIG_SHA,20,0}, + {-1, 0,0,0,0,0,0,0,20,0} +}; + +typedef struct { + int ssl_port; + int decrypted_port; +} SslPortPair; + +static SslPortPair ssl_ports [] = { + {443, 80}, /* https */ + {636, 389}, /* ldap */ + {993, 143}, /* imap */ + {995, 110}, /* pop3 */ + {0,0}}; + + +int ssl_packet_from_server(int port) +{ + SslPortPair* current; + for (current = ssl_ports; current->ssl_port != 0; current++) + { + if (current->ssl_port == port) + return 1; + } + return 0; +} + +int ssl_data_init(StringInfo* str, 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, char* data, unsigned int len) +{ + memcpy(str->data, data, len); + str->data_len = len; + return 0; +} + +void ssl_debug_printf(char* fmt,...) +{ +#ifdef SSL_DECRYPT_DEBUG + va_list ap; + int ret=0; + va_start(ap, fmt); + ret += vfprintf(stderr, fmt, ap); + va_end(ap); +#endif +} + + +void ssl_print_text_data(const char* name, const char* data, int len) +{ +#ifdef SSL_DECRYPT_DEBUG + int i; + fprintf(stderr,"%s: ",name); + for (i=0; i< len; i++) { + fprintf(stderr,"%c",data[i]); + } + fprintf(stderr,"\n"); +#endif +} + +void ssl_print_data(const char* name, const char* data, int len) +{ +#ifdef SSL_DECRYPT_DEBUG + int i; + fprintf(stderr,"%s[%d]:\n",name, len); + for (i=0; i< len; i++) { + if ((i>0) && (i%16 == 0)) + fprintf(stderr,"\n"); + fprintf(stderr,"%.2x ",data[i]&255); + } + fprintf(stderr,"\n"); +#endif +} + +void ssl_print_string(const char* name, const StringInfo* data) +{ +#ifdef SSL_DECRYPT_DEBUG + ssl_print_data(name, data->data, data->data_len); +#endif +} + +int ssl_find_cipher(int num,SslCipherSuite* cs) +{ + SslCipherSuite *c; + + for(c=cipher_suites;c->number!=-1;c++){ + if(c->number==num){ + *cs=*c; + return 0; + } + } + + return -1; +} + +/* get ssl data for this session. if no ssl data is found allocate a new one*/ +SslDecryptSession* ssl_alloc_session(void) +{ + SslDecryptSession*ssl_session = g_malloc0(sizeof(SslDecryptSession)); + if (!ssl_session) + return NULL; + + ssl_debug_printf("ssl_alloc_session ptr %p size %d\n", + ssl_session, sizeof(SslDecryptSession)); + + ssl_session->master_secret.data = ssl_session->_master_secret; + ssl_session->session_id.data = ssl_session->_session_id; + ssl_session->client_random.data = ssl_session->_client_random; + ssl_session->server_random.data = ssl_session->_server_random; + ssl_session->master_secret.data_len = 48; + return ssl_session; +} + +static int tls_hash(StringInfo* secret, + StringInfo* seed, int md, StringInfo* out) +{ + u_int8_t *ptr=out->data; + unsigned int left=out->data_len; + int tocpy; + u_int8_t *A; + u_int8_t _A[20],tmp[20]; + unsigned int A_l,tmp_l; + SSL_HMAC hm; + + memset(&hm, 0, sizeof(hm)); + ssl_print_string("hash secret", secret); + ssl_print_string("hash seed", seed); + ssl_debug_printf("tls_hash: hmac %p\n",md); + 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); + ssl_debug_printf("tls_hash: hmac 1 len %d\n",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); + ssl_debug_printf("tls_hash: hmac 2 len %d\n",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 decodet 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); + + SSL_CIPHER_INIT(&dec->evp,ciph,sk,iv,0); + + 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[8],_iv_s[8]; + u_int8_t _key_c[16],_key_s[16]; + int needed; + u_int8_t *ptr,*c_wk,*s_wk,*c_mk,*s_mk,*c_iv,*s_iv; + + /* 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){ + + iv_c.data = _iv_c; + iv_c.data_len = sizeof(_iv_c); + iv_s.data = _iv_s; + iv_s.data_len = sizeof(_iv_s); + + 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[16]; + StringInfo iv_block; + StringInfo key_null; + u_int8_t _key_null; + + key_null.data = &_key_null; + key_null.data_len = 0; + + /* We only have room for 8 bit IVs, but that's + all we should need. This is a sanity check */ + if(ssl_session->cipher_suite.block>8) { + ssl_debug_printf("ssl_generate_keyring_material cipher suite block must be at most 7 nut is %d\n", ssl_session->cipher_suite.block); + goto fail; + } + + iv_block.data = _iv_block; + iv_block.data_len = sizeof(_iv_block); + + 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,8); + memcpy(_iv_s,iv_block.data+8,8); + } + + 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; + } + } + + 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); + } + + 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_HMAC_INIT(&hm,decoder->mac_key.data,decoder->mac_key.data_len,md); + + 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]); + memset(&mc, 0, sizeof(mc)); + SSL_MD_INIT(&mc,md); + + /* 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 char* in, int inl,char*out,int* outl) +{ + int pad; + 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);*/ + {static int __idx = 0; if (__idx++ > 0)ssl_print_text_data("\n\n",out, inl - decoder->cipher_suite->dig_len);} + *outl=inl; + + /* Now strip off the padding*/ + if(decoder->cipher_suite->block!=1){ + pad=out[inl-1]; + *outl-=(pad+1); + } + + /* And the MAC */ + *outl-=decoder->cipher_suite->dig_len; + mac=out+(*outl); + /*ssl_print_data("Record data",out,*outl);*/ + + /* Now check the MAC */ + ssl_debug_printf("checking mac (len %d, version %X, ct %d)", *outl,ssl->version_netorder, ct); + if(ssl->version_netorder==0x300){ + if(ssl3_check_mac(decoder,ct,out,*outl,mac) < 0) { + ssl_debug_printf("mac falied\n"); + return -1; + } + } + else{ + if(tls_check_mac(decoder,ct,ssl->version_netorder,out,*outl,mac)< 0) { + ssl_debug_printf("mac falied\n"); + return -1; + } + } + ssl_debug_printf("mac ok\n"); + 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; + 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 m 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", p.size, tmp_size); + + if (gcry_mpi_scan( &rsa_params[5], GCRYMPI_FMT_USG, u.data, u.size, &tmp_size) !=0) { + ssl_debug_printf("ssl_load_key: can't convert u rsa param to int (size %d)\n", m.size); + return NULL; + } + ssl_debug_printf("ssl_load_key: got rsa param u size %d (%d)\n", u.size, tmp_size); + + if (gcry_sexp_build( &rsa_priv_key, NULL, + "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", rsa_params[0], + rsa_params[1], rsa_params[2], rsa_params[3], rsa_params[4], + rsa_params[5]) != 0) { + ssl_debug_printf("ssl_load_key: can't built rsa private key s-exp\n"); + return NULL; + } + +#if SSL_FAST + return rsa_params; +#else + return rsa_priv_key; +#endif +} diff -uNr ethereal-0.10.13/epan/dissectors/packet-ssl-utils.h ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.h --- ethereal-0.10.13/epan/dissectors/packet-ssl-utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ethereal-0.10.13-patch/epan/dissectors/packet-ssl-utils.h 2005-11-08 10:28:21.000000000 +0100 @@ -0,0 +1,123 @@ +#ifndef __SSL_UTILS_H_ +#define __SSL_UTILS_H_ + +#include <stdio.h> +#include <gcrypt.h> +#include <gnutls/x509.h> +#include <gnutls/openssl.h> +#define SSL_CIPHER_CTX gcry_cipher_hd_t +#ifdef SSL_FAST +#define SSL_PRIVATE_KEY gcry_mpi_t +#else +#define SSL_PRIVATE_KEY struct gcry_sexp +#endif +#define SSL_LIB_INIT gnutls_global_init + +//#include <epan/address.h> +#include <netinet/in.h> + +typedef struct _StringInfo { + char* data; + unsigned int data_len; +} StringInfo; + +void ssl_debug_printf(char* fmt,...); +void ssl_print_data(const char* name, const char* data, int len); +void ssl_print_string(const char* name, const StringInfo* data); +void ssl_print_text_data(const char* name, const char* data, int len); +SSL_PRIVATE_KEY* ssl_load_key(FILE* fp); + +#define SSL_WRITE_KEY 1 + +#define SSLV3_VERSION 0x300 +#define TLSV1_VERSION 0x301 + +#define SSL_CLIENT_RANDOM 1 +#define SSL_SERVER_RANDOM 2 +#define SSL_CIPHER 4 +#define SSL_HAVE_SESSION_KEY 8 +#define SSL_VERSION 0x10 +#define SSL_MASTER_SECRET 0x20 + +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; +} SslCipherSuite; + +typedef struct _SslDecoder { + SslCipherSuite* cipher_suite; + 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_NULL 0x36 + +#define DIG_MD5 0x40 +#define DIG_SHA 0x41 + +/*typedef struct _SslService { + address addr; + guint port; +} SslService;*/ + +typedef struct _SslDecryptSession { + char _master_secret[48]; + char _session_id[256]; + char _client_random[32]; + char _server_random[32]; + StringInfo session_id; + StringInfo server_random; + StringInfo client_random; + StringInfo master_secret; + StringInfo pre_master_secret; + + int cipher; + int state; + SslCipherSuite cipher_suite; + SslDecoder server; + SslDecoder client; + SSL_PRIVATE_KEY* private_key; + u_int32_t version; + u_int16_t version_netorder; +} SslDecryptSession; + + +int ssl_data_set(StringInfo* data, char* src, unsigned int len); +int ssl_data_init(StringInfo* data, char* src, unsigned int len); + +SslDecryptSession* ssl_alloc_session(void); +int ssl_find_cipher(int num,SslCipherSuite* cs); + +int ssl_packet_from_server(int port); +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 char* in, int inl,char*out,int* outl); +#endif diff -uNr ethereal-0.10.13/Makefile.am ethereal-0.10.13-patch/Makefile.am --- ethereal-0.10.13/Makefile.am 2005-10-10 15:23:13.000000000 +0200 +++ ethereal-0.10.13-patch/Makefile.am 2005-11-08 10:28:21.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:
- Re: [Ethereal-dev] SSL decryption patch for ethereal 0.10.13
- From: Tomas Kukosa
- [Ethereal-dev] Re: SSL decryption patch for ethereal 0.10.13
- From: ronnie sahlberg
- Re: [Ethereal-dev] SSL decryption patch for ethereal 0.10.13
- Prev by Date: [Ethereal-dev] Filter scan result notification from hnse2
- Next by Date: [Ethereal-dev] [Camel] BER error
- Previous by thread: [Ethereal-dev] Filter scan result notification from hnse2
- Next by thread: Re: [Ethereal-dev] SSL decryption patch for ethereal 0.10.13
- Index(es):