diff options
author | Peter Wu <peter@lekensteyn.nl> | 2018-09-13 10:29:29 +0200 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2018-09-16 20:22:18 +0000 |
commit | 624d136f37ecd78dbd47011045c0093f1bb61619 (patch) | |
tree | 81860fdf594681b57496eb8cadc446c3f6047ff7 /epan | |
parent | e22faab56d6b1421df26c7aa2025d41af03a9f55 (diff) |
QUIC: wire up CRYPTO frames with TLS 1.3 Handshake (draft -13)
This recognizes the Client/Server Hello message in the Initial Packets.
Full (handshake) decryption remains a task for later.
Prevent STREAM 0 from being treated as TLS while at it.
Change-Id: I27193a15be777c568b6b009141cbc59bcf3e8ad6
Ping-Bug: 13881
Reviewed-on: https://code.wireshark.org/review/29646
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-quic.c | 23 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.c | 8 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.h | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl.c | 47 |
4 files changed, 76 insertions, 3 deletions
diff --git a/epan/dissectors/packet-quic.c b/epan/dissectors/packet-quic.c index 2a32c65382..95127d5e08 100644 --- a/epan/dissectors/packet-quic.c +++ b/epan/dissectors/packet-quic.c @@ -125,6 +125,7 @@ static gint ett_quic_ftflags = -1; static dissector_handle_t quic_handle; static dissector_handle_t tls_handle; +static dissector_handle_t tls13_handshake_handle; /* * PROTECTED PAYLOAD DECRYPTION (done in first pass) @@ -781,7 +782,7 @@ quic_connection_destroy(gpointer data, gpointer user_data _U_) #ifdef HAVE_LIBGCRYPT_AEAD static int -dissect_quic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint offset, quic_packet_info_t *quic_packet _U_) +dissect_quic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint offset, guint32 version) { proto_item *ti_ft, *ti_ftflags, *ti; proto_tree *ft_tree, *ftflags_tree; @@ -1085,7 +1086,7 @@ dissect_quic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree proto_tree_add_item(ft_tree, hf_quic_stream_data, tvb, offset, (int)length, ENC_NA); - if (stream_id == 0) { /* Special Stream */ + if (is_quic_draft_max(version, 12) && stream_id == 0) { /* Special Stream */ tvbuff_t *next_tvb; proto_item_append_text(ti_stream, " (Cryptographic handshake)"); @@ -1108,6 +1109,20 @@ dissect_quic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree proto_tree_add_item_ret_varint(ft_tree, hf_quic_frame_type_crypt_length, tvb, offset, -1, ENC_VARINT_QUIC, &crypto_length, &lenvar); offset += lenvar; proto_tree_add_item(ft_tree, hf_quic_frame_type_crypt_crypto_data, tvb, offset, (guint32)crypto_length, ENC_NA); + { + tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, (int)crypto_length); + col_set_writable(pinfo->cinfo, -1, FALSE); + /* + * Dissect TLS handshake record. The Client/Server Hello (CH/SH) + * are contained in the Initial Packet. 0-RTT keys are ready + * after CH. HS + 1-RTT keys are ready after SH. + * (Note: keys captured from the client might become available + * after capturing the packets due to processing delay.) + * These keys will be loaded in the first HS/0-RTT/1-RTT msg. + */ + call_dissector(tls13_handshake_handle, next_tvb, pinfo, ft_tree); + col_set_writable(pinfo->cinfo, -1, TRUE); + } offset += (guint32)crypto_length; } break; @@ -1577,6 +1592,7 @@ quic_process_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_ quic_info_data_t *quic_info, quic_packet_info_t *quic_packet, quic_cipher *cipher, guint pkn_len) { quic_decrypt_result_t *decryption = &quic_packet->decryption; + guint32 version = quic_info ? quic_info->version : 0; /* * If no decryption error has occurred yet, try decryption on the first @@ -1598,7 +1614,7 @@ quic_process_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_ guint decrypted_offset = 0; while (tvb_reported_length_remaining(decrypted_tvb, decrypted_offset) > 0) { - decrypted_offset = dissect_quic_frame_type(decrypted_tvb, pinfo, tree, decrypted_offset, quic_packet); + decrypted_offset = dissect_quic_frame_type(decrypted_tvb, pinfo, tree, decrypted_offset, version); } } else if (quic_info->skip_decryption) { expert_add_info_format(pinfo, ti, &ei_quic_decryption_failed, @@ -2566,6 +2582,7 @@ void proto_reg_handoff_quic(void) { tls_handle = find_dissector("tls"); + tls13_handshake_handle = find_dissector("tls13-handshake"); dissector_add_uint_with_preference("udp.port", 0, quic_handle); heur_dissector_add("udp", dissect_quic_heur, "QUIC", "quic", proto_quic, HEURISTIC_ENABLE); } diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c index 866073738e..3cce6609e7 100644 --- a/epan/dissectors/packet-ssl-utils.c +++ b/epan/dissectors/packet-ssl-utils.c @@ -4997,6 +4997,14 @@ void tls13_change_key(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map, gboolean is_from_server, TLSRecordType type) { + if (ssl->state & SSL_QUIC_RECORD_LAYER) { + /* + * QUIC does not use the TLS record layer for message protection. + * The required keys will be extracted later by QUIC. + */ + return; + } + StringInfo *secret = tls13_load_secret(ssl, mk_map, is_from_server, type); if (!secret) { return; diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h index e32911e4a1..23638ff014 100644 --- a/epan/dissectors/packet-ssl-utils.h +++ b/epan/dissectors/packet-ssl-utils.h @@ -237,6 +237,7 @@ static inline guint8 extract_tls13_draft_version(guint32 version) { #define SSL_NEW_SESSION_TICKET (1<<10) #define SSL_ENCRYPT_THEN_MAC (1<<11) #define SSL_SEEN_0RTT_APPDATA (1<<12) +#define SSL_QUIC_RECORD_LAYER (1<<13) /* For QUIC (draft >= -13) */ #define SSL_EXTENDED_MASTER_SECRET_MASK (SSL_CLIENT_EXTENDED_MASTER_SECRET|SSL_SERVER_EXTENDED_MASTER_SECRET) diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c index 65402f3d58..912d83b40f 100644 --- a/epan/dissectors/packet-ssl.c +++ b/epan/dissectors/packet-ssl.c @@ -770,6 +770,52 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) return tvb_captured_length(tvb); } +/* + * Dissect TLS 1.3 handshake messages (without the record layer). + * For use by QUIC (draft -13). + */ +static int +dissect_tls13_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + + conversation_t *conversation; + SslDecryptSession *ssl_session; + SslSession *session; + gint is_from_server; + + ssl_debug_printf("\n%s enter frame #%u (%s)\n", G_STRFUNC, pinfo->num, (pinfo->fd->flags.visited)?"already visited":"first time"); + + conversation = find_or_create_conversation(pinfo); + ssl_session = ssl_get_session(conversation, tls_handle); + session = &ssl_session->session; + is_from_server = ssl_packet_from_server(session, ssl_associations, pinfo); + if (session->version == SSL_VER_UNKNOWN) { + session->version = TLSV1DOT3_VERSION; + ssl_session->state |= SSL_VERSION; + ssl_session->state |= SSL_QUIC_RECORD_LAYER; + } + + /* + * First pass: collect state (including Client Random for key matching). + * Second pass: dissection only, no need to collect state. + */ + if (PINFO_FD_VISITED(pinfo)) { + ssl_session = NULL; + } + + ssl_debug_printf(" conversation = %p, ssl_session = %p, from_server = %d\n", + (void *)conversation, (void *)ssl_session, is_from_server); + + /* Directly add handshake message to the tree (without proto_tls item). */ + dissect_ssl3_handshake(tvb, pinfo, tree, 0, + tvb_reported_length(tvb), FALSE, session, + is_from_server, ssl_session, SSL_ID_HANDSHAKE, TLSV1DOT3_VERSION); + + ssl_debug_flush(); + + return tvb_captured_length(tvb); +} + static gboolean is_sslv3_or_tls(tvbuff_t *tvb) { @@ -4010,6 +4056,7 @@ proto_register_tls(void) proto_tls); tls_handle = register_dissector("tls", dissect_ssl, proto_tls); + register_dissector("tls13-handshake", dissect_tls13_handshake, proto_tls); register_init_routine(ssl_init); register_cleanup_routine(ssl_cleanup); |