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>
This commit is contained in:
Peter Wu 2018-09-13 10:29:29 +02:00
parent e22faab56d
commit 624d136f37
4 changed files with 76 additions and 3 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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);