2017-06-23 05:45:10 +00:00
/* packet-quic.c
2018-04-18 16:39:17 +00:00
* Routines for QUIC ( IETF ) dissection
2017-06-23 05:45:10 +00:00
* Copyright 2017 , Alexis La Goutte < alexis . lagoutte at gmail dot com >
2018-04-18 16:39:17 +00:00
* Copyright 2018 Peter Wu < peter @ lekensteyn . nl >
2017-06-23 05:45:10 +00:00
*
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
* Copyright 1998 Gerald Combs
*
2018-02-12 11:23:27 +00:00
* SPDX - License - Identifier : GPL - 2.0 - or - later
2017-06-23 05:45:10 +00:00
*/
/*
2018-09-17 16:14:02 +00:00
* See https : //quicwg.org
* https : //tools.ietf.org/html/draft-ietf-quic-transport-14
* https : //tools.ietf.org/html/draft-ietf-quic-tls-14
* https : //tools.ietf.org/html/draft-ietf-quic-invariants-02
2017-06-23 05:45:10 +00:00
*/
# include <config.h>
# include <epan/packet.h>
# include <epan/expert.h>
2018-03-20 16:36:38 +00:00
# include <epan/proto_data.h>
2018-04-18 16:39:17 +00:00
# include <epan/to_str.h>
2017-06-23 05:45:10 +00:00
# include "packet-ssl-utils.h"
2018-03-19 23:42:00 +00:00
# include "packet-ssl.h"
2017-06-23 05:45:10 +00:00
# include <epan/prefs.h>
2017-11-15 06:41:45 +00:00
# include <wsutil/pint.h>
2017-06-23 05:45:10 +00:00
2017-11-15 06:41:45 +00:00
# if GCRYPT_VERSION_NUMBER >= 0x010600 /* 1.6.0 */
/* Whether to provide support for authentication in addition to decryption. */
# define HAVE_LIBGCRYPT_AEAD
# endif
2018-09-12 14:11:49 +00:00
# if GCRYPT_VERSION_NUMBER >= 0x010700 /* 1.7.0 */
/* Whether ChaCh20 PNE can be supported. */
# define HAVE_LIBGCRYPT_CHACHA20
# endif
2017-06-23 05:45:10 +00:00
/* Prototypes */
void proto_reg_handoff_quic ( void ) ;
void proto_register_quic ( void ) ;
/* Initialize the protocol and registered fields */
static int proto_quic = - 1 ;
2018-04-23 14:53:40 +00:00
static int hf_quic_connection_number = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_header_form = - 1 ;
static int hf_quic_long_packet_type = - 1 ;
2018-04-18 16:39:17 +00:00
static int hf_quic_dcid = - 1 ;
static int hf_quic_scid = - 1 ;
static int hf_quic_dcil = - 1 ;
static int hf_quic_scil = - 1 ;
2018-09-12 22:34:46 +00:00
static int hf_quic_token_length = - 1 ;
static int hf_quic_token = - 1 ;
static int hf_quic_length = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_packet_number = - 1 ;
2018-03-16 18:44:27 +00:00
static int hf_quic_packet_number_full = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_version = - 1 ;
2018-01-03 19:15:24 +00:00
static int hf_quic_supported_version = - 1 ;
static int hf_quic_vn_unused = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_short_kp_flag = - 1 ;
2018-09-15 09:55:21 +00:00
static int hf_quic_short_reserved = - 1 ;
2018-09-15 15:41:39 +00:00
static int hf_quic_payload = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_protected_payload = - 1 ;
2018-09-16 22:50:08 +00:00
static int hf_quic_odcil_draft13 = - 1 ;
2018-09-17 08:32:50 +00:00
static int hf_quic_odcil = - 1 ;
2018-09-16 22:50:08 +00:00
static int hf_quic_odcid = - 1 ;
static int hf_quic_retry_token = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame = - 1 ;
static int hf_quic_frame_type = - 1 ;
2017-12-24 14:03:58 +00:00
static int hf_quic_frame_type_stream_fin = - 1 ;
static int hf_quic_frame_type_stream_len = - 1 ;
static int hf_quic_frame_type_stream_off = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_stream_stream_id = - 1 ;
static int hf_quic_stream_offset = - 1 ;
2017-12-24 14:03:58 +00:00
static int hf_quic_stream_length = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_stream_data = - 1 ;
static int hf_quic_frame_type_ack_largest_acknowledged = - 1 ;
static int hf_quic_frame_type_ack_ack_delay = - 1 ;
2017-12-31 09:58:09 +00:00
static int hf_quic_frame_type_ack_ack_block_count = - 1 ;
static int hf_quic_frame_type_ack_fab = - 1 ;
static int hf_quic_frame_type_ack_gap = - 1 ;
static int hf_quic_frame_type_ack_ack_block = - 1 ;
2017-06-23 05:45:10 +00:00
2018-04-17 20:41:38 +00:00
static int hf_quic_frame_type_path_challenge_data = - 1 ;
static int hf_quic_frame_type_path_response_data = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_padding_length = - 1 ;
static int hf_quic_frame_type_padding = - 1 ;
static int hf_quic_frame_type_rsts_stream_id = - 1 ;
2017-11-15 06:02:22 +00:00
static int hf_quic_frame_type_rsts_application_error_code = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_rsts_final_offset = - 1 ;
static int hf_quic_frame_type_cc_error_code = - 1 ;
2018-09-17 14:41:04 +00:00
static int hf_quic_frame_type_cc_frame_type = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_cc_reason_phrase_length = - 1 ;
static int hf_quic_frame_type_cc_reason_phrase = - 1 ;
2017-11-14 21:49:45 +00:00
static int hf_quic_frame_type_ac_error_code = - 1 ;
static int hf_quic_frame_type_ac_reason_phrase_length = - 1 ;
static int hf_quic_frame_type_ac_reason_phrase = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_md_maximum_data = - 1 ;
static int hf_quic_frame_type_msd_stream_id = - 1 ;
static int hf_quic_frame_type_msd_maximum_stream_data = - 1 ;
static int hf_quic_frame_type_msi_stream_id = - 1 ;
2018-01-03 07:30:08 +00:00
static int hf_quic_frame_type_blocked_offset = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_sb_stream_id = - 1 ;
2018-01-03 07:30:08 +00:00
static int hf_quic_frame_type_sb_offset = - 1 ;
static int hf_quic_frame_type_sib_stream_id = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_nci_sequence = - 1 ;
2018-04-23 21:00:53 +00:00
static int hf_quic_frame_type_nci_connection_id_length = - 1 ;
2017-06-23 05:45:10 +00:00
static int hf_quic_frame_type_nci_connection_id = - 1 ;
2017-09-01 14:06:22 +00:00
static int hf_quic_frame_type_nci_stateless_reset_token = - 1 ;
2017-09-01 14:29:23 +00:00
static int hf_quic_frame_type_ss_stream_id = - 1 ;
2017-11-15 06:20:36 +00:00
static int hf_quic_frame_type_ss_application_error_code = - 1 ;
2018-09-15 14:06:30 +00:00
static int hf_quic_frame_type_crypto_offset = - 1 ;
static int hf_quic_frame_type_crypto_length = - 1 ;
static int hf_quic_frame_type_crypto_crypto_data = - 1 ;
2018-09-17 15:22:06 +00:00
static int hf_quic_frame_type_nt_length = - 1 ;
static int hf_quic_frame_type_nt_token = - 1 ;
static int hf_quic_frame_type_ae_largest_acknowledged = - 1 ;
static int hf_quic_frame_type_ae_ack_delay = - 1 ;
static int hf_quic_frame_type_ae_ect0_count = - 1 ;
static int hf_quic_frame_type_ae_ect1_count = - 1 ;
static int hf_quic_frame_type_ae_ecn_ce_count = - 1 ;
static int hf_quic_frame_type_ae_ack_block_count = - 1 ;
static int hf_quic_frame_type_ae_fab = - 1 ;
static int hf_quic_frame_type_ae_gap = - 1 ;
static int hf_quic_frame_type_ae_ack_block = - 1 ;
2017-06-23 05:45:10 +00:00
2018-04-23 14:53:40 +00:00
static expert_field ei_quic_connection_unknown = EI_INIT ;
2017-06-23 05:45:10 +00:00
static expert_field ei_quic_ft_unknown = EI_INIT ;
2017-11-15 07:27:27 +00:00
static expert_field ei_quic_decryption_failed = EI_INIT ;
2018-04-17 21:56:26 +00:00
static expert_field ei_quic_protocol_violation = EI_INIT ;
2017-06-23 05:45:10 +00:00
static gint ett_quic = - 1 ;
2018-04-23 14:53:40 +00:00
static gint ett_quic_connection_info = - 1 ;
2017-06-23 05:45:10 +00:00
static gint ett_quic_ft = - 1 ;
static gint ett_quic_ftflags = - 1 ;
static dissector_handle_t quic_handle ;
2018-09-13 08:29:29 +00:00
static dissector_handle_t tls13_handshake_handle ;
2017-06-23 05:45:10 +00:00
2018-03-19 23:42:00 +00:00
/*
* PROTECTED PAYLOAD DECRYPTION ( done in first pass )
*
2018-09-15 23:07:21 +00:00
* Long packet types always use a single cipher depending on packet type .
2018-03-19 23:42:00 +00:00
* Short packet types always use 1 - RTT secrets for packet protection ( pp ) .
* TODO 0 - RTT decryption requires another ( client ) cipher .
*
* Considerations :
* - QUIC packets might appear out - of - order ( short packets before handshake
* message is captured ) , lost or retransmitted / duplicated .
* - During live capture , keys might not be immediately be available . 1 - RTT
* client keys will be ready while client proceses Server Hello ( Handshake ) .
* 1 - RTT server keys will be ready while server creates Handshake message in
2018-09-12 22:34:46 +00:00
* response to Initial Handshake .
2018-03-19 23:42:00 +00:00
* - So delay cipher creation until first short packet is received .
*
* Required input from TLS dissector : TLS - Exporter 0 - RTT / 1 - RTT secrets and
* cipher / hash algorithms .
*
* to - do list :
* DONE key update via KEY_PHASE bit ( untested )
* TODO 0 - RTT decryption
*/
2018-03-20 18:37:30 +00:00
typedef struct quic_decrypt_result {
const guchar * error ; /**< Error message or NULL for success. */
const guint8 * data ; /**< Decrypted result on success (file-scoped). */
guint data_len ; /**< Size of decrypted data. */
} quic_decrypt_result_t ;
2018-04-18 16:39:17 +00:00
typedef struct quic_cid {
guint8 len ;
guint8 cid [ 18 ] ;
} quic_cid_t ;
2018-09-11 21:27:18 +00:00
/** QUIC decryption context. */
typedef struct quic_cipher {
2018-09-12 14:11:49 +00:00
gcry_cipher_hd_t pn_cipher ; /* Packet number protection cipher. */
2018-09-11 21:27:18 +00:00
gcry_cipher_hd_t pp_cipher ; /* Packet protection cipher. */
guint8 pp_iv [ TLS13_AEAD_NONCE_LENGTH ] ;
} quic_cipher ;
2018-03-19 23:42:00 +00:00
/**
* Packet protection state for an endpoint .
*/
typedef struct quic_pp_state {
2018-09-15 15:23:45 +00:00
guint8 * next_secret ; /**< Next application traffic secret. */
2018-09-11 21:27:18 +00:00
quic_cipher cipher [ 2 ] ; /**< Cipher for KEY_PHASE 0/1 */
2018-03-19 23:42:00 +00:00
guint64 changed_in_pkn ; /**< Packet number where key change occurred. */
gboolean key_phase : 1 ; /**< Current key phase. */
} quic_pp_state_t ;
2018-04-21 12:18:03 +00:00
/** Singly-linked list of Connection IDs. */
typedef struct quic_cid_item quic_cid_item_t ;
struct quic_cid_item {
struct quic_cid_item * next ;
quic_cid_t data ;
} ;
/**
* State for a single QUIC connection , identified by one or more Destination
* Connection IDs ( DCID ) .
*/
2017-11-14 21:31:13 +00:00
typedef struct quic_info_data {
2018-04-23 14:53:40 +00:00
guint32 number ; /** Similar to "udp.stream", but for identifying QUIC connections across migrations. */
2018-04-21 12:18:03 +00:00
guint32 version ;
2018-03-20 16:36:38 +00:00
address server_address ;
guint16 server_port ;
2018-03-19 23:42:00 +00:00
gboolean skip_decryption : 1 ; /**< Set to 1 if no keys are available. */
int hash_algo ; /**< Libgcrypt hash algorithm for key derivation. */
2018-09-15 15:23:45 +00:00
int cipher_algo ; /**< Cipher algorithm for packet number and packet encryption. */
int cipher_mode ; /**< Cipher mode for packet encryption. */
2018-09-15 23:07:21 +00:00
quic_cipher client_initial_cipher ;
quic_cipher server_initial_cipher ;
2018-09-11 21:27:18 +00:00
quic_cipher client_handshake_cipher ;
quic_cipher server_handshake_cipher ;
2018-03-19 23:42:00 +00:00
quic_pp_state_t client_pp ;
quic_pp_state_t server_pp ;
2018-04-21 12:18:03 +00:00
guint64 max_client_pkn ;
guint64 max_server_pkn ;
quic_cid_item_t client_cids ; /**< SCID of client from first Initial Packet. */
quic_cid_item_t server_cids ; /**< SCID of server from first Retry/Handshake. */
quic_cid_t client_dcid_initial ; /**< DCID from Initial Packet. */
2017-11-14 21:31:13 +00:00
} quic_info_data_t ;
2018-04-21 12:18:03 +00:00
/** Per-packet information about QUIC, populated on the first pass. */
2018-09-13 15:03:19 +00:00
struct quic_packet_info {
struct quic_packet_info * next ;
2018-04-21 12:18:03 +00:00
guint64 packet_number ; /**< Reconstructed full packet number. */
quic_decrypt_result_t decryption ;
2018-09-12 14:11:49 +00:00
guint8 pkn_len ; /**< Length of PKN (1/2/4) or unknown (0). */
2018-09-13 15:03:19 +00:00
} ;
typedef struct quic_packet_info quic_packet_info_t ;
/** A UDP datagram contains one or more QUIC packets. */
typedef struct quic_datagram {
quic_info_data_t * conn ;
quic_packet_info_t first_packet ;
gboolean from_server : 1 ;
} quic_datagram ;
2018-04-21 12:18:03 +00:00
/**
* Maps CID ( quic_cid_t * ) to a QUIC Connection ( quic_info_data_t * ) .
* This assumes that the CIDs are not shared between two different connections
* ( potentially with different versions ) as that would break dissection .
*
* These mappings are authorative . For example , Initial . SCID is stored in
* quic_client_connections while Retry . SCID is stored in
* quic_server_connections . Retry . DCID should normally correspond to an entry in
* quic_client_connections .
*/
static wmem_map_t * quic_client_connections , * quic_server_connections ;
static wmem_map_t * quic_initial_connections ; /* Initial.DCID -> connection */
static wmem_list_t * quic_connections ; /* All unique connections. */
2018-09-18 22:40:12 +00:00
static guint32 quic_cid_lengths ; /* Bitmap of CID lengths. */
2018-04-23 14:53:40 +00:00
static guint quic_connections_count ;
2018-04-21 12:18:03 +00:00
2018-04-18 16:39:17 +00:00
/* Returns the QUIC draft version or 0 if not applicable. */
static inline guint8 quic_draft_version ( guint32 version ) {
if ( ( version > > 8 ) = = 0xff0000 ) {
return ( guint8 ) version ;
}
return 0 ;
}
static inline gboolean is_quic_draft_max ( guint32 version , guint8 max_version ) {
guint8 draft_version = quic_draft_version ( version ) ;
return draft_version & & draft_version < = max_version ;
}
2018-02-28 07:04:25 +00:00
2017-07-24 19:14:30 +00:00
const value_string quic_version_vals [ ] = {
2018-01-03 19:15:24 +00:00
{ 0x00000000 , " Version Negotiation " } ,
2017-06-23 05:45:10 +00:00
{ 0xff000004 , " draft-04 " } ,
{ 0xff000005 , " draft-05 " } ,
2017-10-02 06:05:14 +00:00
{ 0xff000006 , " draft-06 " } ,
2017-10-22 16:40:47 +00:00
{ 0xff000007 , " draft-07 " } ,
2017-12-23 14:17:36 +00:00
{ 0xff000008 , " draft-08 " } ,
2018-02-07 16:01:09 +00:00
{ 0xff000009 , " draft-09 " } ,
2018-04-16 12:14:02 +00:00
{ 0xff00000a , " draft-10 " } ,
2018-04-18 11:56:47 +00:00
{ 0xff00000b , " draft-11 " } ,
2018-09-12 14:11:49 +00:00
{ 0xff00000c , " draft-12 " } ,
2018-09-12 22:34:46 +00:00
{ 0xff00000d , " draft-13 " } ,
2018-09-17 16:14:02 +00:00
{ 0xff00000e , " draft-14 " } ,
2017-06-23 05:45:10 +00:00
{ 0 , NULL }
} ;
static const value_string quic_short_long_header_vals [ ] = {
{ 0 , " Short Header " } ,
{ 1 , " Long Header " } ,
{ 0 , NULL }
} ;
2018-04-18 16:39:17 +00:00
# define SH_KP 0x40 /* since draft -11 */
static const value_string quic_cid_len_vals [ ] = {
{ 0 , " 0 octets " } ,
{ 1 , " 4 octets " } ,
{ 2 , " 5 octets " } ,
{ 3 , " 6 octets " } ,
{ 4 , " 7 octets " } ,
{ 5 , " 8 octets " } ,
{ 6 , " 9 octets " } ,
{ 7 , " 10 octets " } ,
{ 8 , " 11 octets " } ,
{ 9 , " 12 octets " } ,
{ 10 , " 13 octets " } ,
{ 11 , " 14 octets " } ,
{ 12 , " 15 octets " } ,
{ 13 , " 16 octets " } ,
{ 14 , " 17 octets " } ,
{ 15 , " 18 octets " } ,
{ 0 , NULL }
} ;
2018-01-19 22:01:13 +00:00
# define QUIC_LPT_INITIAL 0x7F
# define QUIC_LPT_RETRY 0x7E
# define QUIC_LPT_HANDSHAKE 0x7D
2018-04-21 12:18:03 +00:00
# define QUIC_LPT_0RTT 0x7C
# define QUIC_SHORT_PACKET 0xff /* dummy value that is definitely not LPT */
2017-06-23 05:45:10 +00:00
static const value_string quic_long_packet_type_vals [ ] = {
2018-01-19 22:01:13 +00:00
{ QUIC_LPT_INITIAL , " Initial " } ,
{ QUIC_LPT_RETRY , " Retry " } ,
{ QUIC_LPT_HANDSHAKE , " Handshake " } ,
2018-04-21 12:18:03 +00:00
{ QUIC_LPT_0RTT , " 0-RTT Protected " } ,
2017-06-23 05:45:10 +00:00
{ 0 , NULL }
} ;
# define FT_PADDING 0x00
# define FT_RST_STREAM 0x01
# define FT_CONNECTION_CLOSE 0x02
2017-11-14 21:49:45 +00:00
# define FT_APPLICATION_CLOSE 0x03 /* Add in draft07 */
2017-06-23 05:45:10 +00:00
# define FT_MAX_DATA 0x04
# define FT_MAX_STREAM_DATA 0x05
# define FT_MAX_STREAM_ID 0x06
# define FT_PING 0x07
# define FT_BLOCKED 0x08
# define FT_STREAM_BLOCKED 0x09
2017-10-02 06:10:29 +00:00
# define FT_STREAM_ID_BLOCKED 0x0a
2017-06-23 05:45:10 +00:00
# define FT_NEW_CONNECTION_ID 0x0b
2017-09-01 14:29:23 +00:00
# define FT_STOP_SENDING 0x0c
2018-04-16 12:14:02 +00:00
# define FT_ACK 0x0d
2018-04-17 20:41:38 +00:00
# define FT_PATH_CHALLENGE 0x0e
# define FT_PATH_RESPONSE 0x0f
2017-12-24 14:03:58 +00:00
# define FT_STREAM_10 0x10
# define FT_STREAM_11 0x11
# define FT_STREAM_12 0x12
# define FT_STREAM_13 0x13
# define FT_STREAM_14 0x14
# define FT_STREAM_15 0x15
# define FT_STREAM_16 0x16
# define FT_STREAM_17 0x17
2018-09-12 23:04:48 +00:00
# define FT_CRYPTO 0x18
2018-09-17 15:22:06 +00:00
# define FT_NEW_TOKEN 0x19 /* Add in draft 13 */
2018-09-17 16:27:57 +00:00
# define FT_ACK_ECN 0x1a /* Add in draft 14 */
# define FT_ACK_ECN_OLD 0x20 /* Remove in draft 14 */
2017-06-23 05:45:10 +00:00
static const range_string quic_frame_type_vals [ ] = {
{ 0x00 , 0x00 , " PADDING " } ,
{ 0x01 , 0x01 , " RST_STREAM " } ,
{ 0x02 , 0x02 , " CONNECTION_CLOSE " } ,
2017-11-14 21:49:45 +00:00
{ 0x03 , 0x03 , " APPLICATION_CLOSE " } ,
2017-06-23 05:45:10 +00:00
{ 0x04 , 0x04 , " MAX_DATA " } ,
{ 0x05 , 0x05 , " MAX_STREAM_DATA " } ,
{ 0x06 , 0x06 , " MAX_STREAM_ID " } ,
{ 0x07 , 0x07 , " PING " } ,
{ 0x08 , 0x08 , " BLOCKED " } ,
{ 0x09 , 0x09 , " STREAM_BLOCKED " } ,
2017-10-02 06:10:29 +00:00
{ 0x0a , 0x0a , " STREAM_ID_BLOCKED " } ,
2017-06-23 05:45:10 +00:00
{ 0x0b , 0x0b , " NEW_CONNECTION_ID " } ,
2017-09-01 14:29:23 +00:00
{ 0x0c , 0x0c , " STOP_SENDING " } ,
2018-04-16 12:14:02 +00:00
{ 0x0d , 0x0d , " ACK " } ,
2018-04-17 20:41:38 +00:00
{ 0x0e , 0x0e , " PATH_CHALLENGE " } ,
{ 0x0f , 0x0f , " PATH_RESPONSE " } ,
2017-12-24 14:03:58 +00:00
{ 0x10 , 0x17 , " STREAM " } ,
2018-09-12 23:04:48 +00:00
{ 0x18 , 0x18 , " CRYPTO " } ,
2018-09-17 15:22:06 +00:00
{ 0x19 , 0x19 , " NEW_TOKEN " } ,
2018-09-17 16:27:57 +00:00
{ 0x1a , 0x1a , " ACK_ECN " } ,
2018-09-17 15:22:06 +00:00
{ 0x20 , 0x20 , " ACK_ECN " } ,
2017-06-23 05:45:10 +00:00
{ 0 , 0 , NULL } ,
} ;
2017-12-24 14:03:58 +00:00
/* >= draft-08 */
# define FTFLAGS_STREAM_FIN 0x01
# define FTFLAGS_STREAM_LEN 0x02
# define FTFLAGS_STREAM_OFF 0x04
2017-11-14 22:09:44 +00:00
/* > draft 07 */
# define QUIC_NO_ERROR 0x0000
# define QUIC_INTERNAL_ERROR 0x0001
2018-04-17 21:56:26 +00:00
# define QUIC_SERVER_BUSY 0x0002
2017-11-14 22:09:44 +00:00
# define QUIC_FLOW_CONTROL_ERROR 0x0003
# define QUIC_STREAM_ID_ERROR 0x0004
# define QUIC_STREAM_STATE_ERROR 0x0005
# define QUIC_FINAL_OFFSET_ERROR 0x0006
2018-09-17 15:32:37 +00:00
# define QUIC_FRAME_ENCODING_ERROR 0x0007
2017-11-14 22:09:44 +00:00
# define QUIC_TRANSPORT_PARAMETER_ERROR 0x0008
# define QUIC_VERSION_NEGOTIATION_ERROR 0x0009
# define QUIC_PROTOCOL_VIOLATION 0x000A
2018-09-17 15:32:37 +00:00
# define QUIC_INVALID_MIGRATION 0x000C
2018-01-15 07:16:18 +00:00
2017-06-23 05:45:10 +00:00
static const value_string quic_error_code_vals [ ] = {
2017-11-14 22:09:44 +00:00
{ QUIC_NO_ERROR , " NO_ERROR (An endpoint uses this with CONNECTION_CLOSE to signal that the connection is being closed abruptly in the absence of any error.) " } ,
2017-06-23 05:45:10 +00:00
{ QUIC_INTERNAL_ERROR , " INTERNAL_ERROR (The endpoint encountered an internal error and cannot continue with the connection) " } ,
2018-04-17 21:56:26 +00:00
{ QUIC_SERVER_BUSY , " SERVER_BUSY (The server is currently busy and does not accept any new connections. " } ,
2017-06-23 05:45:10 +00:00
{ QUIC_FLOW_CONTROL_ERROR , " FLOW_CONTROL_ERROR (An endpoint received more data than An endpoint received more data tha) " } ,
{ QUIC_STREAM_ID_ERROR , " STREAM_ID_ERROR (An endpoint received a frame for a stream identifier that exceeded its advertised maximum stream ID) " } ,
{ QUIC_STREAM_STATE_ERROR , " STREAM_STATE_ERROR (An endpoint received a frame for a stream that was not in a state that permitted that frame) " } ,
{ QUIC_FINAL_OFFSET_ERROR , " FINAL_OFFSET_ERROR (An endpoint received a STREAM frame containing data that exceeded the previously established final offset) " } ,
2018-09-17 15:32:37 +00:00
{ QUIC_FRAME_ENCODING_ERROR , " FRAME_ENCODING_ERROR (An endpoint received a frame that was badly formatted) " } ,
2017-06-23 05:45:10 +00:00
{ QUIC_TRANSPORT_PARAMETER_ERROR , " TRANSPORT_PARAMETER_ERROR (An endpoint received transport parameters that were badly formatted) " } ,
{ QUIC_VERSION_NEGOTIATION_ERROR , " VERSION_NEGOTIATION_ERROR (An endpoint received transport parameters that contained version negotiation parameters that disagreed with the version negotiation that it performed) " } ,
{ QUIC_PROTOCOL_VIOLATION , " PROTOCOL_VIOLATION (An endpoint detected an error with protocol compliance that was not covered by more specific error codes) " } ,
2018-09-17 15:32:37 +00:00
{ QUIC_INVALID_MIGRATION , " A peer has migrated to a different network when the endpoint had disabled migration " } ,
2017-06-23 05:45:10 +00:00
{ 0 , NULL }
} ;
static value_string_ext quic_error_code_vals_ext = VALUE_STRING_EXT_INIT ( quic_error_code_vals ) ;
2018-09-15 15:23:45 +00:00
static void
quic_cipher_reset ( quic_cipher * cipher )
{
gcry_cipher_close ( cipher - > pn_cipher ) ;
gcry_cipher_close ( cipher - > pp_cipher ) ;
memset ( cipher , 0 , sizeof ( * cipher ) ) ;
}
2018-03-16 18:44:27 +00:00
/* Inspired from ngtcp2 */
static guint64 quic_pkt_adjust_pkt_num ( guint64 max_pkt_num , guint64 pkt_num ,
size_t n ) {
2018-03-18 12:20:38 +00:00
guint64 k = max_pkt_num = = G_MAXUINT64 ? max_pkt_num : max_pkt_num + 1 ;
2018-03-16 18:44:27 +00:00
guint64 u = k & ~ ( ( G_GUINT64_CONSTANT ( 1 ) < < n ) - 1 ) ;
guint64 a = u | pkt_num ;
guint64 b = ( u + ( G_GUINT64_CONSTANT ( 1 ) < < n ) ) | pkt_num ;
guint64 a1 = k < a ? a - k : k - a ;
guint64 b1 = k < b ? b - k : k - b ;
if ( a1 < b1 ) {
return a ;
}
return b ;
}
2018-09-12 14:11:49 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
static guint
quic_decrypt_packet_number ( tvbuff_t * tvb , guint offset , quic_cipher * cipher ,
int pn_cipher_algo , guint64 * pkn )
{
guint32 pkt_pkn ;
guint pkn_len ;
guint8 * pkn_bytes = ( guint8 * ) & pkt_pkn ;
gcry_cipher_hd_t h ;
if ( ! cipher | | ! ( h = cipher - > pn_cipher ) ) {
// need to know the cipher.
return 0 ;
}
tvb_memcpy ( tvb , pkn_bytes , offset , sizeof ( pkt_pkn ) ) ;
// Both AES-CTR and ChaCha20 use 16 octets as sample length.
// https://tools.ietf.org/html/draft-ietf-quic-tls-13#section-5.3
const guint sample_length = 16 ;
guint sample_offset = offset + 4 ;
guint8 sample [ 16 ] ;
if ( sample_offset + sample_length > tvb_reported_length ( tvb ) ) {
sample_offset = tvb_reported_length ( tvb ) - sample_length ;
}
tvb_memcpy ( tvb , sample , sample_offset , sample_length ) ;
switch ( pn_cipher_algo ) {
case GCRY_CIPHER_AES128 :
case GCRY_CIPHER_AES256 :
if ( gcry_cipher_setctr ( h , sample , sample_length ) ) {
return 0 ;
}
break ;
# ifdef HAVE_LIBGCRYPT_CHACHA20
case GCRY_CIPHER_CHACHA20 :
/* If Gcrypt receives a 16 byte IV, it will assume the buffer to be
* counter | | nonce ( in little endian ) , as desired . */
if ( gcry_cipher_setiv ( h , sample , 16 ) ) {
return 0 ;
}
break ;
# endif /* HAVE_LIBGCRYPT_CHACHA20 */
default :
return 0 ;
}
/* in-place decrypt. */
if ( gcry_cipher_decrypt ( h , pkn_bytes , 4 , NULL , 0 ) ) {
return 0 ;
}
// | First octet pattern | Encoded Length | Bits Present |
// | 0b0xxxxxxx | 1 octet | 7 |
// | 0b10xxxxxx | 2 | 14 |
// | 0b11xxxxxx | 4 | 30 |
switch ( pkn_bytes [ 0 ] > > 6 ) {
default :
pkn_len = 1 ;
break ;
case 2 :
pkn_len = 2 ;
pkn_bytes [ 0 ] & = 0x3f ;
break ;
case 3 :
pkn_len = 4 ;
pkn_bytes [ 0 ] & = 0x3f ;
break ;
}
* pkn = g_htonl ( pkt_pkn ) > > ( 8 * ( 4 - pkn_len ) ) ;
return pkn_len ;
}
2018-09-17 17:01:17 +00:00
static void
quic_encode_packet_number ( guint8 * output , guint32 pkn , guint pkn_len )
{
switch ( pkn_len ) {
default :
output [ 0 ] = ( guint8 ) pkn ;
break ;
case 2 :
phton16 ( output , ( guint16 ) pkn ) ;
output [ 0 ] | = 0x80 ;
break ;
case 4 :
phton32 ( output , pkn ) ;
output [ 0 ] | = 0xc0 ;
break ;
}
}
2018-09-12 14:11:49 +00:00
# else /* !HAVE_LIBGCRYPT_AEAD */
static inline guint
quic_decrypt_packet_number ( tvbuff_t * tvb _U_ , guint offset _U_ , quic_cipher * cipher _U_ ,
int pn_cipher_algo _U_ , guint64 * pkn _U_ )
{
return 0 ;
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2018-03-20 16:36:38 +00:00
/**
* Calculate the full packet number and store it for later use .
*/
2018-09-12 14:11:49 +00:00
static guint32
2018-03-20 16:36:38 +00:00
dissect_quic_packet_number ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , guint offset ,
quic_info_data_t * quic_info , quic_packet_info_t * quic_packet ,
2018-09-13 15:03:19 +00:00
gboolean from_server ,
2018-09-12 14:11:49 +00:00
quic_cipher * cipher , int pn_cipher_algo , guint64 * pkn_out )
2018-03-20 16:36:38 +00:00
{
proto_item * ti ;
2018-09-12 14:11:49 +00:00
guint pkn_len ;
2018-03-20 16:36:38 +00:00
guint64 pkn ;
2018-09-15 09:55:21 +00:00
/* Try to decrypt on the first pass, reuse results on the second pass. */
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
pkn_len = quic_decrypt_packet_number ( tvb , offset , cipher , pn_cipher_algo , & pkn ) ;
quic_packet - > pkn_len = pkn_len ;
2018-09-12 14:11:49 +00:00
} else {
2018-09-15 09:55:21 +00:00
pkn_len = quic_packet - > pkn_len ;
pkn = quic_packet - > packet_number & ( ( 1UL < < ( 8 * pkn_len ) ) - 1 ) ;
}
if ( ! pkn_len ) {
expert_add_info_format ( pinfo , tree , & ei_quic_decryption_failed , " Failed to decrypt packet number " ) ;
return 0 ;
2018-09-12 14:11:49 +00:00
}
2018-03-20 16:36:38 +00:00
2018-09-15 09:55:21 +00:00
// TODO separate field for encrypted and decrypted PKN?
proto_tree_add_uint64 ( tree , hf_quic_packet_number , tvb , offset , pkn_len , pkn ) ;
2018-04-21 12:18:03 +00:00
if ( ! quic_info ) {
// if not part of a connection, the full PKN cannot be reconstructed.
2018-09-12 14:11:49 +00:00
* pkn_out = pkn ;
return pkn_len ;
2018-04-21 12:18:03 +00:00
}
2018-03-20 16:36:38 +00:00
/* Sequential first pass, try to reconstruct full packet number. */
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
2018-09-13 15:03:19 +00:00
if ( from_server ) {
2018-03-20 16:36:38 +00:00
pkn = quic_pkt_adjust_pkt_num ( quic_info - > max_server_pkn , pkn , 8 * pkn_len ) ;
quic_info - > max_server_pkn = pkn ;
} else {
pkn = quic_pkt_adjust_pkt_num ( quic_info - > max_client_pkn , pkn , 8 * pkn_len ) ;
quic_info - > max_client_pkn = pkn ;
}
quic_packet - > packet_number = pkn ;
} else {
pkn = quic_packet - > packet_number ;
}
/* always add the full packet number for use in columns */
ti = proto_tree_add_uint64 ( tree , hf_quic_packet_number_full , tvb , offset , pkn_len , pkn ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
2018-09-12 14:11:49 +00:00
* pkn_out = pkn ;
return pkn_len ;
2018-03-20 16:36:38 +00:00
}
2018-04-18 16:39:17 +00:00
static const char *
cid_to_string ( const quic_cid_t * cid )
{
if ( cid - > len = = 0 ) {
return " (none) " ;
}
char * str = ( char * ) wmem_alloc0 ( wmem_packet_scope ( ) , 2 * cid - > len + 1 ) ;
bytes_to_hexstr ( str , cid - > cid , cid - > len ) ;
return str ;
}
2018-04-21 12:18:03 +00:00
/* QUIC Connection tracking. {{{ */
static guint
quic_connection_hash ( gconstpointer key )
{
const quic_cid_t * cid = ( const quic_cid_t * ) key ;
return wmem_strong_hash ( ( const guint8 * ) cid , cid - > len ) ;
}
static gboolean
quic_connection_equal ( gconstpointer a , gconstpointer b )
{
const quic_cid_t * cid1 = ( const quic_cid_t * ) a ;
const quic_cid_t * cid2 = ( const quic_cid_t * ) b ;
return cid1 - > len = = cid2 - > len & & ! memcmp ( cid1 - > cid , cid2 - > cid , cid1 - > len ) ;
}
static gboolean
quic_cids_has_match ( const quic_cid_item_t * items , const quic_cid_t * raw_cid )
{
while ( items ) {
const quic_cid_t * cid = & items - > data ;
// "raw_cid" potentially has some trailing data that is not part of the
// actual CID, so accept any prefix match against "cid".
// Note that this explicitly matches an empty CID.
if ( raw_cid - > len > = cid - > len & & ! memcmp ( raw_cid - > cid , cid - > cid , cid - > len ) ) {
return TRUE ;
}
items = items - > next ;
}
return FALSE ;
}
2018-09-18 20:53:00 +00:00
static void
quic_cids_insert ( quic_cid_t * cid , quic_info_data_t * conn , gboolean from_server )
{
wmem_map_t * connections = from_server ? quic_server_connections : quic_client_connections ;
// Replace any previous CID key with the new one.
wmem_map_remove ( connections , cid ) ;
wmem_map_insert ( connections , cid , conn ) ;
2018-09-18 22:40:12 +00:00
quic_cid_lengths | = ( 1 < < cid - > len ) ;
}
static inline gboolean
quic_cids_is_known_length ( const quic_cid_t * cid )
{
return ( quic_cid_lengths & ( 1 < < cid - > len ) ) ! = 0 ;
2018-09-18 20:53:00 +00:00
}
2018-04-21 12:18:03 +00:00
/**
* Tries to lookup a matching connection ( Connection ID is optional ) .
* If connection is found , " from_server " is set accordingly .
*/
static quic_info_data_t *
quic_connection_find_dcid ( packet_info * pinfo , const quic_cid_t * dcid , gboolean * from_server )
{
2018-09-15 09:55:21 +00:00
/* https://tools.ietf.org/html/draft-ietf-quic-transport-13#section-6.2
2018-04-21 12:18:03 +00:00
*
* " If the packet has a Destination Connection ID corresponding to an
* existing connection , QUIC processes that packet accordingly . "
* " If the Destination Connection ID is zero length and the packet matches
* the address / port tuple of a connection where the host did not require
* connection IDs , QUIC processes the packet as part of that connection . "
*/
quic_info_data_t * conn = NULL ;
gboolean check_ports = FALSE ;
2018-09-18 22:40:12 +00:00
if ( dcid & & dcid - > len > 0 & & quic_cids_is_known_length ( dcid ) ) {
2018-04-21 12:18:03 +00:00
conn = ( quic_info_data_t * ) wmem_map_lookup ( quic_client_connections , dcid ) ;
if ( conn ) {
// DCID recognized by client, so it was from server.
* from_server = TRUE ;
// On collision (both client and server choose the same CID), check
// the port to learn about the side.
// This is required for supporting draft -10 which has a single CID.
check_ports = ! ! wmem_map_lookup ( quic_server_connections , dcid ) ;
} else {
conn = ( quic_info_data_t * ) wmem_map_lookup ( quic_server_connections , dcid ) ;
if ( conn ) {
// DCID recognized by server, so it was from client.
* from_server = FALSE ;
}
}
} else {
conversation_t * conv = find_conversation_pinfo ( pinfo , 0 ) ;
if ( conv ) {
conn = ( quic_info_data_t * ) conversation_get_proto_data ( conv , proto_quic ) ;
check_ports = ! ! conn ;
}
}
if ( check_ports ) {
* from_server = conn - > server_port = = pinfo - > srcport & &
addresses_equal ( & conn - > server_address , & pinfo - > src ) ;
}
return conn ;
}
/**
* Try to find a QUIC connection based on DCID . For short header packets , DCID
* will be modified in order to find the actual length .
* DCID can be empty , in that case a connection is looked up by address only .
*/
static quic_info_data_t *
quic_connection_find ( packet_info * pinfo , guint8 long_packet_type ,
quic_cid_t * dcid , gboolean * from_server )
{
gboolean is_long_packet = long_packet_type ! = QUIC_SHORT_PACKET ;
quic_info_data_t * conn = NULL ;
if ( ( long_packet_type = = QUIC_LPT_INITIAL | | long_packet_type = = QUIC_LPT_0RTT ) & & dcid - > len > 0 ) {
conn = ( quic_info_data_t * ) wmem_map_lookup ( quic_initial_connections , dcid ) ;
2018-09-12 22:34:46 +00:00
// Both the client and server can send Initial (since draft -13).
if ( ! conn & & long_packet_type = = QUIC_LPT_INITIAL ) {
conn = quic_connection_find_dcid ( pinfo , dcid , from_server ) ;
}
2018-04-21 12:18:03 +00:00
} else {
conn = quic_connection_find_dcid ( pinfo , dcid , from_server ) ;
}
if ( ! is_long_packet & & ! conn ) {
// For short packets, first try to find a match based on the address.
conn = quic_connection_find_dcid ( pinfo , NULL , from_server ) ;
if ( conn ) {
2018-09-12 22:34:46 +00:00
if ( ( * from_server & & ! quic_cids_has_match ( & conn - > server_cids , dcid ) ) | |
( ! * from_server & & ! quic_cids_has_match ( & conn - > client_cids , dcid ) ) ) {
2018-04-21 12:18:03 +00:00
// Connection does not match packet.
conn = NULL ;
}
}
// No match found so far, potentially connection migration. Length of
// actual DCID is unknown, so just keep decrementing until found.
while ( ! conn & & dcid - > len > 4 ) {
dcid - > len - - ;
2018-09-18 22:40:12 +00:00
if ( quic_cids_is_known_length ( dcid ) ) {
conn = quic_connection_find_dcid ( pinfo , dcid , from_server ) ;
}
2018-04-21 12:18:03 +00:00
}
if ( ! conn ) {
// No match found, truncate DCID (not really needed, but this
// ensures that debug prints clearly show that DCID is invalid).
dcid - > len = 0 ;
}
}
return conn ;
}
/** Create a new QUIC Connection based on a Client Initial packet. */
static quic_info_data_t *
quic_connection_create ( packet_info * pinfo , guint32 version , const quic_cid_t * scid , const quic_cid_t * dcid )
{
quic_info_data_t * conn = NULL ;
conn = wmem_new0 ( wmem_file_scope ( ) , quic_info_data_t ) ;
wmem_list_append ( quic_connections , conn ) ;
2018-04-23 14:53:40 +00:00
conn - > number = quic_connections_count + + ;
2018-04-21 12:18:03 +00:00
conn - > version = version ;
copy_address_wmem ( wmem_file_scope ( ) , & conn - > server_address , & pinfo - > dst ) ;
conn - > server_port = pinfo - > destport ;
// Key connection by Client CID (if provided).
2018-09-11 13:58:22 +00:00
if ( scid - > len ) {
2018-04-21 12:18:03 +00:00
memcpy ( & conn - > client_cids . data , scid , sizeof ( quic_cid_t ) ) ;
2018-09-18 20:53:00 +00:00
quic_cids_insert ( & conn - > client_cids . data , conn , FALSE ) ;
2018-04-21 12:18:03 +00:00
}
if ( dcid - > len > 0 ) {
// According to the spec, the Initial Packet DCID MUST be at least 8
// bytes, but non-conforming implementations could exist.
memcpy ( & conn - > client_dcid_initial , dcid , sizeof ( quic_cid_t ) ) ;
wmem_map_insert ( quic_initial_connections , & conn - > client_dcid_initial , conn ) ;
}
// For faster lookups without having to check DCID
conversation_t * conv = find_or_create_conversation ( pinfo ) ;
conversation_add_proto_data ( conv , proto_quic , conn ) ;
return conn ;
}
2018-09-18 20:53:00 +00:00
/**
* Use the new CID as additional identifier for the specified connection and
* remember it for connection tracking .
*/
static void
quic_connection_add_cid ( quic_info_data_t * conn , const quic_cid_t * new_cid , gboolean from_server )
{
DISSECTOR_ASSERT ( new_cid - > len > 0 ) ;
quic_cid_item_t * items = from_server ? & conn - > server_cids : & conn - > client_cids ;
if ( quic_cids_has_match ( items , new_cid ) ) {
// CID is already known for this connection.
return ;
}
// Insert new CID right after the first known CID (the very first CID cannot
// be overwritten since it might be used as key somewhere else).
quic_cid_item_t * new_item = wmem_new0 ( wmem_file_scope ( ) , quic_cid_item_t ) ;
new_item - > data = * new_cid ;
new_item - > next = items - > next ;
items - > next = new_item ;
quic_cids_insert ( & new_item - > data , conn , from_server ) ;
}
2018-04-21 12:18:03 +00:00
/** Create or update a connection. */
static void
quic_connection_create_or_update ( quic_info_data_t * * conn_p ,
packet_info * pinfo , guint32 long_packet_type ,
guint32 version , const quic_cid_t * scid ,
const quic_cid_t * dcid , gboolean from_server )
{
quic_info_data_t * conn = * conn_p ;
switch ( long_packet_type ) {
case QUIC_LPT_INITIAL :
2018-09-17 10:31:50 +00:00
if ( ! from_server ) {
if ( ! conn ) {
// The first Initial Packet from the client creates a new connection.
* conn_p = quic_connection_create ( pinfo , version , scid , dcid ) ;
} else if ( conn - > client_dcid_initial . len = = 0 & & dcid - > len & &
scid - > len & & ! quic_cids_has_match ( & conn - > server_cids , scid ) ) {
// If this client Initial Packet responds to a Retry Packet,
// then remember the new DCID for the new Initial cipher and
// clear the first server CID such that the next server Initial
// Packet can link the connection with that new SCID.
memcpy ( & conn - > client_dcid_initial , dcid , sizeof ( quic_cid_t ) ) ;
wmem_map_insert ( quic_initial_connections , & conn - > client_dcid_initial , conn ) ;
wmem_map_remove ( quic_server_connections , & conn - > server_cids . data ) ;
memset ( & conn - > server_cids , 0 , sizeof ( quic_cid_t ) ) ;
}
break ;
2018-04-21 12:18:03 +00:00
}
2018-09-12 22:34:46 +00:00
/* fallthrough */
2018-04-21 12:18:03 +00:00
case QUIC_LPT_RETRY :
case QUIC_LPT_HANDSHAKE :
// Remember CID from first server Retry/Handshake packet
2018-09-12 22:34:46 +00:00
// (or from the first server Initial packet, since draft -13).
2018-09-17 10:31:50 +00:00
if ( from_server & & conn ) {
2018-09-17 17:39:32 +00:00
if ( long_packet_type = = QUIC_LPT_RETRY ) {
2018-09-17 10:31:50 +00:00
// Stateless Retry Packet: the next Initial Packet from the
// client should start a new cryptographic handshake. Erase the
// current "Initial DCID" such that the next client Initial
// packet populates the new value.
wmem_map_remove ( quic_initial_connections , & conn - > client_dcid_initial ) ;
memset ( & conn - > client_dcid_initial , 0 , sizeof ( quic_cid_t ) ) ;
}
if ( conn - > server_cids . data . len = = 0 & & scid - > len ) {
memcpy ( & conn - > server_cids . data , scid , sizeof ( quic_cid_t ) ) ;
2018-09-18 20:53:00 +00:00
quic_cids_insert ( & conn - > server_cids . data , conn , TRUE ) ;
2018-04-21 12:18:03 +00:00
}
}
break ;
}
}
static void
2018-05-02 16:31:21 +00:00
quic_connection_destroy ( gpointer data , gpointer user_data _U_ )
2018-04-21 12:18:03 +00:00
{
2018-05-02 16:31:21 +00:00
quic_info_data_t * conn = ( quic_info_data_t * ) data ;
2018-09-15 23:07:21 +00:00
quic_cipher_reset ( & conn - > client_initial_cipher ) ;
quic_cipher_reset ( & conn - > server_initial_cipher ) ;
2018-09-15 15:23:45 +00:00
quic_cipher_reset ( & conn - > client_handshake_cipher ) ;
quic_cipher_reset ( & conn - > server_handshake_cipher ) ;
2018-04-21 12:18:03 +00:00
2018-09-12 14:11:49 +00:00
for ( int i = 0 ; i < 2 ; i + + ) {
2018-09-15 15:23:45 +00:00
quic_cipher_reset ( & conn - > client_pp . cipher [ i ] ) ;
quic_cipher_reset ( & conn - > server_pp . cipher [ i ] ) ;
2018-09-12 14:11:49 +00:00
}
2018-04-21 12:18:03 +00:00
}
/* QUIC Connection tracking. }}} */
2018-01-23 18:21:10 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
2017-06-23 05:45:10 +00:00
static int
2018-09-18 20:53:00 +00:00
dissect_quic_frame_type ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * quic_tree , guint offset , quic_info_data_t * quic_info , gboolean from_server )
2018-04-23 21:00:53 +00:00
{
proto_item * ti_ft , * ti_ftflags , * ti ;
2017-06-23 05:45:10 +00:00
proto_tree * ft_tree , * ftflags_tree ;
guint32 frame_type ;
ti_ft = proto_tree_add_item ( quic_tree , hf_quic_frame , tvb , offset , 1 , ENC_NA ) ;
ft_tree = proto_item_add_subtree ( ti_ft , ett_quic_ft ) ;
ti_ftflags = proto_tree_add_item_ret_uint ( ft_tree , hf_quic_frame_type , tvb , offset , 1 , ENC_NA , & frame_type ) ;
proto_item_set_text ( ti_ft , " %s " , rval_to_str ( frame_type , quic_frame_type_vals , " Unknown " ) ) ;
2018-02-07 14:22:52 +00:00
offset + = 1 ;
switch ( frame_type ) {
case FT_PADDING : {
proto_item * ti_pad_len ;
guint32 padding_offset = offset , pad_len ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PADDING " ) ;
2018-02-07 14:22:52 +00:00
/* get length of padding (with check if it is always a 0) */
while ( tvb_reported_length_remaining ( tvb , padding_offset ) > 0 ) {
if ( tvb_get_guint8 ( tvb , padding_offset ) ! = 0 ) {
break ;
}
padding_offset + + ;
}
pad_len = padding_offset - offset ;
ti_pad_len = proto_tree_add_uint ( ft_tree , hf_quic_frame_type_padding_length , tvb , offset , 0 , pad_len ) ;
PROTO_ITEM_SET_GENERATED ( ti_pad_len ) ;
proto_item_append_text ( ti_ft , " Length: %u " , pad_len ) ;
proto_tree_add_item ( ft_tree , hf_quic_frame_type_padding , tvb , offset , pad_len , ENC_NA ) ;
offset + = pad_len ;
proto_item_set_len ( ti_ft , 1 + pad_len ) ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
case FT_RST_STREAM : {
guint64 stream_id ;
guint32 error_code , len_streamid = 0 , len_finaloffset = 0 ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , RS " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_rsts_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , & stream_id , & len_streamid ) ;
offset + = len_streamid ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_frame_type_rsts_application_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
offset + = 2 ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_rsts_final_offset , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_finaloffset ) ;
offset + = len_finaloffset ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_append_text ( ti_ft , " Stream ID: % " G_GINT64_MODIFIER " u, Error code: %s " , stream_id , val_to_str_ext ( error_code , & quic_error_code_vals_ext , " Unknown (%d) " ) ) ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_streamid + 2 + len_finaloffset ) ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
case FT_CONNECTION_CLOSE : {
2018-09-17 14:41:04 +00:00
guint32 len_reasonphrase , len_frametype , error_code ;
2018-02-07 14:22:52 +00:00
guint64 len_reason = 0 ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , CC " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_frame_type_cc_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
offset + = 2 ;
2017-06-23 05:45:10 +00:00
2018-09-17 14:41:04 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_cc_frame_type , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_frametype ) ;
offset + = len_frametype ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_cc_reason_phrase_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & len_reason , & len_reasonphrase ) ;
offset + = len_reasonphrase ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item ( ft_tree , hf_quic_frame_type_cc_reason_phrase , tvb , offset , ( guint32 ) len_reason , ENC_ASCII | ENC_NA ) ;
offset + = ( guint32 ) len_reason ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_append_text ( ti_ft , " Error code: %s " , val_to_str_ext ( error_code , & quic_error_code_vals_ext , " Unknown (%d) " ) ) ;
proto_item_set_len ( ti_ft , 1 + 2 + len_reasonphrase + ( guint32 ) len_reason ) ;
}
break ;
case FT_APPLICATION_CLOSE : {
guint32 len_reasonphrase , error_code ;
guint64 len_reason ;
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , AC " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_frame_type_ac_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
offset + = 2 ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ac_reason_phrase_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & len_reason , & len_reasonphrase ) ;
offset + = len_reasonphrase ;
proto_tree_add_item ( ft_tree , hf_quic_frame_type_ac_reason_phrase , tvb , offset , ( guint32 ) len_reason , ENC_ASCII | ENC_NA ) ;
offset + = ( guint32 ) len_reason ;
proto_item_append_text ( ti_ft , " Error code: %s " , val_to_str_ext ( error_code , & quic_error_code_vals_ext , " Unknown (%d) " ) ) ;
proto_item_set_len ( ti_ft , 1 + 2 + len_reasonphrase + ( guint32 ) len_reason ) ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
case FT_MAX_DATA : {
guint32 len_maximumdata ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , MD " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_md_maximum_data , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_maximumdata ) ;
offset + = len_maximumdata ;
2017-12-31 15:02:12 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_maximumdata ) ;
}
break ;
case FT_MAX_STREAM_DATA : {
guint32 len_streamid , len_maximumstreamdata ;
2017-12-31 15:02:12 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , MSD " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_msd_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
offset + = len_streamid ;
2017-12-31 15:02:12 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_msd_maximum_stream_data , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_maximumstreamdata ) ;
offset + = len_maximumstreamdata ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_streamid + len_maximumstreamdata ) ;
}
break ;
case FT_MAX_STREAM_ID : {
guint32 len_streamid ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , MSI " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_msi_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
offset + = len_streamid ;
2017-11-14 21:49:45 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_streamid ) ;
}
break ;
case FT_PING : {
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PING " ) ;
2018-02-07 14:22:52 +00:00
}
break ;
case FT_BLOCKED : {
guint32 len_offset ;
2017-12-31 15:02:12 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , B " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_blocked_offset , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_offset ) ;
offset + = len_offset ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_offset ) ;
}
break ;
case FT_STREAM_BLOCKED : {
guint32 len_streamid , len_offset ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SB " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_sb_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
offset + = len_streamid ;
2017-12-31 15:02:12 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_sb_offset , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_offset ) ;
offset + = len_offset ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_streamid + len_offset ) ;
}
break ;
case FT_STREAM_ID_BLOCKED : {
guint32 len_streamid ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SIB " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_sib_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
offset + = len_streamid ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_streamid ) ;
}
break ;
case FT_NEW_CONNECTION_ID : {
guint32 len_sequence ;
2018-04-23 21:00:53 +00:00
guint32 nci_length ;
gboolean valid_cid = FALSE ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , NCI " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_nci_sequence , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_sequence ) ;
offset + = len_sequence ;
2017-06-23 05:45:10 +00:00
2018-09-11 13:58:22 +00:00
ti = proto_tree_add_item_ret_uint ( ft_tree , hf_quic_frame_type_nci_connection_id_length , tvb , offset , 1 , ENC_BIG_ENDIAN , & nci_length ) ;
offset + + ;
2018-04-23 21:00:53 +00:00
2018-09-11 13:58:22 +00:00
valid_cid = nci_length > = 4 & & nci_length < = 18 ;
if ( ! valid_cid ) {
expert_add_info_format ( pinfo , ti , & ei_quic_protocol_violation ,
2018-04-23 21:00:53 +00:00
" Connection ID Length must be between 4 and 18 bytes " ) ;
}
proto_tree_add_item ( ft_tree , hf_quic_frame_type_nci_connection_id , tvb , offset , nci_length , ENC_NA ) ;
2018-09-18 20:53:00 +00:00
if ( valid_cid & & quic_info ) {
quic_cid_t cid = { . len = 0 } ;
tvb_memcpy ( tvb , cid . cid , offset , nci_length ) ;
cid . len = nci_length ;
quic_connection_add_cid ( quic_info , & cid , from_server ) ;
}
2018-04-23 21:00:53 +00:00
offset + = nci_length ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item ( ft_tree , hf_quic_frame_type_nci_stateless_reset_token , tvb , offset , 16 , ENC_NA ) ;
offset + = 16 ;
2017-06-23 05:45:10 +00:00
2018-04-23 21:00:53 +00:00
proto_item_set_len ( ti_ft , 1 + len_sequence + nci_length + 16 ) ;
2018-02-07 14:22:52 +00:00
}
break ;
case FT_STOP_SENDING : {
guint32 len_streamid ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SS " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ss_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
offset + = len_streamid ;
2017-06-23 05:45:10 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item ( ft_tree , hf_quic_frame_type_ss_application_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
offset + = 2 ;
2017-09-01 14:06:22 +00:00
2018-02-07 14:22:52 +00:00
proto_item_set_len ( ti_ft , 1 + len_streamid + 2 ) ;
}
break ;
2018-04-16 12:14:02 +00:00
case FT_ACK : {
2018-02-07 14:22:52 +00:00
guint64 ack_block_count ;
guint32 lenvar ;
2018-01-10 07:16:59 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , ACK " ) ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ack_largest_acknowledged , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
2018-01-10 07:16:59 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ack_ack_delay , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
2018-01-10 07:16:59 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ack_ack_block_count , tvb , offset , - 1 , ENC_VARINT_QUIC , & ack_block_count , & lenvar ) ;
offset + = lenvar ;
2017-12-31 09:58:09 +00:00
2018-02-07 14:22:52 +00:00
/* ACK Block */
/* First ACK Block Length */
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ack_fab , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
2017-12-31 09:58:09 +00:00
2018-02-07 14:22:52 +00:00
/* Repeated "Ack Block Count" */
while ( ack_block_count ) {
2017-12-31 09:58:09 +00:00
2018-02-07 14:22:52 +00:00
/* Gap To Next Block */
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ack_gap , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2017-12-31 09:58:09 +00:00
offset + = lenvar ;
2018-02-07 14:22:52 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ack_ack_block , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2017-12-31 09:58:09 +00:00
offset + = lenvar ;
2018-02-07 14:22:52 +00:00
ack_block_count - - ;
}
}
break ;
2018-04-17 20:41:38 +00:00
case FT_PATH_CHALLENGE : {
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PC " ) ;
2018-04-17 20:41:38 +00:00
proto_tree_add_item ( ft_tree , hf_quic_frame_type_path_challenge_data , tvb , offset , 8 , ENC_NA ) ;
offset + = 8 ;
}
break ;
case FT_PATH_RESPONSE : {
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PR " ) ;
2018-04-17 20:41:38 +00:00
proto_tree_add_item ( ft_tree , hf_quic_frame_type_path_response_data , tvb , offset , 8 , ENC_NA ) ;
offset + = 8 ;
}
break ;
2018-02-07 14:22:52 +00:00
case FT_STREAM_10 :
case FT_STREAM_11 :
case FT_STREAM_12 :
case FT_STREAM_13 :
case FT_STREAM_14 :
case FT_STREAM_15 :
case FT_STREAM_16 :
case FT_STREAM_17 : {
guint64 stream_id , length ;
guint32 lenvar ;
offset - = 1 ;
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , STREAM " ) ;
2018-02-07 14:22:52 +00:00
ftflags_tree = proto_item_add_subtree ( ti_ftflags , ett_quic_ftflags ) ;
proto_tree_add_item ( ftflags_tree , hf_quic_frame_type_stream_fin , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( ftflags_tree , hf_quic_frame_type_stream_len , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( ftflags_tree , hf_quic_frame_type_stream_off , tvb , offset , 1 , ENC_NA ) ;
offset + = 1 ;
2017-12-31 09:58:09 +00:00
2018-09-17 17:39:32 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_stream_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , & stream_id , & lenvar ) ;
2018-02-07 14:22:52 +00:00
offset + = lenvar ;
2017-12-31 09:58:09 +00:00
2018-02-07 14:22:52 +00:00
proto_item_append_text ( ti_ft , " Stream ID: % " G_GINT64_MODIFIER " u " , stream_id ) ;
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " (% " G_GINT64_MODIFIER " u) " , stream_id ) ;
2017-12-31 09:58:09 +00:00
2018-02-07 14:22:52 +00:00
if ( frame_type & FTFLAGS_STREAM_OFF ) {
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_stream_offset , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2017-12-24 14:03:58 +00:00
offset + = lenvar ;
2018-02-07 14:22:52 +00:00
}
2017-12-24 14:03:58 +00:00
2018-02-07 14:22:52 +00:00
if ( frame_type & FTFLAGS_STREAM_LEN ) {
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_stream_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & length , & lenvar ) ;
offset + = lenvar ;
} else {
length = tvb_reported_length_remaining ( tvb , offset ) ;
}
2017-12-24 14:03:58 +00:00
2018-02-07 14:22:52 +00:00
proto_tree_add_item ( ft_tree , hf_quic_stream_data , tvb , offset , ( int ) length , ENC_NA ) ;
offset + = ( int ) length ;
2018-03-17 14:53:04 +00:00
2018-09-12 23:04:48 +00:00
}
break ;
case FT_CRYPTO : {
guint64 crypto_offset , crypto_length ;
guint32 lenvar ;
2018-09-15 14:06:30 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , CRYPTO " ) ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_crypto_offset , tvb , offset , - 1 , ENC_VARINT_QUIC , & crypto_offset , & lenvar ) ;
2018-09-12 23:04:48 +00:00
offset + = lenvar ;
2018-09-15 14:06:30 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_crypto_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & crypto_length , & lenvar ) ;
2018-09-12 23:04:48 +00:00
offset + = lenvar ;
2018-09-15 14:06:30 +00:00
proto_tree_add_item ( ft_tree , hf_quic_frame_type_crypto_crypto_data , tvb , offset , ( guint32 ) crypto_length , ENC_NA ) ;
2018-09-13 08:29:29 +00:00
{
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 ) ;
}
2018-09-12 23:04:48 +00:00
offset + = ( guint32 ) crypto_length ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
2018-09-17 15:22:06 +00:00
case FT_NEW_TOKEN : {
guint64 token_length ;
guint32 lenvar ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , NT " ) ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_nt_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & token_length , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item ( ft_tree , hf_quic_frame_type_nt_token , tvb , offset , ( guint32 ) token_length , ENC_NA ) ;
offset + = ( guint32 ) token_length ;
}
break ;
case FT_ACK_ECN : {
guint64 ack_block_count ;
guint32 lenvar ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , AE " ) ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_largest_acknowledged , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_ack_delay , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_ect0_count , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_ect1_count , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_ecn_ce_count , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_ack_block_count , tvb , offset , - 1 , ENC_VARINT_QUIC , & ack_block_count , & lenvar ) ;
offset + = lenvar ;
/* ACK Block */
/* First ACK Block Length */
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_fab , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
/* Repeated "Ack Block Count" */
while ( ack_block_count ) {
/* Gap To Next Block */
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_gap , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_frame_type_ae_ack_block , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
ack_block_count - - ;
}
}
break ;
2018-02-07 14:22:52 +00:00
default :
expert_add_info_format ( pinfo , ti_ft , & ei_quic_ft_unknown , " Unknown Frame Type %u " , frame_type ) ;
break ;
2017-06-23 05:45:10 +00:00
}
return offset ;
}
2018-01-23 18:21:10 +00:00
# endif /* HAVE_LIBGCRYPT_AEAD */
2017-06-23 05:45:10 +00:00
2017-11-15 06:41:45 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
2018-04-17 20:08:55 +00:00
static gcry_error_t
qhkdf_expand ( int md , const guint8 * secret , guint secret_len ,
const char * label , guint8 * out , guint out_len ) ;
static gboolean
2018-09-12 21:49:15 +00:00
quic_cipher_init ( guint32 version , quic_cipher * cipher , int hash_algo , guint8 key_length , guint8 * secret ) ;
2018-04-17 20:08:55 +00:00
2017-11-15 06:41:45 +00:00
/**
* Given a QUIC message ( header + non - empty payload ) , the actual packet number ,
* try to decrypt it using the cipher .
2018-09-12 14:11:49 +00:00
* As the header points to the original buffer with an encrypted packet number ,
* the ( encrypted ) packet number length is also included .
2017-11-15 06:41:45 +00:00
*
* The actual packet number must be constructed according to
2018-09-15 09:55:21 +00:00
* https : //tools.ietf.org/html/draft-ietf-quic-transport-13#section-4.8
2017-11-15 06:41:45 +00:00
*/
2018-03-20 18:37:30 +00:00
static void
2018-09-12 14:11:49 +00:00
quic_decrypt_message ( quic_cipher * cipher , tvbuff_t * head , guint header_length , guint pkn_len , guint64 packet_number , quic_decrypt_result_t * result )
2017-11-15 06:41:45 +00:00
{
gcry_error_t err ;
2018-09-17 11:11:23 +00:00
guint8 * header ;
2017-11-15 06:41:45 +00:00
guint8 nonce [ TLS13_AEAD_NONCE_LENGTH ] ;
guint8 * buffer ;
guint8 * atag [ 16 ] ;
guint buffer_length ;
2018-03-20 18:37:30 +00:00
const guchar * * error = & result - > error ;
2017-11-15 06:41:45 +00:00
DISSECTOR_ASSERT ( cipher ! = NULL ) ;
2018-09-11 21:27:18 +00:00
DISSECTOR_ASSERT ( cipher - > pp_cipher ! = NULL ) ;
2018-09-12 14:11:49 +00:00
DISSECTOR_ASSERT ( pkn_len < header_length ) ;
DISSECTOR_ASSERT ( 1 < = pkn_len & & pkn_len < = 4 ) ;
// copy header, but replace encrypted PKN by plaintext PKN.
2018-09-17 11:11:23 +00:00
header = ( guint8 * ) tvb_memdup ( wmem_packet_scope ( ) , head , 0 , header_length ) ;
2018-09-17 17:01:17 +00:00
quic_encode_packet_number ( header + header_length - pkn_len , ( guint32 ) packet_number , pkn_len ) ;
2017-11-15 06:41:45 +00:00
/* Input is "header || ciphertext (buffer) || auth tag (16 bytes)" */
buffer_length = tvb_captured_length_remaining ( head , header_length + 16 ) ;
if ( buffer_length = = 0 ) {
* error = " Decryption not possible, ciphertext is too short " ;
2018-03-20 18:37:30 +00:00
return ;
2017-11-15 06:41:45 +00:00
}
2018-03-20 18:37:30 +00:00
buffer = ( guint8 * ) tvb_memdup ( wmem_file_scope ( ) , head , header_length , buffer_length ) ;
2017-11-15 06:41:45 +00:00
tvb_memcpy ( head , atag , header_length + buffer_length , 16 ) ;
2018-09-11 21:27:18 +00:00
memcpy ( nonce , cipher - > pp_iv , TLS13_AEAD_NONCE_LENGTH ) ;
2017-11-15 06:41:45 +00:00
/* Packet number is left-padded with zeroes and XORed with write_iv */
phton64 ( nonce + sizeof ( nonce ) - 8 , pntoh64 ( nonce + sizeof ( nonce ) - 8 ) ^ packet_number ) ;
2018-09-11 21:27:18 +00:00
gcry_cipher_reset ( cipher - > pp_cipher ) ;
err = gcry_cipher_setiv ( cipher - > pp_cipher , nonce , TLS13_AEAD_NONCE_LENGTH ) ;
2017-11-15 06:41:45 +00:00
if ( err ) {
2018-03-20 18:37:30 +00:00
* error = wmem_strdup_printf ( wmem_file_scope ( ) , " Decryption (setiv) failed: %s " , gcry_strerror ( err ) ) ;
return ;
2017-11-15 06:41:45 +00:00
}
/* associated data (A) is the contents of QUIC header */
2018-09-11 21:27:18 +00:00
err = gcry_cipher_authenticate ( cipher - > pp_cipher , header , header_length ) ;
2017-11-15 06:41:45 +00:00
if ( err ) {
2018-03-20 18:37:30 +00:00
* error = wmem_strdup_printf ( wmem_file_scope ( ) , " Decryption (authenticate) failed: %s " , gcry_strerror ( err ) ) ;
return ;
2017-11-15 06:41:45 +00:00
}
/* Output ciphertext (C) */
2018-09-11 21:27:18 +00:00
err = gcry_cipher_decrypt ( cipher - > pp_cipher , buffer , buffer_length , NULL , 0 ) ;
2017-11-15 06:41:45 +00:00
if ( err ) {
2018-03-20 18:37:30 +00:00
* error = wmem_strdup_printf ( wmem_file_scope ( ) , " Decryption (decrypt) failed: %s " , gcry_strerror ( err ) ) ;
return ;
2017-11-15 06:41:45 +00:00
}
2018-09-11 21:27:18 +00:00
err = gcry_cipher_checktag ( cipher - > pp_cipher , atag , 16 ) ;
2017-11-15 06:41:45 +00:00
if ( err ) {
2018-03-20 18:37:30 +00:00
* error = wmem_strdup_printf ( wmem_file_scope ( ) , " Decryption (checktag) failed: %s " , gcry_strerror ( err ) ) ;
return ;
2017-11-15 06:41:45 +00:00
}
2018-03-20 18:37:30 +00:00
result - > error = NULL ;
result - > data = buffer ;
result - > data_len = buffer_length ;
2017-11-15 06:41:45 +00:00
}
2018-09-12 21:49:15 +00:00
static gboolean
quic_hkdf_expand_label ( int hash_algo , guint8 * secret , guint secret_len , const char * label , guint8 * out , guint out_len )
{
const StringInfo secret_si = { secret , secret_len } ;
guchar * out_mem = NULL ;
if ( tls13_hkdf_expand_label ( hash_algo , & secret_si , " quic " , label , out_len , & out_mem ) ) {
memcpy ( out , out_mem , out_len ) ;
wmem_free ( NULL , out_mem ) ;
return TRUE ;
}
return FALSE ;
}
2017-11-15 06:41:45 +00:00
/**
2018-09-15 23:07:21 +00:00
* Compute the client and server initial secrets given Connection ID " cid " .
2017-11-15 06:41:45 +00:00
*
2018-09-15 23:07:21 +00:00
* On success TRUE is returned and the two initial secrets are set .
2018-04-17 20:08:55 +00:00
* FALSE is returned on error ( see " error " parameter for the reason ) .
2017-11-15 06:41:45 +00:00
*/
static gboolean
2018-09-15 23:07:21 +00:00
quic_derive_initial_secrets ( const quic_cid_t * cid ,
guint8 client_initial_secret [ HASH_SHA2_256_LENGTH ] ,
guint8 server_initial_secret [ HASH_SHA2_256_LENGTH ] ,
const gchar * * error )
2017-11-15 06:41:45 +00:00
{
/*
2018-09-12 21:49:15 +00:00
* https : //tools.ietf.org/html/draft-ietf-quic-tls-14#section-5.1.1
*
* initial_salt = 0x9c108f98520a5c5c32968e950e8a2c5fe06d6c38
* initial_secret = HKDF - Extract ( initial_salt , client_dst_connection_id )
*
* client_initial_secret = HKDF - Expand - Label ( initial_secret ,
* " client in " , " " , Hash . length )
* server_initial_secret = HKDF - Expand - Label ( initial_secret ,
* " server in " , " " , Hash . length )
*
2018-04-17 20:08:55 +00:00
* Hash for handshake packets is SHA - 256 ( output size 32 ) .
2017-11-15 06:41:45 +00:00
*/
2018-04-17 20:08:55 +00:00
static const guint8 handshake_salt [ 20 ] = {
0x9c , 0x10 , 0x8f , 0x98 , 0x52 , 0x0a , 0x5c , 0x5c , 0x32 , 0x96 ,
0x8e , 0x95 , 0x0e , 0x8a , 0x2c , 0x5f , 0xe0 , 0x6d , 0x6c , 0x38
2017-11-15 06:41:45 +00:00
} ;
gcry_error_t err ;
2018-04-17 20:08:55 +00:00
guint8 secret [ HASH_SHA2_256_LENGTH ] ;
2017-12-23 14:57:18 +00:00
2018-04-17 20:08:55 +00:00
err = hkdf_extract ( GCRY_MD_SHA256 , handshake_salt , sizeof ( handshake_salt ) ,
2018-04-18 16:39:17 +00:00
cid - > cid , cid - > len , secret ) ;
2017-11-15 06:41:45 +00:00
if ( err ) {
* error = wmem_strdup_printf ( wmem_packet_scope ( ) , " Failed to extract secrets: %s " , gcry_strerror ( err ) ) ;
return FALSE ;
}
2018-09-17 17:39:32 +00:00
if ( ! quic_hkdf_expand_label ( GCRY_MD_SHA256 , secret , sizeof ( secret ) , " client in " ,
client_initial_secret , HASH_SHA2_256_LENGTH ) ) {
* error = " Key expansion (client) failed " ;
return FALSE ;
}
2018-09-12 21:49:15 +00:00
2018-09-17 17:39:32 +00:00
if ( ! quic_hkdf_expand_label ( GCRY_MD_SHA256 , secret , sizeof ( secret ) , " server in " ,
server_initial_secret , HASH_SHA2_256_LENGTH ) ) {
* error = " Key expansion (server) failed " ;
return FALSE ;
2017-11-15 06:41:45 +00:00
}
* error = NULL ;
return TRUE ;
}
2018-09-12 14:11:49 +00:00
/**
* Maps a Packet Protection cipher to the Packet Number protection cipher .
2018-09-17 17:39:32 +00:00
* See https : //tools.ietf.org/html/draft-ietf-quic-tls-14#section-5.3
2018-09-12 14:11:49 +00:00
*/
static gboolean
2018-09-15 15:23:45 +00:00
quic_get_pn_cipher_algo ( int cipher_algo , int * pn_cipher_mode )
2018-09-12 14:11:49 +00:00
{
switch ( cipher_algo ) {
case GCRY_CIPHER_AES128 :
case GCRY_CIPHER_AES256 :
* pn_cipher_mode = GCRY_CIPHER_MODE_CTR ;
return TRUE ;
# ifdef HAVE_LIBGCRYPT_CHACHA20
case GCRY_CIPHER_CHACHA20 :
* pn_cipher_mode = 0 ;
return TRUE ;
# endif /* HAVE_LIBGCRYPT_CHACHA20 */
default :
return FALSE ;
}
}
2018-09-15 15:23:45 +00:00
/*
* ( Re ) initialize the PNE / PP ciphers using the given cipher algorithm .
* If the optional base secret is given , then its length MUST match the hash
* algorithm output .
*/
2017-11-15 06:41:45 +00:00
static gboolean
2018-09-15 15:23:45 +00:00
quic_cipher_prepare ( guint32 version , quic_cipher * cipher , int hash_algo , int cipher_algo , int cipher_mode , guint8 * secret , const char * * error )
2017-11-15 06:41:45 +00:00
{
2018-09-15 15:23:45 +00:00
/* Clear previous state (if any). */
quic_cipher_reset ( cipher ) ;
2017-11-15 06:41:45 +00:00
2018-09-15 15:23:45 +00:00
int pn_cipher_mode ;
if ( ! quic_get_pn_cipher_algo ( cipher_algo , & pn_cipher_mode ) ) {
* error = " Unsupported cipher algorithm " ;
2017-11-15 06:41:45 +00:00
return FALSE ;
}
2018-09-15 15:23:45 +00:00
if ( gcry_cipher_open ( & cipher - > pn_cipher , cipher_algo , pn_cipher_mode , 0 ) | |
gcry_cipher_open ( & cipher - > pp_cipher , cipher_algo , cipher_mode , 0 ) ) {
quic_cipher_reset ( cipher ) ;
* error = " Failed to create ciphers " ;
2018-09-12 14:11:49 +00:00
return FALSE ;
}
2018-09-15 15:23:45 +00:00
if ( secret ) {
guint cipher_keylen = ( guint8 ) gcry_cipher_get_algo_keylen ( cipher_algo ) ;
if ( ! quic_cipher_init ( version , cipher , hash_algo , cipher_keylen , secret ) ) {
quic_cipher_reset ( cipher ) ;
* error = " Failed to derive key material for cipher " ;
return FALSE ;
}
}
return TRUE ;
}
static gboolean
2018-09-15 23:07:21 +00:00
quic_create_initial_decoders ( const quic_cid_t * cid , const gchar * * error , quic_info_data_t * quic_info )
2018-09-15 15:23:45 +00:00
{
guint8 client_secret [ HASH_SHA2_256_LENGTH ] ;
guint8 server_secret [ HASH_SHA2_256_LENGTH ] ;
guint32 version = quic_info - > version ;
2018-09-17 17:39:32 +00:00
if ( ! quic_derive_initial_secrets ( cid , client_secret , server_secret , error ) ) {
2017-11-15 06:41:45 +00:00
return FALSE ;
}
2018-09-15 15:23:45 +00:00
/* Packet numbers are protected with AES128-CTR,
* initial packets are protected with AEAD_AES_128_GCM . */
2018-09-15 23:07:21 +00:00
if ( ! quic_cipher_prepare ( version , & quic_info - > client_initial_cipher , GCRY_MD_SHA256 ,
2018-09-15 15:23:45 +00:00
GCRY_CIPHER_AES128 , GCRY_CIPHER_MODE_GCM , client_secret , error ) | |
2018-09-15 23:07:21 +00:00
! quic_cipher_prepare ( version , & quic_info - > server_initial_cipher , GCRY_MD_SHA256 ,
2018-09-15 15:23:45 +00:00
GCRY_CIPHER_AES128 , GCRY_CIPHER_MODE_GCM , server_secret , error ) ) {
2018-04-17 20:08:55 +00:00
return FALSE ;
}
2017-11-15 07:27:27 +00:00
2017-11-15 06:41:45 +00:00
return TRUE ;
}
2018-03-19 23:42:00 +00:00
2018-09-15 23:07:21 +00:00
static gboolean
quic_create_decoders ( packet_info * pinfo , guint32 version , quic_info_data_t * quic_info , quic_cipher * cipher ,
gboolean from_server , TLSRecordType type , const char * * error )
{
if ( ! quic_info - > hash_algo ) {
if ( ! tls_get_cipher_info ( pinfo , & quic_info - > cipher_algo , & quic_info - > cipher_mode , & quic_info - > hash_algo ) ) {
* error = " Unable to retrieve cipher information " ;
return FALSE ;
}
}
guint hash_len = gcry_md_get_algo_dlen ( quic_info - > hash_algo ) ;
char * secret = ( char * ) wmem_alloc0 ( wmem_packet_scope ( ) , hash_len ) ;
if ( ! tls13_get_quic_secret ( pinfo , from_server , type , hash_len , secret ) ) {
* error = " Unable to retrieve secret " ;
return FALSE ;
}
if ( ! quic_cipher_prepare ( version , cipher , quic_info - > hash_algo ,
quic_info - > cipher_algo , quic_info - > cipher_mode , secret , error ) ) {
return FALSE ;
}
return TRUE ;
}
2018-03-19 23:42:00 +00:00
/**
* Computes QHKDF - Expand ( Secret , Label , Length ) .
* Caller must ensure that " out " is large enough for " out_len " .
*/
static gcry_error_t
qhkdf_expand ( int md , const guint8 * secret , guint secret_len ,
const char * label , guint8 * out , guint out_len )
{
2018-04-17 20:08:55 +00:00
/* https://tools.ietf.org/html/draft-ietf-quic-tls-10#section-5.2.1
2018-03-19 23:42:00 +00:00
* QHKDF - Expand ( Secret , Label , Length ) =
2018-04-17 20:08:55 +00:00
* HKDF - Expand ( Secret , QhkdfLabel , Length )
2018-03-19 23:42:00 +00:00
* struct {
* uint16 length = Length ;
* opaque label < 6. .255 > = " QUIC " + Label ;
2018-04-17 20:08:55 +00:00
* } QhkdfLabel ;
2018-03-19 23:42:00 +00:00
*/
gcry_error_t err ;
const guint label_length = ( guint ) strlen ( label ) ;
/* Some sanity checks */
DISSECTOR_ASSERT ( label_length > 0 & & 5 + label_length < = 255 ) ;
2018-04-17 20:08:55 +00:00
/* info = QhkdfLabel { length, label } */
2018-03-19 23:42:00 +00:00
GByteArray * info = g_byte_array_new ( ) ;
const guint16 length = g_htons ( out_len ) ;
g_byte_array_append ( info , ( const guint8 * ) & length , sizeof ( length ) ) ;
const guint8 label_vector_length = 5 + label_length ;
g_byte_array_append ( info , & label_vector_length , 1 ) ;
2018-04-17 20:08:55 +00:00
g_byte_array_append ( info , " QUIC " , 5 ) ;
2018-03-19 23:42:00 +00:00
g_byte_array_append ( info , label , label_length ) ;
err = hkdf_expand ( md , secret , secret_len , info - > data , info - > len , out , out_len ) ;
g_byte_array_free ( info , TRUE ) ;
return err ;
}
2018-09-15 23:07:21 +00:00
/**
* Tries to obtain the QUIC application traffic secrets .
*/
static gboolean
quic_get_traffic_secret ( packet_info * pinfo , int hash_algo , quic_pp_state_t * pp_state , gboolean from_client )
{
guint hash_len = gcry_md_get_algo_dlen ( hash_algo ) ;
char * secret = ( char * ) wmem_alloc0 ( wmem_packet_scope ( ) , hash_len ) ;
if ( ! tls13_get_quic_secret ( pinfo , ! from_client , TLS_SECRET_APP , hash_len , secret ) ) {
return FALSE ;
}
pp_state - > next_secret = ( guint8 * ) wmem_memdup ( wmem_file_scope ( ) , secret , hash_len ) ;
return TRUE ;
}
2018-03-19 23:42:00 +00:00
/**
2018-04-17 20:08:55 +00:00
* Expands the secret ( length MUST be the same as the " hash_algo " digest size )
* and initialize cipher with the new key .
2018-03-19 23:42:00 +00:00
*/
static gboolean
2018-09-17 17:39:32 +00:00
quic_cipher_init ( guint32 version _U_ , quic_cipher * cipher , int hash_algo , guint8 key_length , guint8 * secret )
2018-03-19 23:42:00 +00:00
{
2018-04-17 20:08:55 +00:00
guchar write_key [ 256 / 8 ] ; /* Maximum key size is for AES256 cipher. */
2018-09-12 14:11:49 +00:00
guchar pn_key [ 256 / 8 ] ;
2018-03-19 23:42:00 +00:00
guint hash_len = gcry_md_get_algo_dlen ( hash_algo ) ;
2018-04-17 20:08:55 +00:00
if ( key_length > sizeof ( write_key ) ) {
2018-03-19 23:42:00 +00:00
return FALSE ;
}
2018-04-17 20:08:55 +00:00
2018-09-17 17:39:32 +00:00
if ( ! quic_hkdf_expand_label ( hash_algo , secret , hash_len , " key " , write_key , key_length ) | |
! quic_hkdf_expand_label ( hash_algo , secret , hash_len , " iv " , cipher - > pp_iv , sizeof ( cipher - > pp_iv ) ) | |
! quic_hkdf_expand_label ( hash_algo , secret , hash_len , " pn " , pn_key , key_length ) ) {
return FALSE ;
2018-03-19 23:42:00 +00:00
}
2018-09-12 14:11:49 +00:00
return gcry_cipher_setkey ( cipher - > pn_cipher , pn_key , key_length ) = = 0 & &
gcry_cipher_setkey ( cipher - > pp_cipher , write_key , key_length ) = = 0 ;
2018-03-19 23:42:00 +00:00
}
/**
* Updates the packet protection secret to the next one .
*/
static void
quic_update_key ( int hash_algo , quic_pp_state_t * pp_state , gboolean from_client )
{
guint hash_len = gcry_md_get_algo_dlen ( hash_algo ) ;
2018-09-15 15:23:45 +00:00
qhkdf_expand ( hash_algo , pp_state - > next_secret , hash_len ,
2018-03-19 23:42:00 +00:00
from_client ? " client 1rtt " : " server 1rtt " ,
2018-09-15 15:23:45 +00:00
pp_state - > next_secret , hash_len ) ;
2018-03-19 23:42:00 +00:00
}
/**
* Tries to construct the appropriate cipher for the current key phase .
* See also " PROTECTED PAYLOAD DECRYPTION " comment on top of this file .
*/
2018-09-11 21:27:18 +00:00
static quic_cipher *
2018-09-15 15:23:45 +00:00
quic_get_pp_cipher ( packet_info * pinfo , gboolean key_phase , quic_info_data_t * quic_info , gboolean from_server )
2018-03-19 23:42:00 +00:00
{
2018-09-12 21:49:15 +00:00
guint32 version = quic_info - > version ;
2018-09-15 15:23:45 +00:00
const char * error = NULL ;
gboolean success = FALSE ;
2018-03-19 23:42:00 +00:00
/* Keys were previously not available. */
if ( quic_info - > skip_decryption ) {
return NULL ;
}
quic_pp_state_t * client_pp = & quic_info - > client_pp ;
quic_pp_state_t * server_pp = & quic_info - > server_pp ;
2018-03-20 18:37:30 +00:00
quic_pp_state_t * pp_state = ! from_server ? client_pp : server_pp ;
2018-03-19 23:42:00 +00:00
/* Try to lookup secrets if not available. */
2018-09-15 15:23:45 +00:00
if ( ! quic_info - > client_pp . next_secret ) {
2018-03-19 23:42:00 +00:00
/* Query TLS for the cipher suite. */
2018-09-15 15:23:45 +00:00
if ( ! tls_get_cipher_info ( pinfo , & quic_info - > cipher_algo , & quic_info - > cipher_mode , & quic_info - > hash_algo ) ) {
2018-03-19 23:42:00 +00:00
/* No previous TLS handshake found or unsupported ciphers, fail. */
quic_info - > skip_decryption = TRUE ;
return NULL ;
}
/* Retrieve secrets for both the client and server. */
2018-09-17 17:39:32 +00:00
if ( ! quic_get_traffic_secret ( pinfo , quic_info - > hash_algo , client_pp , TRUE ) | |
! quic_get_traffic_secret ( pinfo , quic_info - > hash_algo , server_pp , FALSE ) ) {
quic_info - > skip_decryption = TRUE ;
return NULL ;
2018-03-19 23:42:00 +00:00
}
/* Create initial cipher handles for KEY_PHASE 0 and 1. */
2018-09-15 15:23:45 +00:00
if ( ! quic_cipher_prepare ( version , & client_pp - > cipher [ 0 ] , quic_info - > hash_algo ,
quic_info - > cipher_algo , quic_info - > cipher_mode , client_pp - > next_secret , & error ) | |
! quic_cipher_prepare ( version , & server_pp - > cipher [ 0 ] , quic_info - > hash_algo ,
quic_info - > cipher_algo , quic_info - > cipher_mode , server_pp - > next_secret , & error ) ) {
2018-03-19 23:42:00 +00:00
quic_info - > skip_decryption = TRUE ;
return NULL ;
}
2018-09-15 15:23:45 +00:00
quic_update_key ( quic_info - > hash_algo , pp_state , ! from_server ) ;
2018-03-19 23:42:00 +00:00
}
/*
2018-09-15 15:23:45 +00:00
* If the key phase changed , try to decrypt the packet using the new cipher .
* If that fails , then it is either a malicious packet or out - of - order .
* In that case , try the previous cipher ( unless it is the very first KP1 ) .
2018-03-19 23:42:00 +00:00
*/
if ( key_phase ! = pp_state - > key_phase ) {
2018-09-15 15:23:45 +00:00
quic_cipher new_cipher ;
memset ( & new_cipher , 0 , sizeof ( quic_cipher ) ) ;
if ( ! quic_cipher_prepare ( version , & new_cipher , quic_info - > hash_algo ,
quic_info - > cipher_algo , quic_info - > cipher_mode , server_pp - > next_secret , & error ) ) {
/* This should never be reached, if the parameters were wrong
* before , then it should have set " skip_decryption " . */
REPORT_DISSECTOR_BUG ( " quic_cipher_prepare unexpectedly failed: %s " , error ) ;
return NULL ;
}
// TODO verify decryption before switching keys.
success = TRUE ;
if ( success ) {
/* Verified the cipher, use it from now on and rotate the key. */
quic_cipher_reset ( & pp_state - > cipher [ key_phase ] ) ;
pp_state - > cipher [ key_phase ] = new_cipher ;
2018-03-20 18:37:30 +00:00
quic_update_key ( quic_info - > hash_algo , pp_state , ! from_server ) ;
2018-09-15 15:23:45 +00:00
2018-03-19 23:42:00 +00:00
pp_state - > key_phase = key_phase ;
2018-09-15 15:23:45 +00:00
//pp_state->changed_in_pkn = pkn;
return & pp_state - > cipher [ key_phase ] ;
} else {
// TODO fallback to previous cipher
return NULL ;
2018-03-19 23:42:00 +00:00
}
}
return & pp_state - > cipher [ key_phase ] ;
}
2017-11-15 06:41:45 +00:00
# endif /* HAVE_LIBGCRYPT_AEAD */
2018-03-01 16:42:14 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
2018-03-20 18:37:30 +00:00
/**
* Process ( protected ) payload , adding the encrypted payload to the tree . If
* decryption is possible , frame dissection is also attempted .
*
* The given offset must correspond to the end of the QUIC header and begin of
* the ( protected ) payload . Dissected frames are appended to " tree " and expert
* info is attached to " ti " ( the field with the encrypted payload ) .
*/
static void
quic_process_payload ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , proto_item * ti , guint offset ,
2018-09-18 20:53:00 +00:00
quic_info_data_t * quic_info , quic_packet_info_t * quic_packet , gboolean from_server ,
quic_cipher * cipher , guint pkn_len )
2018-03-20 18:37:30 +00:00
{
quic_decrypt_result_t * decryption = & quic_packet - > decryption ;
2017-06-23 05:45:10 +00:00
2018-03-20 18:37:30 +00:00
/*
* If no decryption error has occurred yet , try decryption on the first
* pass and store the result for later use .
*/
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
2018-09-11 21:27:18 +00:00
if ( ! quic_packet - > decryption . error & & cipher & & cipher - > pp_cipher ) {
2018-09-12 14:11:49 +00:00
quic_decrypt_message ( cipher , tvb , offset , pkn_len , quic_packet - > packet_number , & quic_packet - > decryption ) ;
2018-03-20 18:37:30 +00:00
}
}
2017-06-23 05:45:10 +00:00
2018-03-20 18:37:30 +00:00
if ( decryption - > error ) {
expert_add_info_format ( pinfo , ti , & ei_quic_decryption_failed ,
" Decryption failed: %s " , decryption - > error ) ;
} else if ( decryption - > data_len ) {
tvbuff_t * decrypted_tvb = tvb_new_child_real_data ( tvb , decryption - > data ,
decryption - > data_len , decryption - > data_len ) ;
add_new_data_source ( pinfo , decrypted_tvb , " Decrypted QUIC " ) ;
guint decrypted_offset = 0 ;
while ( tvb_reported_length_remaining ( decrypted_tvb , decrypted_offset ) > 0 ) {
2018-09-18 20:53:00 +00:00
decrypted_offset = dissect_quic_frame_type ( decrypted_tvb , pinfo , tree , decrypted_offset , quic_info , from_server ) ;
2018-03-20 18:37:30 +00:00
}
} else if ( quic_info - > skip_decryption ) {
expert_add_info_format ( pinfo , ti , & ei_quic_decryption_failed ,
" Decryption skipped because keys are not available. " ) ;
2018-02-24 16:44:37 +00:00
}
2018-03-20 18:37:30 +00:00
}
# else /* !HAVE_LIBGCRYPT_AEAD */
static void
quic_process_payload ( tvbuff_t * tvb _U_ , packet_info * pinfo , proto_tree * tree _U_ , proto_item * ti , guint offset _U_ ,
2018-09-19 09:26:51 +00:00
quic_info_data_t * quic_info _U_ , quic_packet_info_t * quic_packet _U_ , gboolean from_server _U_ ,
2018-09-18 20:53:00 +00:00
quic_cipher * cipher _U_ , guint pkn_len _U_ )
2018-03-20 18:37:30 +00:00
{
expert_add_info_format ( pinfo , ti , & ei_quic_decryption_failed , " Libgcrypt >= 1.6.0 is required for QUIC decryption " ) ;
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2017-12-23 14:17:36 +00:00
2018-04-23 14:53:40 +00:00
static void
2018-09-13 15:03:19 +00:00
quic_add_connection_info ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , quic_info_data_t * conn )
2018-04-23 14:53:40 +00:00
{
proto_tree * ctree ;
proto_item * pi ;
ctree = proto_tree_add_subtree ( tree , tvb , 0 , 0 , ett_quic_connection_info , NULL , " QUIC Connection information " ) ;
if ( ! conn ) {
expert_add_info ( pinfo , ctree , & ei_quic_connection_unknown ) ;
return ;
}
pi = proto_tree_add_uint ( ctree , hf_quic_connection_number , tvb , 0 , 0 , conn - > number ) ;
PROTO_ITEM_SET_GENERATED ( pi ) ;
#if 0
proto_tree_add_debug_text ( ctree , " Client CID: %s " , cid_to_string ( & conn - > client_cids . data ) ) ;
proto_tree_add_debug_text ( ctree , " Server CID: %s " , cid_to_string ( & conn - > server_cids . data ) ) ;
proto_tree_add_debug_text ( ctree , " InitialCID: %s " , cid_to_string ( & conn - > client_dcid_initial ) ) ;
# endif
}
2018-04-18 16:39:17 +00:00
/**
* Dissects the common part after the first byte for packets using the Long
2018-04-21 12:18:03 +00:00
* Header form .
2018-04-18 16:39:17 +00:00
*/
static int
dissect_quic_long_header_common ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * quic_tree ,
2018-04-21 12:18:03 +00:00
guint offset , const quic_packet_info_t * quic_packet _U_ ,
guint32 * version_out , quic_cid_t * dcid , quic_cid_t * scid )
2018-04-18 16:39:17 +00:00
{
guint32 version ;
guint32 dcil , scil ;
version = tvb_get_ntohl ( tvb , offset ) ;
2018-04-21 12:18:03 +00:00
if ( version_out ) {
* version_out = version ;
2018-04-18 16:39:17 +00:00
}
2018-09-11 13:58:22 +00:00
proto_tree_add_item ( quic_tree , hf_quic_version , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
offset + = 4 ;
2018-04-18 16:39:17 +00:00
2018-09-11 13:58:22 +00:00
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_dcil , tvb , offset , 1 , ENC_BIG_ENDIAN , & dcil ) ;
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_scil , tvb , offset , 1 , ENC_BIG_ENDIAN , & scil ) ;
offset + + ;
2018-04-18 16:39:17 +00:00
2018-09-11 13:58:22 +00:00
if ( dcil ) {
dcil + = 3 ;
proto_tree_add_item ( quic_tree , hf_quic_dcid , tvb , offset , dcil , ENC_NA ) ;
// TODO expert info on CID mismatch with connection
tvb_memcpy ( tvb , dcid - > cid , offset , dcil ) ;
dcid - > len = dcil ;
offset + = dcil ;
}
2018-04-18 16:39:17 +00:00
2018-09-11 13:58:22 +00:00
if ( scil ) {
scil + = 3 ;
proto_tree_add_item ( quic_tree , hf_quic_scid , tvb , offset , scil , ENC_NA ) ;
// TODO expert info on CID mismatch with connection
tvb_memcpy ( tvb , scid - > cid , offset , scil ) ;
scid - > len = scil ;
offset + = scil ;
2018-04-18 16:39:17 +00:00
}
2018-09-11 13:58:22 +00:00
2018-04-18 16:39:17 +00:00
if ( dcid - > len > 0 ) {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , DCID=%s " , cid_to_string ( dcid ) ) ;
}
if ( scid - > len > 0 ) {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SCID=%s " , cid_to_string ( scid ) ) ;
}
return offset ;
}
2018-09-16 22:50:08 +00:00
/* Retry Packet dissection for draft -13 and newer. */
static int
dissect_quic_retry_packet ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * quic_tree ,
quic_datagram * dgram_info _U_ , quic_packet_info_t * quic_packet )
{
guint offset = 0 ;
guint32 version ;
guint32 len_payload_length ;
guint64 payload_length ;
quic_cid_t dcid = { . len = 0 } , scid = { . len = 0 } ;
guint32 odcil = 0 ;
guint retry_token_len ;
proto_tree_add_item ( quic_tree , hf_quic_long_packet_type , tvb , offset , 1 , ENC_NA ) ;
offset + = 1 ;
col_set_str ( pinfo - > cinfo , COL_INFO , " Retry " ) ;
offset = dissect_quic_long_header_common ( tvb , pinfo , quic_tree , offset , quic_packet , & version , & dcid , & scid ) ;
if ( is_quic_draft_max ( version , 13 ) ) {
proto_tree_add_item_ret_varint ( quic_tree , hf_quic_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & payload_length , & len_payload_length ) ;
offset + = len_payload_length ;
// PKN is encrypted, but who cares about draft -13 anyway.
proto_tree_add_item ( quic_tree , hf_quic_packet_number , tvb , offset , 1 , ENC_NA ) ;
offset + = 1 ;
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_odcil_draft13 , tvb , offset , 1 , ENC_NA , & odcil ) ;
2018-09-17 08:32:50 +00:00
} else {
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_odcil , tvb , offset , 1 , ENC_NA , & odcil ) ;
if ( odcil ) {
odcil + = 3 ;
}
2018-09-16 22:50:08 +00:00
}
offset + = 1 ;
proto_tree_add_item ( quic_tree , hf_quic_odcid , tvb , offset , odcil , ENC_NA ) ;
offset + = odcil ;
retry_token_len = tvb_reported_length_remaining ( tvb , offset ) ;
proto_tree_add_item ( quic_tree , hf_quic_retry_token , tvb , offset , retry_token_len , ENC_NA ) ;
offset + = retry_token_len ;
return offset ;
}
2018-02-24 16:44:37 +00:00
static int
2018-09-11 17:28:09 +00:00
dissect_quic_long_header ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * quic_tree ,
2018-09-13 15:03:19 +00:00
quic_datagram * dgram_info , quic_packet_info_t * quic_packet )
2018-03-20 16:36:38 +00:00
{
2018-09-11 17:28:09 +00:00
guint offset = 0 ;
2018-03-16 18:44:27 +00:00
guint32 long_packet_type ;
2018-04-21 12:18:03 +00:00
guint32 version ;
2018-04-18 16:39:17 +00:00
quic_cid_t dcid = { . len = 0 } , scid = { . len = 0 } ;
2018-09-12 22:34:46 +00:00
guint32 len_token_length ;
guint64 token_length ;
2018-04-18 16:39:17 +00:00
guint32 len_payload_length ;
guint64 payload_length ;
2018-09-12 14:11:49 +00:00
guint32 pkn_len ;
2018-04-18 16:39:17 +00:00
guint64 pkn ;
2018-09-13 15:03:19 +00:00
quic_info_data_t * conn = dgram_info - > conn ;
const gboolean from_server = dgram_info - > from_server ;
2018-09-12 14:11:49 +00:00
quic_cipher * cipher = NULL ;
2018-09-15 15:41:39 +00:00
proto_item * ti ;
2017-12-31 07:51:42 +00:00
2018-02-24 16:44:37 +00:00
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_long_packet_type , tvb , offset , 1 , ENC_NA , & long_packet_type ) ;
offset + = 1 ;
2018-04-18 16:39:17 +00:00
col_set_str ( pinfo - > cinfo , COL_INFO , val_to_str ( long_packet_type , quic_long_packet_type_vals , " Long Header " ) ) ;
2017-12-31 07:51:42 +00:00
2018-04-21 12:18:03 +00:00
offset = dissect_quic_long_header_common ( tvb , pinfo , quic_tree , offset , quic_packet , & version , & dcid , & scid ) ;
2017-12-23 14:17:36 +00:00
2018-09-17 17:39:32 +00:00
if ( long_packet_type = = QUIC_LPT_INITIAL ) {
2018-09-12 22:34:46 +00:00
proto_tree_add_item_ret_varint ( quic_tree , hf_quic_token_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & token_length , & len_token_length ) ;
offset + = len_token_length ;
if ( token_length ) {
proto_tree_add_item ( quic_tree , hf_quic_token , tvb , offset , ( guint32 ) token_length , ENC_NA ) ;
offset + = ( guint ) token_length ;
}
}
proto_tree_add_item_ret_varint ( quic_tree , hf_quic_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & payload_length , & len_payload_length ) ;
2018-09-11 13:58:22 +00:00
offset + = len_payload_length ;
2017-12-31 07:51:42 +00:00
2018-09-11 15:41:24 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
2018-09-15 23:07:21 +00:00
if ( conn ) {
2018-09-17 17:39:32 +00:00
if ( long_packet_type = = QUIC_LPT_INITIAL ) {
2018-09-15 23:07:21 +00:00
cipher = ! from_server ? & conn - > client_initial_cipher : & conn - > server_initial_cipher ;
} else if ( long_packet_type = = QUIC_LPT_HANDSHAKE ) {
cipher = ! from_server ? & conn - > client_handshake_cipher : & conn - > server_handshake_cipher ;
}
}
2018-09-11 15:41:24 +00:00
/* Build handshake cipher now for PKN (and handshake) decryption. */
2018-09-15 23:07:21 +00:00
if ( ! PINFO_FD_VISITED ( pinfo ) & & conn ) {
2018-09-11 15:41:24 +00:00
const gchar * error = NULL ;
2018-09-15 23:07:21 +00:00
if ( long_packet_type = = QUIC_LPT_INITIAL & & ! from_server & &
! memcmp ( & dcid , & conn - > client_dcid_initial , sizeof ( quic_cid_t ) ) ) {
/* Create new decryption context based on the Client Connection
* ID from the * very first * Client Initial packet . */
quic_create_initial_decoders ( & dcid , & error , conn ) ;
2018-09-17 17:39:32 +00:00
} else if ( long_packet_type = = QUIC_LPT_HANDSHAKE ) {
2018-09-15 23:07:21 +00:00
if ( ! cipher - > pn_cipher ) {
quic_create_decoders ( pinfo , version , conn , cipher , from_server , TLS_SECRET_HANDSHAKE , & error ) ;
}
}
if ( error ) {
2018-09-11 15:41:24 +00:00
expert_add_info_format ( pinfo , quic_tree , & ei_quic_decryption_failed , " Failed to create decryption context: %s " , error ) ;
quic_packet - > decryption . error = wmem_strdup ( wmem_file_scope ( ) , error ) ;
}
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2018-09-13 15:03:19 +00:00
pkn_len = dissect_quic_packet_number ( tvb , pinfo , quic_tree , offset , conn , quic_packet , from_server ,
2018-09-12 14:11:49 +00:00
cipher , GCRY_CIPHER_AES128 , & pkn ) ;
if ( pkn_len = = 0 ) {
return offset ;
}
offset + = pkn_len ;
2018-04-18 16:39:17 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PKN: % " G_GINT64_MODIFIER " u " , pkn ) ;
2017-06-23 05:45:10 +00:00
2018-02-24 16:44:37 +00:00
/* Payload */
2018-09-15 15:41:39 +00:00
ti = proto_tree_add_item ( quic_tree , hf_quic_payload , tvb , offset , - 1 , ENC_NA ) ;
if ( conn ) {
quic_process_payload ( tvb , pinfo , quic_tree , ti , offset ,
2018-09-18 20:53:00 +00:00
conn , quic_packet , from_server , cipher , pkn_len ) ;
2017-06-23 05:45:10 +00:00
}
2018-09-15 15:41:39 +00:00
offset + = tvb_reported_length_remaining ( tvb , offset ) ;
2017-06-23 05:45:10 +00:00
return offset ;
}
static int
2018-09-11 17:28:09 +00:00
dissect_quic_short_header ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * quic_tree ,
2018-09-13 15:03:19 +00:00
quic_datagram * dgram_info , quic_packet_info_t * quic_packet )
2018-03-20 16:36:38 +00:00
{
2018-09-11 17:28:09 +00:00
guint offset = 0 ;
2018-04-18 16:39:17 +00:00
quic_cid_t dcid = { . len = 0 } ;
2018-03-16 18:44:27 +00:00
guint32 pkn_len ;
2018-03-20 16:36:38 +00:00
guint64 pkn ;
2018-03-16 18:44:27 +00:00
proto_item * ti ;
2018-04-18 16:39:17 +00:00
gboolean key_phase = FALSE ;
2018-09-11 21:27:18 +00:00
quic_cipher * cipher = NULL ;
2018-09-13 15:03:19 +00:00
quic_info_data_t * conn = dgram_info - > conn ;
const gboolean from_server = dgram_info - > from_server ;
2017-06-23 05:45:10 +00:00
2018-09-11 13:58:22 +00:00
proto_tree_add_item_ret_boolean ( quic_tree , hf_quic_short_kp_flag , tvb , offset , 1 , ENC_NA , & key_phase ) ;
2018-09-15 09:55:21 +00:00
proto_tree_add_item ( quic_tree , hf_quic_short_reserved , tvb , offset , 1 , ENC_NA ) ;
2018-09-11 13:58:22 +00:00
if ( conn ) {
2018-09-13 15:03:19 +00:00
dcid . len = from_server ? conn - > client_cids . data . len : conn - > server_cids . data . len ;
2018-04-17 21:56:26 +00:00
}
2017-06-23 05:45:10 +00:00
offset + = 1 ;
/* Connection ID */
2018-04-18 16:39:17 +00:00
if ( dcid . len > 0 ) {
proto_tree_add_item ( quic_tree , hf_quic_dcid , tvb , offset , dcid . len , ENC_NA ) ;
2018-04-23 10:19:38 +00:00
tvb_memcpy ( tvb , dcid . cid , offset , dcid . len ) ;
2018-04-18 16:39:17 +00:00
offset + = dcid . len ;
2017-06-23 05:45:10 +00:00
}
2018-03-16 18:44:27 +00:00
2018-09-12 14:11:49 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
if ( ! PINFO_FD_VISITED ( pinfo ) & & conn ) {
2018-09-15 15:23:45 +00:00
cipher = quic_get_pp_cipher ( pinfo , key_phase , conn , from_server ) ;
2018-09-12 14:11:49 +00:00
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2017-06-23 05:45:10 +00:00
/* Packet Number */
2018-09-13 15:03:19 +00:00
pkn_len = dissect_quic_packet_number ( tvb , pinfo , quic_tree , offset , conn , quic_packet , from_server ,
2018-09-15 15:23:45 +00:00
cipher , conn ? conn - > cipher_algo : 0 , & pkn ) ;
2018-09-12 14:11:49 +00:00
if ( pkn_len = = 0 ) {
return offset ;
}
2017-06-23 05:45:10 +00:00
offset + = pkn_len ;
2018-04-18 16:39:17 +00:00
col_clear ( pinfo - > cinfo , COL_INFO ) ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " Protected Payload (KP%u), PKN: % " G_GINT64_MODIFIER " u " , key_phase , pkn ) ;
2017-06-23 05:45:10 +00:00
2018-04-18 16:39:17 +00:00
if ( dcid . len > 0 ) {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , DCID=%s " , cid_to_string ( & dcid ) ) ;
2017-06-23 05:45:10 +00:00
}
2018-03-19 23:42:00 +00:00
/* Protected Payload */
ti = proto_tree_add_item ( quic_tree , hf_quic_protected_payload , tvb , offset , - 1 , ENC_NA ) ;
2018-03-20 18:37:30 +00:00
2018-04-21 12:18:03 +00:00
if ( conn ) {
quic_process_payload ( tvb , pinfo , quic_tree , ti , offset ,
2018-09-18 20:53:00 +00:00
conn , quic_packet , from_server , cipher , pkn_len ) ;
2018-04-21 12:18:03 +00:00
}
2018-03-19 23:42:00 +00:00
offset + = tvb_reported_length_remaining ( tvb , offset ) ;
2017-06-23 05:45:10 +00:00
return offset ;
}
2018-01-03 19:15:24 +00:00
static int
2018-09-11 17:28:09 +00:00
dissect_quic_version_negotiation ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * quic_tree , const quic_packet_info_t * quic_packet )
2018-04-18 16:39:17 +00:00
{
2018-09-11 17:28:09 +00:00
guint offset = 0 ;
2018-04-18 16:39:17 +00:00
quic_cid_t dcid = { . len = 0 } , scid = { . len = 0 } ;
2018-02-08 14:06:39 +00:00
guint32 supported_version ;
proto_item * ti ;
2018-01-03 19:15:24 +00:00
2018-04-18 16:39:17 +00:00
col_set_str ( pinfo - > cinfo , COL_INFO , " Version Negotiation " ) ;
2018-01-03 19:15:24 +00:00
proto_tree_add_item ( quic_tree , hf_quic_vn_unused , tvb , offset , 1 , ENC_NA ) ;
offset + = 1 ;
2018-04-21 12:18:03 +00:00
offset = dissect_quic_long_header_common ( tvb , pinfo , quic_tree , offset , quic_packet , NULL , & dcid , & scid ) ;
2018-01-03 19:15:24 +00:00
/* Supported Version */
while ( tvb_reported_length_remaining ( tvb , offset ) > 0 ) {
2018-02-08 14:06:39 +00:00
ti = proto_tree_add_item_ret_uint ( quic_tree , hf_quic_supported_version , tvb , offset , 4 , ENC_BIG_ENDIAN , & supported_version ) ;
if ( ( supported_version & 0x0F0F0F0F ) = = 0x0a0a0a0a ) {
proto_item_append_text ( ti , " (GREASE) " ) ;
}
2018-01-03 19:15:24 +00:00
offset + = 4 ;
}
return offset ;
}
2018-09-11 17:28:09 +00:00
static tvbuff_t *
quic_get_message_tvb ( tvbuff_t * tvb , const guint offset )
{
2018-09-12 22:34:46 +00:00
guint64 token_length ;
2018-09-11 17:28:09 +00:00
guint64 payload_length ;
guint8 packet_type = tvb_get_guint8 ( tvb , offset ) ;
2018-09-17 08:32:50 +00:00
guint8 long_packet_type = packet_type & 0x7f ;
// Retry and VN packets cannot be coalesced (clarified in draft -14).
if ( ( packet_type & 0x80 ) & & long_packet_type ! = QUIC_LPT_RETRY ) {
2018-09-11 17:28:09 +00:00
// long header form, check version
guint version = tvb_get_ntohl ( tvb , offset + 1 ) ;
// If this is not a VN packet but a valid long form, extract a subset.
// TODO check for valid QUIC versions as future versions might change the format.
if ( version ! = 0 ) {
guint8 cid_lengths = tvb_get_guint8 ( tvb , offset + 5 ) ;
guint8 dcil = cid_lengths > > 4 ;
guint8 scil = cid_lengths & 0xf ;
guint length = 6 ;
if ( dcil ) {
length + = 3 + dcil ;
}
if ( scil ) {
length + = 3 + scil ;
}
2018-09-17 17:39:32 +00:00
if ( long_packet_type = = QUIC_LPT_INITIAL ) {
2018-09-12 22:34:46 +00:00
length + = tvb_get_varint ( tvb , offset + length , 8 , & token_length , ENC_VARINT_QUIC ) ;
length + = ( guint ) token_length ;
}
2018-09-11 17:28:09 +00:00
length + = tvb_get_varint ( tvb , offset + length , 8 , & payload_length , ENC_VARINT_QUIC ) ;
length + = ( guint ) payload_length ;
if ( payload_length < = G_MAXINT32 & & length < ( guint ) tvb_reported_length_remaining ( tvb , offset ) ) {
return tvb_new_subset_length ( tvb , offset , length ) ;
}
}
}
// short header form, VN or unknown message, return remaining data.
return tvb_new_subset_remaining ( tvb , offset ) ;
}
2018-04-21 12:18:03 +00:00
/**
* Extracts necessary information from header to find any existing connection .
* " long_packet_type " is set to QUIC_SHORT_PACKET for short header packets .
* DCID and SCID are not modified unless available . For short header packets ,
* DCID length is unknown , so the caller should truncate it as needed .
*/
static void
quic_extract_header ( tvbuff_t * tvb , guint8 * long_packet_type , guint32 * version ,
quic_cid_t * dcid , quic_cid_t * scid )
2018-03-19 23:42:00 +00:00
{
2018-04-21 12:18:03 +00:00
guint offset = 0 ;
2018-03-19 23:42:00 +00:00
2018-04-21 12:18:03 +00:00
guint8 packet_type = tvb_get_guint8 ( tvb , offset ) ;
gboolean is_long_header = packet_type & 0x80 ;
if ( is_long_header ) {
// long header form
* long_packet_type = packet_type & 0x7f ;
} else {
// short header form, store dummy value that is not a long packet type.
* long_packet_type = QUIC_SHORT_PACKET ;
}
offset + + ;
2018-04-17 20:08:55 +00:00
2018-09-11 13:58:22 +00:00
* version = tvb_get_ntohl ( tvb , offset ) ;
2018-03-19 23:42:00 +00:00
2018-09-11 13:58:22 +00:00
if ( is_long_header ) {
2018-04-21 12:18:03 +00:00
// skip version
offset + = 4 ;
2017-06-23 05:45:10 +00:00
2018-04-21 12:18:03 +00:00
// read DCIL/SCIL (Connection ID Lengths).
guint8 cid_lengths = tvb_get_guint8 ( tvb , offset ) ;
guint8 dcil = cid_lengths > > 4 ;
guint8 scil = cid_lengths & 0xf ;
offset + + ;
if ( dcil ) {
dcil + = 3 ;
tvb_memcpy ( tvb , dcid - > cid , offset , dcil ) ;
dcid - > len = dcil ;
offset + = dcil ;
2018-03-20 16:36:38 +00:00
}
2018-04-21 12:18:03 +00:00
if ( scil ) {
scil + = 3 ;
tvb_memcpy ( tvb , scid - > cid , offset , scil ) ;
scid - > len = scil ;
2018-03-20 16:36:38 +00:00
}
2018-04-21 12:18:03 +00:00
} else {
// Definitely not draft -10, set version to dummy value.
* version = 0 ;
// For short headers, the DCID length is unknown and could be 0 or
// anything from 4 to 18 bytes. Copy the maximum possible and let the
// consumer truncate it as necessary.
tvb_memcpy ( tvb , dcid - > cid , offset , 18 ) ;
dcid - > len = 18 ;
2018-03-20 16:36:38 +00:00
}
}
2017-06-23 05:45:10 +00:00
static int
dissect_quic ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
void * data _U_ )
{
proto_item * ti ;
proto_tree * quic_tree ;
guint offset = 0 ;
2018-04-18 16:39:17 +00:00
guint32 header_form ;
2018-09-13 15:03:19 +00:00
quic_datagram * dgram_info = NULL ;
2018-03-20 16:36:38 +00:00
quic_packet_info_t * quic_packet = NULL ;
2017-06-23 05:45:10 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " QUIC " ) ;
2018-03-20 16:36:38 +00:00
if ( PINFO_FD_VISITED ( pinfo ) ) {
2018-09-13 15:03:19 +00:00
dgram_info = ( quic_datagram * ) p_get_proto_data ( wmem_file_scope ( ) , pinfo , proto_quic , 0 ) ;
2018-03-20 16:36:38 +00:00
}
2018-09-13 15:03:19 +00:00
if ( ! dgram_info ) {
dgram_info = wmem_new0 ( wmem_file_scope ( ) , quic_datagram ) ;
p_add_proto_data ( wmem_file_scope ( ) , pinfo , proto_quic , 0 , dgram_info ) ;
2018-03-20 16:36:38 +00:00
}
2017-06-23 05:45:10 +00:00
ti = proto_tree_add_item ( tree , proto_quic , tvb , 0 , - 1 , ENC_NA ) ;
quic_tree = proto_item_add_subtree ( ti , ett_quic ) ;
2018-04-21 12:18:03 +00:00
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
guint8 long_packet_type ;
guint32 version ;
quic_cid_t dcid = { . len = 0 } , scid = { . len = 0 } ;
gboolean from_server = FALSE ;
quic_info_data_t * conn ;
quic_extract_header ( tvb , & long_packet_type , & version , & dcid , & scid ) ;
conn = quic_connection_find ( pinfo , long_packet_type , & dcid , & from_server ) ;
2018-09-11 13:58:22 +00:00
quic_connection_create_or_update ( & conn , pinfo , long_packet_type , version , & scid , & dcid , from_server ) ;
2018-09-13 15:03:19 +00:00
dgram_info - > conn = conn ;
dgram_info - > from_server = from_server ;
2018-04-21 12:18:03 +00:00
#if 0
2018-09-13 15:03:19 +00:00
proto_tree_add_debug_text ( quic_tree , " Connection: %d %p DCID=%s SCID=%s from_server:%d " , pinfo - > num , dgram_info - > conn , cid_to_string ( & dcid ) , cid_to_string ( & scid ) , dgram_info - > from_server ) ;
2018-04-21 12:18:03 +00:00
} else {
2018-09-13 15:03:19 +00:00
proto_tree_add_debug_text ( quic_tree , " Connection: %d %p from_server:%d " , pinfo - > num , dgram_info - > conn , dgram_info - > from_server ) ;
2018-04-21 12:18:03 +00:00
# endif
}
2018-09-13 15:03:19 +00:00
quic_add_connection_info ( tvb , pinfo , quic_tree , dgram_info - > conn ) ;
2018-04-23 14:53:40 +00:00
2018-09-11 17:28:09 +00:00
do {
2018-09-13 15:03:19 +00:00
if ( ! quic_packet ) {
quic_packet = & dgram_info - > first_packet ;
} else if ( ! PINFO_FD_VISITED ( pinfo ) ) {
quic_packet - > next = wmem_new0 ( wmem_file_scope ( ) , quic_packet_info_t ) ;
quic_packet = quic_packet - > next ;
} else {
quic_packet = quic_packet - > next ;
DISSECTOR_ASSERT ( quic_packet ) ;
}
2018-09-11 17:28:09 +00:00
tvbuff_t * next_tvb = quic_get_message_tvb ( tvb , offset ) ;
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_header_form , next_tvb , 0 , 1 , ENC_NA , & header_form ) ;
if ( header_form ) {
2018-09-16 22:50:08 +00:00
guint8 long_packet_type = tvb_get_guint8 ( next_tvb , 0 ) & 0x7f ;
guint32 version = tvb_get_ntohl ( next_tvb , 1 ) ;
if ( version = = 0 ) {
2018-09-11 17:28:09 +00:00
dissect_quic_version_negotiation ( next_tvb , pinfo , quic_tree , quic_packet ) ;
break ;
}
2018-09-17 17:39:32 +00:00
if ( long_packet_type = = QUIC_LPT_RETRY ) {
2018-09-16 22:50:08 +00:00
dissect_quic_retry_packet ( next_tvb , pinfo , quic_tree , dgram_info , quic_packet ) ;
} else {
dissect_quic_long_header ( next_tvb , pinfo , quic_tree , dgram_info , quic_packet ) ;
}
2018-09-11 17:28:09 +00:00
} else {
2018-09-13 15:03:19 +00:00
dissect_quic_short_header ( next_tvb , pinfo , quic_tree , dgram_info , quic_packet ) ;
2018-01-03 19:15:24 +00:00
}
2018-09-11 17:28:09 +00:00
offset + = tvb_reported_length ( next_tvb ) ;
} while ( tvb_reported_length_remaining ( tvb , offset ) ) ;
2017-06-23 05:45:10 +00:00
return offset ;
}
2018-09-18 22:42:44 +00:00
static gboolean
dissect_quic_short_header_heur ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
// If this capture does not contain QUIC, skip the more expensive checks.
if ( quic_cid_lengths = = 0 ) {
return FALSE ;
}
// Is this a SH packet after connection migration? SH (draft -14):
// Flag (1) + DCID (4-18) + PKN (1/2/4) + encrypted payload (>= 16).
if ( tvb_captured_length ( tvb ) < 1 + 4 + 1 + 16 ) {
return FALSE ;
}
// DCID length is unknown, so extract the maximum and look for a match.
quic_cid_t dcid = { . len = 18 } ;
tvb_memcpy ( tvb , dcid . cid , 1 , 18 ) ;
gboolean from_server ;
if ( ! quic_connection_find ( pinfo , QUIC_SHORT_PACKET , & dcid , & from_server ) ) {
return FALSE ;
}
conversation_t * conversation = find_or_create_conversation ( pinfo ) ;
conversation_set_dissector ( conversation , quic_handle ) ;
dissect_quic ( tvb , pinfo , tree , NULL ) ;
return TRUE ;
}
2018-02-28 07:04:25 +00:00
static gboolean dissect_quic_heur ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data )
{
2018-04-18 16:39:17 +00:00
/*
2018-09-15 09:55:21 +00:00
* Since draft - 12 :
2018-04-18 16:39:17 +00:00
* Flag ( 1 byte ) + Version ( 4 bytes ) + DCIL / SCIL ( 1 byte ) +
* Destination Connection ID ( 0 / 4. .18 based on DCIL ) +
* Source Connection ID ( 0 / 4. .18 based on SCIL ) +
2018-09-15 09:55:21 +00:00
* Payload length ( 1 / 2 / 4 / 8 ) + Packet number ( 1 / 2 / 4 bytes ) + Payload .
* ( absolute minimum : 8 + payload )
2018-04-18 16:39:17 +00:00
* ( for Version Negotiation , payload len + PKN + payload is replaced by
* Supported Version ( multiple of 4 bytes . )
*/
2018-02-28 07:04:25 +00:00
conversation_t * conversation = NULL ;
int offset = 0 ;
guint8 flags ;
2018-04-18 16:39:17 +00:00
gboolean is_quic = FALSE ;
2018-02-28 07:04:25 +00:00
/* Verify packet size (Flag (1 byte) + Connection ID (8 bytes) + Version (4 bytes)) */
if ( tvb_captured_length ( tvb ) < 13 )
{
return FALSE ;
}
flags = tvb_get_guint8 ( tvb , offset ) ;
/* Check if long Packet is set */
if ( ( flags & 0x80 ) = = 0 ) {
2018-09-18 22:42:44 +00:00
// Perhaps this is a short header, check it.
return dissect_quic_short_header_heur ( tvb , pinfo , tree ) ;
2018-02-28 07:04:25 +00:00
}
offset + = 1 ;
2018-04-18 16:39:17 +00:00
// check for draft QUIC version (for draft -11 and newer)
is_quic = quic_draft_version ( tvb_get_ntohl ( tvb , offset ) ) > = 11 ;
2018-02-28 07:04:25 +00:00
2018-04-18 16:39:17 +00:00
if ( is_quic ) {
2018-02-28 07:04:25 +00:00
conversation = find_or_create_conversation ( pinfo ) ;
conversation_set_dissector ( conversation , quic_handle ) ;
dissect_quic ( tvb , pinfo , tree , data ) ;
}
2018-04-18 16:39:17 +00:00
return is_quic ;
2018-02-28 07:04:25 +00:00
}
2018-04-21 12:18:03 +00:00
/** Initialize QUIC dissection state for a new capture file. */
static void
quic_init ( void )
{
quic_connections = wmem_list_new ( wmem_file_scope ( ) ) ;
2018-04-23 14:53:40 +00:00
quic_connections_count = 0 ;
2018-04-21 12:18:03 +00:00
quic_initial_connections = wmem_map_new ( wmem_file_scope ( ) , quic_connection_hash , quic_connection_equal ) ;
quic_client_connections = wmem_map_new ( wmem_file_scope ( ) , quic_connection_hash , quic_connection_equal ) ;
quic_server_connections = wmem_map_new ( wmem_file_scope ( ) , quic_connection_hash , quic_connection_equal ) ;
2018-09-18 22:40:12 +00:00
quic_cid_lengths = 0 ;
2018-04-21 12:18:03 +00:00
}
/** Release QUIC dissection state on closing a capture file. */
static void
quic_cleanup ( void )
{
2018-05-02 16:31:21 +00:00
wmem_list_foreach ( quic_connections , quic_connection_destroy , NULL ) ;
2018-04-21 12:18:03 +00:00
quic_initial_connections = NULL ;
quic_client_connections = NULL ;
quic_server_connections = NULL ;
}
2017-06-23 05:45:10 +00:00
void
proto_register_quic ( void )
{
expert_module_t * expert_quic ;
static hf_register_info hf [ ] = {
2018-04-23 14:53:40 +00:00
{ & hf_quic_connection_number ,
{ " Connection Number " , " quic.connection.number " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Connection identifier within this capture file " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_header_form ,
{ " Header Form " , " quic.header_form " ,
FT_UINT8 , BASE_DEC , VALS ( quic_short_long_header_vals ) , 0x80 ,
" The most significant bit (0x80) of the first octet is set to 1 for long headers and 0 for short headers. " , HFILL }
} ,
{ & hf_quic_long_packet_type ,
{ " Packet Type " , " quic.long.packet_type " ,
FT_UINT8 , BASE_DEC , VALS ( quic_long_packet_type_vals ) , 0x7F ,
" Long Header Packet Type " , HFILL }
} ,
2018-04-18 16:39:17 +00:00
{ & hf_quic_dcid ,
{ " Destination Connection ID " , " quic.dcid " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_scid ,
{ " Source Connection ID " , " quic.scid " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_dcil ,
{ " Destination Connection ID Length " , " quic.dcil " ,
FT_UINT8 , BASE_DEC , VALS ( quic_cid_len_vals ) , 0xf0 ,
" Destination Connection ID Length (for non-zero lengths, add 3 for actual length) " , HFILL }
} ,
{ & hf_quic_scil ,
{ " Source Connection ID Length " , " quic.scil " ,
FT_UINT8 , BASE_DEC , VALS ( quic_cid_len_vals ) , 0x0f ,
" Source Connection ID Length (for non-zero lengths, add 3 for actual length) " , HFILL }
} ,
2018-09-12 22:34:46 +00:00
{ & hf_quic_token_length ,
{ " Token Length " , " quic.token_length " ,
2018-04-18 16:39:17 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
NULL , HFILL }
} ,
2018-09-12 22:34:46 +00:00
{ & hf_quic_token ,
{ " Token " , " quic.token " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_length ,
{ " Length " , " quic.length " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Length of Packet Number and Payload fields " , HFILL }
} ,
2018-04-18 16:39:17 +00:00
2017-06-23 05:45:10 +00:00
{ & hf_quic_packet_number ,
{ " Packet Number " , " quic.packet_number " ,
2018-03-16 18:44:27 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
NULL , HFILL }
} ,
2018-03-16 18:44:27 +00:00
{ & hf_quic_packet_number_full ,
{ " Packet Number (full) " , " quic.packet_number_full " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Full packet number " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_version ,
{ " Version " , " quic.version " ,
FT_UINT32 , BASE_HEX , VALS ( quic_version_vals ) , 0x0 ,
NULL , HFILL }
} ,
2018-01-03 19:15:24 +00:00
{ & hf_quic_supported_version ,
{ " Supported Version " , " quic.supported_version " ,
FT_UINT32 , BASE_HEX , VALS ( quic_version_vals ) , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_vn_unused , /* <= draft-07 */
{ " Unused " , " quic.vn.unused " ,
FT_UINT8 , BASE_HEX , NULL , 0x7F ,
NULL , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_short_kp_flag ,
{ " Key Phase Bit " , " quic.short.kp_flag " ,
FT_BOOLEAN , 8 , NULL , SH_KP ,
NULL , HFILL }
} ,
2018-09-15 09:55:21 +00:00
{ & hf_quic_short_reserved ,
{ " Reserved " , " quic.short.reserved " ,
FT_UINT8 , BASE_DEC , NULL , 0x07 ,
" Reserved bits for experimentation " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2018-09-15 15:41:39 +00:00
{ & hf_quic_payload ,
{ " Payload " , " quic.payload " ,
2017-12-23 14:17:36 +00:00
FT_BYTES , BASE_NONE , NULL , 0x0 ,
2018-09-15 15:41:39 +00:00
" (Encrypted) payload of a packet " , HFILL }
2017-12-23 14:17:36 +00:00
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_protected_payload ,
{ " Protected Payload " , " quic.protected_payload " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
2018-09-15 15:41:39 +00:00
" 1-RTT protected payload " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2018-09-16 22:50:08 +00:00
{ & hf_quic_odcil_draft13 ,
{ " Original Destination Connection ID Length " , " quic.odcil_draft13 " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2018-09-17 08:32:50 +00:00
{ & hf_quic_odcil ,
{ " Original Destination Connection ID Length " , " quic.odcil " ,
FT_UINT8 , BASE_DEC , VALS ( quic_cid_len_vals ) , 0x0f ,
NULL , HFILL }
} ,
2018-09-16 22:50:08 +00:00
{ & hf_quic_odcid ,
{ " Original Destination Connection ID " , " quic.odcid " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_retry_token ,
{ " Retry Token " , " quic.retry_token " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_frame ,
{ " Frame " , " quic.frame " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_frame_type ,
{ " Frame Type " , " quic.frame_type " ,
FT_UINT8 , BASE_RANGE_STRING | BASE_HEX , RVALS ( quic_frame_type_vals ) , 0x0 ,
NULL , HFILL }
} ,
2017-12-24 14:03:58 +00:00
/* >= draft-08*/
{ & hf_quic_frame_type_stream_fin ,
{ " Fin " , " quic.frame_type.stream.fin " ,
FT_BOOLEAN , 8 , NULL , FTFLAGS_STREAM_FIN ,
NULL , HFILL }
} ,
{ & hf_quic_frame_type_stream_len ,
{ " Len(gth) " , " quic.frame_type.stream.len " ,
FT_BOOLEAN , 8 , NULL , FTFLAGS_STREAM_LEN ,
NULL , HFILL }
} ,
{ & hf_quic_frame_type_stream_off ,
{ " Off(set) " , " quic.frame_type.stream.off " ,
FT_BOOLEAN , 8 , NULL , FTFLAGS_STREAM_OFF ,
NULL , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_stream_stream_id ,
{ " Stream ID " , " quic.stream.stream_id " ,
2017-12-24 14:03:58 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
NULL , HFILL }
} ,
{ & hf_quic_stream_offset ,
{ " Offset " , " quic.stream.offset " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2017-12-24 14:03:58 +00:00
{ & hf_quic_stream_length ,
{ " Length " , " quic.stream.length " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_stream_data ,
{ " Stream Data " , " quic.stream_data " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_frame_type_ack_largest_acknowledged ,
{ " Largest Acknowledged " , " quic.frame_type.ack.largest_acknowledged " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Representing the largest packet number the peer is acknowledging in this packet " , HFILL }
} ,
{ & hf_quic_frame_type_ack_ack_delay ,
2017-12-31 09:58:09 +00:00
{ " ACK Delay " , " quic.frame_type.ack.ack_delay " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" The time from when the largest acknowledged packet, as indicated in the Largest Acknowledged field, was received by this peer to when this ACK was sent " , HFILL }
} ,
2017-12-31 09:58:09 +00:00
{ & hf_quic_frame_type_ack_ack_block_count ,
{ " ACK Block Count " , " quic.frame_type.ack.ack_block_count " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" The number of Additional ACK Block (and Gap) fields after the First ACK Block " , HFILL }
} ,
{ & hf_quic_frame_type_ack_fab ,
{ " First ACK Block " , " quic.frame_type.ack.fab " ,
2017-06-23 05:45:10 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicates the number of contiguous additional packets being acknowledged starting at the Largest Acknowledged " , HFILL }
} ,
2017-12-31 09:58:09 +00:00
{ & hf_quic_frame_type_ack_gap ,
{ " Gap " , " quic.frame_type.ack.gap " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the number of contiguous unacknowledged packets preceding the packet number one lower than the smallest in the preceding ACK Block " , HFILL }
} ,
{ & hf_quic_frame_type_ack_ack_block ,
{ " ACK Block " , " quic.frame_type.ack.ack_block " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the number of contiguous acknowledged packets preceding the largest packet number, as determined by the preceding Gap " , HFILL }
} ,
2018-04-17 20:41:38 +00:00
/* PATH_CHALLENGE */
{ & hf_quic_frame_type_path_challenge_data ,
{ " Data " , " quic.frame_type.path_challenge.data " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Arbitrary data that must be matched by a PATH_RESPONSE frame " , HFILL }
} ,
/* PATH_RESPONSE */
{ & hf_quic_frame_type_path_response_data ,
{ " Data " , " quic.frame_type.path_response.data " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Arbitrary data that must match a PATH_CHALLENGE frame " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
/* PADDING */
{ & hf_quic_frame_type_padding_length ,
{ " Padding Length " , " quic.frame_type.padding.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_frame_type_padding ,
{ " Padding " , " quic.frame_type.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Must be zero " , HFILL }
} ,
/* RST_STREAM */
{ & hf_quic_frame_type_rsts_stream_id ,
{ " Stream ID " , " quic.frame_type.rsts.stream_id " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" Stream ID of the stream being terminated " , HFILL }
} ,
2017-11-15 06:02:22 +00:00
{ & hf_quic_frame_type_rsts_application_error_code ,
{ " Application Error code " , " quic.frame_type.rsts.application_error_code " ,
FT_UINT16 , BASE_DEC | BASE_EXT_STRING , & quic_error_code_vals_ext , 0x0 ,
" Indicates why the stream is being closed " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_frame_type_rsts_final_offset ,
{ " Final offset " , " quic.frame_type.rsts.byte_offset " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the absolute byte offset of the end of data written on this stream " , HFILL }
} ,
/* CONNECTION_CLOSE */
2017-11-14 22:09:44 +00:00
{ & hf_quic_frame_type_cc_error_code , /* >= draft07 */
{ " Error code " , " quic.frame_type.cc.error_code " ,
FT_UINT16 , BASE_DEC | BASE_EXT_STRING , & quic_error_code_vals_ext , 0x0 ,
2017-06-23 05:45:10 +00:00
" Indicates the reason for closing this connection " , HFILL }
} ,
2018-09-17 14:41:04 +00:00
{ & hf_quic_frame_type_cc_frame_type ,
{ " Frame Type " , " quic.frame_type.cc.frame_type " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" The type of frame that triggered the error " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_frame_type_cc_reason_phrase_length ,
{ " Reason phrase Length " , " quic.frame_type.cc.reason_phrase.length " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" Specifying the length of the reason phrase " , HFILL }
} ,
{ & hf_quic_frame_type_cc_reason_phrase ,
{ " Reason phrase " , " quic.frame_type.cc.reason_phrase " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A human-readable explanation for why the connection was closed " , HFILL }
} ,
2017-11-14 21:49:45 +00:00
/* APPLICATION_CLOSE */
{ & hf_quic_frame_type_ac_error_code ,
{ " Application Error code " , " quic.frame_type.ac.error_code " ,
FT_UINT16 , BASE_DEC | BASE_EXT_STRING , & quic_error_code_vals_ext , 0x0 ,
" Indicates the reason for closing this application " , HFILL }
} ,
{ & hf_quic_frame_type_ac_reason_phrase_length ,
{ " Reason phrase Length " , " quic.frame_type.ac.reason_phrase.length " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-11-14 21:49:45 +00:00
" Specifying the length of the reason phrase " , HFILL }
} ,
{ & hf_quic_frame_type_ac_reason_phrase ,
{ " Reason phrase " , " quic.frame_type.ac.reason_phrase " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A human-readable explanation for why the application was closed " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
/* MAX_DATA */
{ & hf_quic_frame_type_md_maximum_data ,
{ " Maximum Data " , " quic.frame_type.md.maximum_data " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the maximum amount of data that can be sent on the entire connection, in units of 1024 octets " , HFILL }
} ,
/* MAX_STREAM_DATA */
{ & hf_quic_frame_type_msd_stream_id ,
{ " Stream ID " , " quic.frame_type.msd.stream_id " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" The stream ID of the stream that is affected " , HFILL }
} ,
{ & hf_quic_frame_type_msd_maximum_stream_data ,
{ " Maximum Stream Data " , " quic.frame_type.msd.maximum_stream_data " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the maximum amount of data that can be sent on the identified stream, in units of octets " , HFILL }
} ,
/* MAX_STREAM_ID */
{ & hf_quic_frame_type_msi_stream_id ,
{ " Stream ID " , " quic.frame_type.msi.stream_id " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" ID of the maximum peer-initiated stream ID for the connection " , HFILL }
} ,
2018-01-03 07:30:08 +00:00
/* BLOCKED */
{ & hf_quic_frame_type_blocked_offset ,
{ " Offset " , " quic.frame_type.sb.offset " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the connection-level offset at which the blocking occurred " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
/* STREAM_BLOCKED */
{ & hf_quic_frame_type_sb_stream_id ,
{ " Stream ID " , " quic.frame_type.sb.stream_id " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" Indicating the stream which is flow control blocked " , HFILL }
} ,
2018-01-03 07:30:08 +00:00
{ & hf_quic_frame_type_sb_offset ,
{ " Offset " , " quic.frame_type.sb.offset " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the offset of the stream at which the blocking occurred " , HFILL }
} ,
/* STREAM_ID_BLOCKED */
{ & hf_quic_frame_type_sib_stream_id ,
{ " Stream ID " , " quic.frame_type.sib.stream_id " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the highest stream ID that the sender was permitted to open " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
/* NEW_CONNECTION_ID */
{ & hf_quic_frame_type_nci_sequence ,
{ " Sequence " , " quic.frame_type.nci.sequence " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
" Increases by 1 for each connection ID that is provided by the server " , HFILL }
} ,
2018-04-23 21:00:53 +00:00
{ & hf_quic_frame_type_nci_connection_id_length ,
{ " Connection ID Length " , " quic.frame_type.nci.connection_id.length " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & hf_quic_frame_type_nci_connection_id ,
{ " Connection ID " , " quic.frame_type.nci.connection_id " ,
2018-04-23 21:00:53 +00:00
FT_BYTES , BASE_NONE , NULL , 0x0 ,
2017-06-23 05:45:10 +00:00
NULL , HFILL }
} ,
2017-09-01 14:06:22 +00:00
{ & hf_quic_frame_type_nci_stateless_reset_token ,
{ " Stateless Reset Token " , " quic.frame_type.stateless_reset_token " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2017-09-01 14:29:23 +00:00
/* STOP_SENDING */
{ & hf_quic_frame_type_ss_stream_id ,
{ " Stream ID " , " quic.frame_type.ss.stream_id " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2017-09-01 14:29:23 +00:00
" Stream ID of the stream being ignored " , HFILL }
} ,
2017-11-15 06:20:36 +00:00
{ & hf_quic_frame_type_ss_application_error_code ,
{ " Application Error code " , " quic.frame_type.ss.application_error_code " ,
FT_UINT16 , BASE_DEC | BASE_EXT_STRING , & quic_error_code_vals_ext , 0x0 ,
" Indicates why the sender is ignoring the stream " , HFILL }
} ,
2017-09-01 14:29:23 +00:00
2018-09-12 23:04:48 +00:00
/* CRYPTO */
2018-09-15 14:06:30 +00:00
{ & hf_quic_frame_type_crypto_offset ,
{ " Offset " , " quic.frame_type.crypto.offset " ,
2018-09-12 23:04:48 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Byte offset into the stream " , HFILL }
} ,
2018-09-15 14:06:30 +00:00
{ & hf_quic_frame_type_crypto_length ,
{ " Length " , " quic.frame_type.crypto.length " ,
2018-09-12 23:04:48 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Length of the Crypto Data field " , HFILL }
} ,
2018-09-15 14:06:30 +00:00
{ & hf_quic_frame_type_crypto_crypto_data ,
{ " Crypto Data " , " quic.frame_type.crypto.crypto_data " ,
2018-09-12 23:04:48 +00:00
FT_NONE , BASE_NONE , NULL , 0x0 ,
" The cryptographic message data " , HFILL }
} ,
2018-09-17 15:22:06 +00:00
/* NEW_TOKEN */
{ & hf_quic_frame_type_nt_length ,
{ " (Token) Length " , " quic.frame_type.nt.length " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Specifying the length of the token " , HFILL }
} ,
{ & hf_quic_frame_type_nt_token ,
{ " Token " , " quic.frame_type.nt.token " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" An opaque blob that the client may use with a future Initial packet " , HFILL }
} ,
/* ACK_ECN */
{ & hf_quic_frame_type_ae_largest_acknowledged ,
{ " Largest Acknowledged " , " quic.frame_type.ae.largest_acknowledged " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Representing the largest packet number the peer is acknowledging in this packet " , HFILL }
} ,
{ & hf_quic_frame_type_ae_ack_delay ,
{ " ACK Delay " , " quic.frame_type.ae.ack_delay " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" The time from when the largest acknowledged packet, as indicated in the Largest Acknowledged field, was received by this peer to when this ACK was sent " , HFILL }
} ,
{ & hf_quic_frame_type_ae_ect0_count ,
{ " ECT(0) Count " , " quic.frame_type.ae.ect0_count " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Representing the total number packets received with the ECT(0) codepoint " , HFILL }
} ,
{ & hf_quic_frame_type_ae_ect1_count ,
{ " ECT(1) Count " , " quic.frame_type.ae.ect1_count " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Representing the total number packets received with the ECT(1) codepoint " , HFILL }
} ,
{ & hf_quic_frame_type_ae_ecn_ce_count ,
{ " CE Count " , " quic.frame_type.ae.ecn_ce_count " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Representing the total number packets received with the CE codepoint " , HFILL }
} ,
{ & hf_quic_frame_type_ae_ack_block_count ,
{ " ACK Block Count " , " quic.frame_type.ae.ack_block_count " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" The number of Additional ACK Block (and Gap) fields after the First ACK Block " , HFILL }
} ,
{ & hf_quic_frame_type_ae_fab ,
{ " First ACK Block " , " quic.frame_type.ack.fab " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicates the number of contiguous additional packets being acknowledged starting at the Largest Acknowledged " , HFILL }
} ,
{ & hf_quic_frame_type_ae_gap ,
{ " Gap " , " quic.frame_type.ae.gap " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the number of contiguous unacknowledged packets preceding the packet number one lower than the smallest in the preceding ACK Block " , HFILL }
} ,
{ & hf_quic_frame_type_ae_ack_block ,
{ " ACK Block " , " quic.frame_type.ae.ack_block " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the number of contiguous acknowledged packets preceding the largest packet number, as determined by the preceding Gap " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
} ;
static gint * ett [ ] = {
& ett_quic ,
2018-04-23 14:53:40 +00:00
& ett_quic_connection_info ,
2017-06-23 05:45:10 +00:00
& ett_quic_ft ,
& ett_quic_ftflags
} ;
static ei_register_info ei [ ] = {
2018-04-23 14:53:40 +00:00
{ & ei_quic_connection_unknown ,
{ " quic.connection.unknown " , PI_PROTOCOL , PI_NOTE ,
" Unknown QUIC connection. Missing Initial Packet or migrated connection? " , EXPFILL }
} ,
2017-06-23 05:45:10 +00:00
{ & ei_quic_ft_unknown ,
{ " quic.ft.unknown " , PI_UNDECODED , PI_NOTE ,
" Unknown Frame Type " , EXPFILL }
2017-11-15 07:27:27 +00:00
} ,
{ & ei_quic_decryption_failed ,
{ " quic.decryption_failed " , PI_DECRYPTION , PI_WARN ,
" Failed to decrypt handshake " , EXPFILL }
} ,
2018-04-17 21:56:26 +00:00
{ & ei_quic_protocol_violation ,
{ " quic.protocol_violation " , PI_PROTOCOL , PI_WARN ,
" Invalid data according to the protocol " , EXPFILL }
} ,
2017-06-23 05:45:10 +00:00
} ;
2018-02-07 16:14:35 +00:00
proto_quic = proto_register_protocol ( " QUIC IETF " , " QUIC " , " quic " ) ;
2017-06-23 05:45:10 +00:00
proto_register_field_array ( proto_quic , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
expert_quic = expert_register_protocol ( proto_quic ) ;
expert_register_field_array ( expert_quic , ei , array_length ( ei ) ) ;
quic_handle = register_dissector ( " quic " , dissect_quic , proto_quic ) ;
2018-04-21 12:18:03 +00:00
register_init_routine ( quic_init ) ;
register_cleanup_routine ( quic_cleanup ) ;
2017-06-23 05:45:10 +00:00
}
void
proto_reg_handoff_quic ( void )
{
2018-09-13 08:29:29 +00:00
tls13_handshake_handle = find_dissector ( " tls13-handshake " ) ;
2018-02-28 07:04:25 +00:00
dissector_add_uint_with_preference ( " udp.port " , 0 , quic_handle ) ;
heur_dissector_add ( " udp " , dissect_quic_heur , " QUIC " , " quic " , proto_quic , HEURISTIC_ENABLE ) ;
2017-06-23 05:45:10 +00:00
}
/*
* Editor modelines - https : //www.wireshark.org/tools/modelines.html
*
* Local variables :
* c - basic - offset : 4
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/