summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2015-02-05 19:54:52 +0100
committerPeter Wu <peter@lekensteyn.nl>2015-02-06 22:51:53 +0100
commit2e7ba71c49c55d0c0273b89c78c10d3ae927a1b2 (patch)
treeb1dc9ebdd1cd63623932361709ef7ab0376e1ca2
parentff6d50325829182dbc752df20f632a7b38c66d1d (diff)
downloadwireshark-2e7ba71c49c55d0c0273b89c78c10d3ae927a1b2.tar.gz
ssl,dtls,ssl-utils: Prepare for STARTTLS handling
All STARTTLS-like dissectors (protocols which can switch to SSL/TLS after a protocol command) currently fail to get called after decryption. The reason for this is that the port is not registered for SSL dissection via ssl_dissector_add. Besides this, the MySQL dissector breaks in the event of multiple segments because it does not properly set desegmentation. The call path TCP | App | SSL | App is a bad, error-prone pattern which requires duplication of required functionality in dissectors. This patch enables to bypass the App (TCP | SSL | App) by registering a SSL as conversation dissector after a STARTTLS switch. Logical overview of changes: - Move srv_addr, srv_ptype and srv_port to SslSession and adjust the users. This allows passing SslSession around which will never be null unlike SslDecryptSession. This is needed for looking up the packet direction (server or client) before calling a subdissector. - Add app_handle to store the dissector and last_nontls_frame the frame that initiated STARTTLS. - The same app_handle is now used to store the dissector handle from a ssl association. - Moved conversation data (SslDecryptSession) to ssl-utils to avoid code duplication. Merge ssl_session_init into it. The new ssl_session_get() is needed for STARTTLS frame/handle storage. - Introduce new "ssl_starttls_ack" function to signal the last non-TLS packet. - Ensure that match_uint is set before calling the conversation dissector. This ensures that dissectors using match_uint to check the direction of a packet (client vs. server) see the TCP port instead of the IP proto. At least the MySQL and SMTP dissectors require such special treatment. - Move epan/conversation.h outside HAVE_LIBGNUTLS, remove from dtls (as it is already included by ssl-utils). - Various comment/debug string updates. Remove outdated comment before SSL association lookup. Besides setting match_uint and caching the app_handle, existing dissectors should not be affected by this patch. Follow-up patches will update existing dissectors to use the new ssl_starttls_ack interface. Bug: 9515 Change-Id: I795d16b6a901e672a5d89e922adc7e5bbcda0333
-rw-r--r--epan/dissectors/packet-dtls.c80
-rw-r--r--epan/dissectors/packet-ssl-utils.c85
-rw-r--r--epan/dissectors/packet-ssl-utils.h43
-rw-r--r--epan/dissectors/packet-ssl.c109
4 files changed, 207 insertions, 110 deletions
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c
index c1ec134976..e82d195773 100644
--- a/epan/dissectors/packet-dtls.c
+++ b/epan/dissectors/packet-dtls.c
@@ -49,7 +49,6 @@
#include "config.h"
#include <epan/packet.h>
-#include <epan/conversation.h>
#include <epan/to_str.h>
#include <epan/asn1.h>
#include <epan/tap.h>
@@ -328,7 +327,6 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
conversation_t *conversation;
- void *conv_data;
proto_item *ti;
proto_tree *dtls_tree;
guint32 offset;
@@ -336,6 +334,7 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
SslDecryptSession *ssl_session;
SslSession *session;
gint is_from_server;
+ gboolean conv_first_seen;
Ssl_private_key_t *private_key;
ti = NULL;
@@ -356,22 +355,16 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* in addition to conv_version
*/
conversation = find_or_create_conversation(pinfo);
- conv_data = conversation_get_proto_data(conversation, proto_dtls);
-
- /* manage dtls decryption data */
- /*get a valid ssl session pointer*/
- if (conv_data != NULL)
- ssl_session = (SslDecryptSession *)conv_data;
- else {
+ conv_first_seen = conversation_get_proto_data(conversation, proto_dtls) == NULL;
+ ssl_session = ssl_get_session(conversation, dtls_handle);
+ if (conv_first_seen) {
SslService dummy;
- ssl_session = wmem_new0(wmem_file_scope(), SslDecryptSession);
- ssl_session_init(ssl_session);
- ssl_session->session.version = SSL_VER_UNKNOWN;
- conversation_add_proto_data(conversation, proto_dtls, ssl_session);
-
/* we need to know witch side of conversation is speaking */
- if (ssl_packet_from_server(ssl_session, dtls_associations, pinfo)) {
+ /* XXX: remove this? it looks like a historical leftover since the initial
+ * commit. Since 0f05597ab17ea7fc5161458c670f56a523cb9c42,
+ * ssl_find_private_key is called so this is not needed */
+ if (ssl_packet_from_server(&ssl_session->session, dtls_associations, pinfo)) {
dummy.addr = pinfo->src;
dummy.port = pinfo->srcport;
}
@@ -395,7 +388,15 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
session = &ssl_session->session;
- is_from_server = ssl_packet_from_server(ssl_session, dtls_associations, pinfo);
+ is_from_server = ssl_packet_from_server(session, dtls_associations, pinfo);
+
+ if (session->last_nontls_frame != 0 &&
+ session->last_nontls_frame >= pinfo->fd->num) {
+ /* This conversation started at a different protocol and STARTTLS was
+ * used, but this packet comes too early. */
+ /* TODO: convert to new-style dissector and return 0 to reject packet. */
+ return;
+ }
/* try decryption only the first time we see this packet
* (to keep cipher synchronized) */
@@ -583,7 +584,7 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
record_length, ssl->state);
/* retrieve decoder for this packet direction */
- if (ssl_packet_from_server(ssl, dtls_associations, pinfo) != 0) {
+ if (ssl_packet_from_server(&ssl->session, dtls_associations, pinfo) != 0) {
ssl_debug_printf("decrypt_dtls_record: using server decoder\n");
decoder = ssl->server;
}
@@ -680,7 +681,6 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
guint8 next_byte;
proto_tree *ti;
proto_tree *dtls_record_tree;
- SslAssociation *association;
SslDataInfo *appl_data;
heur_dtbl_entry_t *hdtbl_entry;
@@ -694,7 +694,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
record_length = tvb_get_ntohs(tvb, offset + 11);
if(ssl){
- if(ssl_packet_from_server(ssl, dtls_associations, pinfo)){
+ if(ssl_packet_from_server(session, dtls_associations, pinfo)){
if (ssl->server) {
ssl->server->seq=(guint32)sequence_number;
ssl->server->epoch=epoch;
@@ -816,7 +816,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
ssl_load_keyfile(dtls_options.keylog_filename, &dtls_keylog_file,
&dtls_master_key_map);
ssl_finalize_decryption(ssl, &dtls_master_key_map);
- ssl_change_cipher(ssl, ssl_packet_from_server(ssl, dtls_associations, pinfo));
+ ssl_change_cipher(ssl, ssl_packet_from_server(session, dtls_associations, pinfo));
}
break;
case SSL_ID_ALERT:
@@ -878,17 +878,24 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/* show on info column what we are decoding */
col_append_str(pinfo->cinfo, COL_INFO, "Application Data");
- /* we need dissector information when the selected packet is shown.
- * ssl session pointer is NULL at that time, so we can't access
- * info cached there*/
- association = ssl_association_find(dtls_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
- association = association ? association : ssl_association_find(dtls_associations, pinfo->destport, pinfo->ptype == PT_TCP);
+ /* app_handle discovery is done here instead of dissect_dtls_payload()
+ * because the protocol name needs to be displayed below. */
+ if (!session->app_handle) {
+ /* Unknown protocol handle, ssl_starttls_ack was not called before.
+ * Try to find an appropriate dissection handle and cache it. */
+ SslAssociation *association;
+ association = ssl_association_find(dtls_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
+ association = association ? association : ssl_association_find(dtls_associations, pinfo->destport, pinfo->ptype == PT_TCP);
+ if (association) session->app_handle = association->handle;
+ }
proto_item_set_text(dtls_record_tree,
"%s Record Layer: %s Protocol: %s",
val_to_str_const(session->version, ssl_version_short_names, "SSL"),
val_to_str_const(content_type, ssl_31_content_type, "unknown"),
- association?association->info:"Application Data");
+ session->app_handle
+ ? dissector_handle_get_dissector_name(session->app_handle)
+ : "Application Data");
/* show decrypted data info, if available */
appl_data = ssl_get_data_info(proto_dtls, pinfo, tvb_raw_offset(tvb)+offset);
@@ -896,6 +903,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
{
tvbuff_t *next_tvb;
gboolean dissected;
+ guint16 saved_match_port;
/* try to dissect decrypted data*/
ssl_debug_printf("dissect_dtls_record decrypted len %d\n",
appl_data->plain_data.data_len);
@@ -908,9 +916,18 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
add_new_data_source(pinfo, next_tvb, "Decrypted DTLS data");
+ saved_match_port = pinfo->match_uint;
+ if (ssl_packet_from_server(session, dtls_associations, pinfo)) {
+ pinfo->match_uint = pinfo->srcport;
+ } else {
+ pinfo->match_uint = pinfo->destport;
+ }
+
/* find out a dissector using server port*/
- if (association && association->handle) {
- ssl_debug_printf("dissect_dtls_record found association %p\n", (void *)association);
+ if (session->app_handle) {
+ ssl_debug_printf("%s: found handle %p (%s)\n", G_STRFUNC,
+ (void *)session->app_handle,
+ dissector_handle_get_dissector_name(session->app_handle));
ssl_print_data("decrypted app data",appl_data->plain_data.data, appl_data->plain_data.data_len);
if (have_tap_listener(exported_pdu_tap)) {
@@ -918,7 +935,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
guint8 tags = EXP_PDU_TAG_IP_SRC_BIT | EXP_PDU_TAG_IP_DST_BIT | EXP_PDU_TAG_SRC_PORT_BIT |
EXP_PDU_TAG_DST_PORT_BIT | EXP_PDU_TAG_ORIG_FNO_BIT;
- exp_pdu_data = load_export_pdu_tags(pinfo, dissector_handle_get_dissector_name(association->handle), -1,
+ exp_pdu_data = load_export_pdu_tags(pinfo, dissector_handle_get_dissector_name(session->app_handle), -1,
&tags, 1);
exp_pdu_data->tvb_captured_length = tvb_captured_length(next_tvb);
@@ -928,12 +945,13 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
}
- dissected = call_dissector_only(association->handle, next_tvb, pinfo, top_tree, NULL);
+ dissected = call_dissector_only(session->app_handle, next_tvb, pinfo, top_tree, NULL);
}
else {
/* try heuristic subdissectors */
dissected = dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, top_tree, &hdtbl_entry, NULL);
}
+ pinfo->match_uint = saved_match_port;
if (dissected)
break;
}
@@ -1321,7 +1339,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
if (ssl) {
/* ClientHello is first packet so set direction and try to
* find a private key matching the server port */
- ssl_set_server(ssl, &pinfo->dst, pinfo->ptype, pinfo->destport);
+ ssl_set_server(session, &pinfo->dst, pinfo->ptype, pinfo->destport);
ssl_find_private_key(ssl, dtls_key_hash, dtls_associations, pinfo);
}
ssl_dissect_hnd_cli_hello(&dissect_dtls_hf, sub_tvb, pinfo,
diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c
index 02d0075b8f..beeebb93a8 100644
--- a/epan/dissectors/packet-ssl-utils.c
+++ b/epan/dissectors/packet-ssl-utils.c
@@ -3809,7 +3809,7 @@ ssl_find_private_key(SslDecryptSession *ssl_session, GHashTable *key_hash, GTree
}
/* we need to know which side of the conversation is speaking */
- if (ssl_packet_from_server(ssl_session, associations, pinfo)) {
+ if (ssl_packet_from_server(&ssl_session->session, associations, pinfo)) {
dummy.addr = pinfo->src;
dummy.port = port = pinfo->srcport;
} else {
@@ -3956,11 +3956,20 @@ ssl_cipher_setiv(SSL_CIPHER_CTX *cipher _U_, guchar* iv _U_, gint iv_len _U_)
#endif /* defined(HAVE_LIBGNUTLS) && defined(HAVE_LIBGCRYPT) */
/* get ssl data for this session. if no ssl data is found allocate a new one*/
-void
-ssl_session_init(SslDecryptSession* ssl_session)
+SslDecryptSession *
+ssl_get_session(conversation_t *conversation, dissector_handle_t ssl_handle)
{
- ssl_debug_printf("ssl_session_init: initializing ptr %p size %" G_GSIZE_MODIFIER "u\n",
- (void *)ssl_session, sizeof(SslDecryptSession));
+ void *conv_data;
+ SslDecryptSession *ssl_session;
+ int proto_ssl;
+
+ proto_ssl = dissector_handle_get_protocol_index(ssl_handle);
+ conv_data = conversation_get_proto_data(conversation, proto_ssl);
+ if (conv_data != NULL)
+ return (SslDecryptSession *)conv_data;
+
+ /* no previous SSL conversation info, initialize it. */
+ ssl_session = wmem_new0(wmem_file_scope(), SslDecryptSession);
/* data_len is the part that is meaningful, not the allocated length */
ssl_session->master_secret.data_len = 0;
@@ -3979,19 +3988,63 @@ ssl_session_init(SslDecryptSession* ssl_session)
ssl_session->client_data_for_iv.data = ssl_session->_client_data_for_iv;
ssl_session->app_data_segment.data = NULL;
ssl_session->app_data_segment.data_len = 0;
- SET_ADDRESS(&ssl_session->srv_addr, AT_NONE, 0, NULL);
- ssl_session->srv_ptype = PT_NONE;
- ssl_session->srv_port = 0;
ssl_session->handshake_data.data=NULL;
ssl_session->handshake_data.data_len=0;
+
+ /* Initialize parameters which are not necessary specific to decryption. */
+ ssl_session->session.version = SSL_VER_UNKNOWN;
+ SET_ADDRESS(&ssl_session->session.srv_addr, AT_NONE, 0, NULL);
+ ssl_session->session.srv_ptype = PT_NONE;
+ ssl_session->session.srv_port = 0;
+
+ conversation_add_proto_data(conversation, proto_ssl, ssl_session);
+ return ssl_session;
}
void
-ssl_set_server(SslDecryptSession* ssl, address *addr, port_type ptype, guint32 port)
+ssl_set_server(SslSession *session, address *addr, port_type ptype, guint32 port)
{
- WMEM_COPY_ADDRESS(wmem_file_scope(), &ssl->srv_addr, addr);
- ssl->srv_ptype = ptype;
- ssl->srv_port = port;
+ WMEM_COPY_ADDRESS(wmem_file_scope(), &session->srv_addr, addr);
+ session->srv_ptype = ptype;
+ session->srv_port = port;
+}
+
+guint32
+ssl_starttls_ack(dissector_handle_t ssl_handle, packet_info *pinfo,
+ dissector_handle_t app_handle)
+{
+ conversation_t *conversation;
+ SslSession *session;
+
+ /* Ignore if the SSL dissector is disabled. */
+ if (!ssl_handle)
+ return 0;
+ /* The caller should always pass a valid handle to its own dissector. */
+ DISSECTOR_ASSERT(app_handle);
+
+ conversation = find_or_create_conversation(pinfo);
+ session = &ssl_get_session(conversation, ssl_handle)->session;
+
+ ssl_debug_printf("%s: old frame %d, app_handle=%p (%s)\n", G_STRFUNC,
+ session->last_nontls_frame,
+ (void *)session->app_handle,
+ dissector_handle_get_dissector_name(session->app_handle));
+ ssl_debug_printf("%s: current frame %d, app_handle=%p (%s)\n", G_STRFUNC,
+ pinfo->fd->num, (void *)app_handle,
+ dissector_handle_get_dissector_name(app_handle));
+
+ /* Do not switch again if a dissector did it before. */
+ if (session->last_nontls_frame) {
+ ssl_debug_printf("%s: not overriding previous app handle!\n", G_STRFUNC);
+ return session->last_nontls_frame;
+ }
+
+ session->app_handle = app_handle;
+ /* The SSL dissector should be called first for this conversation. */
+ conversation_set_dissector(conversation, ssl_handle);
+ /* SSL starts after this frame. */
+ session->last_nontls_frame = pinfo->fd->num;
+ return 0;
}
/* Hash Functions for TLS/DTLS sessions table and private keys table*/
@@ -4158,11 +4211,13 @@ ssl_assoc_from_key_list(gpointer key _U_, gpointer data, gpointer user_data)
}
int
-ssl_packet_from_server(SslDecryptSession* ssl, GTree* associations, packet_info *pinfo)
+ssl_packet_from_server(SslSession *session, GTree *associations, packet_info *pinfo)
{
gint ret;
- if (ssl && (ssl->srv_ptype != PT_NONE)) {
- ret = (ssl->srv_ptype == pinfo->ptype) && (ssl->srv_port == pinfo->srcport) && ADDRESSES_EQUAL(&ssl->srv_addr, &pinfo->src);
+ if (session->srv_ptype != PT_NONE) {
+ ret = (session->srv_ptype == pinfo->ptype) &&
+ (session->srv_port == pinfo->srcport) &&
+ ADDRESSES_EQUAL(&session->srv_addr, &pinfo->src);
} else {
ret = ssl_association_find(associations, pinfo->srcport, pinfo->ptype == PT_TCP) != 0;
}
diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h
index a74f3b911c..19fcf2c26f 100644
--- a/epan/dissectors/packet-ssl-utils.h
+++ b/epan/dissectors/packet-ssl-utils.h
@@ -31,13 +31,13 @@
#include <epan/prefs.h>
#include <epan/wmem/wmem.h>
#include <epan/expert.h>
+#include <epan/conversation.h>
#include <wsutil/wsgcrypt.h>
#ifdef HAVE_LIBGNUTLS
#include <gnutls/x509.h>
#include <gnutls/pkcs12.h>
-#include <epan/conversation.h>
#include "ws_symbol_export.h"
/* #define SSL_FAST 1 */
@@ -353,6 +353,16 @@ typedef struct _SslSession {
guint32 version;
gint8 client_cert_type;
gint8 server_cert_type;
+
+ /* The address/proto/port of the server as determined from heuristics
+ * (e.g. ClientHello) or set externally (via ssl_set_master_secret()). */
+ address srv_addr;
+ port_type srv_ptype;
+ guint srv_port;
+
+ /* The Application layer protocol if known (for STARTTLS support) */
+ dissector_handle_t app_handle;
+ guint32 last_nontls_frame;
} SslSession;
/* RFC 5246, section 8.1 says that the master secret is always 48 bytes */
@@ -389,10 +399,6 @@ typedef struct _SslDecryptSession {
StringInfo app_data_segment;
SslSession session;
- address srv_addr;
- port_type srv_ptype;
- guint srv_port;
-
} SslDecryptSession;
typedef struct _SslAssociation {
@@ -452,14 +458,29 @@ gboolean ssldecrypt_uat_fld_password_chk_cb(void*, const char*, unsigned, const
extern void
ssl_lib_init(void);
-/** Initialize an ssl session struct
- @param ssl pointer to ssl session struct to be initialized */
-extern void
-ssl_session_init(SslDecryptSession* ssl);
+/** Retrieve a SslSession, creating it if it did not already exist.
+ * @param conversation The SSL conversation.
+ * @param ssl_handle The dissector handle for SSL or DTLS.
+ */
+extern SslDecryptSession *
+ssl_get_session(conversation_t *conversation, dissector_handle_t ssl_handle);
/** Set server address and port */
extern void
-ssl_set_server(SslDecryptSession* ssl, address *addr, port_type ptype, guint32 port);
+ssl_set_server(SslSession *session, address *addr, port_type ptype, guint32 port);
+
+/** Marks this packet as the last one before switching to SSL that is supposed
+ * to encapsulate this protocol.
+ * @param ssl_handle The dissector handle for SSL or DTLS.
+ * @param pinfo Packet Info.
+ * @param app_handle Dissector handle for the protocol inside the decrypted
+ * Application Data record.
+ * @return 0 for the first STARTTLS acknowledgement (success) or if ssl_handle
+ * is NULL. >0 if STARTTLS was started before.
+ */
+extern guint32
+ssl_starttls_ack(dissector_handle_t ssl_handle, packet_info *pinfo,
+ dissector_handle_t app_handle);
/** set the data and len for the stringInfo buffer. buf should be big enough to
* contain the provided data
@@ -561,7 +582,7 @@ extern gint
ssl_assoc_from_key_list(gpointer key _U_, gpointer data, gpointer user_data);
extern gint
-ssl_packet_from_server(SslDecryptSession* ssl, GTree* associations, packet_info *pinfo);
+ssl_packet_from_server(SslSession *session, GTree *associations, packet_info *pinfo);
/* add to packet data a copy of the specified real data */
extern void
diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c
index 04e5cced1e..6327743951 100644
--- a/epan/dissectors/packet-ssl.c
+++ b/epan/dissectors/packet-ssl.c
@@ -545,7 +545,6 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
conversation_t *conversation;
- void *conv_data;
proto_item *ti;
proto_tree *ssl_tree;
guint32 offset;
@@ -594,21 +593,16 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
* in addition to conv_version
*/
conversation = find_or_create_conversation(pinfo);
+ ssl_session = ssl_get_session(conversation, ssl_handle);
+ session = &ssl_session->session;
+ is_from_server = ssl_packet_from_server(session, ssl_associations, pinfo);
- conv_data = conversation_get_proto_data(conversation, proto_ssl);
-
- /* PAOLO: manage ssl decryption data */
- /*get a valid ssl session pointer*/
- if (conv_data != NULL)
- ssl_session = (SslDecryptSession *)conv_data;
- else {
- ssl_session = (SslDecryptSession *)wmem_alloc0(wmem_file_scope(), sizeof(SslDecryptSession));
- ssl_session_init(ssl_session);
- ssl_session->session.version = SSL_VER_UNKNOWN;
- conversation_add_proto_data(conversation, proto_ssl, ssl_session);
+ if (session->last_nontls_frame != 0 &&
+ session->last_nontls_frame >= pinfo->fd->num) {
+ /* This conversation started at a different protocol and STARTTLS was
+ * used, but this packet comes too early. */
+ return 0;
}
- session = &ssl_session->session;
- is_from_server = ssl_packet_from_server(ssl_session, ssl_associations, pinfo);
/* try decryption only the first time we see this packet
* (to keep cipher synchronized) */
@@ -775,7 +769,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
* add decrypted data to this packet info */
ssl_debug_printf("decrypt_ssl3_record: app_data len %d, ssl state 0x%02X\n",
record_length, ssl->state);
- direction = ssl_packet_from_server(ssl, ssl_associations, pinfo);
+ direction = ssl_packet_from_server(&ssl->session, ssl_associations, pinfo);
/* retrieve decoder for this packet direction */
if (direction != 0) {
@@ -819,12 +813,12 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
static void
process_ssl_payload(tvbuff_t *tvb, volatile int offset, packet_info *pinfo,
- proto_tree *tree, SslAssociation *association);
+ proto_tree *tree, SslSession *session);
static void
desegment_ssl(tvbuff_t *tvb, packet_info *pinfo, int offset,
guint32 seq, guint32 nxtseq,
- SslAssociation *association,
+ SslSession *session,
proto_tree *root_tree, proto_tree *tree,
SslFlow *flow)
{
@@ -934,7 +928,7 @@ again:
* contain a continuation of a higher-level PDU.
* Call the normal subdissector.
*/
- process_ssl_payload(tvb, offset, pinfo, tree, association);
+ process_ssl_payload(tvb, offset, pinfo, tree, session);
called_dissector = TRUE;
/* Did the subdissector ask us to desegment some more data
@@ -988,7 +982,7 @@ again:
add_new_data_source(pinfo, next_tvb, "Reassembled SSL");
/* call subdissector */
- process_ssl_payload(next_tvb, 0, pinfo, tree, association);
+ process_ssl_payload(next_tvb, 0, pinfo, tree, session);
called_dissector = TRUE;
/*
@@ -1228,15 +1222,18 @@ again:
static void
process_ssl_payload(tvbuff_t *tvb, volatile int offset, packet_info *pinfo,
- proto_tree *tree, SslAssociation *association)
+ proto_tree *tree, SslSession *session)
{
tvbuff_t *next_tvb;
heur_dtbl_entry_t *hdtbl_entry;
+ guint16 saved_match_port;
next_tvb = tvb_new_subset_remaining(tvb, offset);
- if (association && association->handle) {
- ssl_debug_printf("dissect_ssl3_record found association %p\n", (void *)association);
+ if (session->app_handle) {
+ ssl_debug_printf("%s: found handle %p (%s)\n", G_STRFUNC,
+ (void *)session->app_handle,
+ dissector_handle_get_dissector_name(session->app_handle));
if (dissector_try_heuristic(ssl_heur_subdissector_list, next_tvb,
pinfo, proto_tree_get_root(tree), &hdtbl_entry, NULL)) {
@@ -1246,7 +1243,7 @@ process_ssl_payload(tvbuff_t *tvb, volatile int offset, packet_info *pinfo,
guint8 tags = EXP_PDU_TAG_IP_SRC_BIT | EXP_PDU_TAG_IP_DST_BIT | EXP_PDU_TAG_SRC_PORT_BIT |
EXP_PDU_TAG_DST_PORT_BIT | EXP_PDU_TAG_ORIG_FNO_BIT;
- exp_pdu_data = load_export_pdu_tags(pinfo, dissector_handle_get_dissector_name(association->handle), -1,
+ exp_pdu_data = load_export_pdu_tags(pinfo, dissector_handle_get_dissector_name(session->app_handle), -1,
&tags, 1);
exp_pdu_data->tvb_captured_length = tvb_captured_length(next_tvb);
@@ -1255,13 +1252,21 @@ process_ssl_payload(tvbuff_t *tvb, volatile int offset, packet_info *pinfo,
tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
}
- call_dissector(association->handle, next_tvb, pinfo, proto_tree_get_root(tree));
+ saved_match_port = pinfo->match_uint;
+ if (ssl_packet_from_server(session, ssl_associations, pinfo)) {
+ pinfo->match_uint = pinfo->srcport;
+ } else {
+ pinfo->match_uint = pinfo->destport;
+ }
+ call_dissector(session->app_handle, next_tvb, pinfo, proto_tree_get_root(tree));
+ pinfo->match_uint = saved_match_port;
}
}
}
static void
-dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, SslAssociation *association)
+dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset,
+ proto_tree *tree, SslSession *session)
{
gboolean save_fragmented;
guint16 save_can_desegment;
@@ -1290,8 +1295,10 @@ dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *t
if (ssl_desegment_app_data) {
/* Yes. */
pinfo->can_desegment = 2;
- desegment_ssl(next_tvb, pinfo, 0, appl_data->seq, appl_data->nxtseq, association, proto_tree_get_root(tree), tree, appl_data->flow);
- } else if (association && association->handle) {
+ desegment_ssl(next_tvb, pinfo, 0, appl_data->seq, appl_data->nxtseq,
+ session, proto_tree_get_root(tree), tree,
+ appl_data->flow);
+ } else if (session->app_handle) {
/* No - just call the subdissector.
Mark this as fragmented, so if somebody throws an exception,
we don't report it as a malformed frame. */
@@ -1299,7 +1306,7 @@ dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *t
save_fragmented = pinfo->fragmented;
pinfo->fragmented = TRUE;
- process_ssl_payload(next_tvb, 0, pinfo, tree, association);
+ process_ssl_payload(next_tvb, 0, pinfo, tree, session);
pinfo->fragmented = save_fragmented;
}
@@ -1345,7 +1352,6 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
guint8 next_byte;
proto_tree *ti;
proto_tree *ssl_record_tree;
- SslAssociation *association;
guint32 available_bytes;
ti = NULL;
@@ -1557,7 +1563,7 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
ssl_load_keyfile(ssl_options.keylog_filename, &ssl_keylog_file,
&ssl_master_key_map);
ssl_finalize_decryption(ssl, &ssl_master_key_map);
- ssl_change_cipher(ssl, ssl_packet_from_server(ssl, ssl_associations, pinfo));
+ ssl_change_cipher(ssl, ssl_packet_from_server(session, ssl_associations, pinfo));
}
break;
case SSL_ID_ALERT:
@@ -1622,23 +1628,30 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
/* show on info column what we are decoding */
col_append_str(pinfo->cinfo, COL_INFO, "Application Data");
- /* we need dissector information when the selected packet is shown.
- * ssl session pointer is NULL at that time, so we can't access
- * info cached there*/
- association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
- association = association ? association: ssl_association_find(ssl_associations, pinfo->destport, pinfo->ptype == PT_TCP);
- association = association ? association: ssl_association_find(ssl_associations, 0, pinfo->ptype == PT_TCP);
+ /* app_handle discovery is done here instead of dissect_ssl_payload()
+ * because the protocol name needs to be displayed below. */
+ if (!session->app_handle) {
+ /* Unknown protocol handle, ssl_starttls_ack was not called before.
+ * Try to find an appropriate dissection handle and cache it. */
+ SslAssociation *association;
+ association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
+ association = association ? association: ssl_association_find(ssl_associations, pinfo->destport, pinfo->ptype == PT_TCP);
+ association = association ? association: ssl_association_find(ssl_associations, 0, pinfo->ptype == PT_TCP);
+ if (association) session->app_handle = association->handle;
+ }
proto_item_set_text(ssl_record_tree,
"%s Record Layer: %s Protocol: %s",
val_to_str_const(session->version, ssl_version_short_names, "SSL"),
val_to_str_const(content_type, ssl_31_content_type, "unknown"),
- association?association->info:"Application Data");
+ session->app_handle
+ ? dissector_handle_get_dissector_name(session->app_handle)
+ : "Application Data");
proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb,
offset, record_length, ENC_NA);
- dissect_ssl_payload(tvb, pinfo, offset, tree, association);
+ dissect_ssl_payload(tvb, pinfo, offset, tree, session);
break;
case SSL_ID_HEARTBEAT:
@@ -1659,7 +1672,7 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
gboolean plaintext = TRUE;
/* heartbeats before ChangeCipherSpec are unencrypted */
if (ssl) {
- if (ssl_packet_from_server(ssl, ssl_associations, pinfo)) {
+ if (ssl_packet_from_server(session, ssl_associations, pinfo)) {
plaintext = ssl->server == NULL;
} else {
plaintext = ssl->client == NULL;
@@ -1919,7 +1932,7 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
if (ssl) {
/* ClientHello is first packet so set direction and try to
* find a private key matching the server port */
- ssl_set_server(ssl, &pinfo->dst, pinfo->ptype, pinfo->destport);
+ ssl_set_server(session, &pinfo->dst, pinfo->ptype, pinfo->destport);
ssl_find_private_key(ssl, ssl_key_hash, ssl_associations, pinfo);
}
ssl_dissect_hnd_cli_hello(&dissect_ssl3_hf, tvb, pinfo,
@@ -2571,7 +2584,7 @@ dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, packet_info *pinfo,
}
if (ssl) {
- ssl_set_server(ssl, &pinfo->dst, pinfo->ptype, pinfo->destport);
+ ssl_set_server(&ssl->session, &pinfo->dst, pinfo->ptype, pinfo->destport);
ssl_find_private_key(ssl, ssl_key_hash, ssl_associations, pinfo);
}
@@ -3201,7 +3214,6 @@ void ssl_set_master_secret(guint32 frame_num, address *addr_srv, address *addr_c
guint32 client_seq, guint32 server_seq)
{
conversation_t *conversation;
- void *conv_data;
SslDecryptSession *ssl;
guint iv_len;
@@ -3214,20 +3226,11 @@ void ssl_set_master_secret(guint32 frame_num, address *addr_srv, address *addr_c
conversation = conversation_new(frame_num, addr_srv, addr_cli, ptype, port_srv, port_cli, 0);
ssl_debug_printf(" new conversation = %p created\n", (void *)conversation);
}
- conv_data = conversation_get_proto_data(conversation, proto_ssl);
-
- if (conv_data) {
- ssl = (SslDecryptSession *)conv_data;
- } else {
- ssl = (SslDecryptSession *)wmem_alloc0(wmem_file_scope(), sizeof(SslDecryptSession));
- ssl_session_init(ssl);
- ssl->session.version = SSL_VER_UNKNOWN;
- conversation_add_proto_data(conversation, proto_ssl, ssl);
- }
+ ssl = ssl_get_session(conversation, ssl_handle);
ssl_debug_printf(" conversation = %p, ssl_session = %p\n", (void *)conversation, (void *)ssl);
- ssl_set_server(ssl, addr_srv, ptype, port_srv);
+ ssl_set_server(&ssl->session, addr_srv, ptype, port_srv);
/* version */
if ((ssl->session.version==SSL_VER_UNKNOWN) && (version!=SSL_VER_UNKNOWN)) {