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
2019-04-24 06:07:27 +00:00
* https : //tools.ietf.org/html/draft-ietf-quic-transport-20
* https : //tools.ietf.org/html/draft-ietf-quic-tls-20
* https : //tools.ietf.org/html/draft-ietf-quic-invariants-04
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>
2018-09-14 15:30:31 +00:00
# include "packet-tls-utils.h"
# include "packet-tls.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 ;
2019-01-21 00:10:31 +00:00
static int hf_quic_long_reserved = - 1 ;
static int hf_quic_packet_number_length = - 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 ;
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 ;
2019-01-21 00:45:09 +00:00
static int hf_quic_fixed_bit = - 1 ;
static int hf_quic_spin_bit = - 1 ;
2018-09-15 09:55:21 +00:00
static int hf_quic_short_reserved = - 1 ;
2019-01-21 00:45:09 +00:00
static int hf_quic_key_phase = - 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-20 19:44:31 +00:00
static int hf_quic_remaining_payload = - 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 ;
2019-01-21 11:31:16 +00:00
static int hf_quic_padding_length = - 1 ;
static int hf_quic_ack_largest_acknowledged = - 1 ;
static int hf_quic_ack_ack_delay = - 1 ;
2019-01-23 10:50:31 +00:00
static int hf_quic_ack_ack_range_count = - 1 ;
static int hf_quic_ack_first_ack_range = - 1 ;
2019-01-21 11:31:16 +00:00
static int hf_quic_ack_gap = - 1 ;
2019-01-23 10:50:31 +00:00
static int hf_quic_ack_ack_range = - 1 ;
static int hf_quic_ack_ect0_count = - 1 ;
static int hf_quic_ack_ect1_count = - 1 ;
static int hf_quic_ack_ecn_ce_count = - 1 ;
2019-01-21 11:31:16 +00:00
static int hf_quic_rsts_stream_id = - 1 ;
static int hf_quic_rsts_application_error_code = - 1 ;
2019-01-23 10:32:12 +00:00
static int hf_quic_rsts_final_size = - 1 ;
2019-01-21 11:31:16 +00:00
static int hf_quic_ss_stream_id = - 1 ;
static int hf_quic_ss_application_error_code = - 1 ;
static int hf_quic_crypto_offset = - 1 ;
static int hf_quic_crypto_length = - 1 ;
static int hf_quic_crypto_crypto_data = - 1 ;
static int hf_quic_nt_length = - 1 ;
static int hf_quic_nt_token = - 1 ;
static int hf_quic_stream_fin = - 1 ;
static int hf_quic_stream_len = - 1 ;
static int hf_quic_stream_off = - 1 ;
2019-01-16 20:12:39 +00:00
static int hf_quic_stream_stream_id = - 1 ;
static int hf_quic_stream_offset = - 1 ;
static int hf_quic_stream_length = - 1 ;
static int hf_quic_stream_data = - 1 ;
2019-01-21 11:31:16 +00:00
static int hf_quic_md_maximum_data = - 1 ;
static int hf_quic_msd_stream_id = - 1 ;
static int hf_quic_msd_maximum_stream_data = - 1 ;
static int hf_quic_ms_max_streams = - 1 ;
static int hf_quic_db_stream_data_limit = - 1 ;
static int hf_quic_sdb_stream_id = - 1 ;
static int hf_quic_sdb_stream_data_limit = - 1 ;
static int hf_quic_sb_stream_limit = - 1 ;
static int hf_quic_nci_sequence = - 1 ;
static int hf_quic_nci_connection_id_length = - 1 ;
static int hf_quic_nci_connection_id = - 1 ;
static int hf_quic_nci_stateless_reset_token = - 1 ;
static int hf_quic_rci_sequence = - 1 ;
static int hf_quic_path_challenge_data = - 1 ;
static int hf_quic_path_response_data = - 1 ;
static int hf_quic_cc_error_code = - 1 ;
static int hf_quic_cc_error_code_app = - 1 ;
static int hf_quic_cc_error_code_tls_alert = - 1 ;
static int hf_quic_cc_frame_type = - 1 ;
static int hf_quic_cc_reason_phrase_length = - 1 ;
static int hf_quic_cc_reason_phrase = - 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 ) .
*
* 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 .
*
2019-01-20 18:04:28 +00:00
* QUIC payload decryption requires proper reconstruction of the packet number
* which requires proper header decryption . The different states are :
*
* Packet type Packet number space Secrets
* Long : Initial Initial Initial secrets
* Long : Handshake Handshake Handshake
2019-01-23 10:27:26 +00:00
* Long : 0 - RTT 0 / 1 - RTT ( appdata ) 0 - RTT
2019-01-20 18:04:28 +00:00
* Short header 0 / 1 - RTT ( appdata ) 1 - RTT ( KP0 / KP1 )
*
* Important to note is that Short Header decryption requires TWO ciphers ( one
* for each key phase ) , but that header protection uses only KP0 . Total state
* needed for each peer ( client and server ) :
* - 3 packet number spaces : Initial , Handshake , 0 / 1 - RTT ( appdata ) .
* - 4 header protection ciphers : initial , 0 - RTT , HS , 1 - RTT .
* - 5 payload protection ciphers : initial , 0 - RTT , HS , 1 - RTT ( KP0 ) , 1 - RTT ( KP1 ) .
2018-03-19 23:42:00 +00:00
*/
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 {
2019-01-10 21:25:42 +00:00
// TODO hp_cipher does not change after KeyUpdate, but is still tied to the
// current encryption level (initial, 0rtt, handshake, appdata).
// Maybe move this into quic_info_data (2x) and quic_pp_state?
// See https://tools.ietf.org/html/draft-ietf-quic-tls-17#section-5.4
gcry_cipher_hd_t hp_cipher ; /**< Header protection cipher. */
gcry_cipher_hd_t pp_cipher ; /**< Packet protection cipher. */
2018-09-11 21:27:18 +00:00
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 ;
2019-06-21 22:03:18 +00:00
quic_cipher client_0rtt_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 ;
2019-01-20 18:04:28 +00:00
guint64 max_client_pkn [ 3 ] ; /**< Packet number spaces for Initial, Handshake and appdata. */
guint64 max_server_pkn [ 3 ] ;
2018-04-21 12:18:03 +00:00
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 ;
2019-01-10 21:25:42 +00:00
guint8 pkn_len ; /**< Length of PKN (1/2/3/4) or unknown (0). */
2019-01-20 18:04:28 +00:00
guint8 first_byte ; /**< Decrypted flag byte, valid only if pkn_len is non-zero. */
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 ;
}
2018-12-23 15:57:44 +00:00
#if 0
2018-04-18 16:39:17 +00:00
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-12-23 15:57:44 +00:00
# endif
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 " } ,
2018-09-10 18:48:10 +00:00
{ 0x51303434 , " Google Q044 " } ,
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 " } ,
2018-10-28 15:06:10 +00:00
{ 0xff00000f , " draft-15 " } ,
2018-12-22 17:56:39 +00:00
{ 0xff000010 , " draft-16 " } ,
2019-01-06 08:49:45 +00:00
{ 0xff000011 , " draft-17 " } ,
2019-01-23 10:28:33 +00:00
{ 0xff000012 , " draft-18 " } ,
2019-04-12 02:15:28 +00:00
{ 0xff000013 , " draft-19 " } ,
2019-04-24 00:23:01 +00:00
{ 0xff000014 , " draft-20 " } ,
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 }
} ;
2019-01-20 19:21:38 +00:00
# define SH_KP 0x04
2018-04-18 16:39:17 +00:00
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 }
} ;
2019-01-06 10:13:19 +00:00
# define QUIC_LPT_INITIAL 0x0
2019-01-20 12:18:03 +00:00
# define QUIC_LPT_0RTT 0x1
2019-01-06 10:13:19 +00:00
# define QUIC_LPT_HANDSHAKE 0x2
2019-01-20 12:18:03 +00:00
# define QUIC_LPT_RETRY 0x3
2018-04-21 12:18:03 +00:00
# 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 " } ,
2019-01-23 10:27:26 +00:00
{ QUIC_LPT_0RTT , " 0-RTT " } ,
2017-06-23 05:45:10 +00:00
{ 0 , NULL }
} ;
2019-01-06 08:49:45 +00:00
# define FT_PADDING 0x00
# define FT_PING 0x01
# define FT_ACK 0x02
# define FT_ACK_ECN 0x03
# define FT_RESET_STREAM 0x04
# define FT_STOP_SENDING 0x05
# define FT_CRYPTO 0x06
# define FT_NEW_TOKEN 0x07
# define FT_STREAM_8 0x08
# define FT_STREAM_9 0x09
# define FT_STREAM_A 0x0a
# define FT_STREAM_B 0x0b
# define FT_STREAM_C 0x0c
# define FT_STREAM_D 0x0d
# define FT_STREAM_E 0x0e
# define FT_STREAM_F 0x0f
# define FT_MAX_DATA 0x10
# define FT_MAX_STREAM_DATA 0x11
# define FT_MAX_STREAMS_BIDI 0x12
# define FT_MAX_STREAMS_UNI 0x13
# define FT_DATA_BLOCKED 0x14
# define FT_STREAM_DATA_BLOCKED 0x15
# define FT_STREAMS_BLOCKED_BIDI 0x16
# define FT_STREAMS_BLOCKED_UNI 0x17
# define FT_NEW_CONNECTION_ID 0x18
# define FT_RETIRE_CONNECTION_ID 0x19
# define FT_PATH_CHALLENGE 0x1a
# define FT_PATH_RESPONSE 0x1b
# define FT_CONNECTION_CLOSE_TPT 0x1c
# define FT_CONNECTION_CLOSE_APP 0x1d
2017-06-23 05:45:10 +00:00
2018-10-28 16:07:56 +00:00
static const range_string quic_frame_type_vals [ ] = {
{ 0x00 , 0x00 , " PADDING " } ,
2019-01-06 08:49:45 +00:00
{ 0x01 , 0x01 , " PING " } ,
{ 0x02 , 0x03 , " ACK " } ,
{ 0x04 , 0x04 , " RESET_STREAM " } ,
{ 0x05 , 0x05 , " STOP_SENDING " } ,
{ 0x06 , 0x06 , " CRYPTO " } ,
{ 0x07 , 0x07 , " NEW_TOKEN " } ,
{ 0x08 , 0x0f , " STREAM " } ,
{ 0x10 , 0x10 , " MAX_DATA " } ,
{ 0x11 , 0x11 , " MAX_STREAM_DATA " } ,
{ 0x12 , 0x12 , " MAX_STREAMS (BIDI) " } ,
{ 0x13 , 0x13 , " MAX_STREAMS (UNI) " } ,
{ 0x14 , 0x14 , " DATA_BLOCKED " } ,
{ 0x15 , 0x15 , " STREAM_DATA_BLOCKED " } ,
{ 0x16 , 0x16 , " STREAMS_BLOCKED (BIDI) " } ,
{ 0x16 , 0x17 , " STREAMS_BLOCKED (UNI) " } ,
{ 0x18 , 0x18 , " NEW_CONNECTION_ID " } ,
{ 0x19 , 0x19 , " RETIRE_CONNECTION_ID " } ,
{ 0x1a , 0x1a , " PATH_CHALLENGE " } ,
{ 0x1b , 0x1b , " PATH_RESPONSE " } ,
{ 0x1c , 0x1c , " CONNECTION_CLOSE (Transport) " } ,
{ 0x1d , 0x1d , " CONNECTION_CLOSE (Application) " } ,
2018-10-28 16:07:56 +00:00
{ 0 , 0 , NULL } ,
} ;
2017-06-23 05:45:10 +00:00
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
2018-09-19 10:45:09 +00:00
static const range_string quic_transport_error_code_vals [ ] = {
{ 0x0000 , 0x0000 , " NO_ERROR " } ,
{ 0x0001 , 0x0001 , " INTERNAL_ERROR " } ,
{ 0x0002 , 0x0002 , " SERVER_BUSY " } ,
{ 0x0003 , 0x0003 , " FLOW_CONTROL_ERROR " } ,
{ 0x0004 , 0x0004 , " STREAM_ID_ERROR " } ,
{ 0x0005 , 0x0005 , " STREAM_STATE_ERROR " } ,
2019-01-23 10:32:12 +00:00
{ 0x0006 , 0x0006 , " FINAL_SIZE_ERROR " } ,
2018-09-19 10:45:09 +00:00
{ 0x0007 , 0x0007 , " FRAME_ENCODING_ERROR " } ,
{ 0x0008 , 0x0008 , " TRANSPORT_PARAMETER_ERROR " } ,
2019-04-12 02:15:28 +00:00
{ 0x0009 , 0x0009 , " VERSION_NEGOTIATION_ERROR " } , // removed in draft -19
2018-09-19 10:45:09 +00:00
{ 0x000A , 0x000A , " PROTOCOL_VIOLATION " } ,
{ 0x000C , 0x000C , " INVALID_MIGRATION " } ,
2019-04-24 00:23:01 +00:00
{ 0x000D , 0x000D , " CRYPTO_BUFFER_EXCEEDED " } ,
2018-09-19 10:55:05 +00:00
{ 0x0100 , 0x01FF , " CRYPTO_ERROR " } ,
2018-09-19 10:45:09 +00:00
{ 0 , 0 , NULL }
2017-06-23 05:45:10 +00:00
} ;
2018-09-19 10:35:12 +00:00
static const value_string quic_application_error_code_vals [ ] = {
{ 0x0000 , " STOPPING " } ,
{ 0 , NULL }
} ;
2019-01-21 00:10:31 +00:00
static const value_string quic_packet_number_lengths [ ] = {
{ 0 , " 1 bytes " } ,
{ 1 , " 2 bytes " } ,
{ 2 , " 3 bytes " } ,
{ 3 , " 4 bytes " } ,
{ 0 , NULL }
} ;
static void
quic_extract_header ( tvbuff_t * tvb , guint8 * long_packet_type , guint32 * version ,
quic_cid_t * dcid , quic_cid_t * scid ) ;
2018-09-15 15:23:45 +00:00
static void
quic_cipher_reset ( quic_cipher * cipher )
{
2019-01-10 21:25:42 +00:00
gcry_cipher_close ( cipher - > hp_cipher ) ;
2018-09-15 15:23:45 +00:00
gcry_cipher_close ( cipher - > pp_cipher ) ;
memset ( cipher , 0 , sizeof ( * cipher ) ) ;
}
2019-01-21 14:22:32 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
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 ;
}
2019-01-10 21:25:42 +00:00
/**
* Given a header protection cipher , a buffer and the packet number offset ,
* return the unmasked first byte and packet number .
*/
static gboolean
quic_decrypt_header ( tvbuff_t * tvb , guint pn_offset , gcry_cipher_hd_t hp_cipher , int hp_cipher_algo ,
guint8 * first_byte , guint32 * pn )
2018-09-12 14:11:49 +00:00
{
2019-01-10 21:25:42 +00:00
gcry_cipher_hd_t h = hp_cipher ;
if ( ! hp_cipher ) {
2018-09-12 14:11:49 +00:00
// need to know the cipher.
2019-01-10 21:25:42 +00:00
return FALSE ;
2018-09-12 14:11:49 +00:00
}
2019-01-10 21:25:42 +00:00
// Sample is always 16 bytes and starts after PKN (assuming length 4).
// https://tools.ietf.org/html/draft-ietf-quic-tls-17#section-5.4.2
2018-09-12 14:11:49 +00:00
guint8 sample [ 16 ] ;
2019-01-10 21:25:42 +00:00
tvb_memcpy ( tvb , sample , pn_offset + 4 , 16 ) ;
2018-09-12 14:11:49 +00:00
2019-01-10 21:25:42 +00:00
guint8 mask [ 5 ] = { 0 } ;
switch ( hp_cipher_algo ) {
2018-09-12 14:11:49 +00:00
case GCRY_CIPHER_AES128 :
case GCRY_CIPHER_AES256 :
2019-01-10 21:25:42 +00:00
/* Encrypt in-place with AES-ECB and extract the mask. */
if ( gcry_cipher_encrypt ( h , sample , sizeof ( sample ) , NULL , 0 ) ) {
return FALSE ;
2018-09-12 14:11:49 +00:00
}
2019-01-10 21:25:42 +00:00
memcpy ( mask , sample , sizeof ( mask ) ) ;
2018-09-12 14:11:49 +00:00
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 ) ) {
2019-01-10 21:25:42 +00:00
return FALSE ;
}
/* Apply ChaCha20, encrypt in-place five zero bytes. */
if ( gcry_cipher_encrypt ( h , mask , sizeof ( mask ) , NULL , 0 ) ) {
return FALSE ;
2018-09-12 14:11:49 +00:00
}
break ;
# endif /* HAVE_LIBGCRYPT_CHACHA20 */
default :
2019-01-10 21:25:42 +00:00
return FALSE ;
2018-09-12 14:11:49 +00:00
}
2019-01-10 21:25:42 +00:00
// https://tools.ietf.org/html/draft-ietf-quic-tls-17#section-5.4.1
guint8 packet0 = tvb_get_guint8 ( tvb , 0 ) ;
if ( ( packet0 & 0x80 ) = = 0x80 ) {
// Long header: 4 bits masked
packet0 ^ = mask [ 0 ] & 0x0f ;
} else {
// Short header: 5 bits masked
packet0 ^ = mask [ 0 ] & 0x1f ;
2018-09-12 14:11:49 +00:00
}
2019-01-10 21:25:42 +00:00
guint pkn_len = ( packet0 & 0x03 ) + 1 ;
2018-09-17 17:01:17 +00:00
2019-01-10 21:25:42 +00:00
guint8 pkn_bytes [ 4 ] ;
tvb_memcpy ( tvb , pkn_bytes , pn_offset , pkn_len ) ;
guint32 pkt_pkn = 0 ;
for ( guint i = 0 ; i < pkn_len ; i + + ) {
pkt_pkn | = ( pkn_bytes [ i ] ^ mask [ 1 + i ] ) < < ( 8 * ( pkn_len - 1 - i ) ) ;
2018-09-17 17:01:17 +00:00
}
2019-01-10 21:25:42 +00:00
* first_byte = packet0 ;
* pn = pkt_pkn ;
return TRUE ;
2019-01-11 15:44:29 +00:00
}
2018-09-12 14:11:49 +00:00
2018-03-20 16:36:38 +00:00
/**
2019-01-20 18:04:28 +00:00
* Retrieve the maximum valid packet number space for a peer .
2018-03-20 16:36:38 +00:00
*/
2019-01-20 18:04:28 +00:00
static guint64 *
quic_max_packet_number ( quic_info_data_t * quic_info , gboolean from_server , guint8 first_byte )
2018-03-20 16:36:38 +00:00
{
2019-01-20 18:04:28 +00:00
int pkn_space ;
if ( ( first_byte & 0x80 ) & & ( first_byte & 0x30 ) > > 4 = = QUIC_LPT_INITIAL ) {
// Long header, Initial
pkn_space = 0 ;
} else if ( ( first_byte & 0x80 ) & & ( first_byte & 0x30 ) > > 4 = = QUIC_LPT_HANDSHAKE ) {
// Long header, Handshake
pkn_space = 1 ;
2018-09-12 14:11:49 +00:00
} else {
2019-01-23 10:27:26 +00:00
// Long header (0-RTT) or Short Header (1-RTT appdata).
2019-01-20 18:04:28 +00:00
pkn_space = 2 ;
2018-09-15 09:55:21 +00:00
}
2019-01-20 18:04:28 +00:00
if ( from_server ) {
return & quic_info - > max_server_pkn [ pkn_space ] ;
} else {
return & quic_info - > max_client_pkn [ pkn_space ] ;
2018-09-12 14:11:49 +00:00
}
2019-01-20 18:04:28 +00:00
}
2018-03-20 16:36:38 +00:00
2019-01-20 18:04:28 +00:00
/**
* Calculate the full packet number and store it for later use .
*/
static void
quic_set_full_packet_number ( quic_info_data_t * quic_info , quic_packet_info_t * quic_packet ,
gboolean from_server , guint8 first_byte , guint32 pkn32 )
{
guint pkn_len = ( first_byte & 3 ) + 1 ;
guint64 pkn_full ;
guint64 max_pn = * quic_max_packet_number ( quic_info , from_server , first_byte ) ;
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. */
2019-01-20 18:04:28 +00:00
pkn_full = quic_pkt_adjust_pkt_num ( max_pn , pkn32 , 8 * pkn_len ) ;
quic_packet - > pkn_len = pkn_len ;
quic_packet - > packet_number = pkn_full ;
}
2019-01-21 14:22:32 +00:00
# endif /* !HAVE_LIBGCRYPT_AEAD */
2019-01-20 18:04:28 +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 ;
2019-06-09 05:10:46 +00:00
if ( long_packet_type = = QUIC_LPT_0RTT & & dcid - > len > 0 ) {
// The 0-RTT packet always matches the SCID/DCID of the Client Initial
2018-04-21 12:18:03 +00:00
conn = ( quic_info_data_t * ) wmem_map_lookup ( quic_initial_connections , dcid ) ;
2019-06-09 05:10:46 +00:00
* from_server = FALSE ;
2018-04-21 12:18:03 +00:00
} else {
2019-06-09 05:10:46 +00:00
// Find a connection for Handshake and Server Initial packets by
// matching their DCID against the SCIDs of the original Initial packets
// from the peer. For Client Initial packets, match DCID of the first
// Client Initial (these may contain ACK frames).
2018-04-21 12:18:03 +00:00
conn = quic_connection_find_dcid ( pinfo , dcid , from_server ) ;
2019-06-09 05:10:46 +00:00
if ( long_packet_type = = QUIC_LPT_INITIAL & & conn & & ! * from_server & & dcid - > len > 0 & &
memcmp ( dcid , & conn - > client_dcid_initial , sizeof ( quic_cid_t ) ) & &
! quic_cids_has_match ( & conn - > server_cids , dcid ) ) {
// If the Initial Packet is from the client, it must either match
// the DCID from the first Client Initial, or the DCID that was
// assigned by the server. Otherwise this must be considered a fresh
// Client Initial, for example after the Version Negotiation packet,
// and the connection must be cleared to avoid decryption failure.
conn = NULL ;
}
2018-04-21 12:18:03 +00:00
}
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-19 10:39:09 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
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-09-19 10:39:09 +00:00
# endif
2018-09-18 20:53:00 +00:00
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 ;
2018-09-18 19:40:51 +00:00
guint orig_offset = offset ;
2017-06-23 05:45:10 +00:00
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 ) ;
2018-12-23 08:32:23 +00:00
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 : {
2018-09-17 11:03:52 +00:00
guint32 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-09-17 11:03:52 +00:00
/* A padding frame consists of a single zero octet, but for brevity
* sake let ' s combine multiple zeroes into a single field . */
pad_len = 1 + tvb_skip_guint8 ( tvb , offset , tvb_reported_length_remaining ( tvb , offset ) , ' \0 ' ) - offset ;
2019-01-21 11:31:16 +00:00
ti = proto_tree_add_uint ( ft_tree , hf_quic_padding_length , tvb , offset , 0 , pad_len ) ;
2019-04-03 21:32:30 +00:00
proto_item_set_generated ( ti ) ;
2018-02-07 14:22:52 +00:00
proto_item_append_text ( ti_ft , " Length: %u " , pad_len ) ;
2018-09-17 11:03:52 +00:00
offset + = pad_len - 1 ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
2019-01-16 20:12:39 +00:00
case FT_PING : {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PING " ) ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
2019-01-23 10:50:31 +00:00
case FT_ACK :
case FT_ACK_ECN : {
guint64 ack_range_count ;
2019-01-16 20:12:39 +00:00
guint32 lenvar ;
2017-06-23 05:45:10 +00:00
2019-01-23 10:50:31 +00:00
if ( frame_type = = FT_ACK ) {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , ACK " ) ;
} else {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , ACK_ECN " ) ;
}
2018-03-17 14:53:04 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_largest_acknowledged , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2019-01-06 08:49:45 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_ack_delay , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2017-06-23 05:45:10 +00:00
2019-01-23 10:50:31 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_ack_range_count , tvb , offset , - 1 , ENC_VARINT_QUIC , & ack_range_count , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2018-09-17 14:41:04 +00:00
2019-01-23 10:50:31 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_first_ack_range , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2017-06-23 05:45:10 +00:00
2019-01-23 10:50:31 +00:00
/* ACK Ranges - Repeated "Ack Range Count" */
while ( ack_range_count ) {
2017-06-23 05:45:10 +00:00
2019-01-16 20:12:39 +00:00
/* Gap To Next Block */
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_gap , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2017-06-23 05:45:10 +00:00
2019-01-23 10:50:31 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_ack_range , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2018-03-17 14:53:04 +00:00
2019-01-23 10:50:31 +00:00
ack_range_count - - ;
2019-01-16 20:12:39 +00:00
}
2017-12-31 15:02:12 +00:00
2019-01-23 10:50:31 +00:00
/* ECN Counts. */
if ( frame_type = = FT_ACK_ECN ) {
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_ect0_count , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2017-06-23 05:45:10 +00:00
2019-01-23 10:50:31 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_ect1_count , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2018-03-17 14:53:04 +00:00
2019-01-23 10:50:31 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ack_ecn_ce_count , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & lenvar ) ;
offset + = lenvar ;
2019-01-16 20:12:39 +00:00
}
2018-02-07 14:22:52 +00:00
}
break ;
2019-01-16 20:12:39 +00:00
case FT_RESET_STREAM : {
guint64 stream_id ;
2019-01-23 10:32:12 +00:00
guint32 error_code , len_streamid = 0 , len_finalsize = 0 ;
2018-03-17 14:53:04 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , RS " ) ;
2019-01-06 08:49:45 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_rsts_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , & stream_id , & len_streamid ) ;
2019-01-16 20:12:39 +00:00
offset + = len_streamid ;
2018-04-23 21:00:53 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_rsts_application_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
2019-01-16 20:12:39 +00:00
offset + = 2 ;
2018-04-23 21:00:53 +00:00
2019-01-23 10:32:12 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_rsts_final_size , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_finalsize ) ;
offset + = len_finalsize ;
2017-06-23 05:45:10 +00:00
2019-01-16 20:12:39 +00:00
proto_item_append_text ( ti_ft , " Stream ID: % " G_GINT64_MODIFIER " u, Error code: %s " , stream_id , val_to_str ( error_code , quic_application_error_code_vals , " 0x%04x " ) ) ;
2018-02-07 14:22:52 +00:00
}
break ;
case FT_STOP_SENDING : {
2018-09-19 10:35:12 +00:00
guint32 len_streamid , error_code ;
2017-06-23 05:45:10 +00:00
2018-03-17 14:53:04 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SS " ) ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ss_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
2018-02-07 14:22:52 +00:00
offset + = len_streamid ;
2017-06-23 05:45:10 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_ss_application_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
2018-02-07 14:22:52 +00:00
offset + = 2 ;
2018-09-19 10:35:12 +00:00
proto_item_append_text ( ti_ft , " Error code: 0x%04x " , error_code ) ;
2018-02-07 14:22:52 +00:00
}
break ;
2019-01-16 20:12:39 +00:00
case FT_CRYPTO : {
guint64 crypto_offset , crypto_length ;
2018-12-23 08:32:23 +00:00
guint32 lenvar ;
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , CRYPTO " ) ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_crypto_offset , tvb , offset , - 1 , ENC_VARINT_QUIC , & crypto_offset , & lenvar ) ;
2018-12-23 08:32:23 +00:00
offset + = lenvar ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_crypto_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & crypto_length , & lenvar ) ;
2018-12-23 08:32:23 +00:00
offset + = lenvar ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_crypto_crypto_data , tvb , offset , ( guint32 ) crypto_length , ENC_NA ) ;
2019-01-16 20:12:39 +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 .
*/
2019-04-15 00:30:09 +00:00
call_dissector_with_data ( tls13_handshake_handle , next_tvb , pinfo , ft_tree , GUINT_TO_POINTER ( crypto_offset ) ) ;
2019-01-16 20:12:39 +00:00
col_set_writable ( pinfo - > cinfo , - 1 , TRUE ) ;
2018-02-07 14:22:52 +00:00
}
2019-01-16 20:12:39 +00:00
offset + = ( guint32 ) crypto_length ;
2018-02-07 14:22:52 +00:00
}
break ;
2019-01-16 20:12:39 +00:00
case FT_NEW_TOKEN : {
guint64 token_length ;
guint32 lenvar ;
2018-03-17 14:53:04 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , NT " ) ;
2018-03-17 14:53:04 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_nt_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & token_length , & lenvar ) ;
2019-01-16 20:12:39 +00:00
offset + = lenvar ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_nt_token , tvb , offset , ( guint32 ) token_length , ENC_NA ) ;
2019-01-16 20:12:39 +00:00
offset + = ( guint32 ) token_length ;
2018-04-17 20:41:38 +00:00
}
break ;
2019-01-06 08:49:45 +00:00
case FT_STREAM_8 :
case FT_STREAM_9 :
case FT_STREAM_A :
case FT_STREAM_B :
case FT_STREAM_C :
case FT_STREAM_D :
case FT_STREAM_E :
case FT_STREAM_F : {
2018-02-07 14:22:52 +00:00
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 ) ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ftflags_tree , hf_quic_stream_fin , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( ftflags_tree , hf_quic_stream_len , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( ftflags_tree , hf_quic_stream_off , tvb , offset , 1 , ENC_NA ) ;
2018-02-07 14:22:52 +00:00
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-09-12 23:04:48 +00:00
}
break ;
2019-01-16 20:12:39 +00:00
case FT_MAX_DATA : {
guint32 len_maximumdata ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , MD " ) ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_md_maximum_data , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_maximumdata ) ;
2019-01-16 20:12:39 +00:00
offset + = len_maximumdata ;
2017-06-23 05:45:10 +00:00
}
2018-02-07 14:22:52 +00:00
break ;
2019-01-16 20:12:39 +00:00
case FT_MAX_STREAM_DATA : {
guint32 len_streamid , len_maximumstreamdata ;
2018-09-17 15:22:06 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , MSD " ) ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_msd_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
2019-01-16 20:12:39 +00:00
offset + = len_streamid ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_msd_maximum_stream_data , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_maximumstreamdata ) ;
2019-01-16 20:12:39 +00:00
offset + = len_maximumstreamdata ;
2018-09-17 15:22:06 +00:00
}
break ;
2019-01-16 20:12:39 +00:00
case FT_MAX_STREAMS_BIDI :
case FT_MAX_STREAMS_UNI : {
guint32 len_streamid ;
2018-09-17 15:22:06 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , MS " ) ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_ms_max_streams , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
2019-01-16 20:12:39 +00:00
offset + = len_streamid ;
}
break ;
case FT_DATA_BLOCKED : {
guint32 len_offset ;
2018-09-17 15:22:06 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , DB " ) ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_db_stream_data_limit , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_offset ) ;
2019-01-16 20:12:39 +00:00
offset + = len_offset ;
}
break ;
case FT_STREAM_DATA_BLOCKED : {
guint32 len_streamid , len_offset ;
2018-09-17 15:22:06 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SDB " ) ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_sdb_stream_id , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
2019-01-16 20:12:39 +00:00
offset + = len_streamid ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_sdb_stream_data_limit , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_offset ) ;
2019-01-16 20:12:39 +00:00
offset + = len_offset ;
}
break ;
case FT_STREAMS_BLOCKED_BIDI :
case FT_STREAMS_BLOCKED_UNI : {
guint32 len_streamid ;
2018-09-17 15:22:06 +00:00
2019-01-16 20:12:39 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , SB " ) ;
2018-09-17 15:22:06 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_sb_stream_limit , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_streamid ) ;
2019-01-16 20:12:39 +00:00
offset + = len_streamid ;
}
break ;
case FT_NEW_CONNECTION_ID : {
guint32 len_sequence ;
guint32 nci_length ;
gboolean valid_cid = FALSE ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , NCI " ) ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_nci_sequence , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_sequence ) ;
2019-01-16 20:12:39 +00:00
offset + = len_sequence ;
2019-01-21 11:31:16 +00:00
ti = proto_tree_add_item_ret_uint ( ft_tree , hf_quic_nci_connection_id_length , tvb , offset , 1 , ENC_BIG_ENDIAN , & nci_length ) ;
2019-01-16 20:12:39 +00:00
offset + + ;
valid_cid = nci_length > = 4 & & nci_length < = 18 ;
if ( ! valid_cid ) {
expert_add_info_format ( pinfo , ti , & ei_quic_protocol_violation ,
" Connection ID Length must be between 4 and 18 bytes " ) ;
2018-09-17 15:22:06 +00:00
}
2018-10-28 16:07:56 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_nci_connection_id , tvb , offset , nci_length , ENC_NA ) ;
2019-01-16 20:12:39 +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 ) ;
}
offset + = nci_length ;
2018-10-28 16:07:56 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_nci_stateless_reset_token , tvb , offset , 16 , ENC_NA ) ;
2019-01-16 20:12:39 +00:00
offset + = 16 ;
}
break ;
case FT_RETIRE_CONNECTION_ID : {
guint32 len_sequence ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_rci_sequence , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_sequence ) ;
2019-01-16 20:12:39 +00:00
offset + = len_sequence ;
}
break ;
case FT_PATH_CHALLENGE : {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PC " ) ;
2018-10-28 16:07:56 +00:00
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_path_challenge_data , tvb , offset , 8 , ENC_NA ) ;
2019-01-16 20:12:39 +00:00
offset + = 8 ;
}
break ;
case FT_PATH_RESPONSE : {
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PR " ) ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_path_response_data , tvb , offset , 8 , ENC_NA ) ;
2019-01-16 20:12:39 +00:00
offset + = 8 ;
}
break ;
case FT_CONNECTION_CLOSE_TPT :
case FT_CONNECTION_CLOSE_APP : {
guint32 len_reasonphrase , len_frametype , error_code ;
guint64 len_reason = 0 ;
const char * tls_alert = NULL ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , CC " ) ;
if ( frame_type = = FT_CONNECTION_CLOSE_TPT ) {
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_cc_error_code , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
2019-01-16 20:12:39 +00:00
if ( ( error_code & 0xff00 ) = = 0x0100 ) { // CRYPTO_ERROR
tls_alert = try_val_to_str ( error_code & 0xff , ssl_31_alert_description ) ;
if ( tls_alert ) {
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_cc_error_code_tls_alert , tvb , offset + 1 , 1 , ENC_BIG_ENDIAN ) ;
2019-01-16 20:12:39 +00:00
}
}
offset + = 2 ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_cc_frame_type , tvb , offset , - 1 , ENC_VARINT_QUIC , NULL , & len_frametype ) ;
2019-01-16 20:12:39 +00:00
offset + = len_frametype ;
} else { /* FT_CONNECTION_CLOSE_APP) */
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_uint ( ft_tree , hf_quic_cc_error_code_app , tvb , offset , 2 , ENC_BIG_ENDIAN , & error_code ) ;
2019-01-16 20:12:39 +00:00
offset + = 2 ;
}
2019-01-21 11:31:16 +00:00
proto_tree_add_item_ret_varint ( ft_tree , hf_quic_cc_reason_phrase_length , tvb , offset , - 1 , ENC_VARINT_QUIC , & len_reason , & len_reasonphrase ) ;
2019-01-16 20:12:39 +00:00
offset + = len_reasonphrase ;
2019-01-21 11:31:16 +00:00
proto_tree_add_item ( ft_tree , hf_quic_cc_reason_phrase , tvb , offset , ( guint32 ) len_reason , ENC_ASCII | ENC_NA ) ;
2019-01-16 20:12:39 +00:00
offset + = ( guint32 ) len_reason ;
proto_item_append_text ( ti_ft , " Error code: %s " , rval_to_str ( error_code , quic_transport_error_code_vals , " Unknown (%d) " ) ) ;
if ( tls_alert ) {
proto_item_append_text ( ti_ft , " (%s) " , tls_alert ) ;
}
2018-09-17 15:22:06 +00:00
}
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
}
2018-09-18 19:40:51 +00:00
proto_item_set_len ( ti_ft , offset - orig_offset ) ;
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 gboolean
2019-01-20 23:19:11 +00:00
quic_cipher_init ( 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
2019-01-10 21:25:42 +00:00
quic_decrypt_message ( quic_cipher * cipher , tvbuff_t * head , guint header_length ,
guint8 first_byte , 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 ) ;
2019-01-10 21:25:42 +00:00
// copy header, but replace encrypted first byte and PKN by plaintext.
2018-09-17 11:11:23 +00:00
header = ( guint8 * ) tvb_memdup ( wmem_packet_scope ( ) , head , 0 , header_length ) ;
2019-01-10 21:25:42 +00:00
header [ 0 ] = first_byte ;
for ( guint i = 0 ; i < pkn_len ; i + + ) {
header [ header_length - 1 - i ] = ( guint8 ) ( packet_number > > ( 8 * i ) ) ;
}
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 ;
2019-01-10 21:25:42 +00:00
if ( tls13_hkdf_expand_label ( hash_algo , & secret_si , " tls13 " , label , out_len , & out_mem ) ) {
2018-09-12 21:49:15 +00:00
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
{
/*
2019-01-10 21:25:42 +00:00
* https : //tools.ietf.org/html/draft-ietf-quic-tls-17#section-5.2
2018-09-12 21:49:15 +00:00
*
2019-01-10 21:25:42 +00:00
* initial_salt = 0xef4fb0abb47470c41befcf8031334fae485e09a0
2018-09-12 21:49:15 +00:00
* 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 ] = {
2019-01-10 21:25:42 +00:00
0xef , 0x4f , 0xb0 , 0xab , 0xb4 , 0x74 , 0x70 , 0xc4 , 0x1b , 0xef ,
0xcf , 0x80 , 0x31 , 0x33 , 0x4f , 0xae , 0x48 , 0x5e , 0x09 , 0xa0
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 .
2019-01-10 21:25:42 +00:00
* See https : //tools.ietf.org/html/draft-ietf-quic-tls-17#section-5.4.3
2018-09-12 14:11:49 +00:00
*/
static gboolean
2019-01-10 21:25:42 +00:00
quic_get_pn_cipher_algo ( int cipher_algo , int * hp_cipher_mode )
2018-09-12 14:11:49 +00:00
{
switch ( cipher_algo ) {
case GCRY_CIPHER_AES128 :
case GCRY_CIPHER_AES256 :
2019-01-10 21:25:42 +00:00
* hp_cipher_mode = GCRY_CIPHER_MODE_ECB ;
2018-09-12 14:11:49 +00:00
return TRUE ;
# ifdef HAVE_LIBGCRYPT_CHACHA20
case GCRY_CIPHER_CHACHA20 :
2019-01-20 16:36:17 +00:00
* hp_cipher_mode = GCRY_CIPHER_MODE_STREAM ;
2018-09-12 14:11:49 +00:00
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
2019-01-20 23:19:11 +00:00
quic_cipher_prepare ( 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
2019-01-10 21:25:42 +00:00
int hp_cipher_mode ;
if ( ! quic_get_pn_cipher_algo ( cipher_algo , & hp_cipher_mode ) ) {
2018-09-15 15:23:45 +00:00
* error = " Unsupported cipher algorithm " ;
2017-11-15 06:41:45 +00:00
return FALSE ;
}
2019-01-10 21:25:42 +00:00
if ( gcry_cipher_open ( & cipher - > hp_cipher , cipher_algo , hp_cipher_mode , 0 ) | |
2018-09-15 15:23:45 +00:00
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 ) ;
2019-01-20 23:19:11 +00:00
if ( ! quic_cipher_init ( cipher , hash_algo , cipher_keylen , secret ) ) {
2018-09-15 15:23:45 +00:00
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 ] ;
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 . */
2019-01-20 23:19:11 +00:00
if ( ! quic_cipher_prepare ( & 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 ) | |
2019-01-20 23:19:11 +00:00
! quic_cipher_prepare ( & 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
2019-06-21 22:03:18 +00:00
static gboolean
quic_create_0rtt_decoder ( guint i , gchar * early_data_secret , guint early_data_secret_len ,
quic_cipher * cipher , int * cipher_algo )
{
static const guint16 tls13_ciphers [ ] = {
0x1301 , /* TLS_AES_128_GCM_SHA256 */
0x1302 , /* TLS_AES_256_GCM_SHA384 */
0x1303 , /* TLS_CHACHA20_POLY1305_SHA256 */
0x1304 , /* TLS_AES_128_CCM_SHA256 */
0x1305 , /* TLS_AES_128_CCM_8_SHA256 */
} ;
if ( i > = G_N_ELEMENTS ( tls13_ciphers ) ) {
// end of list
return FALSE ;
}
int cipher_mode = 0 , hash_algo = 0 ;
const char * error_ignored = NULL ;
if ( tls_get_cipher_info ( NULL , tls13_ciphers [ i ] , cipher_algo , & cipher_mode , & hash_algo ) ) {
guint hash_len = gcry_md_get_algo_dlen ( hash_algo ) ;
if ( hash_len = = early_data_secret_len & & quic_cipher_prepare ( cipher , hash_algo , * cipher_algo , cipher_mode , early_data_secret , & error_ignored ) ) {
return TRUE ;
}
}
/* This cipher failed, but there are more to try. */
quic_cipher_reset ( cipher ) ;
return TRUE ;
}
2018-09-15 23:07:21 +00:00
static gboolean
2019-01-20 23:19:11 +00:00
quic_create_decoders ( packet_info * pinfo , quic_info_data_t * quic_info , quic_cipher * cipher ,
2018-09-15 23:07:21 +00:00
gboolean from_server , TLSRecordType type , const char * * error )
{
if ( ! quic_info - > hash_algo ) {
2019-06-21 22:03:18 +00:00
if ( ! tls_get_cipher_info ( pinfo , 0 , & quic_info - > cipher_algo , & quic_info - > cipher_mode , & quic_info - > hash_algo ) ) {
2018-09-15 23:07:21 +00:00
* 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 ) ) {
2018-09-20 19:44:31 +00:00
* error = " Secrets are not available " ;
2018-09-15 23:07:21 +00:00
return FALSE ;
}
2019-01-20 23:19:11 +00:00
if ( ! quic_cipher_prepare ( cipher , quic_info - > hash_algo ,
2018-09-15 23:07:21 +00:00
quic_info - > cipher_algo , quic_info - > cipher_mode , secret , error ) ) {
return FALSE ;
}
return TRUE ;
}
/**
* 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
2019-01-20 23:19:11 +00:00
quic_cipher_init ( 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. */
2019-01-10 21:25:42 +00:00
guchar hp_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
2019-01-10 21:25:42 +00:00
if ( ! quic_hkdf_expand_label ( hash_algo , secret , hash_len , " quic key " , write_key , key_length ) | |
! quic_hkdf_expand_label ( hash_algo , secret , hash_len , " quic iv " , cipher - > pp_iv , sizeof ( cipher - > pp_iv ) ) | |
! quic_hkdf_expand_label ( hash_algo , secret , hash_len , " quic hp " , hp_key , key_length ) ) {
2018-09-17 17:39:32 +00:00
return FALSE ;
2018-03-19 23:42:00 +00:00
}
2019-01-10 21:25:42 +00:00
return gcry_cipher_setkey ( cipher - > hp_cipher , hp_key , key_length ) = = 0 & &
2018-09-12 14:11:49 +00:00
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
2019-05-20 15:44:07 +00:00
quic_update_key ( int hash_algo , quic_pp_state_t * pp_state )
2018-03-19 23:42:00 +00:00
{
guint hash_len = gcry_md_get_algo_dlen ( hash_algo ) ;
2019-05-20 15:44:07 +00:00
gboolean ret = quic_hkdf_expand_label ( hash_algo , pp_state - > next_secret , hash_len ,
" traffic upd " , pp_state - > next_secret , hash_len ) ;
/* This must always succeed as our hash algorithm was already validated. */
DISSECTOR_ASSERT ( ret ) ;
2018-03-19 23:42:00 +00:00
}
/**
2019-01-20 19:21:38 +00:00
* Retrieves the header protection cipher for short header packets and prepares
* the packet protection cipher .
2018-03-19 23:42:00 +00:00
*/
2019-01-20 19:21:38 +00:00
static gcry_cipher_hd_t
quic_get_1rtt_hp_cipher ( packet_info * pinfo , quic_info_data_t * quic_info , gboolean from_server )
2018-03-19 23:42:00 +00:00
{
2018-09-15 15:23:45 +00:00
const char * error = NULL ;
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. */
2019-06-21 22:03:18 +00:00
if ( ! tls_get_cipher_info ( pinfo , 0 , & 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
}
2019-05-20 15:44:07 +00:00
// Create initial cipher handles for KEY_PHASE 0 using the 1-RTT keys.
2019-01-20 23:19:11 +00:00
if ( ! quic_cipher_prepare ( & client_pp - > cipher [ 0 ] , quic_info - > hash_algo ,
2018-09-15 15:23:45 +00:00
quic_info - > cipher_algo , quic_info - > cipher_mode , client_pp - > next_secret , & error ) | |
2019-01-20 23:19:11 +00:00
! quic_cipher_prepare ( & server_pp - > cipher [ 0 ] , quic_info - > hash_algo ,
2018-09-15 15:23:45 +00:00
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 ;
}
2019-05-20 15:44:07 +00:00
// Rotate the 1-RTT key for the client and server for the next key update.
quic_update_key ( quic_info - > hash_algo , client_pp ) ;
quic_update_key ( quic_info - > hash_algo , server_pp ) ;
2018-03-19 23:42:00 +00:00
}
2019-01-20 19:21:38 +00:00
// Note: Header Protect cipher does not change after Key Update.
return pp_state - > cipher [ 0 ] . hp_cipher ;
}
/**
* Tries to construct the appropriate cipher for the current key phase .
* See also " PROTECTED PAYLOAD DECRYPTION " comment on top of this file .
*/
static quic_cipher *
quic_get_pp_cipher ( gboolean key_phase , quic_info_data_t * quic_info , gboolean from_server )
{
const char * error = NULL ;
gboolean success = FALSE ;
/* 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 ;
quic_pp_state_t * pp_state = ! from_server ? client_pp : server_pp ;
2019-01-10 21:25:42 +00:00
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 ) .
2019-05-20 15:44:07 +00:00
* ' ! ! ' is due to key_phase being a signed bitfield , it forces - 1 into 1.
2018-03-19 23:42:00 +00:00
*/
2019-05-20 15:44:07 +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 ) ) ;
2019-01-20 23:19:11 +00:00
if ( ! quic_cipher_prepare ( & new_cipher , quic_info - > hash_algo ,
2019-05-20 15:44:07 +00:00
quic_info - > cipher_algo , quic_info - > cipher_mode , pp_state - > next_secret , & error ) ) {
2018-09-15 15:23:45 +00:00
/* 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 ;
2019-05-20 15:44:07 +00:00
quic_update_key ( quic_info - > hash_algo , pp_state ) ;
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 ,
2019-01-10 21:25:42 +00:00
quic_cipher * cipher , guint8 first_byte , 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 ) {
2019-01-10 21:25:42 +00:00
quic_decrypt_message ( cipher , tvb , offset , first_byte , 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_ ,
2019-01-10 21:25:42 +00:00
quic_cipher * cipher _U_ , guint8 first_byte _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 ) ;
2019-04-03 21:32:30 +00:00
proto_item_set_generated ( pi ) ;
2018-04-23 14:53:40 +00:00
#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 ;
}
2019-05-08 17:33:58 +00:00
/* Retry Packet dissection */
2018-09-16 22:50:08 +00:00
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 ;
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 ) ;
2018-12-22 17:57:29 +00:00
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 ;
2019-05-08 17:33:58 +00:00
col_set_str ( pinfo - > cinfo , COL_INFO , " Retry " ) ;
offset = dissect_quic_long_header_common ( tvb , pinfo , quic_tree , offset , quic_packet , & version , & dcid , & scid ) ;
2018-09-16 22:50:08 +00:00
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 ;
2019-01-21 00:10:31 +00:00
guint8 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 ;
2019-01-10 21:25:42 +00:00
guint8 first_byte = 0 ;
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
2019-01-21 00:10:31 +00:00
quic_extract_header ( tvb , & long_packet_type , & version , & dcid , & scid ) ;
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 ;
2019-06-21 22:03:18 +00:00
} else if ( long_packet_type = = QUIC_LPT_0RTT & & ! from_server ) {
cipher = & conn - > client_0rtt_cipher ;
2018-09-15 23:07:21 +00:00
} else if ( long_packet_type = = QUIC_LPT_HANDSHAKE ) {
cipher = ! from_server ? & conn - > client_handshake_cipher : & conn - > server_handshake_cipher ;
}
}
2019-01-21 00:10:31 +00:00
/* Prepare the Initial/Handshake cipher for header/payload decryption. */
if ( ! PINFO_FD_VISITED ( pinfo ) & & conn & & cipher ) {
2019-06-21 22:03:18 +00:00
# define DIGEST_MAX_SIZE 48 /* SHA384 */
2018-09-11 15:41:24 +00:00
const gchar * error = NULL ;
2019-06-21 22:03:18 +00:00
gchar early_data_secret [ DIGEST_MAX_SIZE ] ;
guint early_data_secret_len = 0 ;
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 ) ;
2019-06-21 22:03:18 +00:00
} else if ( long_packet_type = = QUIC_LPT_0RTT ) {
early_data_secret_len = tls13_get_quic_secret ( pinfo , FALSE , TLS_SECRET_0RTT_APP , DIGEST_MAX_SIZE , early_data_secret ) ;
if ( early_data_secret_len = = 0 ) {
error = " Secrets are not available " ;
}
2018-09-17 17:39:32 +00:00
} else if ( long_packet_type = = QUIC_LPT_HANDSHAKE ) {
2019-01-10 21:25:42 +00:00
if ( ! cipher - > hp_cipher ) {
2019-01-20 23:19:11 +00:00
quic_create_decoders ( pinfo , conn , cipher , from_server , TLS_SECRET_HANDSHAKE , & error ) ;
2018-09-15 23:07:21 +00:00
}
}
2019-01-21 00:10:31 +00:00
if ( ! error ) {
guint32 pkn32 = 0 ;
int hp_cipher_algo = long_packet_type ! = QUIC_LPT_INITIAL & & conn ? conn - > cipher_algo : GCRY_CIPHER_AES128 ;
guint pn_offset = 6 + dcid . len + scid . len ;
if ( long_packet_type = = QUIC_LPT_INITIAL ) {
pn_offset + = tvb_get_varint ( tvb , pn_offset , 8 , & token_length , ENC_VARINT_QUIC ) ;
pn_offset + = ( guint ) token_length ;
}
pn_offset + = tvb_get_varint ( tvb , pn_offset , 8 , & payload_length , ENC_VARINT_QUIC ) ;
2019-06-21 22:03:18 +00:00
// Assume failure unless proven otherwise.
error = " Header deprotection failed " ;
if ( long_packet_type ! = QUIC_LPT_0RTT ) {
if ( quic_decrypt_header ( tvb , pn_offset , cipher - > hp_cipher , hp_cipher_algo , & first_byte , & pkn32 ) ) {
error = NULL ;
}
} else {
// Cipher is not stored with 0-RTT data or key, perform trial decryption.
for ( guint i = 0 ; quic_create_0rtt_decoder ( i , early_data_secret , early_data_secret_len , cipher , & hp_cipher_algo ) ; i + + ) {
if ( cipher - > hp_cipher & & quic_decrypt_header ( tvb , pn_offset , cipher - > hp_cipher , hp_cipher_algo , & first_byte , & pkn32 ) ) {
error = NULL ;
break ;
}
}
}
if ( ! error ) {
2019-01-21 00:10:31 +00:00
quic_set_full_packet_number ( conn , quic_packet , from_server , first_byte , pkn32 ) ;
quic_packet - > first_byte = first_byte ;
}
}
2018-09-15 23:07:21 +00:00
if ( error ) {
2018-09-11 15:41:24 +00:00
quic_packet - > decryption . error = wmem_strdup ( wmem_file_scope ( ) , error ) ;
}
2019-02-11 16:12:02 +00:00
} else if ( conn & & quic_packet - > pkn_len ) {
first_byte = quic_packet - > first_byte ;
2018-09-11 15:41:24 +00:00
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2019-01-21 00:10:31 +00:00
2019-01-21 00:45:09 +00:00
proto_tree_add_item ( quic_tree , hf_quic_fixed_bit , tvb , offset , 1 , ENC_NA ) ;
2019-01-23 13:12:35 +00:00
proto_tree_add_item ( quic_tree , hf_quic_long_packet_type , tvb , offset , 1 , ENC_NA ) ;
2019-01-21 00:10:31 +00:00
if ( quic_packet - > pkn_len ) {
proto_tree_add_uint ( quic_tree , hf_quic_long_reserved , tvb , offset , 1 , first_byte ) ;
proto_tree_add_uint ( quic_tree , hf_quic_packet_number_length , tvb , offset , 1 , first_byte ) ;
}
offset + = 1 ;
col_set_str ( pinfo - > cinfo , COL_INFO , val_to_str_const ( long_packet_type , quic_long_packet_type_vals , " Long Header " ) ) ;
offset = dissect_quic_long_header_common ( tvb , pinfo , quic_tree , offset , quic_packet , NULL , & dcid , & scid ) ;
if ( long_packet_type = = QUIC_LPT_INITIAL ) {
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 ) ;
offset + = len_payload_length ;
2018-09-20 19:44:31 +00:00
if ( quic_packet - > decryption . error ) {
expert_add_info_format ( pinfo , quic_tree , & ei_quic_decryption_failed ,
" Failed to create decryption context: %s " , quic_packet - > decryption . error ) ;
return offset ;
}
2019-01-20 18:04:28 +00:00
if ( ! conn | | quic_packet - > pkn_len = = 0 ) {
// if not part of a connection, the full PKN cannot be reconstructed.
expert_add_info_format ( pinfo , quic_tree , & ei_quic_decryption_failed , " Failed to decrypt packet number " ) ;
2018-09-12 14:11:49 +00:00
return offset ;
}
2019-01-20 18:04:28 +00:00
2019-01-21 00:19:32 +00:00
proto_tree_add_uint64 ( quic_tree , hf_quic_packet_number , tvb , offset , quic_packet - > pkn_len , quic_packet - > packet_number ) ;
2019-01-20 18:04:28 +00:00
offset + = quic_packet - > pkn_len ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PKN: % " G_GINT64_MODIFIER " u " , quic_packet - > packet_number ) ;
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 ,
2019-01-20 18:04:28 +00:00
conn , quic_packet , from_server , cipher , first_byte , quic_packet - > pkn_len ) ;
}
2019-01-21 14:22:32 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
2019-01-20 18:04:28 +00:00
if ( ! PINFO_FD_VISITED ( pinfo ) & & ! quic_packet - > decryption . error ) {
// Packet number is verified to be valid, remember it.
* quic_max_packet_number ( conn , from_server , first_byte ) = quic_packet - > packet_number ;
2017-06-23 05:45:10 +00:00
}
2019-01-21 14:22:32 +00:00
# endif /* !HAVE_LIBGCRYPT_AEAD */
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 } ;
2019-01-10 21:25:42 +00:00
guint8 first_byte = 0 ;
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
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
}
2019-01-20 19:21:38 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
if ( ! PINFO_FD_VISITED ( pinfo ) & & conn ) {
2019-01-21 14:22:32 +00:00
guint32 pkn32 = 0 ;
gcry_cipher_hd_t hp_cipher = quic_get_1rtt_hp_cipher ( pinfo , conn , from_server ) ;
2019-01-20 19:21:38 +00:00
if ( hp_cipher & & quic_decrypt_header ( tvb , 1 + dcid . len , hp_cipher , conn - > cipher_algo , & first_byte , & pkn32 ) ) {
quic_set_full_packet_number ( conn , quic_packet , from_server , first_byte , pkn32 ) ;
quic_packet - > first_byte = first_byte ;
}
} else if ( conn & & quic_packet - > pkn_len ) {
first_byte = quic_packet - > first_byte ;
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2019-01-21 00:45:09 +00:00
proto_tree_add_item ( quic_tree , hf_quic_fixed_bit , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( quic_tree , hf_quic_spin_bit , tvb , offset , 1 , ENC_NA ) ;
2019-01-20 19:21:38 +00:00
if ( quic_packet - > pkn_len ) {
key_phase = ( first_byte & SH_KP ) ! = 0 ;
proto_tree_add_uint ( quic_tree , hf_quic_short_reserved , tvb , offset , 1 , first_byte ) ;
proto_tree_add_boolean ( quic_tree , hf_quic_key_phase , tvb , offset , 1 , key_phase ) ;
2019-01-21 00:10:31 +00:00
proto_tree_add_uint ( quic_tree , hf_quic_packet_number_length , tvb , offset , 1 , first_byte ) ;
2019-01-20 19:21:38 +00:00
}
2017-06-23 05:45:10 +00:00
offset + = 1 ;
2018-09-20 19:44:31 +00:00
col_clear ( pinfo - > cinfo , COL_INFO ) ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " Protected Payload (KP%u) " , key_phase ) ;
2017-06-23 05:45:10 +00:00
/* 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 ;
2018-09-20 19:44:31 +00:00
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , DCID=%s " , cid_to_string ( & dcid ) ) ;
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 ) {
2019-01-20 19:21:38 +00:00
cipher = quic_get_pp_cipher ( key_phase , conn , from_server ) ;
2018-09-12 14:11:49 +00:00
}
# endif /* !HAVE_LIBGCRYPT_AEAD */
2019-01-20 18:04:28 +00:00
if ( ! conn | | conn - > skip_decryption | | quic_packet - > pkn_len = = 0 ) {
2018-09-20 19:44:31 +00:00
return offset ;
}
2018-09-12 14:11:49 +00:00
2017-06-23 05:45:10 +00:00
/* Packet Number */
2019-01-21 00:19:32 +00:00
proto_tree_add_uint64 ( quic_tree , hf_quic_packet_number , tvb , offset , quic_packet - > pkn_len , quic_packet - > packet_number ) ;
2019-01-20 18:04:28 +00:00
offset + = quic_packet - > pkn_len ;
col_append_fstr ( pinfo - > cinfo , COL_INFO , " , PKN: % " G_GINT64_MODIFIER " u " , quic_packet - > packet_number ) ;
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 ,
2019-01-20 18:04:28 +00:00
conn , quic_packet , from_server , cipher , first_byte , quic_packet - > pkn_len ) ;
2019-01-21 14:22:32 +00:00
# ifdef HAVE_LIBGCRYPT_AEAD
2019-01-20 18:04:28 +00:00
if ( ! PINFO_FD_VISITED ( pinfo ) & & ! quic_packet - > decryption . error ) {
// Packet number is verified to be valid, remember it.
* quic_max_packet_number ( conn , from_server , first_byte ) = quic_packet - > packet_number ;
}
2019-01-21 14:22:32 +00:00
# endif /* !HAVE_LIBGCRYPT_AEAD */
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 ) ;
2019-01-06 10:13:19 +00:00
guint8 long_packet_type = ( packet_type & 0x30 ) > > 4 ;
2018-09-17 08:32:50 +00:00
// 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.
2019-01-20 23:08:39 +00:00
if ( version ! = 0 ) {
2018-09-11 17:28:09 +00:00
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
2019-01-06 10:13:19 +00:00
* long_packet_type = ( packet_type & 0x30 ) > > 4 ;
2018-04-21 12:18:03 +00:00
} 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_ )
{
2019-01-30 15:28:05 +00:00
proto_item * quic_ti ;
2017-06-23 05:45:10 +00:00
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
}
2019-01-30 15:28:05 +00:00
quic_ti = proto_tree_add_item ( tree , proto_quic , tvb , 0 , - 1 , ENC_NA ) ;
quic_tree = proto_item_add_subtree ( quic_ti , ett_quic ) ;
2017-06-23 05:45:10 +00:00
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 ) ;
}
2019-01-30 15:28:05 +00:00
/* Ensure that coalesced QUIC packets end up separated. */
if ( offset > 0 ) {
quic_ti = proto_tree_add_item ( tree , proto_quic , tvb , offset , - 1 , ENC_NA ) ;
quic_tree = proto_item_add_subtree ( quic_ti , ett_quic ) ;
}
2018-09-11 17:28:09 +00:00
tvbuff_t * next_tvb = quic_get_message_tvb ( tvb , offset ) ;
2019-01-30 15:28:05 +00:00
proto_item_set_len ( quic_ti , tvb_reported_length ( next_tvb ) ) ;
2018-09-11 17:28:09 +00:00
proto_tree_add_item_ret_uint ( quic_tree , hf_quic_header_form , next_tvb , 0 , 1 , ENC_NA , & header_form ) ;
2018-09-20 19:44:31 +00:00
guint new_offset = 0 ;
2018-09-11 17:28:09 +00:00
if ( header_form ) {
2019-01-20 12:18:03 +00:00
guint8 long_packet_type = ( tvb_get_guint8 ( next_tvb , 0 ) & 0x30 ) > > 4 ;
2018-09-16 22:50:08 +00:00
guint32 version = tvb_get_ntohl ( next_tvb , 1 ) ;
if ( version = = 0 ) {
2018-09-30 22:42:21 +00:00
offset + = dissect_quic_version_negotiation ( next_tvb , pinfo , quic_tree , quic_packet ) ;
2018-09-11 17:28:09 +00:00
break ;
}
2018-09-17 17:39:32 +00:00
if ( long_packet_type = = QUIC_LPT_RETRY ) {
2018-09-20 19:44:31 +00:00
new_offset = dissect_quic_retry_packet ( next_tvb , pinfo , quic_tree , dgram_info , quic_packet ) ;
2018-09-16 22:50:08 +00:00
} else {
2018-09-20 19:44:31 +00:00
new_offset = dissect_quic_long_header ( next_tvb , pinfo , quic_tree , dgram_info , quic_packet ) ;
2018-09-16 22:50:08 +00:00
}
2018-09-11 17:28:09 +00:00
} else {
2018-09-20 19:44:31 +00:00
new_offset = dissect_quic_short_header ( next_tvb , pinfo , quic_tree , dgram_info , quic_packet ) ;
}
if ( tvb_reported_length_remaining ( next_tvb , new_offset ) ) {
// should usually not be present unless decryption is not possible.
proto_tree_add_item ( quic_tree , hf_quic_remaining_payload , next_tvb , new_offset , - 1 , ENC_NA ) ;
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-09-10 18:48:10 +00:00
guint32 version ;
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 ;
2019-01-20 23:08:39 +00:00
// check for draft QUIC version (for draft -11 and newer)
2018-09-10 18:48:10 +00:00
version = tvb_get_ntohl ( tvb , offset ) ;
2019-01-20 23:08:39 +00:00
is_quic = ( quic_draft_version ( version ) > = 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 " ,
2019-01-06 10:13:19 +00:00
FT_UINT8 , BASE_DEC , VALS ( quic_long_packet_type_vals ) , 0x30 ,
2017-06-23 05:45:10 +00:00
" Long Header Packet Type " , HFILL }
} ,
2019-01-21 00:10:31 +00:00
{ & hf_quic_long_reserved ,
{ " Reserved " , " quic.long.reserved " ,
FT_UINT8 , BASE_DEC , NULL , 0x0c ,
" Reserved bits (protected using header protection) " , HFILL }
} ,
{ & hf_quic_packet_number_length ,
{ " Packet Number Length " , " quic.packet_number_length " ,
FT_UINT8 , BASE_DEC , VALS ( quic_packet_number_lengths ) , 0x03 ,
" Packet Number field length (protected using header protection) " , 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 ,
2019-01-21 00:19:32 +00:00
" Decoded packet number " , HFILL }
2018-03-16 18:44:27 +00:00
} ,
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 }
} ,
2019-01-21 00:45:09 +00:00
{ & hf_quic_spin_bit ,
{ " Spin Bit " , " quic.spin_bit " ,
FT_BOOLEAN , 8 , NULL , 0x20 ,
" Latency Spin Bit " , HFILL }
} ,
{ & hf_quic_fixed_bit ,
{ " Fixed Bit " , " quic.fixed_bit " ,
FT_BOOLEAN , 8 , NULL , 0x40 ,
" Must be 1 " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2018-09-15 09:55:21 +00:00
{ & hf_quic_short_reserved ,
{ " Reserved " , " quic.short.reserved " ,
2019-01-20 19:21:38 +00:00
FT_UINT8 , BASE_DEC , NULL , 0x18 ,
" Reserved bits (protected using header protection) " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-21 00:45:09 +00:00
{ & hf_quic_key_phase ,
{ " Key Phase Bit " , " quic.key_phase " ,
FT_BOOLEAN , 8 , NULL , SH_KP ,
" Selects the packet protection keys to use (protected using header protection) " , HFILL }
} ,
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-20 19:44:31 +00:00
{ & hf_quic_remaining_payload ,
{ " Remaining Payload " , " quic.remaining_payload " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Remaining payload in a packet (possibly PKN followed by encrypted payload) " , HFILL }
} ,
2017-06-23 05:45:10 +00:00
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 }
} ,
2019-01-16 20:12:39 +00:00
/* PADDING */
2019-01-21 11:31:16 +00:00
{ & hf_quic_padding_length ,
{ " Padding Length " , " quic.padding_length " ,
2019-01-16 20:12:39 +00:00
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
2017-12-24 14:03:58 +00:00
NULL , HFILL }
} ,
2019-01-16 20:12:39 +00:00
/* ACK */
2019-01-21 11:31:16 +00:00
{ & hf_quic_ack_largest_acknowledged ,
{ " Largest Acknowledged " , " quic.ack.largest_acknowledged " ,
2019-01-16 20:12:39 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Largest packet number the peer is acknowledging in this packet " , HFILL }
2017-12-24 14:03:58 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_ack_ack_delay ,
{ " ACK Delay " , " quic.ack.ack_delay " ,
2019-01-16 20:12:39 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" 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-24 14:03:58 +00:00
} ,
2019-01-23 10:50:31 +00:00
{ & hf_quic_ack_ack_range_count ,
{ " ACK Range Count " , " quic.ack.ack_range_count " ,
2017-12-24 14:03:58 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Number of Gap and ACK Range fields in the frame " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-23 10:50:31 +00:00
{ & hf_quic_ack_first_ack_range ,
{ " First ACK Range " , " quic.ack.first_ack_range " ,
2017-06-23 05:45:10 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Number of contiguous packets preceding the Largest Acknowledged that are being acknowledged " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_ack_gap ,
{ " Gap " , " quic.ack.gap " ,
2017-12-24 14:03:58 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Number of contiguous unacknowledged packets preceding the packet number one lower than the smallest in the preceding ACK Range " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-23 10:50:31 +00:00
{ & hf_quic_ack_ack_range ,
{ " ACK Range " , " quic.ack.ack_range " ,
2017-12-31 09:58:09 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Number of contiguous acknowledged packets preceding the largest packet number, as determined by the preceding Gap " , HFILL }
2017-12-31 09:58:09 +00:00
} ,
2019-01-23 10:50:31 +00:00
{ & hf_quic_ack_ect0_count ,
{ " ECT(0) Count " , " quic.ack.ect0_count " ,
2017-06-23 05:45:10 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Total number of packets received with the ECT(0) codepoint " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-23 10:50:31 +00:00
{ & hf_quic_ack_ect1_count ,
{ " ECT(1) Count " , " quic.ack.ect1_count " ,
2017-12-31 09:58:09 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Total number of packets received with the ECT(1) codepoint " , HFILL }
2017-12-31 09:58:09 +00:00
} ,
2019-01-23 10:50:31 +00:00
{ & hf_quic_ack_ecn_ce_count ,
{ " ECN-CE Count " , " quic.ack.ecn_ce_count " ,
2017-12-31 09:58:09 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:50:31 +00:00
" Total number of packets received with the CE codepoint " , HFILL }
2017-12-31 09:58:09 +00:00
} ,
2019-01-16 20:12:39 +00:00
/* RESET_STREAM */
2019-01-21 11:31:16 +00:00
{ & hf_quic_rsts_stream_id ,
{ " Stream ID " , " quic.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 }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_rsts_application_error_code ,
{ " Application Error code " , " quic.rsts.application_error_code " ,
2018-09-19 10:35:12 +00:00
FT_UINT16 , BASE_DEC , VALS ( quic_application_error_code_vals ) , 0x0 ,
2017-11-15 06:02:22 +00:00
" Indicates why the stream is being closed " , HFILL }
} ,
2019-01-23 10:32:12 +00:00
{ & hf_quic_rsts_final_size ,
{ " Final Size " , " quic.rsts.final_size " ,
2017-06-23 05:45:10 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-23 10:32:12 +00:00
" The final size of the stream by the RESET_STREAM sender (in bytes) " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-16 20:12:39 +00:00
/* STOP_SENDING */
2019-01-21 11:31:16 +00:00
{ & hf_quic_ss_stream_id ,
{ " Stream ID " , " quic.ss.stream_id " ,
2019-01-16 20:12:39 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Stream ID of the stream being ignored " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_ss_application_error_code ,
{ " Application Error code " , " quic.ss.application_error_code " ,
2019-01-16 20:12:39 +00:00
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
" Indicates why the sender is ignoring the stream " , HFILL }
2019-01-06 08:49:45 +00:00
} ,
2019-01-16 20:12:39 +00:00
/* CRYPTO */
2019-01-21 11:31:16 +00:00
{ & hf_quic_crypto_offset ,
{ " Offset " , " quic.crypto.offset " ,
2019-01-16 20:12:39 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Byte offset into the stream " , HFILL }
2018-09-19 10:55:05 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_crypto_length ,
{ " Length " , " quic.crypto.length " ,
2018-09-17 14:41:04 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-16 20:12:39 +00:00
" Length of the Crypto Data field " , HFILL }
2018-09-17 14:41:04 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_crypto_crypto_data ,
{ " Crypto Data " , " quic.crypto.crypto_data " ,
2019-01-16 20:12:39 +00:00
FT_NONE , BASE_NONE , NULL , 0x0 ,
" The cryptographic message data " , HFILL }
} ,
/* NEW_TOKEN */
2019-01-21 11:31:16 +00:00
{ & hf_quic_nt_length ,
{ " (Token) Length " , " quic.nt.length " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-16 20:12:39 +00:00
" Specifying the length of the token " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_nt_token ,
{ " Token " , " quic.nt.token " ,
2019-01-16 20:12:39 +00:00
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" An opaque blob that the client may use with a future Initial packet " , HFILL }
} ,
/* STREAM */
2019-01-21 11:31:16 +00:00
{ & hf_quic_stream_fin ,
{ " Fin " , " quic.stream.fin " ,
2019-01-16 20:12:39 +00:00
FT_BOOLEAN , 8 , NULL , FTFLAGS_STREAM_FIN ,
NULL , HFILL }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_stream_len ,
{ " Len(gth) " , " quic.stream.len " ,
2019-01-16 20:12:39 +00:00
FT_BOOLEAN , 8 , NULL , FTFLAGS_STREAM_LEN ,
NULL , HFILL }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_stream_off ,
{ " Off(set) " , " quic.stream.off " ,
2019-01-16 20:12:39 +00:00
FT_BOOLEAN , 8 , NULL , FTFLAGS_STREAM_OFF ,
NULL , HFILL }
} ,
{ & hf_quic_stream_stream_id ,
{ " Stream ID " , " quic.stream.stream_id " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_stream_offset ,
{ " Offset " , " quic.stream.offset " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_stream_length ,
{ " Length " , " quic.stream.length " ,
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_quic_stream_data ,
{ " Stream Data " , " quic.stream_data " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
2017-06-23 05:45:10 +00:00
} ,
/* MAX_DATA */
2019-01-21 11:31:16 +00:00
{ & hf_quic_md_maximum_data ,
{ " Maximum Data " , " quic.md.maximum_data " ,
2017-06-23 05:45:10 +00:00
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 */
2019-01-21 11:31:16 +00:00
{ & hf_quic_msd_stream_id ,
{ " Stream ID " , " quic.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 }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_msd_maximum_stream_data ,
{ " Maximum Stream Data " , " quic.msd.maximum_stream_data " ,
2017-06-23 05:45:10 +00:00
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 }
} ,
2019-01-06 08:49:45 +00:00
/* MAX_STREAMS */
2019-01-21 11:31:16 +00:00
{ & hf_quic_ms_max_streams ,
{ " Max Streams " , " quic.ms.max_streams " ,
2017-12-31 15:02:12 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-06 08:49:45 +00:00
" A count of the cumulative number of streams of the corresponding type that can be opened over the lifetime of the connection " , HFILL }
2017-06-23 05:45:10 +00:00
} ,
2019-01-06 08:49:45 +00:00
/* DATA_BLOCKED */
2019-01-21 11:31:16 +00:00
{ & hf_quic_db_stream_data_limit ,
{ " Stream Data Limit " , " quic.sb.stream_data_limit " ,
2018-01-03 07:30:08 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-06 08:49:45 +00:00
" Indicating the connection-level limit at which the blocking occurred " , HFILL }
2018-01-03 07:30:08 +00:00
} ,
2019-01-06 08:49:45 +00:00
/* STREAM_DATA_BLOCKED */
2019-01-21 11:31:16 +00:00
{ & hf_quic_sdb_stream_id ,
{ " Stream ID " , " quic.sdb.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 }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_sdb_stream_data_limit ,
{ " Stream Data Limit " , " quic.sb.stream_data_limit " ,
2018-01-03 07:30:08 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" Indicating the offset of the stream at which the blocking occurred " , HFILL }
} ,
2019-01-06 08:49:45 +00:00
/* STREAMS_BLOCKED */
2019-01-21 11:31:16 +00:00
{ & hf_quic_sb_stream_limit ,
{ " Stream Limit " , " quic.sib.stream_limit " ,
2018-01-03 07:30:08 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-06 08:49:45 +00:00
" Indicating the stream limit at the time the frame was sent " , HFILL }
2018-01-03 07:30:08 +00:00
} ,
2017-06-23 05:45:10 +00:00
/* NEW_CONNECTION_ID */
2019-01-21 11:31:16 +00:00
{ & hf_quic_nci_sequence ,
{ " Sequence " , " quic.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 }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_nci_connection_id_length ,
{ " Connection ID Length " , " quic.nci.connection_id.length " ,
2018-04-23 21:00:53 +00:00
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_nci_connection_id ,
{ " Connection ID " , " quic.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 }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_nci_stateless_reset_token ,
{ " Stateless Reset Token " , " quic.stateless_reset_token " ,
2017-09-01 14:06:22 +00:00
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2019-01-16 20:12:39 +00:00
/* RETIRE_CONNECTION_ID */
2019-01-21 11:31:16 +00:00
{ & hf_quic_rci_sequence ,
{ " Sequence " , " quic.rci.sequence " ,
2018-09-17 15:22:06 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-16 20:12:39 +00:00
" The sequence number of the connection ID being retired " , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-16 20:12:39 +00:00
/* PATH_CHALLENGE */
2019-01-21 11:31:16 +00:00
{ & hf_quic_path_challenge_data ,
{ " Data " , " quic.path_challenge.data " ,
2019-01-16 20:12:39 +00:00
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Arbitrary data that must be matched by a PATH_RESPONSE frame " , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-16 20:12:39 +00:00
/* PATH_RESPONSE */
2019-01-21 11:31:16 +00:00
{ & hf_quic_path_response_data ,
{ " Data " , " quic.path_response.data " ,
2019-01-16 20:12:39 +00:00
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Arbitrary data that must match a PATH_CHALLENGE frame " , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-16 20:12:39 +00:00
/* CONNECTION_CLOSE */
2019-01-21 11:31:16 +00:00
{ & hf_quic_cc_error_code ,
{ " Error code " , " quic.cc.error_code " ,
2019-01-16 20:12:39 +00:00
FT_UINT16 , BASE_DEC | BASE_RANGE_STRING , RVALS ( quic_transport_error_code_vals ) , 0x0 ,
" Indicates the reason for closing this connection " , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_cc_error_code_app ,
{ " Application Error code " , " quic.cc.error_code.app " ,
2019-01-16 20:12:39 +00:00
FT_UINT16 , BASE_DEC , VALS ( quic_application_error_code_vals ) , 0x0 ,
" Indicates the reason for closing this application " , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_cc_error_code_tls_alert ,
{ " TLS Alert Description " , " quic.cc.error_code.tls_alert " ,
2019-01-16 20:12:39 +00:00
FT_UINT8 , BASE_DEC , VALS ( ssl_31_alert_description ) , 0x0 ,
NULL , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_cc_frame_type ,
{ " Frame Type " , " quic.cc.frame_type " ,
2019-01-16 20:12:39 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
" The type of frame that triggered the error " , HFILL }
2018-09-17 15:22:06 +00:00
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_cc_reason_phrase_length ,
{ " Reason phrase Length " , " quic.cc.reason_phrase.length " ,
2018-11-02 19:58:32 +00:00
FT_UINT64 , BASE_DEC , NULL , 0x0 ,
2019-01-16 20:12:39 +00:00
" Specifying the length of the reason phrase " , HFILL }
} ,
2019-01-21 11:31:16 +00:00
{ & hf_quic_cc_reason_phrase ,
{ " Reason phrase " , " quic.cc.reason_phrase " ,
2019-01-16 20:12:39 +00:00
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A human-readable explanation for why the connection was closed " , HFILL }
2018-11-02 19:58:32 +00:00
} ,
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 :
*/