summaryrefslogtreecommitdiff
path: root/epan
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2017-01-25 21:52:27 +0100
committerAnders Broman <a.broman58@gmail.com>2017-01-28 03:43:34 +0000
commit77404250d53a4b123f05c834108e231a8885305a (patch)
tree1fd9bdaf6ab810b9cc2344588cf55e71a8a3a45c /epan
parent990b5dc14c41fc3be69f9f8894f73d375d0d7db9 (diff)
downloadwireshark-77404250d53a4b123f05c834108e231a8885305a.tar.gz
(D)TLS: consolidate and simplify decrypted records handling
Previously there was a distinction between decrypted handshake Application Data records ("Decrypted SSL data") and some others (like Alerts, Handshake and Heartbeat, "Decrypted SSL record"). Remove this distinction and always decrypt the payload before passing it on and always display a data sources for decrypted contents ("Decrypted SSL"). This is prepatory work for TLS 1.3 support where the content type is located in the encrypted record, having the record decryption in one place makes it easier to adapt. Change-Id: I92c51c7f9e87e5c93231d28c39a8e896f5afd1ef Ping-Bug: 12779 Reviewed-on: https://code.wireshark.org/review/19789 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/packet-dtls.c118
-rw-r--r--epan/dissectors/packet-ssl-utils.c107
-rw-r--r--epan/dissectors/packet-ssl-utils.h33
-rw-r--r--epan/dissectors/packet-ssl.c158
4 files changed, 157 insertions, 259 deletions
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c
index ac416394dc..7b25cafbf2 100644
--- a/epan/dissectors/packet-dtls.c
+++ b/epan/dissectors/packet-dtls.c
@@ -567,21 +567,19 @@ dtls_is_null_cipher(guint cipher )
}
}
-static gint
+static gboolean
decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
guint32 record_length, guint8 content_type, SslDecryptSession* ssl,
- gboolean save_plaintext)
+ gboolean allow_fragments)
{
- gint ret;
+ gboolean success;
SslDecoder *decoder;
- ret = 0;
-
/* if we can decrypt and decryption have success
* add decrypted data to this packet info */
- if (!ssl || (!save_plaintext && !(ssl->state & SSL_HAVE_SESSION_KEY))) {
+ if (!ssl || !(ssl->state & SSL_HAVE_SESSION_KEY)) {
ssl_debug_printf("decrypt_dtls_record: no session key\n");
- return ret;
+ return FALSE;
}
ssl_debug_printf("decrypt_dtls_record: app_data len %d, ssl state %X\n",
record_length, ssl->state);
@@ -598,7 +596,7 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
if (!decoder && !dtls_is_null_cipher(ssl->session.cipher)) {
ssl_debug_printf("decrypt_dtls_record: no decoder available\n");
- return ret;
+ return FALSE;
}
/* ensure we have enough storage space for decrypted data */
@@ -618,25 +616,33 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
if (ssl->state & SSL_HAVE_SESSION_KEY) {
if (!decoder) {
ssl_debug_printf("decrypt_dtls_record: no decoder available\n");
- return ret;
+ return FALSE;
}
- if (ssl_decrypt_record(ssl, decoder, content_type, tvb_get_ptr(tvb, offset, record_length), record_length,
- &dtls_compressed_data, &dtls_decrypted_data, &dtls_decrypted_data_avail) == 0)
- ret = 1;
+ success = ssl_decrypt_record(ssl, decoder, content_type, tvb_get_ptr(tvb, offset, record_length), record_length,
+ &dtls_compressed_data, &dtls_decrypted_data, &dtls_decrypted_data_avail) == 0;
}
else if (dtls_is_null_cipher(ssl->session.cipher)) {
/* Non-encrypting cipher NULL-XXX */
tvb_memcpy(tvb, dtls_decrypted_data.data, offset, record_length);
dtls_decrypted_data_avail = dtls_decrypted_data.data_len = record_length;
- ret = 1;
+ success = TRUE;
+ } else {
+ success = FALSE;
}
- if (ret && save_plaintext) {
- ssl_add_data_info(proto_dtls, pinfo, dtls_decrypted_data.data, dtls_decrypted_data_avail,
- tvb_raw_offset(tvb)+offset, 0);
- }
+ if (success && dtls_decrypted_data_avail > 0) {
+ const guchar *data = dtls_decrypted_data.data;
+ guint datalen = dtls_decrypted_data_avail;
+
+ // XXX does DTLS have a flow like TLS?
- return ret;
+ // XXX in DTLS, there is only one record per datagram right? Then the "key"
+ // (tvb_raw_offset(tvb)+offset) should not really be needed and can be "0"?
+ ssl_add_record_info(proto_dtls, pinfo, data, datalen,
+ tvb_raw_offset(tvb)+offset,
+ allow_fragments ? decoder->flow : NULL, (ContentType)content_type);
+ }
+ return success;
}
static void
@@ -694,7 +700,8 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *ti;
proto_tree *dtls_record_tree;
proto_item *pi;
- SslDataInfo *appl_data;
+ tvbuff_t *decrypted;
+ SslRecordInfo *record = NULL;
heur_dtbl_entry_t *hdtbl_entry;
/*
@@ -784,8 +791,17 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
*/
ssl_debug_printf("dissect_dtls_record: content_type %d\n",content_type);
- /* PAOLO try to decrypt each record (we must keep ciphers "in sync")
- * store plain text only for app data */
+ /* try to decrypt record on the first pass, if possible. Store decrypted
+ * record for later usage (without having to decrypt again). */
+ if (ssl) {
+ decrypt_dtls_record(tvb, pinfo, offset, record_length, content_type, ssl,
+ content_type == SSL_ID_APP_DATA || content_type == SSL_ID_HANDSHAKE);
+ }
+ decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset, &record);
+ if (decrypted) {
+ add_new_data_source(pinfo, decrypted, "Decrypted DTLS");
+ }
+
switch ((ContentType) content_type) {
case SSL_ID_CHG_CIPHER_SPEC:
@@ -807,15 +823,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
break;
case SSL_ID_ALERT:
{
- tvbuff_t* decrypted;
- decrypted = 0;
- if (ssl&&decrypt_dtls_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE))
- ssl_add_record_info(proto_dtls, pinfo, dtls_decrypted_data.data,
- dtls_decrypted_data_avail, tvb_raw_offset(tvb)+offset);
-
/* try to retrieve and use decrypted alert record, if any. */
- decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset);
if (decrypted) {
dissect_dtls_alert(decrypted, pinfo, dtls_record_tree, 0,
session);
@@ -828,22 +836,9 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
}
case SSL_ID_HANDSHAKE:
{
- tvbuff_t* decrypted;
- decrypted = 0;
-
ssl_calculate_handshake_hash(ssl, tvb, offset, record_length);
- /* try to decrypt handshake record, if possible. Store decrypted
- * record for later usage. The offset is used as 'key' to identify
- * this record into the packet (we can have multiple handshake records
- * in the same frame) */
- if (ssl && decrypt_dtls_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE))
- ssl_add_record_info(proto_dtls, pinfo, dtls_decrypted_data.data,
- dtls_decrypted_data_avail, tvb_raw_offset(tvb)+offset);
-
/* try to retrieve and use decrypted handshake record, if any. */
- decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset);
if (decrypted) {
dissect_dtls_handshake(decrypted, pinfo, dtls_record_tree, 0,
tvb_reported_length(decrypted), session, is_from_server,
@@ -857,10 +852,6 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
break;
}
case SSL_ID_APP_DATA:
- if (ssl)
- decrypt_dtls_record(tvb, pinfo, offset,
- record_length, content_type, ssl, TRUE);
-
/* show on info column what we are decoding */
col_append_str(pinfo->cinfo, COL_INFO, "Application Data");
@@ -884,23 +875,12 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
: "Application Data");
/* show decrypted data info, if available */
- appl_data = ssl_get_data_info(proto_dtls, pinfo, tvb_raw_offset(tvb)+offset);
- if (appl_data && (appl_data->plain_data.data_len > 0))
+ if (decrypted)
{
- 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);
-
- /* create a new TVB structure for desegmented data */
- next_tvb = tvb_new_child_real_data(tvb,
- appl_data->plain_data.data,
- appl_data->plain_data.data_len,
- appl_data->plain_data.data_len);
-
- add_new_data_source(pinfo, next_tvb, "Decrypted DTLS data");
+ ssl_debug_printf("%s decrypted len %d\n", G_STRFUNC, record->data_len);
saved_match_port = pinfo->match_uint;
if (ssl_packet_from_server(session, dtls_associations, pinfo)) {
@@ -914,20 +894,20 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
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);
+ ssl_print_data("decrypted app data", record->plain_data, record->data_len);
if (have_tap_listener(exported_pdu_tap)) {
- export_pdu_packet(next_tvb, pinfo, EXP_PDU_TAG_PROTO_NAME,
+ export_pdu_packet(decrypted, pinfo, EXP_PDU_TAG_PROTO_NAME,
dissector_handle_get_dissector_name(session->app_handle));
}
- dissected = call_dissector_only(session->app_handle, next_tvb, pinfo, top_tree, NULL);
+ dissected = call_dissector_only(session->app_handle, decrypted, pinfo, top_tree, NULL);
}
else {
/* try heuristic subdissectors */
- dissected = dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, top_tree, &hdtbl_entry, NULL);
+ dissected = dissector_try_heuristic(heur_subdissector_list, decrypted, pinfo, top_tree, &hdtbl_entry, NULL);
if (dissected && have_tap_listener(exported_pdu_tap)) {
- export_pdu_packet(next_tvb, pinfo, EXP_PDU_TAG_HEUR_PROTO_NAME, hdtbl_entry->short_name);
+ export_pdu_packet(decrypted, pinfo, EXP_PDU_TAG_HEUR_PROTO_NAME, hdtbl_entry->short_name);
}
}
pinfo->match_uint = saved_match_port;
@@ -939,16 +919,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
offset, record_length, ENC_NA);
break;
case SSL_ID_HEARTBEAT:
- {
- tvbuff_t* decrypted;
-
- if (ssl && decrypt_dtls_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE))
- ssl_add_record_info(proto_dtls, pinfo, dtls_decrypted_data.data,
- dtls_decrypted_data_avail, tvb_raw_offset(tvb)+offset);
-
/* try to retrieve and use decrypted alert record, if any. */
- decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset);
if (decrypted) {
dissect_dtls_heartbeat(decrypted, pinfo, dtls_record_tree, 0,
session, tvb_reported_length (decrypted), TRUE);
@@ -958,7 +929,6 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
session, record_length, FALSE);
}
break;
- }
}
offset += record_length; /* skip to end of record */
diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c
index 4e3a93e6ef..46645d3421 100644
--- a/epan/dissectors/packet-ssl-utils.c
+++ b/epan/dissectors/packet-ssl-utils.c
@@ -4449,103 +4449,68 @@ ssl_packet_from_server(SslSession *session, dissector_table_t table, packet_info
/* Links SSL records with the real packet data. {{{ */
-/* add to packet data a copy of the specified real data */
+/**
+ * Remembers the decrypted TLS record fragment (TLSInnerPlaintext in TLS 1.3) to
+ * avoid the need for a decoder in the second pass. Additionally, it remembers
+ * sequence numbers (for reassembly and Follow SSL Stream).
+ *
+ * @param proto The protocol identifier (proto_ssl or proto_dtls).
+ * @param pinfo The packet where the record originates from.
+ * @param data Decrypted data to store in the record.
+ * @param data_len Length of decrypted record data.
+ * @param record_id The identifier for this record within the current packet.
+ * @param flow Information about sequence numbers, etc.
+ * @param type TLS Content Type (such as handshake or application_data).
+ */
void
-ssl_add_record_info(gint proto, packet_info *pinfo, guchar* data, gint data_len, gint record_id)
+ssl_add_record_info(gint proto, packet_info *pinfo, const guchar *data, gint data_len, gint record_id, SslFlow *flow, ContentType type)
{
- guchar* real_data;
- SslRecordInfo* rec;
+ SslRecordInfo* rec, **prec;
SslPacketInfo* pi;
pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, 0);
if (!pi)
{
- pi = (SslPacketInfo *)wmem_alloc0(wmem_file_scope(), sizeof(SslPacketInfo));
+ pi = wmem_new0(wmem_file_scope(), SslPacketInfo);
p_add_proto_data(wmem_file_scope(), pinfo, proto, 0, pi);
}
- real_data = (guchar *)wmem_alloc(wmem_file_scope(), data_len);
- memcpy(real_data, data, data_len);
-
- rec = (SslRecordInfo *)wmem_alloc(wmem_file_scope(), sizeof(SslRecordInfo));
- rec->id = record_id;
- rec->real_data = real_data;
+ rec = wmem_new(wmem_file_scope(), SslRecordInfo);
+ rec->plain_data = (guchar *)wmem_memdup(wmem_file_scope(), data, data_len);
rec->data_len = data_len;
+ rec->id = record_id;
+ rec->type = type;
+ rec->next = NULL;
- /* head insertion */
- rec->next= pi->handshake_data;
- pi->handshake_data = rec;
-}
-
-/* search in packet data for the specified id; return a newly created tvb for the associated data */
-tvbuff_t*
-ssl_get_record_info(tvbuff_t *parent_tvb, int proto, packet_info *pinfo, gint record_id)
-{
- SslRecordInfo* rec;
- SslPacketInfo* pi;
- pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, 0);
-
- if (!pi)
- return NULL;
-
- for (rec = pi->handshake_data; rec; rec = rec->next)
- if (rec->id == record_id)
- /* link new real_data_tvb with a parent tvb so it is freed when frame dissection is complete */
- return tvb_new_child_real_data(parent_tvb, rec->real_data, rec->data_len, rec->data_len);
-
- return NULL;
-}
-
-void
-ssl_add_data_info(gint proto, packet_info *pinfo, guchar* data, gint data_len, gint key, SslFlow *flow)
-{
- SslDataInfo *rec, **prec;
- SslPacketInfo *pi;
-
- pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, 0);
- if (!pi)
- {
- pi = (SslPacketInfo *)wmem_alloc0(wmem_file_scope(), sizeof(SslPacketInfo));
- p_add_proto_data(wmem_file_scope(), pinfo, proto, 0, pi);
- }
-
- rec = (SslDataInfo *)wmem_alloc(wmem_file_scope(), sizeof(SslDataInfo)+data_len);
- rec->key = key;
- rec->plain_data.data = (guchar*)(rec + 1);
- memcpy(rec->plain_data.data, data, data_len);
- rec->plain_data.data_len = data_len;
- if (flow)
- {
+ if (flow) {
rec->seq = flow->byte_seq;
- rec->nxtseq = flow->byte_seq + data_len;
rec->flow = flow;
flow->byte_seq += data_len;
}
- rec->next = NULL;
- /* insertion */
- prec = &pi->appl_data;
+ /* Remember decrypted records. */
+ prec = &pi->records;
while (*prec) prec = &(*prec)->next;
*prec = rec;
-
- ssl_debug_printf("ssl_add_data_info: new data inserted data_len = %d, seq = %u, nxtseq = %u\n",
- rec->plain_data.data_len, rec->seq, rec->nxtseq);
}
-SslDataInfo*
-ssl_get_data_info(int proto, packet_info *pinfo, gint key)
+/* search in packet data for the specified id; return a newly created tvb for the associated data */
+tvbuff_t*
+ssl_get_record_info(tvbuff_t *parent_tvb, int proto, packet_info *pinfo, gint record_id, SslRecordInfo **matched_record)
{
- SslDataInfo* rec;
+ SslRecordInfo* rec;
SslPacketInfo* pi;
pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, 0);
- if (!pi) return NULL;
+ if (!pi)
+ return NULL;
- rec = pi->appl_data;
- while (rec) {
- if (rec->key == key) return rec;
- rec = rec->next;
- }
+ for (rec = pi->records; rec; rec = rec->next)
+ if (rec->id == record_id) {
+ *matched_record = rec;
+ /* link new real_data_tvb with a parent tvb so it is freed when frame dissection is complete */
+ return tvb_new_child_real_data(parent_tvb, rec->plain_data, rec->data_len, rec->data_len);
+ }
return NULL;
}
diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h
index b3094993f4..39875c6191 100644
--- a/epan/dissectors/packet-ssl-utils.h
+++ b/epan/dissectors/packet-ssl-utils.h
@@ -352,24 +352,19 @@ typedef struct {
} SslDigestAlgo;
typedef struct _SslRecordInfo {
- guchar *real_data;
- gint data_len;
- gint id;
+ guchar *plain_data; /**< Decrypted data. */
+ guint data_len; /**< Length of decrypted data. */
+ gint id; /**< Identifies the exact record within a frame
+ (there can be multiple records in a frame). */
+ ContentType type; /**< Content type of the decrypted record data. */
+ SslFlow *flow; /**< Flow where this record fragment is a part of.
+ Can be NULL if this record type may not be fragmented. */
+ guint32 seq; /**< Data offset within the flow. */
struct _SslRecordInfo* next;
} SslRecordInfo;
-typedef struct _SslDataInfo {
- gint key;
- StringInfo plain_data;
- guint32 seq;
- guint32 nxtseq;
- SslFlow *flow;
- struct _SslDataInfo *next;
-} SslDataInfo;
-
typedef struct {
- SslDataInfo *appl_data;
- SslRecordInfo* handshake_data;
+ SslRecordInfo *records; /**< Decrypted records within this frame. */
} SslPacketInfo;
typedef struct _SslSession {
@@ -587,17 +582,11 @@ ssl_packet_from_server(SslSession *session, dissector_table_t table, packet_info
/* add to packet data a copy of the specified real data */
extern void
-ssl_add_record_info(gint proto, packet_info *pinfo, guchar* data, gint data_len, gint record_id);
+ssl_add_record_info(gint proto, packet_info *pinfo, const guchar *data, gint data_len, gint record_id, SslFlow *flow, ContentType type);
/* search in packet data for the specified id; return a newly created tvb for the associated data */
extern tvbuff_t*
-ssl_get_record_info(tvbuff_t *parent_tvb, gint proto, packet_info *pinfo, gint record_id);
-
-void
-ssl_add_data_info(gint proto, packet_info *pinfo, guchar* data, gint data_len, gint key, SslFlow *flow);
-
-SslDataInfo*
-ssl_get_data_info(int proto, packet_info *pinfo, gint key);
+ssl_get_record_info(tvbuff_t *parent_tvb, gint proto, packet_info *pinfo, gint record_id, SslRecordInfo **matched_record);
/* initialize/reset per capture state data (ssl sessions cache) */
extern void
diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c
index 90548d527d..2ca0dd4798 100644
--- a/epan/dissectors/packet-ssl.c
+++ b/epan/dissectors/packet-ssl.c
@@ -474,12 +474,12 @@ ssl_follow_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _
{
follow_info_t * follow_info = (follow_info_t*) tapdata;
follow_record_t * follow_record = NULL;
- const SslDataInfo * appl_data = NULL;
- const SslPacketInfo * pi = (const SslPacketInfo*)ssl;
+ const SslRecordInfo *appl_data = NULL;
+ const SslPacketInfo *pi = (const SslPacketInfo*)ssl;
show_stream_t from = FROM_CLIENT;
/* Skip packets without decrypted payload data. */
- if (!pi || !pi->appl_data) return FALSE;
+ if (!pi || !pi->records) return FALSE;
/* Compute the packet's sender. */
if (follow_info->client_port == 0) {
@@ -493,7 +493,11 @@ ssl_follow_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _
from = FROM_SERVER;
}
- for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) {
+ for (appl_data = pi->records; appl_data != NULL; appl_data = appl_data->next) {
+
+ /* Include only application data in the record, skipping things like
+ * Handshake messages and alerts. */
+ if (appl_data->type != SSL_ID_APP_DATA) continue;
/* TCP segments that contain the end of two or more SSL PDUs will be
queued to SSL taps for each of those PDUs. Therefore a single
@@ -517,14 +521,14 @@ ssl_follow_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _
follow_record->is_server = (from == FROM_SERVER);
follow_record->packet_num = pinfo->num;
- follow_record->data = g_byte_array_sized_new(appl_data->plain_data.data_len);
+ follow_record->data = g_byte_array_sized_new(appl_data->data_len);
follow_record->data = g_byte_array_append(follow_record->data,
- appl_data->plain_data.data,
- appl_data->plain_data.data_len);
+ appl_data->plain_data,
+ appl_data->data_len);
/* Append the record to the follow_info structure. */
follow_info->payload = g_list_append(follow_info->payload, follow_record);
- follow_info->bytes_written[from] += appl_data->plain_data.data_len;
+ follow_info->bytes_written[from] += appl_data->data_len;
}
return FALSE;
@@ -854,6 +858,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
if (need_desegmentation) {
ssl_debug_printf(" need_desegmentation: offset = %d, reported_length_remaining = %d\n",
offset, tvb_reported_length_remaining(tvb, offset));
+ /* XXX: this seems unused due to new "Follow SSL" method, remove? */
tap_queue_packet(ssl_tap, pinfo, p_get_proto_data(wmem_file_scope(), pinfo, proto_ssl, 0));
return tvb_captured_length(tvb);
}
@@ -866,23 +871,28 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
ssl_debug_flush();
+ /* XXX: this seems unused due to new "Follow SSL" method, remove? */
tap_queue_packet(ssl_tap, pinfo, p_get_proto_data(wmem_file_scope(), pinfo, proto_ssl, 0));
return tvb_captured_length(tvb);
}
-static gint
+/**
+ * Try to decrypt the record and update the internal cipher state.
+ * On success, the decrypted data will be available in "ssl_decrypted_data" of
+ * length "ssl_decrypted_data_avail".
+ */
+static gboolean
decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
guint32 record_length, guint8 content_type, SslDecryptSession *ssl,
- gboolean save_plaintext)
+ gboolean allow_fragments)
{
- gint ret;
+ gboolean success;
gint direction;
StringInfo *data_for_iv;
gint data_for_iv_len;
SslDecoder *decoder;
- ret = 0;
/* if we can decrypt and decryption was a success
* add decrypted data to this packet info */
ssl_debug_printf("decrypt_ssl3_record: app_data len %d, ssl state 0x%02X\n",
@@ -906,27 +916,35 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
if (!decoder) {
ssl_debug_printf("decrypt_ssl3_record: no decoder available\n");
- return ret;
+ return FALSE;
}
/* run decryption and add decrypted payload to protocol data, if decryption
* is successful*/
ssl_decrypted_data_avail = ssl_decrypted_data.data_len;
- if (ssl_decrypt_record(ssl, decoder,
+ success = ssl_decrypt_record(ssl, decoder,
content_type, tvb_get_ptr(tvb, offset, record_length),
- record_length, &ssl_compressed_data, &ssl_decrypted_data, &ssl_decrypted_data_avail) == 0)
- ret = 1;
+ record_length, &ssl_compressed_data, &ssl_decrypted_data, &ssl_decrypted_data_avail) == 0;
/* */
- if (!ret) {
+ if (!success) {
/* save data to update IV if valid session key is obtained later */
data_for_iv = (direction != 0) ? &ssl->server_data_for_iv : &ssl->client_data_for_iv;
data_for_iv_len = (record_length < 24) ? record_length : 24;
ssl_data_set(data_for_iv, (const guchar*)tvb_get_ptr(tvb, offset + record_length - data_for_iv_len, data_for_iv_len), data_for_iv_len);
}
- if (ret && save_plaintext) {
- ssl_add_data_info(proto_ssl, pinfo, ssl_decrypted_data.data, ssl_decrypted_data_avail, tvb_raw_offset(tvb)+offset, decoder->flow);
+ if (success && ssl_decrypted_data_avail > 0) {
+ const guchar *data = ssl_decrypted_data.data;
+ guint datalen = ssl_decrypted_data_avail;
+
+ // XXX extract content type, check padding
+
+ /* In TLS 1.3 only Handshake and Application Data can be fragmented.
+ * Alert messages MUST NOT be fragmented across records, so do not
+ * bother maintaining a flow for those. */
+ ssl_add_record_info(proto_ssl, pinfo, data, datalen, tvb_raw_offset(tvb)+offset,
+ allow_fragments ? decoder->flow : NULL, (ContentType)content_type);
}
- return ret;
+ return success;
}
static void
@@ -1435,40 +1453,29 @@ process_ssl_payload(tvbuff_t *tvb, int offset, packet_info *pinfo,
}
static void
-dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset,
+dissect_ssl_payload(tvbuff_t *decrypted, packet_info *pinfo,
proto_tree *tree, SslSession *session,
+ SslRecordInfo *record,
dissector_handle_t app_handle_port)
{
gboolean save_fragmented;
guint16 save_can_desegment;
- SslDataInfo *appl_data;
- tvbuff_t *next_tvb;
/* Preserve current desegmentation ability to prevent the subdissector
* from messing up the ssl desegmentation */
save_can_desegment = pinfo->can_desegment;
- /* show decrypted data info, if available */
- appl_data = ssl_get_data_info(proto_ssl, pinfo, tvb_raw_offset(tvb)+offset);
- if (!appl_data || !appl_data->plain_data.data_len) return;
-
/* try to dissect decrypted data*/
- ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", appl_data->plain_data.data_len);
- ssl_print_data("decrypted app data fragment", appl_data->plain_data.data, appl_data->plain_data.data_len);
-
- /* create a new TVB structure for desegmented data */
- next_tvb = tvb_new_child_real_data(tvb, appl_data->plain_data.data, appl_data->plain_data.data_len, appl_data->plain_data.data_len);
-
- /* add desegmented data to the data source list */
- add_new_data_source(pinfo, next_tvb, "Decrypted SSL data");
+ ssl_debug_printf("%s decrypted len %d\n", G_STRFUNC, record->data_len);
+ ssl_print_data("decrypted app data fragment", record->plain_data, record->data_len);
/* Can we desegment this segment? */
if (ssl_desegment_app_data) {
/* Yes. */
pinfo->can_desegment = 2;
- desegment_ssl(next_tvb, pinfo, 0, appl_data->seq, appl_data->nxtseq,
+ desegment_ssl(decrypted, pinfo, 0, record->seq, record->seq + record->data_len,
session, proto_tree_get_root(tree), tree,
- appl_data->flow, app_handle_port);
+ record->flow, app_handle_port);
} else if (session->app_handle || app_handle_port) {
/* No - just call the subdissector.
Mark this as fragmented, so if somebody throws an exception,
@@ -1477,7 +1484,7 @@ dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset,
save_fragmented = pinfo->fragmented;
pinfo->fragmented = TRUE;
- process_ssl_payload(next_tvb, 0, pinfo, tree, session, app_handle_port);
+ process_ssl_payload(decrypted, 0, pinfo, tree, session, app_handle_port);
pinfo->fragmented = save_fragmented;
}
@@ -1525,6 +1532,9 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *ssl_record_tree;
proto_item *pi;
guint32 available_bytes;
+ tvbuff_t *decrypted;
+ SslRecordInfo *record = NULL;
+
ti = NULL;
ssl_record_tree = NULL;
@@ -1682,8 +1692,20 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
*/
ssl_debug_printf("dissect_ssl3_record: content_type %d %s\n",content_type, val_to_str_const(content_type, ssl_31_content_type, "unknown"));
- /* PAOLO try to decrypt each record (we must keep ciphers "in sync")
- * store plain text only for app data */
+ /* try to decrypt record on the first pass, if possible. Store decrypted
+ * record for later usage (without having to decrypt again). The offset is
+ * used as 'key' to identify this record in the packet (we can have multiple
+ * handshake records in the same frame). */
+ if (ssl) {
+ decrypt_ssl3_record(tvb, pinfo, offset, record_length, content_type, ssl,
+ content_type == SSL_ID_APP_DATA ||
+ content_type == SSL_ID_HANDSHAKE);
+ }
+ /* try to retrieve and use decrypted alert/handshake/appdata record, if any. */
+ decrypted = ssl_get_record_info(tvb, proto_ssl, pinfo, tvb_raw_offset(tvb)+offset, &record);
+ if (decrypted) {
+ add_new_data_source(pinfo, decrypted, "Decrypted SSL");
+ }
switch ((ContentType) content_type) {
case SSL_ID_CHG_CIPHER_SPEC:
@@ -1704,44 +1726,15 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
session->is_session_resumed = FALSE;
break;
case SSL_ID_ALERT:
- {
- tvbuff_t *decrypted;
-
- if (ssl&&decrypt_ssl3_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE))
- ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data,
- ssl_decrypted_data_avail, tvb_raw_offset(tvb)+offset);
-
- /* try to retrieve and use decrypted alert record, if any. */
- decrypted = ssl_get_record_info(tvb, proto_ssl, pinfo, tvb_raw_offset(tvb)+offset);
if (decrypted) {
- add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
dissect_ssl3_alert(decrypted, pinfo, ssl_record_tree, 0, session);
} else {
dissect_ssl3_alert(tvb, pinfo, ssl_record_tree, offset, session);
}
break;
- }
case SSL_ID_HANDSHAKE:
- {
- tvbuff_t *decrypted;
-
ssl_calculate_handshake_hash(ssl, tvb, offset, record_length);
-
- /* try to decrypt handshake record, if possible. Store decrypted
- * record for later usage. The offset is used as 'key' to identify
- * this record in the packet (we can have multiple handshake records
- * in the same frame) */
- if (ssl && decrypt_ssl3_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE))
- ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data,
- ssl_decrypted_data_avail, tvb_raw_offset(tvb)+offset);
-
- /* try to retrieve and use decrypted handshake record, if any. */
- decrypted = ssl_get_record_info(tvb, proto_ssl, pinfo, tvb_raw_offset(tvb)+offset);
if (decrypted) {
- /* add desegmented data to the data source list */
- add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
dissect_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0,
tvb_reported_length(decrypted), session,
is_from_server, ssl, content_type, version);
@@ -1751,20 +1744,10 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
content_type, version);
}
break;
- }
case SSL_ID_APP_DATA:
{
dissector_handle_t app_handle;
- if (ssl){
- decrypt_ssl3_record(tvb, pinfo, offset,
- record_length, content_type, ssl, TRUE);
- /* if application data desegmentation is allowed and needed */
- /* if (ssl_desegment_app_data && *need_desegmentation)
- ssl_desegment_ssl_app_data(ssl,pinfo);
- */
- }
-
/* show on info column what we are decoding */
col_append_str(pinfo->cinfo, COL_INFO, "Application Data");
@@ -1789,7 +1772,9 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb,
offset, record_length, ENC_NA);
- dissect_ssl_payload(tvb, pinfo, offset, tree, session, app_handle);
+ if (decrypted) {
+ dissect_ssl_payload(decrypted, pinfo, tree, session, record, app_handle);
+ }
/* Set app proto again in case the heuristics found a different proto. */
if (session->app_handle && session->app_handle != app_handle)
@@ -1802,18 +1787,7 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
break;
}
case SSL_ID_HEARTBEAT:
- {
- tvbuff_t *decrypted;
-
- if (ssl && decrypt_ssl3_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE))
- ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data,
- ssl_decrypted_data_avail, tvb_raw_offset(tvb)+offset);
-
- /* try to retrieve and use decrypted handshake record, if any. */
- decrypted = ssl_get_record_info(tvb, proto_ssl, pinfo, tvb_raw_offset(tvb)+offset);
if (decrypted) {
- add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
dissect_ssl3_heartbeat(decrypted, pinfo, ssl_record_tree, 0, session, tvb_reported_length (decrypted), TRUE);
} else {
gboolean plaintext = TRUE;
@@ -1828,7 +1802,6 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
dissect_ssl3_heartbeat(tvb, pinfo, ssl_record_tree, offset, session, record_length, plaintext);
}
break;
- }
}
offset += record_length; /* skip to end of record */
@@ -4252,6 +4225,7 @@ proto_register_ssl(void)
register_cleanup_routine(ssl_cleanup);
register_decode_as(&ssl_da);
+ /* XXX: this seems unused due to new "Follow SSL" method, remove? */
ssl_tap = register_tap("ssl");
ssl_debug_printf("proto_register_ssl: registered tap %s:%d\n",
"ssl", ssl_tap);