summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-dtls.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--epan/dissectors/packet-dtls.c1595
1 files changed, 1224 insertions, 371 deletions
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c
index fecc56e2..ea7bdd29 100644
--- a/epan/dissectors/packet-dtls.c
+++ b/epan/dissectors/packet-dtls.c
@@ -47,10 +47,12 @@
#include <epan/decode_as.h>
#include <epan/proto_data.h>
#include <epan/secrets.h> /* for privkey_hash_table_new */
+#include <epan/tfs.h>
#include <wsutil/str_util.h>
#include <wsutil/strtoi.h>
#include <wsutil/utf8_entities.h>
#include <wsutil/rsa.h>
+#include <wsutil/pint.h>
#include "packet-tls-utils.h"
#include "packet-dtls.h"
#include "packet-rtp.h"
@@ -60,8 +62,8 @@ void proto_register_dtls(void);
#ifdef HAVE_LIBGNUTLS
/* DTLS User Access Table */
-static ssldecrypt_assoc_t *dtlskeylist_uats = NULL;
-static guint ndtlsdecrypt = 0;
+static ssldecrypt_assoc_t *dtlskeylist_uats;
+static unsigned ndtlsdecrypt;
#endif
/* we need to remember the top tree so that subdissectors we call are created
@@ -85,6 +87,12 @@ static proto_tree *top_tree;
#define SRTP_AEAD_AES_128_GCM 0x0007
#define SRTP_AEAD_AES_256_GCM 0x0008
+#define DTLS13_FIXED_MASK 0xE0
+#define DTLS13_C_BIT_MASK 0x10
+#define DTLS13_S_BIT_MASK 0x08
+#define DTLS13_L_BIT_MASK 0x04
+#define DTLS13_HDR_EPOCH_BIT_MASK 0x3
+
static const value_string srtp_protection_profile_vals[] = {
{ SRTP_AES128_CM_HMAC_SHA1_80, "SRTP_AES128_CM_HMAC_SHA1_80" }, /* RFC 5764 */
{ SRTP_AES128_CM_HMAC_SHA1_32, "SRTP_AES128_CM_HMAC_SHA1_32" },
@@ -95,96 +103,118 @@ static const value_string srtp_protection_profile_vals[] = {
{ 0x00, NULL },
};
+static const true_false_string dtls_uni_hdr_seq_tfs = {
+ "16 bits",
+ "8 bits"
+};
+
/* Initialize the protocol and registered fields */
-static gint dtls_tap = -1;
-static gint exported_pdu_tap = -1;
-static gint proto_dtls = -1;
-static gint hf_dtls_record = -1;
-static gint hf_dtls_record_content_type = -1;
-static gint hf_dtls_record_special_type = -1;
-static gint hf_dtls_record_version = -1;
-static gint hf_dtls_record_epoch = -1;
-static gint hf_dtls_record_sequence_number = -1;
-static gint hf_dtls_record_connection_id = -1;
-static gint hf_dtls_record_length = -1;
-static gint hf_dtls_record_appdata = -1;
-static gint hf_dtls_record_appdata_proto = -1;
-static gint hf_dtls_record_encrypted_content = -1;
-static gint hf_dtls_alert_message = -1;
-static gint hf_dtls_alert_message_level = -1;
-static gint hf_dtls_alert_message_description = -1;
-static gint hf_dtls_handshake_protocol = -1;
-static gint hf_dtls_handshake_type = -1;
-static gint hf_dtls_handshake_length = -1;
-static gint hf_dtls_handshake_message_seq = -1;
-static gint hf_dtls_handshake_fragment_offset = -1;
-static gint hf_dtls_handshake_fragment_length = -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;
-static gint hf_dtls_fragment_overlap_conflicts = -1;
-static gint hf_dtls_fragment_multiple_tails = -1;
-static gint hf_dtls_fragment_too_long_fragment = -1;
-static gint hf_dtls_fragment_error = -1;
-static gint hf_dtls_fragment_count = -1;
-static gint hf_dtls_reassembled_in = -1;
-static gint hf_dtls_reassembled_length = -1;
-
-static gint hf_dtls_hs_ext_use_srtp_protection_profiles_length = -1;
-static gint hf_dtls_hs_ext_use_srtp_protection_profile = -1;
-static gint hf_dtls_hs_ext_use_srtp_mki_length = -1;
-static gint hf_dtls_hs_ext_use_srtp_mki = -1;
+static int dtls_tap = -1;
+static int exported_pdu_tap = -1;
+static int proto_dtls;
+static int hf_dtls_record;
+static int hf_dtls_record_content_type;
+static int hf_dtls_record_special_type;
+static int hf_dtls_record_version;
+static int hf_dtls_ack_record_numbers;
+static int hf_dtls_record_epoch;
+static int hf_dtls_record_epoch64;
+static int hf_dtls_record_sequence_number;
+static int hf_dtls_record_sequence_suffix;
+static int hf_dtls_record_sequence_suffix_dec;
+static int hf_dtls_record_connection_id;
+static int hf_dtls_record_length;
+static int hf_dtls_record_appdata;
+static int hf_dtls_record_appdata_proto;
+static int hf_dtls_record_encrypted_content;
+static int hf_dtls_alert_message;
+static int hf_dtls_alert_message_level;
+static int hf_dtls_alert_message_description;
+static int hf_dtls_handshake_protocol;
+static int hf_dtls_handshake_type;
+static int hf_dtls_handshake_length;
+static int hf_dtls_handshake_message_seq;
+static int hf_dtls_handshake_fragment_offset;
+static int hf_dtls_handshake_fragment_length;
+
+static int hf_dtls_heartbeat_message;
+static int hf_dtls_heartbeat_message_type;
+static int hf_dtls_heartbeat_message_payload_length;
+static int hf_dtls_heartbeat_message_payload;
+static int hf_dtls_heartbeat_message_padding;
+
+static int hf_dtls_ack_message;
+static int hf_dtls_ack_record_numbers_length;
+static int hf_dtls_fragments;
+static int hf_dtls_fragment;
+static int hf_dtls_fragment_overlap;
+static int hf_dtls_fragment_overlap_conflicts;
+static int hf_dtls_fragment_multiple_tails;
+static int hf_dtls_fragment_too_long_fragment;
+static int hf_dtls_fragment_error;
+static int hf_dtls_fragment_count;
+static int hf_dtls_reassembled_in;
+static int hf_dtls_reassembled_length;
+
+static int hf_dtls_hs_ext_use_srtp_protection_profiles_length;
+static int hf_dtls_hs_ext_use_srtp_protection_profile;
+static int hf_dtls_hs_ext_use_srtp_mki_length;
+static int hf_dtls_hs_ext_use_srtp_mki;
+
+static int hf_dtls_uni_hdr;
+static int hf_dtls_uni_hdr_fixed;
+static int hf_dtls_uni_hdr_cid;
+static int hf_dtls_uni_hdr_seq;
+static int hf_dtls_uni_hdr_len;
+static int hf_dtls_uni_hdr_epoch;
/* header fields used in ssl-utils, but defined here. */
-static dtls_hfs_t dtls_hfs = { -1, -1 };
+static dtls_hfs_t dtls_hfs;
/* Initialize the subtree pointers */
-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_certs = -1;
-
-static gint ett_dtls_fragment = -1;
-static gint ett_dtls_fragments = -1;
-
-static expert_field ei_dtls_handshake_fragment_length_too_long = EI_INIT;
-static expert_field ei_dtls_handshake_fragment_length_zero = EI_INIT;
-static expert_field ei_dtls_handshake_fragment_past_end_msg = EI_INIT;
-static expert_field ei_dtls_msg_len_diff_fragment = EI_INIT;
-static expert_field ei_dtls_heartbeat_payload_length = EI_INIT;
-static expert_field ei_dtls_cid_invalid_content_type = EI_INIT;
-static expert_field ei_dtls_use_srtp_profiles_length = EI_INIT;
+static int ett_dtls;
+static int ett_dtls_record;
+static int ett_dtls_alert;
+static int ett_dtls_handshake;
+static int ett_dtls_heartbeat;
+static int ett_dtls_ack;
+static int ett_dtls_ack_record_numbers;
+static int ett_dtls_ack_record_number;
+static int ett_dtls_certs;
+static int ett_dtls_uni_hdr;
+
+static int ett_dtls_fragment;
+static int ett_dtls_fragments;
+
+static expert_field ei_dtls_handshake_fragment_length_too_long;
+static expert_field ei_dtls_handshake_fragment_length_zero;
+static expert_field ei_dtls_handshake_fragment_past_end_msg;
+static expert_field ei_dtls_msg_len_diff_fragment;
+static expert_field ei_dtls_heartbeat_payload_length;
+static expert_field ei_dtls_cid_invalid_content_type;
+static expert_field ei_dtls_use_srtp_profiles_length;
#if 0
-static expert_field ei_dtls_cid_invalid_enc_content = EI_INIT;
+static expert_field ei_dtls_cid_invalid_enc_content;
#endif
#ifdef HAVE_LIBGNUTLS
-static GHashTable *dtls_key_hash = NULL;
-static wmem_stack_t *key_list_stack = NULL;
-static uat_t *dtlsdecrypt_uat = NULL;
-static const gchar *dtls_keys_list = NULL;
+static GHashTable *dtls_key_hash;
+static wmem_stack_t *key_list_stack;
+static uat_t *dtlsdecrypt_uat;
+static const char *dtls_keys_list;
#endif
static reassembly_table dtls_reassembly_table;
-static dissector_table_t dtls_associations = NULL;
-static dissector_handle_t dtls_handle = NULL;
-static StringInfo dtls_compressed_data = {NULL, 0};
-static StringInfo dtls_decrypted_data = {NULL, 0};
-static gint dtls_decrypted_data_avail = 0;
+static dissector_table_t dtls_associations;
+static dissector_handle_t dtls_handle;
+static StringInfo dtls_compressed_data;
+static StringInfo dtls_decrypted_data;
+static int dtls_decrypted_data_avail;
-static ssl_common_options_t dtls_options = { NULL, NULL};
-static const gchar *dtls_debug_file_name = NULL;
+static ssl_common_options_t dtls_options;
+static const char *dtls_debug_file_name;
-static guint32 dtls_default_client_cid_length;
-static guint32 dtls_default_server_cid_length;
+static uint32_t dtls_default_client_cid_length;
+static uint32_t dtls_default_server_cid_length;
static heur_dissector_list_t heur_subdissector_list;
@@ -254,7 +284,7 @@ dtls_cleanup(void)
static void
dtls_parse_uat(void)
{
- guint i, port;
+ unsigned i, port;
dissector_handle_t handle;
if (dtls_key_hash)
@@ -268,7 +298,7 @@ dtls_parse_uat(void)
port = GPOINTER_TO_UINT(wmem_stack_pop(key_list_stack));
handle = dissector_get_uint_handle(dtls_associations, port);
if (handle != NULL)
- ssl_association_remove("dtls.port", dtls_handle, handle, port, FALSE);
+ ssl_association_remove("dtls.port", dtls_handle, handle, port, false);
}
}
@@ -285,7 +315,7 @@ dtls_parse_uat(void)
for (i = 0; i < ndtlsdecrypt; i++)
{
ssldecrypt_assoc_t *d = &(dtlskeylist_uats[i]);
- ssl_parse_key_list(d, dtls_key_hash, "dtls.port", dtls_handle, FALSE);
+ ssl_parse_key_list(d, dtls_key_hash, "dtls.port", dtls_handle, false);
if (key_list_stack && ws_strtou32(d->port, NULL, &port))
wmem_stack_push(key_list_stack, GUINT_TO_POINTER(port));
}
@@ -305,9 +335,9 @@ dtls_reset_uat(void)
static void
dtls_parse_old_keys(void)
{
- gchar **old_keys, **parts, *err;
- guint i;
- gchar *uat_entry;
+ char **old_keys, **parts, *err;
+ unsigned i;
+ char *uat_entry;
/* Import old-style keys */
if (dtlsdecrypt_uat && dtls_keys_list && dtls_keys_list[0]) {
@@ -315,7 +345,7 @@ dtls_parse_old_keys(void)
for (i = 0; old_keys[i] != NULL; i++) {
parts = g_strsplit(old_keys[i], ",", 4);
if (parts[0] && parts[1] && parts[2] && parts[3]) {
- gchar *path = uat_esc(parts[3], (guint)strlen(parts[3]));
+ char *path = uat_esc(parts[3], (unsigned)strlen(parts[3]));
uat_entry = wmem_strdup_printf(NULL, "\"%s\",\"%s\",\"%s\",\"%s\",\"\"",
parts[0], parts[1], parts[2], path);
g_free(path);
@@ -338,41 +368,49 @@ dtls_parse_old_keys(void)
*
*/
-/* record layer dissector */
-static gint dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
- proto_tree *tree, guint32 offset,
- SslSession *session, gint is_from_server,
+/* record layer dissectors */
+static int dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, uint32_t offset,
+ SslSession *session, int is_from_server,
SslDecryptSession *conv_data,
- guint8 curr_layer_num_ssl);
+ uint8_t curr_layer_num_ssl);
+static int dissect_dtls13_record(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, uint32_t offset,
+ SslSession *session, int is_from_server,
+ SslDecryptSession *conv_data,
+ uint8_t curr_layer_num_ssl);
/* alert message dissector */
static void dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
- proto_tree *tree, guint32 offset,
+ proto_tree *tree, uint32_t offset,
const SslSession *session);
/* handshake protocol dissector */
static void dissect_dtls_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, guint8 content_type);
+ proto_tree *tree, uint32_t offset,
+ uint32_t record_length, bool maybe_encrypted,
+ SslSession *session, int is_from_server,
+ SslDecryptSession *conv_data, uint8_t content_type);
/* heartbeat message dissector */
static void dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
- proto_tree *tree, guint32 offset,
- const SslSession *session, guint32 record_length,
- gboolean decrypted);
+ proto_tree *tree, uint32_t offset,
+ const SslSession *session, uint32_t record_length,
+ bool decrypted);
+
+/* acknowledgement message dissector */
+static void dissect_dtls_ack(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, uint32_t record_length);
static int dissect_dtls_hnd_hello_verify_request(ssl_common_dissect_t *hf, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree,
- guint32 offset, guint32 offset_end);
+ uint32_t offset, uint32_t offset_end);
/*
* Support Functions
*
*/
-static gint looks_like_dtls(tvbuff_t *tvb, guint32 offset);
+static int looks_like_dtls(tvbuff_t *tvb, uint32_t offset);
/*********************************************************************
*
@@ -389,11 +427,11 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
conversation_t *conversation;
proto_item *ti;
proto_tree *dtls_tree;
- guint32 offset;
+ uint32_t offset;
SslDecryptSession *ssl_session = NULL;
SslSession *session = NULL;
- gint is_from_server;
- guint8 curr_layer_num_ssl = pinfo->curr_layer_num;
+ int is_from_server;
+ uint8_t curr_layer_num_ssl = pinfo->curr_layer_num;
ti = NULL;
dtls_tree = NULL;
@@ -413,7 +451,7 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
*/
conversation = find_or_create_conversation(pinfo);
- guint8 record_type = tvb_get_guint8(tvb, offset);
+ uint8_t record_type = tvb_get_uint8(tvb, offset);
/* try to get decrypt session from the connection ID only for the first pass,
* it should be available from the conversation in the second pass
@@ -440,7 +478,12 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
if (session->last_nontls_frame != 0 &&
session->last_nontls_frame >= pinfo->num) {
/* This conversation started at a different protocol and STARTTLS was
- * used, but this packet comes too early. */
+ * used, but this packet comes too early.
+ * XXX - Does anything use STARTTLS with DTLS? Would we get here anyway,
+ * since we don't call conversation_set_dissector[_from_frame_number] for
+ * DTLS? Regardless, dissect_dtls_heur should check for this 0 and return
+ * false.
+ */
return 0;
}
@@ -468,40 +511,28 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
{
/* first try to dispatch off the cached version
* known to be associated with the conversation
+ *
+ * In fact, all versions of DTLS have the same dissector. Note as
+ * we don't set DTLS as the conversation dissector, either
+ * looks_like_dtls() passed in dissect_dtls_heur(), or this has
+ * been set to DTLS explicitly via the port or some other method,
+ * so we already think this is DTLS. We don't expect Continuation
+ * Data over UDP datagrams (unlike TCP segments), but we'll check
+ * the content type in dissect_dtls_record and mark as Continuation
+ * Data if an unknown type, so the only thing calling looks_like_dtls()
+ * here would do is additionally verify the legacy_record_version -
+ * which MUST be ignored for all purposes per RFC 9147.
*/
switch(session->version) {
case DTLSV1DOT0_VERSION:
case DTLSV1DOT0_OPENSSL_VERSION:
case DTLSV1DOT2_VERSION:
+ case DTLSV1DOT3_VERSION:
+ default:
offset = dissect_dtls_record(tvb, pinfo, dtls_tree,
offset, session, is_from_server,
ssl_session, curr_layer_num_ssl);
break;
-
- /* that failed, so apply some heuristics based
- * on this individual packet
- */
- default:
- if (looks_like_dtls(tvb, offset))
- {
- /* looks like dtls */
- offset = dissect_dtls_record(tvb, pinfo, dtls_tree,
- offset, session, is_from_server,
- ssl_session, curr_layer_num_ssl);
- }
- else
- {
- /* looks like something unknown, so lump into
- * continuation data
- */
- offset = tvb_reported_length(tvb);
- col_append_sep_str(pinfo->cinfo, COL_INFO,
- NULL, "Continuation Data");
-
- /* Set the protocol column */
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTLS");
- }
- break;
}
}
@@ -510,68 +541,111 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
return tvb_captured_length(tvb);
}
-static guint8 dtls_cid_length(SslSession *session, gboolean is_from_server)
+static uint8_t dtls_cid_length(SslSession *session, bool is_from_server)
{
- guint8 cid_length;
+ uint8_t cid_length;
if (is_from_server) {
if (session && session->client_cid_len_present) {
cid_length = session->client_cid_len;
} else {
- cid_length = (guint8)dtls_default_client_cid_length;
+ cid_length = (uint8_t)dtls_default_client_cid_length;
}
} else {
if (session && session->server_cid_len_present) {
cid_length = session->server_cid_len;
} else {
- cid_length = (guint8)dtls_default_server_cid_length;
+ cid_length = (uint8_t)dtls_default_server_cid_length;
}
}
return cid_length;
}
-static gboolean
+static bool
dissect_dtls_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
/* Stronger confirmation of DTLS packet is provided by verifying the
* captured payload length against the remainder of the UDP packet size. */
- guint length = tvb_captured_length(tvb);
- guint offset = 0;
+ unsigned length = tvb_captured_length(tvb);
+ unsigned offset = 0;
+ unsigned record_length = 0;
+ SslDecryptSession *ssl_session = NULL;
+ SslSession *session = NULL;
if (tvb_reported_length(tvb) == length) {
/* The entire payload was captured. */
while (offset + 13 <= length && looks_like_dtls(tvb, offset)) {
/* Advance offset to the end of the current DTLS record */
- guint8 record_type = tvb_get_guint8(tvb, offset);
-
- if (record_type == SSL_ID_TLS12_CID) {
- /* CID length is not embedded in the packet */
- SslDecryptSession *ssl_session = ssl_get_session_by_cid(tvb, offset + 11);
- SslSession *session = ssl_session ? &ssl_session->session : NULL;
- gint is_from_server = ssl_packet_from_server(session, dtls_associations, pinfo);
- offset += dtls_cid_length(session, is_from_server);
+ uint8_t record_type = tvb_get_uint8(tvb, offset);
+
+ if ((record_type & DTLS13_FIXED_MASK) >> 5 == 1) {
+ offset += 1;
+ /* With the DTLS 1.3 Unified Header, the legacy_record_version
+ * field is encrypted, so our heuristics are weaker. Only accept
+ * the frame if we already have seen DTLS (with the correct CID,
+ * if the CID is included) on the connection.
+ * N.B. - We don't call conversation_set_dissector_from_frame_number
+ * like in packet-tls.c because DTLS is commonly multiplexed with
+ * SRTP/SRTCP/STUN/TURN/ZRTP per RFC 7983. (And now QUIC, RFC 9443.)
+ */
+ if (record_type & DTLS13_C_BIT_MASK) {
+ /* CID length is not embedded in the packet */
+ ssl_session = ssl_get_session_by_cid(tvb, offset);
+ session = ssl_session ? &ssl_session->session : NULL;
+ int is_from_server = ssl_packet_from_server(session, dtls_associations, pinfo);
+ offset += dtls_cid_length(session, is_from_server);
+ } else {
+ /* No CID, just look for a session on this conversation. Don't
+ * call ssl_get_session here, as we don't want to allocate a new
+ * session. */
+ conversation_t *conversation = find_or_create_conversation(pinfo);
+ ssl_session = conversation_get_proto_data(conversation, proto_dtls);
+ session = ssl_session ? &ssl_session->session : NULL;
+ }
+ if (session == NULL) {
+ return false;
+ }
+ offset += (record_type & DTLS13_S_BIT_MASK) ? 2 : 1;
+ if (record_type & DTLS13_L_BIT_MASK) {
+ record_length = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ } else {
+ /* Length not present, so the heuristic is weaker. */
+ record_length = tvb_reported_length_remaining(tvb, offset);
+ }
+ } else {
+ offset += 11;
+ if (record_type == SSL_ID_TLS12_CID) {
+ /* CID length is not embedded in the packet */
+ ssl_session = ssl_get_session_by_cid(tvb, offset);
+ session = ssl_session ? &ssl_session->session : NULL;
+ int is_from_server = ssl_packet_from_server(session, dtls_associations, pinfo);
+ offset += dtls_cid_length(session, is_from_server);
+ }
+ record_length = tvb_get_ntohs(tvb, offset);
+ offset += 2;
}
- offset += tvb_get_ntohs(tvb, offset + 11) + 13;
+ offset += record_length;
if (offset == length) {
dissect_dtls(tvb, pinfo, tree, data);
- return TRUE;
+ return true;
}
}
if (pinfo->fragmented && offset >= 13) {
dissect_dtls(tvb, pinfo, tree, data);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/* This packet was truncated by the capture process due to a snapshot
* length - do our best with what we've got. */
while (tvb_captured_length_remaining(tvb, offset) >= 3) {
if (!looks_like_dtls(tvb, offset))
- return FALSE;
+ return false;
offset += 3;
if (tvb_captured_length_remaining(tvb, offset) >= 10 ) {
@@ -579,12 +653,12 @@ dissect_dtls_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
} else {
/* Dissect what we've got, which might be as little as 3 bytes. */
dissect_dtls(tvb, pinfo, tree, data);
- return TRUE;
+ return true;
}
if (offset == length) {
/* Can this ever happen? Well, just in case ... */
dissect_dtls(tvb, pinfo, tree, data);
- return TRUE;
+ return true;
}
}
@@ -593,13 +667,13 @@ dissect_dtls_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
* a packet fragment that's also been truncated. */
if ((length >= 3) && (offset <= tvb_reported_length(tvb) || pinfo->fragmented)) {
dissect_dtls(tvb, pinfo, tree, data);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static gboolean
-dtls_is_null_cipher(guint cipher )
+static bool
+dtls_is_null_cipher(unsigned cipher )
{
switch(cipher) {
case 0x0000:
@@ -623,23 +697,23 @@ dtls_is_null_cipher(guint cipher )
case 0xc039:
case 0xc03a:
case 0xc03b:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
static void
-dtls_save_decrypted_record(packet_info *pinfo, gint record_id, guint8 content_type, guint8 curr_layer_num_ssl)
+dtls_save_decrypted_record(packet_info *pinfo, int record_id, uint8_t content_type, uint8_t curr_layer_num_ssl, bool inner_content_type)
{
- const guchar *data = dtls_decrypted_data.data;
- guint datalen = dtls_decrypted_data_avail;
+ const unsigned char *data = dtls_decrypted_data.data;
+ unsigned datalen = dtls_decrypted_data_avail;
if (datalen == 0) {
return;
}
- if (content_type == SSL_ID_TLS12_CID) {
+ if (content_type == SSL_ID_TLS12_CID || inner_content_type) {
/*
* The actual data is followed by the content type and then zero or
* more padding. Scan backwards for content type, skipping padding.
@@ -661,19 +735,19 @@ dtls_save_decrypted_record(packet_info *pinfo, gint record_id, guint8 content_ty
ssl_add_record_info(proto_dtls, pinfo, data, datalen, record_id, NULL, (ContentType)content_type, curr_layer_num_ssl);
}
-static gboolean
-decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryptSession *ssl,
- guint8 content_type, guint16 record_version, guint16 record_length, guint8 curr_layer_num_ssl,
- const guchar *cid, guint8 cid_length)
+static bool
+decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, uint32_t offset, SslDecryptSession *ssl,
+ uint8_t content_type, uint16_t record_version, uint16_t record_length, uint8_t curr_layer_num_ssl,
+ const unsigned char *cid, uint8_t cid_length)
{
- gboolean success;
+ bool success;
SslDecoder *decoder;
/* if we can decrypt and decryption have success
* add decrypted data to this packet info */
- if (!ssl || !(ssl->state & SSL_HAVE_SESSION_KEY)) {
+ if (!ssl || ((ssl->session.version != DTLSV1DOT3_VERSION) && !(ssl->state & SSL_HAVE_SESSION_KEY))) {
ssl_debug_printf("decrypt_dtls_record: no session key\n");
- return FALSE;
+ return false;
}
ssl_debug_printf("decrypt_dtls_record: app_data len %d, ssl state %X\n",
record_length, ssl->state);
@@ -690,7 +764,7 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
if (!decoder && !dtls_is_null_cipher(ssl->session.cipher)) {
ssl_debug_printf("decrypt_dtls_record: no decoder available\n");
- return FALSE;
+ return false;
}
/* ensure we have enough storage space for decrypted data */
@@ -699,7 +773,7 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
ssl_debug_printf("decrypt_dtls_record: allocating %d bytes"
" for decrypt data (old len %d)\n",
record_length + 32, dtls_decrypted_data.data_len);
- dtls_decrypted_data.data = (guchar *)g_realloc(dtls_decrypted_data.data,
+ dtls_decrypted_data.data = (unsigned char *)g_realloc(dtls_decrypted_data.data,
record_length + 32);
dtls_decrypted_data.data_len = record_length + 32;
}
@@ -707,12 +781,12 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
/* run decryption and add decrypted payload to protocol data, if decryption
* is successful*/
dtls_decrypted_data_avail = dtls_decrypted_data.data_len;
- if (ssl->state & SSL_HAVE_SESSION_KEY) {
+ if (ssl->state & SSL_HAVE_SESSION_KEY || ssl->session.version == DTLSV1DOT3_VERSION) {
if (!decoder) {
ssl_debug_printf("decrypt_dtls_record: no decoder available\n");
- return FALSE;
+ return false;
}
- success = ssl_decrypt_record(ssl, decoder, content_type, record_version, FALSE,
+ success = ssl_decrypt_record(ssl, decoder, content_type, record_version, false,
tvb_get_ptr(tvb, offset, record_length), record_length, cid, cid_length,
&dtls_compressed_data, &dtls_decrypted_data, &dtls_decrypted_data_avail) == 0;
}
@@ -720,19 +794,19 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
/* 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;
- success = TRUE;
+ success = true;
} else {
- success = FALSE;
+ success = false;
}
if (success) {
- dtls_save_decrypted_record(pinfo, tvb_raw_offset(tvb)+offset, content_type, curr_layer_num_ssl);
+ dtls_save_decrypted_record(pinfo, tvb_raw_offset(tvb)+offset, content_type, curr_layer_num_ssl, ssl->session.version == DTLSV1DOT3_VERSION);
}
return success;
}
static void
-export_pdu_packet(tvbuff_t *tvb, packet_info *pinfo, guint8 tag, const gchar *name)
+export_pdu_packet(tvbuff_t *tvb, packet_info *pinfo, uint8_t tag, const char *name)
{
exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, name, tag);
@@ -749,12 +823,93 @@ export_pdu_packet(tvbuff_t *tvb, packet_info *pinfo, guint8 tag, const gchar *na
* DTLS Dissection Routines
*
*********************************************************************/
-static gint
+
+static void
+dissect_dtls_appdata(tvbuff_t *tvb, packet_info *pinfo, uint32_t offset,
+ uint32_t record_length, SslSession *session,
+ proto_tree *dtls_record_tree, bool is_from_server,
+ tvbuff_t *decrypted, SslRecordInfo *record)
+{
+ heur_dtbl_entry_t *hdtbl_entry;
+ proto_item *ti;
+ /* show on info column what we are decoding */
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Application Data");
+
+ /* 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. */
+ dissector_handle_t handle;
+ handle = dissector_get_uint_handle(dtls_associations, pinfo->srcport);
+ handle = handle ? handle : dissector_get_uint_handle(dtls_associations, pinfo->destport);
+ if (handle) session->app_handle = handle;
+ }
+
+ proto_item_set_text(dtls_record_tree,
+ "%s Record Layer: %s Protocol: %s",
+ val_to_str_const(session->version, ssl_version_short_names, "DTLS"),
+ val_to_str_const(SSL_ID_APP_DATA, ssl_31_content_type, "unknown"),
+ session->app_handle
+ ? dissector_handle_get_protocol_long_name(session->app_handle)
+ : "Application Data");
+
+ proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb,
+ offset, record_length, ENC_NA);
+
+ if (session->app_handle) {
+ ti = proto_tree_add_string(dtls_record_tree, hf_dtls_record_appdata_proto, tvb, 0, 0, dissector_handle_get_protocol_long_name(session->app_handle));
+ proto_item_set_generated(ti);
+ }
+
+ /* show decrypted data info, if available */
+ if (decrypted) {
+ bool dissected;
+ uint16_t saved_match_port;
+ /* try to dissect decrypted data*/
+ ssl_debug_printf("%s decrypted len %d\n", G_STRFUNC, record->data_len);
+
+ saved_match_port = pinfo->match_uint;
+ if (is_from_server) {
+ pinfo->match_uint = pinfo->srcport;
+ } else {
+ pinfo->match_uint = pinfo->destport;
+ }
+
+ /* find out a dissector using server port*/
+ 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", record->plain_data, record->data_len);
+
+ if (have_tap_listener(exported_pdu_tap)) {
+ export_pdu_packet(decrypted, pinfo, EXP_PDU_TAG_DISSECTOR_NAME,
+ dissector_handle_get_dissector_name(session->app_handle));
+ }
+
+ dissected = (bool)call_dissector_only(session->app_handle, decrypted, pinfo, top_tree, NULL);
+ }
+ else {
+ /* try heuristic subdissectors */
+ 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(decrypted, pinfo, EXP_PDU_TAG_HEUR_DISSECTOR_NAME, hdtbl_entry->short_name);
+ }
+ }
+ pinfo->match_uint = saved_match_port;
+ /* fallback to data dissector */
+ if (!dissected)
+ call_data_dissector(decrypted, pinfo, top_tree);
+ }
+}
+/* Dissect a DTLS record from version 1.2 and below */
+static int
dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
- proto_tree *tree, guint32 offset,
- SslSession *session, gint is_from_server,
+ proto_tree *tree, uint32_t offset,
+ SslSession *session, int is_from_server,
SslDecryptSession* ssl,
- guint8 curr_layer_num_ssl)
+ uint8_t curr_layer_num_ssl)
{
/*
@@ -792,22 +947,21 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
*
*/
- guint32 dtls_record_length;
- guint32 record_length;
- guint16 version;
- guint16 epoch;
- guint64 sequence_number;
- guint8 content_type;
- guint content_type_offset;
- guint8 next_byte;
+ uint32_t dtls_record_length;
+ uint32_t record_length;
+ uint16_t version;
+ uint16_t epoch;
+ uint64_t sequence_number;
+ uint8_t content_type;
+ unsigned content_type_offset;
+ uint8_t next_byte;
proto_tree *ti;
proto_tree *dtls_record_tree;
proto_item *length_pi, *ct_pi;
tvbuff_t *decrypted;
SslRecordInfo *record = NULL;
- heur_dtbl_entry_t *hdtbl_entry;
- guint8 *cid = NULL;
- guint8 cid_length;
+ uint8_t *cid = NULL;
+ uint8_t cid_length;
/* Connection ID length to use if any */
cid_length = dtls_cid_length(session, is_from_server);
@@ -815,13 +969,18 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/*
* Get the record layer fields of interest
*/
- content_type = tvb_get_guint8(tvb, offset);
+ content_type = tvb_get_uint8(tvb, offset);
+ if ((content_type & DTLS13_FIXED_MASK) >> 5 == 1) {
+ /* RFC 9147 s4.1: this is a DTLS 1.3 Unified Header record */
+ return dissect_dtls13_record(tvb, pinfo, tree, offset, session,
+ is_from_server, ssl, curr_layer_num_ssl);
+ }
version = tvb_get_ntohs(tvb, offset + 1);
epoch = tvb_get_ntohs(tvb, offset + 3);
sequence_number = tvb_get_ntoh48(tvb, offset + 5);
if (content_type == SSL_ID_TLS12_CID && cid_length > 0) {
- cid = tvb_memdup(wmem_packet_scope(), tvb, offset + 11, cid_length);
+ cid = tvb_memdup(pinfo->pool, tvb, offset + 11, cid_length);
record_length = tvb_get_ntohs(tvb, offset + cid_length + 11);
dtls_record_length = 13 + cid_length + record_length;
} else {
@@ -844,8 +1003,6 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
val_to_str_const(session->version, ssl_version_short_names, "DTLS"),
content_type);
- /* Set the protocol column */
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTLS");
return offset + dtls_record_length;
}
@@ -910,12 +1067,30 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/*
* if we don't already have a version set for this conversation,
* but this message's version is authoritative (i.e., it's
- * not client_hello, then save the version to the conversation
- * structure and print the column version
+ * not client_hello), then save the version to the conversation
+ * structure and print the column version.
*/
- next_byte = tvb_get_guint8(tvb, offset);
- if (session->version == SSL_VER_UNKNOWN)
- ssl_try_set_version(session, ssl, content_type, next_byte, TRUE, version);
+ next_byte = tvb_get_uint8(tvb, offset);
+ if (session->version == SSL_VER_UNKNOWN) {
+ if (version == DTLSV1DOT2_VERSION && content_type == SSL_ID_HANDSHAKE) {
+ /*
+ * if the version in the header is DTLS 1.2, this may actually be
+ * a DTLS 1.3 handshake; this must be determined from any
+ * supported_versions extension in the hello messages. We'll check
+ * this later in dissect_dtls_handshake, but try to get the column
+ * correct here on the first pass if we can.
+ */
+ if (next_byte == SSL_HND_SERVER_HELLO && record_length > 12 && tvb_bytes_exist(tvb, offset, 12)) {
+ uint32_t fragment_offset = tvb_get_ntoh24(tvb, offset + 6);
+ uint32_t fragment_length = tvb_get_ntoh24(tvb, offset + 9);
+ if (fragment_offset == 0 && tvb_bytes_exist(tvb, offset + 12, fragment_length)) {
+ /* Only look at the first fragment. */
+ tls_scan_server_hello(tvb, offset + 12, offset + 12 + fragment_length, &version, NULL);
+ }
+ }
+ }
+ ssl_try_set_version(session, ssl, content_type, next_byte, true, version);
+ }
col_set_str(pinfo->cinfo, COL_PROTOCOL,
val_to_str_const(session->version, ssl_version_short_names, "DTLS"));
@@ -925,8 +1100,9 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
ssl_debug_printf("dissect_dtls_record: content_type %d epoch %d seq %"PRIu64"\n", content_type, epoch, sequence_number);
/* try to decrypt record on the first pass, if possible. Store decrypted
- * record for later usage (without having to decrypt again). */
- if (ssl) {
+ * record for later usage (without having to decrypt again).
+ * DTLSv1.3 records are decrypted from dissect_dtls13_record */
+ if (ssl && (ssl->session.version != DTLSV1DOT3_VERSION)) {
decrypt_dtls_record(tvb, pinfo, offset, ssl, content_type, version, record_length, curr_layer_num_ssl, cid, cid_length);
}
decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset, curr_layer_num_ssl, &record);
@@ -964,14 +1140,14 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
dtls_record_tree, offset, session,
is_from_server, ssl);
if (ssl) {
- ssl_finalize_decryption(ssl, tls_get_master_key_map(TRUE));
+ ssl_finalize_decryption(ssl, tls_get_master_key_map(true));
ssl_change_cipher(ssl, is_from_server);
}
/* Heuristic: any later ChangeCipherSpec is not a resumption of this
* session. Set the flag after ssl_finalize_decryption such that it has
* a chance to use resume using Session Tickets. */
if (is_from_server)
- session->is_session_resumed = FALSE;
+ session->is_session_resumed = false;
break;
case SSL_ID_ALERT:
{
@@ -990,112 +1166,629 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/* try to retrieve and use decrypted handshake record, if any. */
if (decrypted) {
dissect_dtls_handshake(decrypted, pinfo, dtls_record_tree, 0,
- tvb_reported_length(decrypted), FALSE, session, is_from_server,
+ tvb_reported_length(decrypted), false, session, is_from_server,
ssl, content_type);
} else {
dissect_dtls_handshake(tvb, pinfo, dtls_record_tree, offset,
- record_length, TRUE, session, is_from_server, ssl,
+ record_length, true, session, is_from_server, ssl,
content_type);
}
break;
}
case SSL_ID_APP_DATA:
- /* show on info column what we are decoding */
- col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Application Data");
-
- /* 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. */
- dissector_handle_t handle;
- handle = dissector_get_uint_handle(dtls_associations, pinfo->srcport);
- handle = handle ? handle : dissector_get_uint_handle(dtls_associations, pinfo->destport);
- if (handle) session->app_handle = handle;
- }
-
- proto_item_set_text(dtls_record_tree,
- "%s Record Layer: %s Protocol: %s",
- val_to_str_const(session->version, ssl_version_short_names, "DTLS"),
- val_to_str_const(content_type, ssl_31_content_type, "unknown"),
- session->app_handle
- ? dissector_handle_get_protocol_long_name(session->app_handle)
- : "Application Data");
-
- proto_tree_add_item(dtls_record_tree, hf_dtls_record_appdata, tvb,
- offset, record_length, ENC_NA);
-
- if (session->app_handle) {
- ti = proto_tree_add_string(dtls_record_tree, hf_dtls_record_appdata_proto, tvb, 0, 0, dissector_handle_get_protocol_long_name(session->app_handle));
- proto_item_set_generated(ti);
- }
-
- /* show decrypted data info, if available */
- if (decrypted)
- {
- gboolean dissected;
- guint16 saved_match_port;
- /* try to dissect decrypted data*/
- ssl_debug_printf("%s decrypted len %d\n", G_STRFUNC, record->data_len);
-
- saved_match_port = pinfo->match_uint;
- if (is_from_server) {
- pinfo->match_uint = pinfo->srcport;
- } else {
- pinfo->match_uint = pinfo->destport;
- }
-
- /* find out a dissector using server port*/
- 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", record->plain_data, record->data_len);
-
- if (have_tap_listener(exported_pdu_tap)) {
- export_pdu_packet(decrypted, pinfo, EXP_PDU_TAG_DISSECTOR_NAME,
- dissector_handle_get_dissector_name(session->app_handle));
- }
-
- dissected = call_dissector_only(session->app_handle, decrypted, pinfo, top_tree, NULL);
- }
- else {
- /* try heuristic subdissectors */
- 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(decrypted, pinfo, EXP_PDU_TAG_HEUR_DISSECTOR_NAME, hdtbl_entry->short_name);
- }
- }
- pinfo->match_uint = saved_match_port;
- /* fallback to data dissector */
- if (!dissected)
- call_data_dissector(decrypted, pinfo, top_tree);
- }
+ dissect_dtls_appdata(tvb, pinfo, offset, record_length, session,
+ dtls_record_tree, is_from_server, decrypted, record);
break;
case SSL_ID_HEARTBEAT:
/* try to retrieve and use decrypted alert record, if any. */
if (decrypted) {
dissect_dtls_heartbeat(decrypted, pinfo, dtls_record_tree, 0,
- session, tvb_reported_length (decrypted), TRUE);
+ session, tvb_reported_length (decrypted), true);
} else {
dissect_dtls_heartbeat(tvb, pinfo, dtls_record_tree, offset,
- session, record_length, FALSE);
+ session, record_length, false);
}
break;
case SSL_ID_TLS12_CID:
expert_add_info_format(pinfo, ct_pi, &ei_dtls_cid_invalid_content_type,
"Invalid content type (%d)", content_type);
break;
+ case SSL_ID_DTLS13_ACK:
+ if (decrypted) {
+ dissect_dtls_ack(decrypted, pinfo, dtls_record_tree, 0, tvb_reported_length(decrypted));
+ } else {
+ dissect_dtls_ack(tvb, pinfo, dtls_record_tree, offset, record_length);
+ }
}
offset += record_length; /* skip to end of record */
return offset;
}
+
+/* setup cryptographic keys based on dtls13_current_epoch */
+static int
+dtls13_load_keys_from_epoch(SslDecryptSession *session, bool is_from_server, uint64_t epoch)
+{
+ ssl_master_key_map_t *master_key_map = NULL;
+ TLSRecordType secret_type;
+ SslDecoder *dec;
+
+ if (!session) {
+ ssl_debug_printf("dtls13_load_keys_from_epoch: no session\n");
+ return -1;
+ }
+
+ dec = NULL;
+ if (is_from_server)
+ dec = session->server;
+ else
+ dec = session->client;
+
+ if (dec && dec->dtls13_epoch == epoch)
+ return 0;
+
+ /* The DTLS dissector does not support decrypting packets from epoch < N once
+ * it decrypted a packet from epoch N. In order to do that, the dissector
+ * needs to maintain the expected next sequence number per epoch. The added
+ * complexity makes it not worthwhile. */
+ if (dec && dec->dtls13_epoch > epoch) {
+ ssl_debug_printf("%s: refuse to load past epoch %" PRIu64"\n", G_STRFUNC, epoch);
+ return 0;
+ }
+
+ /* double check that we increment the epoch by one after hs */
+ if (dec && dec->dtls13_epoch != 0 && epoch != dec->dtls13_epoch + 1)
+ return 0;
+
+ master_key_map = tls_get_master_key_map(true);
+ if (master_key_map == NULL) {
+ ssl_debug_printf("dtls13_load_keys_from_epoch: no master key map\n");
+ return -1;
+ }
+
+ switch (epoch)
+ {
+ case 1:
+ secret_type = TLS_SECRET_0RTT_APP;
+ tls13_change_key(session, master_key_map, is_from_server, secret_type);
+ break;
+ case 2:
+ secret_type = TLS_SECRET_HANDSHAKE;
+ tls13_change_key(session, master_key_map, is_from_server, secret_type);
+ break;
+ case 3:
+ secret_type = TLS_SECRET_APP;
+ tls13_change_key(session, master_key_map, is_from_server, secret_type);
+ break;
+ default:
+ tls13_key_update(session, is_from_server);
+ break;
+ }
+
+ if (is_from_server && session->server) {
+ session->server->dtls13_epoch = epoch;
+ } else if (session->client) {
+ session->client->dtls13_epoch = epoch;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Reconstructs sequence numbers in DTLS 1.3.
+ *
+ * This function takes the expected sequence number, the low bits of the sequence number,
+ * and a mask as input. It finds the closest number to the expected sequence number that
+ * has the lower bits equal to @seq_low_bits.
+ * @param expected_seq_number The expected sequence number.
+ * @param seq_low_bits The low bits of the sequence number (encrypted).
+ * @param len The length of @enc_seq_low_bits.
+ * @param dec_mask The decryption mask for @enc_seq_low_bits.
+ * @return The reconstructed dequeued sequence number.
+ */
+static uint64_t dtls13_reconstruct_seq_number(uint64_t expected_seq_number, uint16_t seq_low_bits,
+ int len, uint8_t *dec_mask)
+{
+ uint16_t expected_low_bits;
+ uint64_t c1, c2, d1, d2;
+ uint16_t mask;
+
+ /* we just need 1 or 2 bytes of the xor mask */
+ if (len == 1) {
+ dec_mask[1] = 0;
+ }
+ seq_low_bits ^= (dec_mask[0] << 8 | dec_mask[1]);
+
+ mask = (len == 2) ? 0xffff : 0xff;
+ expected_low_bits = expected_seq_number & mask;
+ c1 = (expected_seq_number & ~(mask)) | seq_low_bits;
+
+ if (expected_low_bits == seq_low_bits) {
+ return c1;
+ }
+ if (expected_low_bits < seq_low_bits) {
+ d1 = c1 - expected_seq_number;
+ c2 = c1 - (mask + 1);
+ d2 = expected_seq_number - c2;
+ } else {
+ d1 = expected_seq_number - c1;
+ c2 = c1 + (mask + 1);
+ d2 = c2 - expected_seq_number;
+ }
+
+ if (d1 < d2)
+ return c1;
+ return c2;
+}
+
+#define DTLS13_RECORD_NUMBER_MASK_SZ 16
+static int dtls13_get_record_number_xor_mask(SslDecoder *dec, const uint8_t *ciphertext, uint8_t *mask)
+{
+ if (!dec->cipher_suite)
+ return -1;
+
+ if (dec->cipher_suite->enc == ENC_NULL) {
+ memset(mask, 0, DTLS13_RECORD_NUMBER_MASK_SZ);
+ return 0;
+ }
+
+ if (!dec->sn_evp) {
+ return -1;
+ }
+
+ if (dec->cipher_suite->enc == ENC_AES || dec->cipher_suite->enc == ENC_AES256) {
+ if (gcry_cipher_encrypt(dec->sn_evp, mask, DTLS13_RECORD_NUMBER_MASK_SZ,
+ ciphertext, DTLS13_RECORD_NUMBER_MASK_SZ) != 0) {
+ ssl_debug_printf("dtls1.3: record mask generation failed\n");
+ return -1;
+ }
+ return 0;
+ }
+
+ if (dec->cipher_suite->enc == ENC_CHACHA20) {
+ if (gcry_cipher_setiv(dec->sn_evp, ciphertext, DTLS13_RECORD_NUMBER_MASK_SZ) != 0) {
+ ssl_debug_printf("dtls1.3: record mask generation failed: can't set iv\n");
+ return -1;
+ }
+ memset(mask, 0, DTLS13_RECORD_NUMBER_MASK_SZ);
+ if (gcry_cipher_encrypt(dec->sn_evp, mask, DTLS13_RECORD_NUMBER_MASK_SZ, mask, DTLS13_RECORD_NUMBER_MASK_SZ) != 0) {
+ ssl_debug_printf("dtls1.3: record mask generation failed\n");
+ return -1;
+ }
+ return 0;
+ }
+
+ ssl_debug_printf("dtls1.3: unsupported cipher\n");
+ return -1;
+}
+
+static bool dtls13_create_aad(tvbuff_t *tvb, SslDecryptSession *ssl, bool is_from_server, uint8_t hdr_flags, uint32_t hdr_off, uint32_t hdr_size,
+ uint64_t sequence_number, uint16_t dtls_record_length)
+{
+ unsigned int cid_length = 0;
+ SslDecoder *dec = NULL;
+ int seq_length;
+
+ if (is_from_server && ssl->server) {
+ dec = ssl->server;
+ } else if (ssl->client) {
+ dec = ssl->client;
+ }
+ if (!dec)
+ return false;
+
+ dec->seq = sequence_number;
+ dec->dtls13_aad.data = wmem_realloc(wmem_file_scope(), dec->dtls13_aad.data, hdr_size);
+ dec->dtls13_aad.data_len = hdr_size;
+ dec->dtls13_aad.data[0] = hdr_flags;
+ cid_length = 0;
+
+ seq_length = 1;
+ if (hdr_flags & DTLS13_S_BIT_MASK)
+ seq_length = 2;
+ if (hdr_flags & DTLS13_C_BIT_MASK) {
+ /* total - 1 byte for hdr flag, 1 or 2 byte for seq suffix, 0 or 2 bytes for len */
+ cid_length = hdr_size - 1 - seq_length;
+ if (hdr_flags & DTLS13_L_BIT_MASK)
+ cid_length -= 2;
+ DISSECTOR_ASSERT(cid_length < hdr_size);
+ memcpy(&dec->dtls13_aad.data[1], tvb_get_ptr(tvb, hdr_off + 1, cid_length), cid_length);
+ }
+
+ if (seq_length == 2) {
+ phton16(&dec->dtls13_aad.data[1 + cid_length], sequence_number);
+ } else {
+ dec->dtls13_aad.data[1 + cid_length] = sequence_number;
+ }
+ if (hdr_flags & DTLS13_L_BIT_MASK) {
+ phton16(&dec->dtls13_aad.data[1 + cid_length + seq_length], dtls_record_length);
+ }
+
+ return true;
+}
+
+static bool dtls13_decrypt_unified_record(tvbuff_t *tvb, packet_info *pinfo, uint32_t hdr_off, uint32_t hdr_size,
+ uint8_t hdr_flags, bool is_from_server,
+ SslDecryptSession *ssl, uint32_t dtls_record_length, uint8_t curr_layer_num_ssl,
+ uint16_t seq_suffix, uint8_t seq_length)
+{
+ uint8_t mask[DTLS13_RECORD_NUMBER_MASK_SZ];
+ uint64_t sequence_number;
+ SslDecoder *dec = NULL;
+ bool success;
+
+ if (is_from_server && ssl->server) {
+ dec = ssl->server;
+ } else if (ssl->client) {
+ dec = ssl->client;
+ }
+
+ if (dec == NULL) {
+ ssl_debug_printf("dissect_dtls13_record: no decoder available\n");
+ return false;
+ }
+
+ if (dtls13_get_record_number_xor_mask(dec, tvb_get_ptr(tvb, hdr_off + hdr_size, DTLS13_RECORD_NUMBER_MASK_SZ), mask) != 0) {
+ ssl_debug_printf("dissect_dtls13_record: can't get record number mask\n");
+ return false;
+ }
+
+ sequence_number = dtls13_reconstruct_seq_number(ssl->session.dtls13_next_seq_num[is_from_server], seq_suffix, seq_length, mask);
+
+ /* setup parameter for decryption of this packet */
+ if (!dtls13_create_aad(tvb, ssl, is_from_server, hdr_flags, hdr_off, hdr_size, sequence_number, dtls_record_length)) {
+ ssl_debug_printf("%s: can't create AAD\n", G_STRFUNC);
+ return false;
+ }
+
+ /* CID is already included in dtls13_add, there is no need to add it here */
+ success = decrypt_dtls_record(tvb, pinfo, hdr_off + hdr_size, ssl, 0, ssl->session.version, dtls_record_length, curr_layer_num_ssl, NULL, 0);
+ if (sequence_number >= ssl->session.dtls13_next_seq_num[is_from_server]) {
+ ssl->session.dtls13_next_seq_num[is_from_server] = sequence_number + 1;
+ }
+
+ return success;
+}
+
+/**
+ * Try to guess the early data cipher using trial decryption. based on decrypt_tls13_early_data.
+ * Requires Libgcrypt 1.6 or newer for verifying that decryption is successful.
+ */
+static bool
+dtls13_decrypt_early_data(tvbuff_t *tvb, packet_info *pinfo, uint32_t hdr_off, uint32_t hdr_size, uint8_t hdr_flags,
+ uint16_t record_length, SslDecryptSession *ssl,
+ uint8_t curr_layer_num_ssl, uint16_t seq_suffix, uint8_t seq_length)
+{
+ StringInfo *secret;
+
+ static const uint16_t tls13_ciphers[] = {
+ 0x1301, /* TLS_AES_128_GCM_SHA256 */
+ 0x1302, /* TLS_AES_256_GCM_SHA384 */
+ 0x1303, /* TLS_CHACHA20_POLY1305_SHA256 */
+ 0x1304, /* TLS_AES_128_CCM_SHA256 */
+ 0x1305, /* TLS_AES_128_CCM_8_SHA256 */
+ };
+
+ bool success = false;
+
+ ssl_debug_printf("Trying early data encryption, first record / trial decryption: %s\n",
+ !(ssl->state & SSL_SEEN_0RTT_APPDATA) ? "true" : "false");
+
+
+ secret = tls13_load_secret(ssl, tls_get_master_key_map(true), false, TLS_SECRET_0RTT_APP);
+ if (!secret) {
+ ssl_debug_printf("Missing secrets, early data decryption not possible!\n");
+ return false;
+ }
+
+ for (unsigned i = 0; i < G_N_ELEMENTS(tls13_ciphers); i++) {
+ uint16_t cipher = tls13_ciphers[i];
+
+ ssl_debug_printf("Performing early data trial decryption, cipher = %#x\n", cipher);
+ ssl->session.cipher = cipher;
+ ssl->cipher_suite = ssl_find_cipher(cipher);
+ if (!tls13_generate_keys(ssl, secret, false)) {
+ /* Unable to create cipher (old Libgcrypt) */
+ continue;
+ }
+
+ success = dtls13_decrypt_unified_record(tvb, pinfo, hdr_off, hdr_size, hdr_flags, false, ssl, record_length, curr_layer_num_ssl, seq_suffix, seq_length);
+ if (success) {
+ /* update epoch number to decrypt other 0RTT packets */
+ ssl->client->dtls13_epoch = 1;
+ ssl_debug_printf("Early data decryption succeeded, cipher = %#x\n", cipher);
+ break;
+ }
+ }
+ if (!success) {
+ ssl_debug_printf("Trial decryption of early data failed!\n");
+ }
+ return success;
+}
+
+static bool dtls13_setup_keys(uint8_t hdr_flags, bool is_from_server, SslDecryptSession *ssl, uint32_t dtls_record_length,
+ bool *first_early_data)
+{
+ uint64_t epoch, curr_max_epoch;
+
+ epoch = (hdr_flags & DTLS13_HDR_EPOCH_BIT_MASK);
+
+ if (first_early_data != NULL)
+ *first_early_data = false;
+
+ /* DTLSv1.3 minimum payload is 16 bytes */
+ if (dtls_record_length < 16) {
+ ssl_debug_printf("dtls13: record too short\n");
+ return false;
+ }
+
+ /* determine the epoch */
+ curr_max_epoch = ssl->session.dtls13_current_epoch[is_from_server];
+
+ if ((curr_max_epoch & 0x3) != epoch) {
+ /* No KeyUpdate seen, we are still in the handshake (epoch 1 or 2) or using traffic_secret_0 (epoch 3) */
+ if (curr_max_epoch < 4) {
+ if (epoch > curr_max_epoch) {
+ ssl->session.dtls13_current_epoch[is_from_server] = epoch;
+ }
+ } else {
+
+ /* try to decrypt with the last epoch with the same low bits */
+ epoch = (curr_max_epoch & ~(0x3)) | epoch;
+ if (epoch > curr_max_epoch)
+ epoch -= 4;
+ }
+ } else {
+ epoch = curr_max_epoch;
+ }
+
+ if (epoch == 0) {
+ ssl_debug_printf("dtls13: unified header with epoch 0 (plaintext)\n");
+ return false;
+ }
+
+ /* early data */
+ if (epoch == 1) {
+ if (ssl->session.dtls13_current_epoch[is_from_server] > 1) {
+ ssl_debug_printf("%s: early data received after encrypted HS, abort decryption\n", G_STRFUNC);
+ return false;
+ }
+ if (!ssl->has_early_data) {
+ ssl_debug_printf("%s: early data received but not advertised in CH extensions, abort decryption\n", G_STRFUNC);
+ return false;
+ }
+ /* first early data packet, need to go into trial decryption */
+ if (!(ssl->client && (ssl->client->dtls13_epoch == 1))) {
+ if (first_early_data != NULL)
+ *first_early_data = true;
+ return true;
+ }
+ }
+
+ if (dtls13_load_keys_from_epoch(ssl, is_from_server, epoch) < 0) {
+ ssl_debug_printf("dtls13: can't load keys\n");
+ return false;
+ }
+
+ return true;
+}
+
+/* Dissect a DTLS record from version 1.3 */
+static int
+dissect_dtls13_record(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, uint32_t offset,
+ SslSession *session, int is_from_server,
+ SslDecryptSession* ssl,
+ uint8_t curr_layer_num_ssl _U_)
+{
+ /*
+ * struct {
+ * ContentType type;
+ * ProtocolVersion legacy_record_version;
+ * uint16 epoch = 0
+ * uint48 sequence_number;
+ * uint16 length;
+ * opaque fragment[DTLSPlaintext.length];
+ * } DTLSPlaintext;
+ *
+ * struct {
+ * opaque content[DTLSPlaintext.length];
+ * ContentType type;
+ * uint8 zeros[length_of_padding];
+ * } DTLSInnerPlaintext;
+ *
+ * struct {
+ * opaque unified_hdr[variable];
+ * opaque encrypted_record[length];
+ * } DTLSCiphertext;
+ *
+ * unified_hdr:
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |0|0|1|C|S|L|E E|
+ * +-+-+-+-+-+-+-+-+
+ * | Connection ID | Legend:
+ * | (if any, |
+ * / length as / C - Connection ID (CID) present
+ * | negotiated) | S - Sequence number length
+ * +-+-+-+-+-+-+-+-+ L - Length present
+ * | 8 or 16 bit | E - Epoch
+ * |Sequence Number|
+ * +-+-+-+-+-+-+-+-+
+ * | 16 bit Length |
+ * | (if present) |
+ * +-+-+-+-+-+-+-+-+
+ */
+
+ static int * const uni_hdr_flags[] = {
+ &hf_dtls_uni_hdr_fixed,
+ &hf_dtls_uni_hdr_cid,
+ &hf_dtls_uni_hdr_seq,
+ &hf_dtls_uni_hdr_len,
+ &hf_dtls_uni_hdr_epoch,
+ NULL
+ };
+
+ proto_tree *dtls_record_tree;
+ proto_item *ti;
+ proto_item *length_pi;
+ uint32_t dtls_record_length = 0;
+
+ uint32_t hdr_offset = offset;
+ uint32_t hdr_start = offset;
+ uint8_t hdr_flags;
+ bool c_bit; /* 1 = Connection ID field is present */
+ bool s_bit; /* 0 = 8-bit sequence number, 1 = 16-bit */
+ bool l_bit; /* 1 = Length field is present */
+
+ uint8_t seq_length;
+ uint8_t cid_length = 0;
+ uint16_t seq_suffix;
+ tvbuff_t *decrypted = NULL;
+ SslRecordInfo *record = NULL;
+ bool success;
+ bool is_first_early_data;
+
+ hdr_flags = tvb_get_uint8(tvb, hdr_offset);
+ c_bit = (hdr_flags & DTLS13_C_BIT_MASK) == DTLS13_C_BIT_MASK;
+ s_bit = (hdr_flags & DTLS13_S_BIT_MASK) == DTLS13_S_BIT_MASK;
+ l_bit = (hdr_flags & DTLS13_L_BIT_MASK) == DTLS13_L_BIT_MASK;
+ hdr_offset += 1;
+
+ if (c_bit) {
+ /* Connection ID length to use if any */
+ cid_length = dtls_cid_length(session, is_from_server);
+ hdr_offset += cid_length;
+ }
+
+ if (s_bit) {
+ /* Lowest 16 bits of the sequence number */
+ seq_length = 2;
+ seq_suffix = tvb_get_ntohs(tvb, hdr_offset);
+ }
+ else {
+ /* Lowest 8 bits of the sequence number */
+ seq_length = 1;
+ seq_suffix = tvb_get_uint8(tvb, hdr_offset);
+ }
+ /* Note: seq_suffix is encrypted if the payload is encrypted,
+ * as per RFC 9147 section 4.2.3. To get the real sequence number,
+ * we need to decrypt, and *then* use the result to find the sequence
+ * number closest to one plus the last sequence number.
+ */
+ hdr_offset += seq_length;
+
+ if (l_bit) {
+ dtls_record_length = tvb_get_ntohs(tvb, hdr_offset);
+ hdr_offset += 2;
+ }
+ else {
+ dtls_record_length = tvb_captured_length_remaining(tvb, hdr_offset);
+ }
+
+ /*
+ * If GUI, fill in record layer part of tree
+ */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL,
+ val_to_str_const(session->version, ssl_version_short_names, "DTLS"));
+
+ ti = proto_tree_add_item(tree, hf_dtls_record, tvb, offset,
+ (hdr_offset - offset) + dtls_record_length, ENC_NA);
+ dtls_record_tree = proto_item_add_subtree(ti, ett_dtls_record);
+
+ proto_tree_add_bitmask_with_flags(dtls_record_tree, tvb, offset,
+ hf_dtls_uni_hdr, ett_dtls_uni_hdr, uni_hdr_flags,
+ ENC_BIG_ENDIAN, BMT_NO_INT);
+
+ offset += 1;
+
+ if (c_bit && cid_length > 0) {
+ proto_tree_add_item(dtls_record_tree, hf_dtls_record_connection_id, tvb, offset, cid_length, ENC_NA);
+ offset += cid_length;
+ }
+
+ proto_tree_add_uint(dtls_record_tree, hf_dtls_record_sequence_suffix, tvb, offset, seq_length, seq_suffix);
+ offset += seq_length;
+
+ if (l_bit) {
+ proto_tree_add_item(dtls_record_tree, hf_dtls_record_length, tvb,
+ offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ }
+ else {
+ length_pi = proto_tree_add_uint(dtls_record_tree, hf_dtls_record_length, tvb,
+ offset, 0, dtls_record_length);
+ proto_item_set_generated(length_pi);
+ }
+
+ if (ssl) {
+ success = dtls13_setup_keys(hdr_flags, is_from_server, ssl, dtls_record_length, &is_first_early_data);
+ if (success) {
+ if (!is_from_server && is_first_early_data) {
+ /* try to decrypt early data */
+ dtls13_decrypt_early_data(tvb, pinfo, hdr_start, hdr_offset - hdr_start, hdr_flags, dtls_record_length, ssl, curr_layer_num_ssl, seq_suffix, seq_length);
+ } else {
+ dtls13_decrypt_unified_record(tvb, pinfo, hdr_start, hdr_offset - hdr_start, hdr_flags, is_from_server, ssl, dtls_record_length, curr_layer_num_ssl, seq_suffix, seq_length);
+ }
+ }
+ }
+
+ decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset, curr_layer_num_ssl, &record);
+ if (decrypted)
+ {
+ /* on first pass add seq suffix decrypted info */
+ if (ssl) {
+ if (is_from_server && ssl->server) {
+ record->dtls13_seq_suffix = ssl->server->seq;
+ } else if (ssl->client) {
+ record->dtls13_seq_suffix = ssl->client->seq;
+ }
+ }
+
+ ti = proto_tree_add_uint(dtls_record_tree, hf_dtls_record_sequence_suffix_dec, tvb, hdr_start + 1 + cid_length,
+ seq_length, record->dtls13_seq_suffix);
+ proto_item_set_generated(ti);
+ add_new_data_source(pinfo, decrypted, "Decrypted DTLS");
+ /* real content type*/
+ switch ((record->type))
+ {
+ case SSL_ID_HANDSHAKE:
+ dissect_dtls_handshake(decrypted, pinfo, dtls_record_tree, 0,
+ tvb_reported_length(decrypted), false, session, is_from_server,
+ ssl, record->type);
+ break;
+ case SSL_ID_ALERT:
+ dissect_dtls_alert(decrypted, pinfo, dtls_record_tree, 0,
+ session);
+ break;
+ case SSL_ID_DTLS13_ACK:
+ dissect_dtls_ack(decrypted, pinfo, dtls_record_tree, 0, tvb_reported_length(decrypted));
+ break;
+ case SSL_ID_APP_DATA:
+ dissect_dtls_appdata(tvb, pinfo, offset, dtls_record_length, session,
+ dtls_record_tree, is_from_server, decrypted, record);
+ break;
+ default:
+ break;
+ }
+ } else {
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Encrypted Data");
+ proto_tree_add_item(dtls_record_tree, hf_dtls_record_encrypted_content, tvb,
+ offset, dtls_record_length, ENC_NA);
+ proto_item_set_text(dtls_record_tree,
+ "%s Record Layer: Encrypted Data",
+ val_to_str_const(session->version, ssl_version_short_names, "DTLS"));
+ }
+
+ return offset + dtls_record_length;
+}
+
/* dissects the alert message, filling in the tree */
static void
dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
- proto_tree *tree, guint32 offset,
+ proto_tree *tree, uint32_t offset,
const SslSession *session)
{
/* struct {
@@ -1106,9 +1799,9 @@ dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *ti;
proto_tree *ssl_alert_tree;
- const gchar *level;
- const gchar *desc;
- guint8 byte;
+ const char *level;
+ const char *desc;
+ uint8_t byte;
ti = proto_tree_add_item(tree, hf_dtls_alert_message, tvb,
offset, 2, ENC_NA);
@@ -1119,10 +1812,10 @@ dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
*/
/* first lookup the names for the alert level and description */
- byte = tvb_get_guint8(tvb, offset); /* grab the level byte */
+ byte = tvb_get_uint8(tvb, offset); /* grab the level byte */
level = try_val_to_str(byte, ssl_31_alert_level);
- byte = tvb_get_guint8(tvb, offset+1); /* grab the desc byte */
+ byte = tvb_get_uint8(tvb, offset+1); /* grab the desc byte */
desc = try_val_to_str(byte, ssl_31_alert_description);
/* now set the text in the record layer line */
@@ -1162,14 +1855,37 @@ dissect_dtls_alert(tvbuff_t *tvb, packet_info *pinfo,
}
}
+static void
+dtls13_maybe_increase_max_epoch(SslDecryptSession *ssl, bool is_from_server)
+{
+ SslDecoder *dec;
+
+ if (ssl == NULL)
+ return;
+
+ if (is_from_server)
+ dec = ssl->server;
+ else
+ dec = ssl->client;
+
+ if (dec == NULL)
+ return;
+
+ /* be sure to increment from the current epoch just once, and to increment
+ * again only after the new epoch was seen. This assures that the dissector
+ * can always compute the next epoch, and avoid that duplicate packets wrongly
+ * increment the max epoch multiple times. */
+ if (dec->dtls13_epoch == ssl->session.dtls13_current_epoch[is_from_server])
+ ssl->session.dtls13_current_epoch[is_from_server]++;
+}
/* dissects the handshake protocol, filling the tree */
static void
dissect_dtls_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, guint8 content_type)
+ proto_tree *tree, uint32_t offset,
+ uint32_t record_length, bool maybe_encrypted,
+ SslSession *session, int is_from_server,
+ SslDecryptSession* ssl, uint8_t content_type)
{
/* struct {
* HandshakeType msg_type;
@@ -1195,18 +1911,19 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *ti, *length_item = NULL, *fragment_length_item = NULL;
proto_tree *ssl_hand_tree;
- const gchar *msg_type_str;
- guint8 msg_type;
- guint32 length;
- guint16 message_seq;
- guint32 fragment_offset;
- guint32 fragment_length;
- gboolean first_iteration;
- guint32 reassembled_length;
+ const char *msg_type_str;
+ uint8_t msg_type;
+ uint32_t length;
+ uint16_t version;
+ uint16_t message_seq;
+ uint32_t fragment_offset;
+ uint32_t fragment_length;
+ bool first_iteration;
+ uint32_t reassembled_length;
tvbuff_t *sub_tvb;
msg_type_str = NULL;
- first_iteration = TRUE;
+ first_iteration = true;
/* just as there can be multiple records per packet, there
* can be multiple messages per record as long as they have
@@ -1218,19 +1935,20 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
/* set record_length to the max offset */
record_length += offset;
for (; offset < record_length; offset += fragment_length,
- first_iteration = FALSE) /* set up for next pass, if any */
+ first_iteration = false) /* set up for next pass, if any */
{
fragment_head *frag_msg = NULL;
tvbuff_t *new_tvb = NULL;
- const gchar *frag_str = NULL;
- gboolean fragmented;
- guint32 hs_offset = offset;
+ const char *frag_str = NULL;
+ bool fragmented;
+ uint32_t hs_offset = offset;
+ bool is_hrr = 0;
/* add a subtree for the handshake protocol */
ti = proto_tree_add_item(tree, hf_dtls_handshake_protocol, tvb, offset, -1, ENC_NA);
ssl_hand_tree = proto_item_add_subtree(ti, ett_dtls_handshake);
- msg_type = tvb_get_guint8(tvb, offset);
+ msg_type = tvb_get_uint8(tvb, offset);
fragment_length = tvb_get_ntoh24(tvb, offset + 9);
/* Check the fragment length in the handshake message. Assume it's an
@@ -1239,8 +1957,16 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
* situation where the first octet of the encrypted handshake
* message is actually a known handshake message type.
*/
- if (!maybe_encrypted || offset + fragment_length <= record_length)
- msg_type_str = try_val_to_str(msg_type, ssl_31_handshake_type);
+ if (!maybe_encrypted || offset + fragment_length <= record_length) {
+ if (msg_type == SSL_HND_SERVER_HELLO) {
+ tls_scan_server_hello(tvb, offset+12, fragment_length, &version, &is_hrr);
+ }
+ if (is_hrr) {
+ msg_type_str = try_val_to_str(SSL_HND_HELLO_RETRY_REQUEST, ssl_31_handshake_type);
+ } else {
+ msg_type_str = try_val_to_str(msg_type, ssl_31_handshake_type);
+ }
+ }
if (!msg_type_str && !first_iteration)
{
@@ -1291,7 +2017,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
offset += 3;
proto_item_set_len(ti, fragment_length + 12);
- fragmented = FALSE;
+ fragmented = false;
if (fragment_length + fragment_offset > length)
{
if (fragment_offset == 0)
@@ -1300,7 +2026,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
}
else
{
- fragmented = TRUE;
+ fragmented = true;
expert_add_info(pinfo, fragment_length_item, &ei_dtls_handshake_fragment_past_end_msg);
}
}
@@ -1314,20 +2040,20 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
}
else if (fragment_length < length)
{
- fragmented = TRUE;
+ fragmented = true;
/* Handle fragments of known message type, ignore others */
- if (ssl_is_valid_handshake_type(msg_type, TRUE))
+ if (ssl_is_valid_handshake_type(msg_type, true))
{
/* Fragmented handshake message */
- pinfo->fragmented = TRUE;
+ pinfo->fragmented = true;
/* Don't pass the reassembly code data that doesn't exist */
tvb_ensure_bytes_exist(tvb, offset, fragment_length);
frag_msg = fragment_add(&dtls_reassembly_table,
tvb, offset, pinfo, message_seq, NULL,
- fragment_offset, fragment_length, TRUE);
+ fragment_offset, fragment_length, true);
/*
* Do we already have a length for this reassembly?
*/
@@ -1459,16 +2185,22 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
ssl_hand_tree, 0, length, session, ssl,
&dtls_hfs);
if (ssl) {
- tls_save_crandom(ssl, tls_get_master_key_map(FALSE));
+ tls_save_crandom(ssl, tls_get_master_key_map(false));
+ /* force DTLSv1.3 version if early data is seen */
+ if (ssl->has_early_data) {
+ session->version = DTLSV1DOT3_VERSION;
+ ssl->state |= SSL_VERSION;
+ ssl_debug_printf("%s forcing version 0x%04X -> state 0x%02X\n", G_STRFUNC, DTLSV1DOT3_VERSION, ssl->state);
+ }
}
break;
case SSL_HND_SERVER_HELLO:
- ssl_try_set_version(session, ssl, SSL_ID_HANDSHAKE, SSL_HND_SERVER_HELLO, TRUE,
- tvb_get_ntohs(sub_tvb, 0));
+ tls_scan_server_hello(sub_tvb, 0, fragment_length, &version, &is_hrr);
+ ssl_try_set_version(session, ssl, SSL_ID_HANDSHAKE, SSL_HND_SERVER_HELLO, true, version);
ssl_dissect_hnd_srv_hello(&dissect_dtls_hf, sub_tvb, pinfo, ssl_hand_tree,
- 0, length, session, ssl, TRUE, FALSE);
+ 0, length, session, ssl, true, is_hrr);
break;
case SSL_HND_HELLO_VERIFY_REQUEST:
@@ -1492,18 +2224,18 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
/* no need to load keylog file here as it only links a previous
* master key with this Session Ticket */
ssl_dissect_hnd_new_ses_ticket(&dissect_dtls_hf, sub_tvb, pinfo,
- ssl_hand_tree, 0, length, session, ssl, TRUE,
- tls_get_master_key_map(FALSE)->tickets);
+ ssl_hand_tree, 0, length, session, ssl, true,
+ tls_get_master_key_map(false)->tickets);
break;
case SSL_HND_HELLO_RETRY_REQUEST:
ssl_dissect_hnd_hello_retry_request(&dissect_dtls_hf, sub_tvb, pinfo, ssl_hand_tree,
- 0, length, session, ssl, TRUE);
+ 0, length, session, ssl, true);
break;
case SSL_HND_CERTIFICATE:
ssl_dissect_hnd_cert(&dissect_dtls_hf, sub_tvb, ssl_hand_tree, 0, length,
- pinfo, session, ssl, is_from_server, TRUE);
+ pinfo, session, ssl, is_from_server, true);
break;
case SSL_HND_SERVER_KEY_EXCHG:
@@ -1511,12 +2243,12 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
break;
case SSL_HND_CERT_REQUEST:
- ssl_dissect_hnd_cert_req(&dissect_dtls_hf, sub_tvb, pinfo, ssl_hand_tree, 0, length, session, TRUE);
+ ssl_dissect_hnd_cert_req(&dissect_dtls_hf, sub_tvb, pinfo, ssl_hand_tree, 0, length, session, true);
break;
case SSL_HND_SVR_HELLO_DONE:
/* This is not an abbreviated handshake, it is certainly not resumed. */
- session->is_session_resumed = FALSE;
+ session->is_session_resumed = false;
break;
case SSL_HND_CERT_VERIFY:
@@ -1534,7 +2266,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
#ifdef HAVE_LIBGNUTLS
dtls_key_hash,
#endif
- tls_get_master_key_map(TRUE))) {
+ tls_get_master_key_map(true))) {
ssl_debug_printf("dissect_dtls_handshake can't generate pre master secret\n");
}
break;
@@ -1551,11 +2283,17 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
case SSL_HND_CERT_URL:
case SSL_HND_SUPPLEMENTAL_DATA:
case SSL_HND_KEY_UPDATE:
+ tls13_dissect_hnd_key_update(&dissect_dtls_hf, sub_tvb, ssl_hand_tree, 0);
+ if (ssl && ssl->session.version == DTLSV1DOT3_VERSION) {
+ dtls13_maybe_increase_max_epoch(ssl, is_from_server);
+ }
+ break;
case SSL_HND_ENCRYPTED_EXTS:
case SSL_HND_END_OF_EARLY_DATA: /* TLS 1.3 */
case SSL_HND_COMPRESSED_CERTIFICATE:
+ break;
case SSL_HND_ENCRYPTED_EXTENSIONS: /* TLS 1.3 */
- /* TODO: does this need further dissection? */
+ ssl_dissect_hnd_encrypted_extensions(&dissect_dtls_hf, sub_tvb, pinfo, ssl_hand_tree, 0, length, session, ssl, 1);
break;
}
}
@@ -1564,9 +2302,9 @@ 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,
- const SslSession *session, guint32 record_length,
- gboolean decrypted)
+ proto_tree *tree, uint32_t offset,
+ const SslSession *session, uint32_t record_length,
+ bool decrypted)
{
/* struct {
* HeartbeatMessageType type;
@@ -1578,10 +2316,10 @@ dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *ti;
proto_tree *dtls_heartbeat_tree;
- const gchar *type;
- guint8 byte;
- guint16 payload_length;
- guint16 padding_length;
+ const char *type;
+ uint8_t byte;
+ uint16_t payload_length;
+ uint16_t padding_length;
ti = proto_tree_add_item(tree, hf_dtls_heartbeat_message, tvb,
offset, record_length - 32, ENC_NA);
@@ -1592,7 +2330,7 @@ dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
*/
/* first lookup the names for the message type and the payload length */
- byte = tvb_get_guint8(tvb, offset);
+ byte = tvb_get_uint8(tvb, offset);
type = try_val_to_str(byte, tls_heartbeat_type);
payload_length = tvb_get_ntohs(tvb, offset + 1);
@@ -1647,10 +2385,63 @@ dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
}
}
+/* dissects the acknowledgement message from RFC 9147 section 7 */
+static void
+dissect_dtls_ack(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, uint32_t offset,
+ uint32_t record_length)
+{
+ /*
+ * section 4:
+ * struct {
+ * uint64 epoch;
+ * uint64 sequence_number;
+ * } RecordNumber;
+ *
+ * section 7:
+ * struct {
+ * RecordNumber record_numbers<0..2^16-1>;
+ * } ACK;
+ */
+
+ uint32_t i;
+ uint32_t record_number_length;
+ proto_tree *ti;
+ proto_tree *dtls_ack_tree, *rn_tree;
+ uint64_t epoch;
+ uint64_t number;
+
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Acknowledgement");
+ ti = proto_tree_add_item(tree, hf_dtls_ack_message, tvb,
+ offset, record_length, ENC_NA);
+ dtls_ack_tree = proto_item_add_subtree(ti, ett_dtls_ack);
+
+ /* record_numbers<2..2^16-2> */
+ if (!ssl_add_vector(&dissect_dtls_hf, tvb, pinfo, dtls_ack_tree, offset, record_length, &record_number_length,
+ hf_dtls_ack_record_numbers_length, 2, UINT16_MAX - 1)) {
+ return;
+ }
+
+ offset += 2;
+ ti = proto_tree_add_none_format(dtls_ack_tree, hf_dtls_ack_record_numbers, tvb, offset, record_number_length,
+ "RecordNumbers (%u record number%s)",
+ record_number_length / 16, plurality(record_number_length / 16, "", "s"));
+ dtls_ack_tree = proto_item_add_subtree(ti, ett_dtls_ack_record_numbers);
+
+ for (i = 0; i < record_number_length; i += 16) {
+ rn_tree = proto_tree_add_subtree(dtls_ack_tree, tvb, offset + i, 16, ett_dtls_ack_record_number, NULL, "");
+ proto_tree_add_item_ret_uint64(rn_tree, hf_dtls_record_epoch64, tvb,
+ offset + i + 0, 8, ENC_BIG_ENDIAN, &epoch);
+ proto_tree_add_item_ret_uint64(rn_tree, hf_dtls_record_sequence_number, tvb,
+ offset + i + 8, 8, ENC_BIG_ENDIAN, &number);
+ proto_item_set_text(rn_tree, "RecordNumber: epoch %" PRIu64 ", sequence number %" PRIu64, epoch, number);
+ }
+}
+
static int
dissect_dtls_hnd_hello_verify_request(ssl_common_dissect_t *hf, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree,
- guint32 offset, guint32 offset_end)
+ uint32_t offset, uint32_t offset_end)
{
/*
* struct {
@@ -1659,7 +2450,7 @@ dissect_dtls_hnd_hello_verify_request(ssl_common_dissect_t *hf, tvbuff_t *tvb,
* } HelloVerifyRequest;
*/
- guint32 cookie_length;
+ uint32_t cookie_length;
/* show the client version */
proto_tree_add_item(tree, dissect_dtls_hf.hf.hs_server_version, tvb,
@@ -1682,10 +2473,10 @@ dissect_dtls_hnd_hello_verify_request(ssl_common_dissect_t *hf, tvbuff_t *tvb,
return offset;
}
-gint
+int
dtls_dissect_hnd_hello_ext_use_srtp(packet_info *pinfo, tvbuff_t *tvb,
- proto_tree *tree, guint32 offset,
- guint32 ext_len, gboolean is_server)
+ proto_tree *tree, uint32_t offset,
+ uint32_t ext_len, bool is_server)
{
/* From https://tools.ietf.org/html/rfc5764#section-4.1.1
*
@@ -1700,7 +2491,7 @@ dtls_dissect_hnd_hello_ext_use_srtp(packet_info *pinfo, tvbuff_t *tvb,
*/
proto_item *ti;
- guint32 profiles_length, profiles_end, profile, mki_length;
+ uint32_t profiles_length, profiles_end, profile, mki_length;
if (ext_len < 2) {
/* XXX expert info, record too small */
@@ -1813,19 +2604,22 @@ dtls_dissect_hnd_hello_ext_use_srtp(packet_info *pinfo, tvbuff_t *tvb,
* or not the data beginning at offset looks like a
* valid dtls record.
*/
-static gint
-looks_like_dtls(tvbuff_t *tvb, guint32 offset)
+static int
+looks_like_dtls(tvbuff_t *tvb, uint32_t offset)
{
/* have to have a valid content type followed by a valid
* protocol version
*/
- guint8 byte;
- guint16 version;
+ uint8_t byte;
+ uint16_t version;
/* see if the first byte is a valid content type */
- byte = tvb_get_guint8(tvb, offset);
+ byte = tvb_get_uint8(tvb, offset);
if (!ssl_is_valid_content_type(byte))
{
+ if ((byte & DTLS13_FIXED_MASK) >> 5 == 1) {
+ return 1;
+ }
return 0;
}
@@ -1887,12 +2681,12 @@ UAT_FILENAME_CB_DEF(sslkeylist_uats,keyfile,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,password,ssldecrypt_assoc_t)
static bool
-dtlsdecrypt_uat_fld_protocol_chk_cb(void* r _U_, const char* p, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
+dtlsdecrypt_uat_fld_protocol_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
{
if (!p || strlen(p) == 0u) {
// This should be removed in favor of Decode As. Make it optional.
*err = NULL;
- return TRUE;
+ return true;
}
if (!find_dissector(p)) {
@@ -1905,19 +2699,19 @@ dtlsdecrypt_uat_fld_protocol_chk_cb(void* r _U_, const char* p, guint len _U_, c
*err = ws_strdup_printf("Could not find dissector for: '%s'\nCommonly used DTLS dissectors include:\n%s", p, ssl_str);
g_free(ssl_str);
}
- return FALSE;
+ return false;
}
*err = NULL;
- return TRUE;
+ return true;
}
#endif
static void
-dtls_src_prompt(packet_info *pinfo, gchar *result)
+dtls_src_prompt(packet_info *pinfo, char *result)
{
SslPacketInfo* pi;
- guint32 srcport = pinfo->srcport;
+ uint32_t srcport = pinfo->srcport;
pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto_dtls, pinfo->curr_layer_num);
if (pi != NULL)
@@ -1926,7 +2720,7 @@ dtls_src_prompt(packet_info *pinfo, gchar *result)
snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "source (%u%s)", srcport, UTF8_RIGHTWARDS_ARROW);
}
-static gpointer
+static void *
dtls_src_value(packet_info *pinfo)
{
SslPacketInfo* pi;
@@ -1939,10 +2733,10 @@ dtls_src_value(packet_info *pinfo)
}
static void
-dtls_dst_prompt(packet_info *pinfo, gchar *result)
+dtls_dst_prompt(packet_info *pinfo, char *result)
{
SslPacketInfo* pi;
- guint32 destport = pinfo->destport;
+ uint32_t destport = pinfo->destport;
pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto_dtls, pinfo->curr_layer_num);
if (pi != NULL)
@@ -1951,7 +2745,7 @@ dtls_dst_prompt(packet_info *pinfo, gchar *result)
snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "destination (%s%u)", UTF8_RIGHTWARDS_ARROW, destport);
}
-static gpointer
+static void *
dtls_dst_value(packet_info *pinfo)
{
SslPacketInfo* pi;
@@ -1964,10 +2758,10 @@ dtls_dst_value(packet_info *pinfo)
}
static void
-dtls_both_prompt(packet_info *pinfo, gchar *result)
+dtls_both_prompt(packet_info *pinfo, char *result)
{
SslPacketInfo* pi;
- guint32 srcport = pinfo->srcport,
+ uint32_t srcport = pinfo->srcport,
destport = pinfo->destport;
pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto_dtls, pinfo->curr_layer_num);
@@ -2018,11 +2812,26 @@ proto_register_dtls(void)
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_dtls_record_epoch64,
+ { "Epoch", "dtls.record.epoch",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_dtls_record_sequence_number,
{ "Sequence Number", "dtls.record.sequence_number",
FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_dtls_record_sequence_suffix,
+ { "Sequence Number suffix", "dtls.record.sequence_suffix",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Lowest-order bits of the sequence number", HFILL }
+ },
+ { &hf_dtls_record_sequence_suffix_dec,
+ { "Sequence Number suffix (decrypted)", "dtls.record.sequence_suffix_dec",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Lowest-order bits of the sequence number (decrypted)", HFILL }
+ },
{ &hf_dtls_record_connection_id,
{ "Connection ID", "dtls.record.connection_id",
FT_BYTES, BASE_NONE, NULL, 0x0,
@@ -2035,7 +2844,7 @@ proto_register_dtls(void)
},
{ &hf_dtls_record_appdata,
{ "Encrypted Application Data", "dtls.app_data",
- FT_BYTES, BASE_NONE, NULL, 0x0,
+ FT_BYTES, BASE_NONE|BASE_NO_DISPLAY_VALUE, NULL, 0x0,
"Payload is encrypted application data", HFILL }
},
{ &hf_dtls_record_appdata_proto,
@@ -2045,7 +2854,7 @@ proto_register_dtls(void)
},
{ &hf_dtls_record_encrypted_content,
{ "Encrypted Record Content", "dtls.enc_content",
- FT_BYTES, BASE_NONE, NULL, 0x0,
+ FT_BYTES, BASE_NONE|BASE_NO_DISPLAY_VALUE, NULL, 0x0,
"Encrypted record data", HFILL }
},
{ & hf_dtls_alert_message,
@@ -2125,6 +2934,16 @@ proto_register_dtls(void)
{ "Payload Length", "dtls.heartbeat_message.padding",
FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
+ { &hf_dtls_ack_message,
+ { "Acknowledgement Message", "dtls.ack_message",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_dtls_ack_record_numbers_length,
+ { "Record Number Length", "dtls.ack.record_numbers_length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_dtls_fragments,
{ "Message fragments", "dtls.fragments",
FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
@@ -2133,6 +2952,11 @@ proto_register_dtls(void)
{ "Message fragment", "dtls.fragment",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
+ { &hf_dtls_ack_record_numbers,
+ { "Record Numbers", "dtls.ack.record_numbers",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_dtls_fragment_overlap,
{ "Message fragment overlap", "dtls.fragment.overlap",
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }
@@ -2183,17 +3007,46 @@ proto_register_dtls(void)
{ "MKI", "dtls.use_srtp.mki",
FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
},
+ { &hf_dtls_uni_hdr,
+ { "Unified header bitmask", "dtls.unified_header.bitmask",
+ FT_UINT8, BASE_HEX, NULL, 0x00, "DTLS 1.3 unified header bitmask", HFILL }
+ },
+ { &hf_dtls_uni_hdr_fixed,
+ { "Fixed bits", "dtls.unified_header.fixed",
+ FT_UINT8, BASE_HEX, NULL, DTLS13_FIXED_MASK, NULL, HFILL }
+ },
+ { &hf_dtls_uni_hdr_cid,
+ { "CID field", "dtls.unified_header.cid_present",
+ FT_BOOLEAN, 8, TFS(&tfs_present_not_present), DTLS13_C_BIT_MASK, NULL, HFILL }
+ },
+ { &hf_dtls_uni_hdr_seq,
+ { "Sequence number size", "dtls.unified_header.seq_size",
+ FT_BOOLEAN, 8, TFS(&dtls_uni_hdr_seq_tfs), DTLS13_S_BIT_MASK, NULL, HFILL }
+ },
+ { &hf_dtls_uni_hdr_len,
+ { "Length field", "dtls.unified_header.length",
+ FT_BOOLEAN, 8, TFS(&tfs_present_not_present), DTLS13_L_BIT_MASK, NULL, HFILL }
+ },
+ { &hf_dtls_uni_hdr_epoch,
+ { "Epoch lowest-order bits", "dtls.unified_header.epoch_bits",
+ FT_UINT8, BASE_DEC, NULL, 0x03, NULL, HFILL }
+ },
+
SSL_COMMON_HF_LIST(dissect_dtls_hf, "dtls")
};
/* Setup protocol subtree array */
- static gint *ett[] = {
+ static int *ett[] = {
&ett_dtls,
&ett_dtls_record,
&ett_dtls_alert,
&ett_dtls_handshake,
&ett_dtls_heartbeat,
+ &ett_dtls_ack,
+ &ett_dtls_ack_record_number,
+ &ett_dtls_ack_record_numbers,
&ett_dtls_certs,
+ &ett_dtls_uni_hdr,
&ett_dtls_fragment,
&ett_dtls_fragments,
SSL_COMMON_ETT_LIST(dissect_dtls_hf)
@@ -2256,7 +3109,7 @@ proto_register_dtls(void)
dtlsdecrypt_uat = uat_new("DTLS RSA Keylist",
sizeof(ssldecrypt_assoc_t),
"dtlsdecrypttablefile", /* filename */
- TRUE, /* from_profile */
+ true, /* from_profile */
&dtlskeylist_uats, /* data_ptr */
&ndtlsdecrypt, /* numitems_ptr */
UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
@@ -2282,7 +3135,7 @@ proto_register_dtls(void)
prefs_register_filename_preference(dtls_module, "debug_file", "DTLS debug file",
"redirect dtls debug to file name; leave empty to disable debug, "
"use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n",
- &dtls_debug_file_name, TRUE);
+ &dtls_debug_file_name, true);
prefs_register_uint_preference(dtls_module, "client_cid_length", "Client Connection ID length",
"Default client Connection ID length used when the Client Handshake message is missing",
@@ -2292,7 +3145,7 @@ proto_register_dtls(void)
"Default server Connection ID length used when the Server Handshake message is missing",
10, &dtls_default_server_cid_length);
- ssl_common_register_options(dtls_module, &dtls_options, TRUE);
+ ssl_common_register_options(dtls_module, &dtls_options, true);
}
dtls_handle = register_dissector("dtls", dissect_dtls, proto_dtls);
@@ -2306,7 +3159,7 @@ proto_register_dtls(void)
ssl_debug_printf("proto_register_dtls: registered tap %s:%d\n",
"dtls", dtls_tap);
- heur_subdissector_list = register_heur_dissector_list("dtls", proto_dtls);
+ heur_subdissector_list = register_heur_dissector_list_with_description("dtls", "DTLS payload fallback", proto_dtls);
}
@@ -2317,14 +3170,14 @@ proto_register_dtls(void)
void
proto_reg_handoff_dtls(void)
{
- static gboolean initialized = FALSE;
+ static bool initialized = false;
#ifdef HAVE_LIBGNUTLS
dtls_parse_uat();
dtls_parse_old_keys();
#endif
- if (initialized == FALSE) {
+ if (initialized == false) {
heur_dissector_add("udp", dissect_dtls_heur, "DTLS over UDP", "dtls_udp", proto_dtls, HEURISTIC_ENABLE);
heur_dissector_add("stun", dissect_dtls_heur, "DTLS over STUN", "dtls_stun", proto_dtls, HEURISTIC_DISABLE);
heur_dissector_add("classicstun", dissect_dtls_heur, "DTLS over CLASSICSTUN", "dtls_classicstun", proto_dtls, HEURISTIC_DISABLE);
@@ -2336,19 +3189,19 @@ proto_reg_handoff_dtls(void)
exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
}
- initialized = TRUE;
+ initialized = true;
}
void
-dtls_dissector_add(guint port, dissector_handle_t handle)
+dtls_dissector_add(unsigned port, dissector_handle_t handle)
{
- ssl_association_add("dtls.port", dtls_handle, handle, port, FALSE);
+ ssl_association_add("dtls.port", dtls_handle, handle, port, false);
}
void
-dtls_dissector_delete(guint port, dissector_handle_t handle)
+dtls_dissector_delete(unsigned port, dissector_handle_t handle)
{
- ssl_association_remove("dtls.port", dtls_handle, handle, port, FALSE);
+ ssl_association_remove("dtls.port", dtls_handle, handle, port, false);
}
/*