From Robin Seggelmann: Add support for RFC 6520.
authortuexen <tuexen@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 26 Feb 2012 13:50:52 +0000 (13:50 +0000)
committertuexen <tuexen@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 26 Feb 2012 13:50:52 +0000 (13:50 +0000)
From me: Some cleanup
Initial work was done by Denis Jaeger and
Lukas Scharlau, but the code got rewritten by Robin.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@41189 f5534014-38df-0310-8fa8-9805f1628bb7

epan/dissectors/packet-dtls.c
epan/dissectors/packet-ssl-utils.c
epan/dissectors/packet-ssl-utils.h
epan/dissectors/packet-ssl.c

index 3ae3fd3..dd3a75e 100644 (file)
@@ -133,6 +133,13 @@ static gint hf_dtls_handshake_dnames            = -1;
 static gint hf_dtls_handshake_dname_len         = -1;
 static gint hf_dtls_handshake_dname             = -1;
 
+static gint hf_dtls_heartbeat_extension_mode          = -1;
+static gint hf_dtls_heartbeat_message                 = -1;
+static gint hf_dtls_heartbeat_message_type            = -1;
+static gint hf_dtls_heartbeat_message_payload_length  = -1;
+static gint hf_dtls_heartbeat_message_payload         = -1;
+static gint hf_dtls_heartbeat_message_padding         = -1;
+
 static gint hf_dtls_fragments                   = -1;
 static gint hf_dtls_fragment                    = -1;
 static gint hf_dtls_fragment_overlap            = -1;
@@ -149,6 +156,7 @@ static gint ett_dtls                   = -1;
 static gint ett_dtls_record            = -1;
 static gint ett_dtls_alert             = -1;
 static gint ett_dtls_handshake         = -1;
+static gint ett_dtls_heartbeat         = -1;
 static gint ett_dtls_cipher_suites     = -1;
 static gint ett_dtls_comp_methods      = -1;
 static gint ett_dtls_extension         = -1;
@@ -312,6 +320,11 @@ static void dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
                                    guint *conv_version,
                                    SslDecryptSession *conv_data, guint8 content_type);
 
+/* heartbeat message dissector */
+static void dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
+                                   proto_tree *tree, guint32 offset,
+                                   guint *conv_version, guint32 record_length);
+
 
 static void dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
                                        proto_tree *tree,
@@ -923,6 +936,27 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
     proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb,
                         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, offset);
+
+    /* try to retrive and use decrypted alert record, if any. */
+    decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, offset);
+    if (decrypted) {
+      dissect_dtls_heartbeat(decrypted, pinfo, dtls_record_tree, 0,
+                             conv_version, record_length);
+      add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
+    } else {
+      dissect_dtls_heartbeat(tvb, pinfo, dtls_record_tree, offset,
+                             conv_version, record_length);
+    }
+    break;
+  }
 
   default:
     /* shouldn't get here since we check above for valid types */
@@ -1377,6 +1411,86 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
     }
 }
 
+/* dissects the heartbeat message, filling in the tree */
+static void
+dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
+                       proto_tree *tree, guint32 offset,
+                       guint* conv_version, guint32 record_length)
+{
+  /*     struct {
+   *         HeartbeatMessageType type;
+   *         uint16 payload_length;
+   *         opaque payload;
+   *         opaque padding;
+   *     } HeartbeatMessage;
+   */
+
+  proto_tree  *ti;
+  proto_tree  *dtls_heartbeat_tree;
+  const gchar *type;
+  guint8       byte;
+  guint16      payload_length;
+  guint16      padding_length;
+
+  dtls_heartbeat_tree = NULL;
+
+  if (tree) {
+    ti = proto_tree_add_item(tree, hf_dtls_heartbeat_message, tvb,
+                             offset, record_length - 32, ENC_NA);
+    dtls_heartbeat_tree = proto_item_add_subtree(ti, ett_dtls_heartbeat);
+  }
+
+  /*
+   * set the record layer label
+   */
+
+  /* first lookup the names for the message type and the payload length */
+  byte = tvb_get_guint8(tvb, offset);
+  type = match_strval(byte, tls_heartbeat_type);
+
+  payload_length = tvb_get_ntohs(tvb, offset + 1);
+  padding_length = record_length - 3 - payload_length;
+
+  /* now set the text in the record layer line */
+  if (type && (payload_length <= record_length - 16 - 3)) {
+    col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat %s", type);
+  } else {
+    col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Heartbeat");
+  }
+
+  if (tree) {
+    if (type && (payload_length <= record_length - 16 - 3)) {
+      proto_item_set_text(tree, "%s Record Layer: Heartbeat "
+                                "%s",
+                                val_to_str_const(*conv_version, ssl_version_short_names, "SSL"),
+                                type);
+      proto_tree_add_item(dtls_heartbeat_tree, hf_dtls_heartbeat_message_type,
+                          tvb, offset, 1, ENC_BIG_ENDIAN);
+      offset += 1;
+      proto_tree_add_uint(dtls_heartbeat_tree, hf_dtls_heartbeat_message_payload_length,
+                          tvb, offset, 2, payload_length);
+      offset += 2;
+      proto_tree_add_bytes_format(dtls_heartbeat_tree, hf_dtls_heartbeat_message_payload,
+                                  tvb, offset, payload_length,
+                                  NULL, "Payload (%u byte%s)",
+                                  payload_length,
+                                  plurality(payload_length, "", "s"));
+      offset += payload_length;
+      proto_tree_add_bytes_format(dtls_heartbeat_tree, hf_dtls_heartbeat_message_padding,
+                                  tvb, offset, padding_length,
+                                  NULL, "Padding and HMAC (%u byte%s)",
+                                  padding_length,
+                                  plurality(padding_length, "", "s"));
+    } else {
+      proto_item_set_text(tree,
+                         "%s Record Layer: Encrypted Heartbeat",
+                         val_to_str_const(*conv_version, ssl_version_short_names, "SSL"));
+      proto_item_set_text(dtls_heartbeat_tree,
+                          "Encrypted Heartbeat Message");
+    }
+  }
+}
+
 static gint
 dissect_dtls_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
                               guint32 offset, SslDecryptSession* ssl, gint from_server)
@@ -1497,11 +1611,20 @@ dissect_dtls_hnd_hello_ext(tvbuff_t *tvb,
                           tvb, offset, 2, ext_len);
       offset += 2;
 
-      proto_tree_add_bytes_format(ext_tree, hf_dtls_handshake_extension_data,
-                                  tvb, offset, ext_len, NULL,
-                                  "Data (%u byte%s)", ext_len,
-                                  plurality(ext_len, "", "s"));
-      offset += ext_len;
+      switch (ext_type) {
+      case SSL_HND_HELLO_EXT_HEARTBEAT:
+          proto_tree_add_item(ext_tree, hf_dtls_heartbeat_extension_mode,
+                              tvb, offset, 1, ENC_BIG_ENDIAN);
+          break;
+      default:
+          proto_tree_add_bytes_format(ext_tree, hf_dtls_handshake_extension_data,
+                                      tvb, offset, ext_len, NULL,
+                                      "Data (%u byte%s)",
+                                      ext_len, plurality(ext_len, "", "s"));
+          offset += ext_len;
+          break;
+      }
+
       left   -= 2 + 2 + ext_len;
     }
 
@@ -2369,6 +2492,33 @@ proto_register_dtls(void)
         FT_BYTES, BASE_NONE, NULL, 0x0,
         "Distinguished name of a CA that server trusts", HFILL }
     },
+    { &hf_dtls_heartbeat_extension_mode,
+      { "Mode", "dtls.handshake.extension.heartbeat.mode",
+        FT_UINT8, BASE_DEC, VALS(tls_heartbeat_mode), 0x0,
+        "Heartbeat extension mode", HFILL }
+    },
+    { &hf_dtls_heartbeat_message,
+      { "Heartbeat Message", "dtls.heartbeat_message",
+        FT_NONE, BASE_NONE, NULL, 0x0,
+        NULL, HFILL }
+    },
+    { &hf_dtls_heartbeat_message_type,
+      { "Type", "dtls.heartbeat_message.type",
+        FT_UINT8, BASE_DEC, VALS(tls_heartbeat_type), 0x0,
+        "Heartbeat message type", HFILL }
+    },
+    { &hf_dtls_heartbeat_message_payload_length,
+      { "Payload Length", "dtls.heartbeat_message.payload_length",
+        FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
+    },
+    { &hf_dtls_heartbeat_message_payload,
+      { "Payload Length", "dtls.heartbeat_message.payload",
+        FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
+    },
+    { &hf_dtls_heartbeat_message_padding,
+      { "Payload Length", "dtls.heartbeat_message.padding",
+        FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
+    },
     { &hf_dtls_fragments,
       { "Message fragments", "dtls.fragments",
         FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
@@ -2419,6 +2569,7 @@ proto_register_dtls(void)
     &ett_dtls_record,
     &ett_dtls_alert,
     &ett_dtls_handshake,
+    &ett_dtls_heartbeat,
     &ett_dtls_cipher_suites,
     &ett_dtls_comp_methods,
     &ett_dtls_extension,
index 10c6fc1..a56bd43 100644 (file)
@@ -405,6 +405,7 @@ const value_string ssl_31_content_type[] = {
     { 21, "Alert" },
     { 22, "Handshake" },
     { 23, "Application Data" },
+    { 24, "Heartbeat" },
     { 0x00, NULL }
 };
 
@@ -484,6 +485,18 @@ const value_string ssl_31_handshake_type[] = {
     { 0x00, NULL }
 };
 
+const value_string tls_heartbeat_type[] = {
+    { 1, "Request" },
+    { 2, "Response" },
+    { 0x00, NULL }
+};
+
+const value_string tls_heartbeat_mode[] = {
+    { 1, "Peer allowed to send requests" },
+    { 2, "Peer not allowed to send requests" },
+    { 0x00, NULL }
+};
+
 const value_string ssl_31_compression_method[] = {
     { 0, "null" },
     { 1, "DEFLATE" },
@@ -899,6 +912,7 @@ const value_string tls_hello_extension_types[] = {
     { 12, "srp" },  /* RFC 5054 */
     { 13, "signature_algorithms" },  /* RFC 5246 */
     { 14, "use_srtp" },
+    { SSL_HND_HELLO_EXT_HEARTBEAT, "Heartbeat" },  /* RFC 6520 */
     { 35, "SessionTicket TLS" },  /* RFC 4507 */
     { 65281, "renegotiation_info" },
     { 0, NULL }
@@ -3270,16 +3284,18 @@ ssl_association_add(GTree* associations, dissector_handle_t handle, guint port,
         assoc->handle = find_dissector("data");
     }
 
-    if(!assoc->handle) {
+    if (!assoc->handle) {
         fprintf(stderr, "association_add() could not find handle for protocol:%s\n",protocol);
     } else {
-        if(port) {
-            if(tcp)
+        if (port) {
+            if (tcp)
                 dissector_add_uint("tcp.port", port, handle);
             else
                 dissector_add_uint("udp.port", port, handle);
         }
         g_tree_insert(associations, assoc, assoc);
+
+        dissector_add("sctp.port", port, handle);
     }
 }
 
@@ -3586,7 +3602,7 @@ ssl_restore_session(SslDecryptSession* ssl, GHashTable *session_hash)
 int
 ssl_is_valid_content_type(guint8 type)
 {
-    if (type >= 0x14 && type <= 0x17)
+    if (type >= 0x14 && type <= 0x18)
     {
         return 1;
     }
index 6e11f59..478681c 100644 (file)
@@ -71,6 +71,7 @@
 #define SSL_ID_ALERT                   0x15
 #define SSL_ID_HANDSHAKE               0x16
 #define SSL_ID_APP_DATA                0x17
+#define SSL_ID_HEARTBEAT               0x18
 
 #define SSL_HND_HELLO_REQUEST          0
 #define SSL_HND_CLIENT_HELLO           1
 
 #define SSL_HND_HELLO_EXT_ELLIPTIC_CURVES    0x000a
 #define SSL_HND_HELLO_EXT_EC_POINT_FORMATS   0x000b
+#define SSL_HND_HELLO_EXT_HEARTBEAT          0x000f
 
 #define SSL_HND_CERT_STATUS_TYPE_OCSP  1
 
@@ -162,6 +164,8 @@ extern const value_string ssl_31_change_cipher_spec[];
 extern const value_string ssl_31_alert_level[];
 extern const value_string ssl_31_alert_description[];
 extern const value_string ssl_31_handshake_type[];
+extern const value_string tls_heartbeat_type[];
+extern const value_string tls_heartbeat_mode[];
 extern const value_string ssl_31_compression_method[];
 extern const value_string ssl_31_key_exchange_algorithm[];
 extern const value_string ssl_31_signature_algorithm[];
index 87c0406..0abf6d4 100644 (file)
@@ -254,11 +254,19 @@ static int hf_ssl_segment_too_long_fragment   = -1;
 static int hf_ssl_segment_error               = -1;
 static int hf_ssl_segment_count               = -1;
 
+static gint hf_ssl_heartbeat_extension_mode          = -1;
+static gint hf_ssl_heartbeat_message                 = -1;
+static gint hf_ssl_heartbeat_message_type            = -1;
+static gint hf_ssl_heartbeat_message_payload_length  = -1;
+static gint hf_ssl_heartbeat_message_payload         = -1;
+static gint hf_ssl_heartbeat_message_padding         = -1;
+
 /* Initialize the subtree pointers */
 static gint ett_ssl                   = -1;
 static gint ett_ssl_record            = -1;
 static gint ett_ssl_alert             = -1;
 static gint ett_ssl_handshake         = -1;
+static gint ett_ssl_heartbeat         = -1;
 static gint ett_ssl_cipher_suites     = -1;
 static gint ett_ssl_comp_methods      = -1;
 static gint ett_ssl_extension         = -1;
@@ -455,6 +463,11 @@ static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
                                    guint *conv_version, guint conv_cipher,
                                    SslDecryptSession *conv_data, const guint8 content_type);
 
+/* heartbeat message dissector */
+static void dissect_ssl3_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
+                                   proto_tree *tree, guint32 offset,
+                                   guint *conv_version, guint32 record_length);
+
 /* hello extension dissector */
 static gint dissect_ssl3_hnd_hello_ext_elliptic_curves(tvbuff_t *tvb,
                                                        proto_tree *tree, guint32 offset);
@@ -1659,6 +1672,25 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
         dissect_ssl_payload(tvb, pinfo, offset, tree, association);
 
         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, offset);
+
+        /* try to retrieve and use decrypted handshake record, if any. */
+        decrypted = ssl_get_record_info(tvb, proto_ssl, pinfo, offset);
+        if (decrypted) {
+            add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
+            dissect_ssl3_heartbeat(decrypted, pinfo, ssl_record_tree, 0, conv_version, record_length);
+        } else {
+            dissect_ssl3_heartbeat(tvb, pinfo, ssl_record_tree, offset, conv_version, record_length);
+        }
+        break;
+    }
 
     default:
         /* shouldn't get here since we check above for valid types */
@@ -2107,6 +2139,86 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
     }
 }
 
+/* dissects the heartbeat message, filling in the tree */
+static void
+dissect_ssl3_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
+                       proto_tree *tree, guint32 offset,
+                       guint* conv_version, guint32 record_length)
+{
+    /*     struct {
+     *         HeartbeatMessageType type;
+     *         uint16 payload_length;
+     *         opaque payload;
+     *         opaque padding;
+     *     } HeartbeatMessage;
+     */
+
+    proto_tree  *ti;
+    proto_tree  *tls_heartbeat_tree;
+    const gchar *type;
+    guint8       byte;
+    guint16      payload_length;
+    guint16      padding_length;
+
+    tls_heartbeat_tree = NULL;
+
+    if (tree) {
+        ti = proto_tree_add_item(tree, hf_ssl_heartbeat_message, tvb,
+                                 offset, record_length - 32, ENC_NA);
+        tls_heartbeat_tree = proto_item_add_subtree(ti, ett_ssl_heartbeat);
+    }
+
+    /*
+     * set the record layer label
+     */
+
+    /* first lookup the names for the message type and the payload length */
+    byte = tvb_get_guint8(tvb, offset);
+    type = match_strval(byte, tls_heartbeat_type);
+
+    payload_length = tvb_get_ntohs(tvb, offset + 1);
+    padding_length = record_length - 3 - payload_length;
+
+    /* now set the text in the record layer line */
+    if (type && (payload_length <= record_length - 16 - 3)) {
+        col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat %s", type);
+    } else {
+        col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Heartbeat");
+    }
+
+    if (tree) {
+        if (type && (payload_length <= record_length - 16 - 3)) {
+            proto_item_set_text(tree, "%s Record Layer: Heartbeat "
+                                "%s",
+                                val_to_str_const(*conv_version, ssl_version_short_names, "SSL"),
+                                type);
+            proto_tree_add_item(tls_heartbeat_tree, hf_ssl_heartbeat_message_type,
+                                tvb, offset, 1, ENC_BIG_ENDIAN);
+            offset += 1;
+            proto_tree_add_uint(tls_heartbeat_tree, hf_ssl_heartbeat_message_payload_length,
+                                tvb, offset, 2, payload_length);
+            offset += 2;
+            proto_tree_add_bytes_format(tls_heartbeat_tree, hf_ssl_heartbeat_message_payload,
+                                        tvb, offset, payload_length,
+                                        NULL, "Payload (%u byte%s)",
+                                        payload_length,
+                                        plurality(payload_length, "", "s"));
+            offset += payload_length;
+            proto_tree_add_bytes_format(tls_heartbeat_tree, hf_ssl_heartbeat_message_padding,
+                                        tvb, offset, padding_length,
+                                        NULL, "Padding and HMAC (%u byte%s)",
+                                        padding_length,
+                                        plurality(padding_length, "", "s"));
+        } else {
+            proto_item_set_text(tree,
+                                "%s Record Layer: Encrypted Heartbeat",
+                                val_to_str_const(*conv_version, ssl_version_short_names, "SSL"));
+            proto_item_set_text(tls_heartbeat_tree,
+                                "Encrypted Heartbeat Message");
+        }
+    }
+}
+
 static gint
 dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
                               guint32 offset, SslDecryptSession* ssl, gint from_server)
@@ -2233,6 +2345,10 @@ dissect_ssl3_hnd_hello_ext(tvbuff_t *tvb,
         case SSL_HND_HELLO_EXT_EC_POINT_FORMATS:
             offset = dissect_ssl3_hnd_hello_ext_ec_point_formats(tvb, ext_tree, offset);
             break;
+        case SSL_HND_HELLO_EXT_HEARTBEAT:
+            proto_tree_add_item(ext_tree, hf_ssl_heartbeat_extension_mode,
+                                tvb, offset, 1, ENC_BIG_ENDIAN);
+            break;
         default:
             proto_tree_add_bytes_format(ext_tree, hf_ssl_handshake_extension_data,
                                         tvb, offset, ext_len, NULL,
@@ -5064,6 +5180,33 @@ proto_register_ssl(void)
             FT_NONE, BASE_NONE, NULL, 0x0,
             "Distinguished name of a CA that server trusts", HFILL }
         },
+        { &hf_ssl_heartbeat_extension_mode,
+          { "Mode", "ssl.handshake.extension.heartbeat.mode",
+            FT_UINT8, BASE_DEC, VALS(tls_heartbeat_mode), 0x0,
+            "Heartbeat extension mode", HFILL }
+        },
+        { &hf_ssl_heartbeat_message,
+          { "Heartbeat Message", "ssl.heartbeat_message",
+            FT_NONE, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }
+        },
+        { &hf_ssl_heartbeat_message_type,
+          { "Type", "ssl.heartbeat_message.type",
+            FT_UINT8, BASE_DEC, VALS(tls_heartbeat_type), 0x0,
+            "Heartbeat message type", HFILL }
+        },
+        { &hf_ssl_heartbeat_message_payload_length,
+          { "Payload Length", "ssl.heartbeat_message.payload_length",
+            FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
+        },
+        { &hf_ssl_heartbeat_message_payload,
+          { "Payload Length", "ssl.heartbeat_message.payload",
+            FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
+        },
+        { &hf_ssl_heartbeat_message_padding,
+          { "Payload Length", "ssl.heartbeat_message.padding",
+            FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
+        },
         { &hf_ssl2_handshake_challenge,
           { "Challenge", "ssl.handshake.challenge",
             FT_NONE, BASE_NONE, NULL, 0x0,
@@ -5246,6 +5389,7 @@ proto_register_ssl(void)
         &ett_ssl_record,
         &ett_ssl_alert,
         &ett_ssl_handshake,
+        &ett_ssl_heartbeat,
         &ett_ssl_cipher_suites,
         &ett_ssl_comp_methods,
         &ett_ssl_extension,