summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-ssl.c176
1 files changed, 103 insertions, 73 deletions
diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c
index 869355b076..8b1bad7765 100644
--- a/epan/dissectors/packet-ssl.c
+++ b/epan/dissectors/packet-ssl.c
@@ -556,12 +556,12 @@ static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo,
const SslSession *session);
/* handshake protocol dissector */
-static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
+static void process_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, guint32 offset,
guint32 record_length, gboolean maybe_encrypted,
SslSession *session, gint is_from_server,
SslDecryptSession *conv_data,
- const guint8 content_type, const guint16 version);
+ const guint16 version);
/* heartbeat message dissector */
static void dissect_ssl3_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
@@ -1845,13 +1845,13 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
break;
case SSL_ID_HANDSHAKE:
if (decrypted) {
- dissect_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0,
+ process_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0,
tvb_reported_length(decrypted), FALSE, session,
- is_from_server, ssl, content_type, version);
+ is_from_server, ssl, version);
} else {
- dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset,
+ process_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset,
record_length, TRUE, session,
- is_from_server, ssl, content_type, version);
+ is_from_server, ssl, version);
}
break;
case SSL_ID_APP_DATA:
@@ -2001,10 +2001,9 @@ dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo,
static void
dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, guint32 offset,
- guint32 record_length, gboolean maybe_encrypted,
SslSession *session, gint is_from_server,
- SslDecryptSession *ssl, const guint8 content_type,
- const guint16 version)
+ SslDecryptSession *ssl, const guint16 version,
+ gboolean is_first_message)
{
/* struct {
* HandshakeType msg_type;
@@ -2030,79 +2029,35 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
const gchar *msg_type_str;
guint8 msg_type;
guint32 length;
- gboolean first_iteration = TRUE;
proto_item *ti;
- /*
- * If this is not a decrypted buffer, then perhaps it is still in plaintext.
- * Heuristics: if the buffer is too small, it is likely not encrypted.
- * Otherwise assume that the Handshake does not contain two successive
- * HelloRequest messages (type=0x00 length=0x000000, type=0x00). If this
- * occurs, then we have possibly found the explicit nonce preceding the
- * encrypted contents for GCM/CCM cipher suites as used in TLS 1.2.
- */
- if (maybe_encrypted) {
- maybe_encrypted = tvb_bytes_exist(tvb, offset, 5) && tvb_get_ntoh40(tvb, offset) == 0;
- }
-
- /* just as there can be multiple records per packet, there
- * can be multiple messages per record as long as they have
- * the same content type
- *
- * we really only care about this for handshake messages
- */
-
- /* set record_length to the max offset */
- record_length += offset;
- while (offset < record_length)
{
guint32 hs_offset = offset;
msg_type = tvb_get_guint8(tvb, offset);
length = tvb_get_ntoh24(tvb, offset + 1);
- /* Check the length in the handshake message. Assume it's an
- * encrypted handshake message if the message would pass
- * the record_length boundary. This is a workaround for the
- * situation where the first octet of the encrypted handshake
- * message is actually a known handshake message type.
- */
- if (!maybe_encrypted && offset + length <= record_length)
- msg_type_str = try_val_to_str(msg_type, ssl_31_handshake_type);
- else
- msg_type_str = NULL;
+ msg_type_str = try_val_to_str(msg_type, ssl_31_handshake_type);
+ /* Caller should have checked that the msg type is valid! */
+ DISSECTOR_ASSERT(msg_type_str != NULL);
ssl_debug_printf("dissect_ssl3_handshake iteration %d type %d offset %d length %d "
- "bytes, remaining %d \n", first_iteration, msg_type, offset, length, record_length);
- if (!msg_type_str && !first_iteration)
- {
- /* only dissect / report messages if they're
- * either the first message in this record
- * or they're a valid message type
- */
- return;
- }
+ "bytes\n", is_first_message, msg_type, offset, length);
/*
* Update our info string
*/
- col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
- (msg_type_str != NULL) ? msg_type_str : "Encrypted Handshake Message");
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msg_type_str);
/* set the label text on the record layer expanding node */
- if (first_iteration)
- {
- proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s",
+ if (is_first_message) {
+ proto_item_set_text(tree, "%s Record Layer: Handshake Protocol: %s",
val_to_str_const(version, ssl_version_short_names, "SSL"),
- val_to_str_const(content_type, ssl_31_content_type, "unknown"),
- (msg_type_str!=NULL) ? msg_type_str :
- "Encrypted Handshake Message");
- }
- else
- {
- proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s",
+ msg_type_str);
+ } else {
+ /* TODO just append sth like ", Certificate" instead? */
+ proto_item_set_text(tree, "%s Record Layer: Handshake Protocol: %s",
val_to_str_const(version, ssl_version_short_names, "SSL"),
- val_to_str_const(content_type, ssl_31_content_type, "unknown"),
"Multiple Handshake Messages");
}
@@ -2112,13 +2067,7 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
ssl_hand_tree = proto_item_add_subtree(ti, ett_ssl_handshake);
/* set the text label on the subtree node */
- proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s",
- (msg_type_str != NULL) ? msg_type_str :
- "Encrypted Handshake Message");
-
- /* if we don't have a valid handshake type, just quit dissecting */
- if (!msg_type_str)
- return;
+ proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s", msg_type_str);
/* add nodes for the message type and message length */
proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_type,
@@ -2278,9 +2227,90 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
dissect_ssl3_hnd_encrypted_exts(tvb, ssl_hand_tree, offset);
break;
}
+ }
+}
+
+/* process Handshake protocol messages, performing reassembly if needed. */
+static void
+process_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, guint32 offset,
+ guint32 record_length, gboolean maybe_encrypted,
+ SslSession *session, gint is_from_server,
+ SslDecryptSession *ssl, const guint16 version)
+{
+ /*
+ * A single record can have multiple handshake messages and a single
+ * handshake message can span multiple records. This function uses a loop to
+ * handle the former and reassembly to handle the latter.
+ */
+ guint32 offset_end = offset + record_length;
+ const gchar *msg_type_str;
+ guint8 msg_type;
+ guint32 length;
+ gboolean is_first_message = TRUE;
+ gboolean is_continuation = FALSE;
+
+ if (!is_continuation) {
+ /*
+ * If this is not a decrypted buffer, then perhaps it is still in plaintext.
+ * Heuristics: if the buffer is too small, it is likely not encrypted.
+ * Otherwise assume that the Handshake does not contain two successive
+ * HelloRequest messages (type=0x00 length=0x000000, type=0x00). If this
+ * occurs, then we have possibly found the explicit nonce preceding the
+ * encrypted contents for GCM/CCM cipher suites as used in TLS 1.2.
+ */
+ if (maybe_encrypted) {
+ maybe_encrypted = tvb_bytes_exist(tvb, offset, 5) && tvb_get_ntoh40(tvb, offset) == 0;
+ }
+ if (maybe_encrypted) {
+ msg_type = tvb_get_guint8(tvb, offset);
+ msg_type_str = try_val_to_str(msg_type, ssl_31_handshake_type);
+ /*
+ * TODO reduce false detection of plaintext from 7.8% (20/256) to
+ * .61% by checking the next valid content type.
+ */
+ if (msg_type_str == NULL) {
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
+ "Encrypted Handshake Message");
+
+ /* set the label text on the record layer expanding node */
+ proto_item_set_text(tree, "%s Record Layer: Handshake Protocol: %s",
+ val_to_str_const(version, ssl_version_short_names, "SSL"),
+ "Encrypted Handshake Message");
+ return;
+ }
+ }
+ }
+
+ while (offset < offset_end) {
+ msg_type = tvb_get_guint8(tvb, offset);
+ length = tvb_get_ntoh24(tvb, offset + 1);
+
+ /* Check the length in the handshake message. Assume it's an
+ * encrypted handshake message if the message would pass
+ * the record_length boundary. This is a workaround for the
+ * situation where the first octet of the encrypted handshake
+ * message is actually a known handshake message type.
+ */
+ if (!maybe_encrypted && offset + 4 + length <= offset_end)
+ msg_type_str = try_val_to_str(msg_type, ssl_31_handshake_type);
+ else
+ msg_type_str = NULL;
+
+ if (!msg_type_str) {
+ /* only dissect further messages if the message type is valid. */
+ return;
+ }
+
+ /*
+ * We have a valid message type and received all data, start the
+ * actual handshake dissection.
+ */
+ dissect_ssl3_handshake(tvb, pinfo, tree, offset, session,
+ is_from_server, ssl, version, is_first_message);
- offset += length;
- first_iteration = FALSE; /* set up for next pass, if any */
+ offset += 4 + length;
+ is_first_message = FALSE; /* set up for next pass, if any */
}
}