From 6bdd072803b4f9964416c89a36be66f8643fd4c7 Mon Sep 17 00:00:00 2001 From: Alexis La Goutte Date: Mon, 24 Jul 2017 21:14:30 +0200 Subject: TLS: Add QUIC Transport Parameters See https://tools.ietf.org/html/draft-ietf-quic-tls Bug: 13881 Change-Id: Id8ae5cdc2f7232e5db28846e528ae378fc0ac58d Reviewed-on: https://code.wireshark.org/review/22780 Petri-Dish: Alexis La Goutte Tested-by: Petri Dish Buildbot Reviewed-by: Alexis La Goutte Reviewed-by: Michael Mann --- epan/dissectors/packet-quic.c | 10 ++- epan/dissectors/packet-ssl-utils.c | 157 +++++++++++++++++++++++++++++++++++++ epan/dissectors/packet-ssl-utils.h | 102 +++++++++++++++++++++++- 3 files changed, 266 insertions(+), 3 deletions(-) (limited to 'epan') diff --git a/epan/dissectors/packet-quic.c b/epan/dissectors/packet-quic.c index 5a07796a7a..04929b7c5d 100644 --- a/epan/dissectors/packet-quic.c +++ b/epan/dissectors/packet-quic.c @@ -106,7 +106,7 @@ static gint ett_quic_ftflags = -1; static dissector_handle_t quic_handle; static dissector_handle_t ssl_handle; -static const value_string quic_version_vals[] = { +const value_string quic_version_vals[] = { { 0xff000004, "draft-04" }, { 0xff000005, "draft-05" }, { 0, NULL } @@ -237,6 +237,11 @@ static const value_string len_ack_block_vals[] = { #define QUIC_VERSION_NEGOTIATION_ERROR 0x80000009 #define QUIC_PROTOCOL_VIOLATION 0x8000000A +/* QUIC TLS Error */ +#define QUIC_TLS_HANDSHAKE_FAILED 0xC000001C +#define QUIC_TLS_FATAL_ALERT_GENERATED 0xC000001D +#define QUIC_TLS_FATAL_ALERT_RECEIVED 0xC000001E + static const value_string quic_error_code_vals[] = { { QUIC_NO_ERROR, "NO_ERROR (An endpoint uses this with CONNECTION_CLOSE to signal that the connection is being closed abruptly in the absence of any error)" }, { QUIC_INTERNAL_ERROR, "INTERNAL_ERROR (The endpoint encountered an internal error and cannot continue with the connection)" }, @@ -249,6 +254,9 @@ static const value_string quic_error_code_vals[] = { { QUIC_TRANSPORT_PARAMETER_ERROR, "TRANSPORT_PARAMETER_ERROR (An endpoint received transport parameters that were badly formatted)" }, { QUIC_VERSION_NEGOTIATION_ERROR, "VERSION_NEGOTIATION_ERROR (An endpoint received transport parameters that contained version negotiation parameters that disagreed with the version negotiation that it performed)" }, { QUIC_PROTOCOL_VIOLATION, "PROTOCOL_VIOLATION (An endpoint detected an error with protocol compliance that was not covered by more specific error codes)" }, + { QUIC_TLS_HANDSHAKE_FAILED, "TLS_HANDSHAKE_FAILED (The TLS handshake failed)" }, + { QUIC_TLS_FATAL_ALERT_GENERATED, "TLS_FATAL_ALERT_GENERATED (A TLS fatal alert was sent, causing the TLS connection to end prematurel)" }, + { QUIC_TLS_FATAL_ALERT_RECEIVED, "TLS_FATAL_ALERT_RECEIVED (A TLS fatal alert was received, causing the TLS connection to end prematurely)" }, { 0, NULL } }; static value_string_ext quic_error_code_vals_ext = VALUE_STRING_EXT_INIT(quic_error_code_vals); diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c index cd94d70fc1..ceb94619ea 100644 --- a/epan/dissectors/packet-ssl-utils.c +++ b/epan/dissectors/packet-ssl-utils.c @@ -1203,6 +1203,7 @@ const value_string tls_hello_extension_types[] = { { SSL_HND_HELLO_EXT_EXTENDED_MASTER_SECRET, "extended_master_secret" }, /* RFC 7627 */ { SSL_HND_HELLO_EXT_TOKEN_BINDING, "token_binding" }, /* https://tools.ietf.org/html/draft-ietf-tokbind-negotiation */ { SSL_HND_HELLO_EXT_CACHED_INFO, "cached_info" }, /* RFC 7924 */ + { SSL_HND_HELLO_EXT_QUIC_TRANSPORT_PARAMETERS, "quic_transports_parameters" }, /* https://tools.ietf.org/html/draft-ietf-quic-tls */ { SSL_HND_HELLO_EXT_SESSION_TICKET_TLS, "SessionTicket TLS" }, /* RFC 4507 */ { SSL_HND_HELLO_EXT_KEY_SHARE, "key_share" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */ { SSL_HND_HELLO_EXT_PRE_SHARED_KEY, "pre_shared_key" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */ @@ -1395,6 +1396,16 @@ static const ssl_alpn_protocol_t ssl_alpn_protocols[] = { { "h2", TRUE, "http2" }, /* final version */ }; +const value_string quic_transport_parameter_id[] = { + { SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_DATA, "initial_max_stream_data" }, + { SSL_HND_QUIC_TP_INITIAL_MAX_DATA, "initial_max_data" }, + { SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID, "initial_max_stream_id" }, + { SSL_HND_QUIC_TP_IDLE_TIMEOUT, "idle_timeout" }, + { SSL_HND_QUIC_TP_OMIT_CONNECTION_ID, "omit_connection_id" }, + { SSL_HND_QUIC_TP_MAX_PACKET_SIZE, "max_packet_size" }, + { 0, NULL } +}; + /* Lookup tables }}} */ /* we keep this internal to packet-ssl-utils, as there should be @@ -6315,6 +6326,149 @@ ssl_dissect_hnd_hello_ext_cert_type(ssl_common_dissect_t *hf, tvbuff_t *tvb, return offset; } +static guint32 +ssl_dissect_hnd_hello_ext_quic_transport_parameters(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, guint32 offset, guint32 offset_end, + guint8 hnd_type, SslDecryptSession *ssl _U_) +{ + guint32 quic_length, parameter_length, supported_versions_length, next_offset; + + /* https://tools.ietf.org/html/draft-ietf-quic-transport-04#section-7.3 + * uint32 QuicVersion; + * enum { + * initial_max_stream_data(0), + * initial_max_data(1), + * initial_max_stream_id(2), + * idle_timeout(3), + * truncate_connection_id(4), + * max_packet_size(5), + * (65535) + * } TransportParameterId; + * + * struct { + * TransportParameterId parameter; + * opaque value<0..2^16-1>; + * } TransportParameter; + * + * struct { + * select (Handshake.msg_type) { + * case client_hello: + * QuicVersion negotiated_version; + * QuicVersion initial_version; + * + * case encrypted_extensions: + * QuicVersion supported_versions<2..2^8-4>; + * }; + * TransportParameter parameters<30..2^16-1>; + * } TransportParameters; + */ + switch (hnd_type) { + case SSL_HND_CLIENT_HELLO: + proto_tree_add_item(tree, hf->hf.hs_ext_quictp_negotiated_version, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf->hf.hs_ext_quictp_initial_version, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case SSL_HND_ENCRYPTED_EXTENSIONS: + /* QuicVersion supported_versions<2..2^8-4>;*/ + if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &supported_versions_length, + hf->hf.hs_ext_quictp_supported_versions_len, 2, G_MAXUINT8-3)) { + return offset_end; + } + offset += 1; + next_offset = offset + supported_versions_length; + + while (offset < next_offset) { + proto_tree_add_item(tree, hf->hf.hs_ext_quictp_supported_versions, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } + break; + case SSL_HND_NEWSESSION_TICKET: + break; + default: + return offset; + } + + /* TransportParameter parameters<30..2^16-1>; */ + if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &quic_length, + hf->hf.hs_ext_quictp_len, 30, G_MAXUINT16)) { + return offset_end; + } + offset += 2; + next_offset = offset + quic_length; + + while (offset < next_offset) { + guint32 parameter_type; + proto_tree *parameter_tree; + + parameter_tree = proto_tree_add_subtree(tree, tvb, offset, 4, hf->ett.hs_ext_quictp_parameter, + NULL, "Parameter"); + /* TransportParameterId parameter */ + proto_tree_add_item_ret_uint(parameter_tree, hf->hf.hs_ext_quictp_parameter_type, + tvb, offset, 2, ENC_BIG_ENDIAN, ¶meter_type); + offset += 2; + proto_item_append_text(parameter_tree, ": %s", val_to_str(parameter_type, quic_transport_parameter_id, "Unknown")); + + /* opaque value<0..2^16-1> */ + if (!ssl_add_vector(hf, tvb, pinfo, parameter_tree, offset, next_offset, ¶meter_length, + hf->hf.hs_ext_quictp_parameter_len, 0, G_MAXUINT16)) { + return next_offset; + } + offset += 2; + proto_item_append_text(parameter_tree, " (len=%u)", parameter_length); + + proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_value, + tvb, offset, parameter_length, ENC_NA); + + switch (parameter_type) { + case SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_DATA: + proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_stream_data, + tvb, offset, 4, ENC_BIG_ENDIAN); + proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset)); + offset += 4; + break; + case SSL_HND_QUIC_TP_INITIAL_MAX_DATA: + proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_data, + tvb, offset, 4, ENC_BIG_ENDIAN); + proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset)); + offset += 4; + break; + case SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID: + proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_stream_id, + tvb, offset, 4, ENC_BIG_ENDIAN); + proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset)); + offset += 4; + break; + case SSL_HND_QUIC_TP_IDLE_TIMEOUT: + proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_idle_timeout, + tvb, offset, 2, ENC_BIG_ENDIAN); + proto_item_append_text(parameter_tree, " %u secs", tvb_get_ntohs(tvb, offset)); + offset += 2; + break; + case SSL_HND_QUIC_TP_OMIT_CONNECTION_ID: + /* No Payload */ + break; + case SSL_HND_QUIC_TP_MAX_PACKET_SIZE: + proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_max_packet_size, + tvb, offset, 2, ENC_BIG_ENDIAN); + proto_item_append_text(parameter_tree, " %u", tvb_get_ntohs(tvb, offset)); + /*TODO display expert info about invalid value (< 1252 or >65527) ? */ + offset += 2; + break; + default: + offset += parameter_length; + /*TODO display expert info about unknown ? */ + break; + } + + } + + return offset; +} + static gint ssl_dissect_hnd_hello_common(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree, guint32 offset, @@ -7623,6 +7777,9 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t } } break; + case SSL_HND_HELLO_EXT_QUIC_TRANSPORT_PARAMETERS: + offset = ssl_dissect_hnd_hello_ext_quic_transport_parameters(hf, tvb, pinfo, ext_tree, offset, next_offset, hnd_type, ssl); + break; case SSL_HND_HELLO_EXT_SESSION_TICKET_TLS: offset = ssl_dissect_hnd_hello_ext_session_ticket(hf, tvb, ext_tree, offset, next_offset, hnd_type, ssl); break; diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h index a9dc8a1e3a..cc1cf3c4fe 100644 --- a/epan/dissectors/packet-ssl-utils.h +++ b/epan/dissectors/packet-ssl-utils.h @@ -163,6 +163,7 @@ typedef enum { #define SSL_HND_HELLO_EXT_EXTENDED_MASTER_SECRET 23 #define SSL_HND_HELLO_EXT_TOKEN_BINDING 24 #define SSL_HND_HELLO_EXT_CACHED_INFO 25 +#define SSL_HND_HELLO_EXT_QUIC_TRANSPORT_PARAMETERS 26 /* Not yet assigned by IANA (QUIC-TLS Draft04) */ /* 26-34 Unassigned*/ #define SSL_HND_HELLO_EXT_SESSION_TICKET_TLS 35 /* TLS 1.3 draft */ @@ -203,6 +204,12 @@ typedef enum { #define SSL_HND_CERT_STATUS_TYPE_OCSP_MULTI 2 #define SSL_HND_CERT_TYPE_RAW_PUBLIC_KEY 2 +#define SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_DATA 0 +#define SSL_HND_QUIC_TP_INITIAL_MAX_DATA 1 +#define SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID 2 +#define SSL_HND_QUIC_TP_IDLE_TIMEOUT 3 +#define SSL_HND_QUIC_TP_OMIT_CONNECTION_ID 4 +#define SSL_HND_QUIC_TP_MAX_PACKET_SIZE 5 /* * Lookup tables */ @@ -243,6 +250,8 @@ extern const value_string ssl_curve_types[]; extern const value_string tls_hello_ext_server_name_type_vs[]; extern const value_string tls_hello_ext_psk_ke_mode[]; extern const value_string tls13_key_update_request[]; +extern const value_string quic_transport_parameter_id[]; +extern const value_string quic_version_vals[]; /* XXX Should we use GByteArray instead? */ typedef struct _StringInfo { @@ -818,6 +827,22 @@ typedef struct ssl_common_dissect { gint hs_ext_oid_filters_oid; gint hs_ext_oid_filters_values_length; + /* QUIC Transport Parameters */ + gint hs_ext_quictp_negotiated_version; + gint hs_ext_quictp_initial_version; + gint hs_ext_quictp_supported_versions_len; + gint hs_ext_quictp_supported_versions; + gint hs_ext_quictp_len; + gint hs_ext_quictp_parameter; + gint hs_ext_quictp_parameter_type; + gint hs_ext_quictp_parameter_len; + gint hs_ext_quictp_parameter_value; + gint hs_ext_quictp_parameter_initial_max_stream_data; + gint hs_ext_quictp_parameter_initial_max_data; + gint hs_ext_quictp_parameter_initial_max_stream_id; + gint hs_ext_quictp_parameter_idle_timeout; + gint hs_ext_quictp_parameter_max_packet_size; + /* do not forget to update SSL_COMMON_LIST_T and SSL_COMMON_HF_LIST! */ } hf; struct { @@ -834,6 +859,7 @@ typedef struct ssl_common_dissect { gint hs_ext_psk_identity; gint hs_ext_server_name; gint hs_ext_oid_filter; + gint hs_ext_quictp_parameter; gint hs_sig_hash_alg; gint hs_sig_hash_algs; gint urlhash; @@ -1011,11 +1037,12 @@ ssl_common_dissect_t name = { \ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + -1, -1, -1, -1, -1, -1, -1, -1, -1, \ }, \ /* ett */ { \ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ - -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ }, \ /* ei */ { \ EI_INIT, EI_INIT, EI_INIT, EI_INIT, EI_INIT, EI_INIT, \ @@ -1721,6 +1748,76 @@ ssl_common_dissect_t name = { \ { "Certificate Extension Values Length", prefix ".extension.oid_filters.values_length", \ FT_UINT16, BASE_DEC, NULL, 0x00, \ NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_negotiated_version, \ + { "Negotiated Version", prefix ".quic.negotiated_version", \ + FT_UINT32, BASE_HEX, VALS(quic_version_vals), 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_initial_version, \ + { "Initial Version", prefix ".quic.initial_version", \ + FT_UINT32, BASE_HEX, VALS(quic_version_vals), 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_supported_versions_len, \ + { "Supported Versions Length", prefix ".quic.supported_versions.len", \ + FT_UINT16, BASE_DEC, NULL, 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_supported_versions, \ + { "Supported Versions", prefix ".quic.supported_versions", \ + FT_UINT32, BASE_HEX, VALS(quic_version_vals), 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_len, \ + { "Parameters Length", prefix ".quic.len", \ + FT_UINT16, BASE_DEC, NULL, 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter, \ + { "Parameter", prefix ".quic.parameter", \ + FT_NONE, BASE_NONE, NULL, 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_type, \ + { "Type", prefix ".quic.parameter.type", \ + FT_UINT16, BASE_HEX, VALS(quic_transport_parameter_id), 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_len, \ + { "Length", prefix ".quic.parameter.length", \ + FT_UINT16, BASE_DEC, NULL, 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_value, \ + { "Value", prefix ".quic.parameter.value", \ + FT_BYTES, BASE_NONE, NULL, 0x00, \ + NULL, HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_initial_max_stream_data, \ + { "initial_max_stream_data", prefix ".quic.parameter.initial_max_stream_data", \ + FT_UINT32, BASE_DEC, NULL, 0x00, \ + "Contains the initial value for the maximum data that can be sent on any newly created stream", HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_initial_max_data, \ + { "initial_max_data", prefix ".quic.parameter.initial_max_data", \ + FT_UINT32, BASE_DEC, NULL, 0x00, \ + "Contains the initial value for the maximum amount of data that can be sent on the connection", HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_initial_max_stream_id, \ + { "initial_max_stream_id", prefix ".quic.parameter.initial_max_stream_id", \ + FT_UINT32, BASE_DEC, NULL, 0x00, \ + "Contains the initial maximum stream number the peer may initiate", HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_idle_timeout, \ + { "idle_timeout", prefix ".quic.parameter.idle_timeout", \ + FT_UINT16, BASE_DEC, NULL, 0x00, \ + "In seconds", HFILL } \ + }, \ + { & name .hf.hs_ext_quictp_parameter_max_packet_size, \ + { "max_packet_size", prefix ".quic.parameter.max_packet_size", \ + FT_UINT16, BASE_DEC, NULL, 0x00, \ + "Indicates that packets larger than this limit will be dropped", HFILL } \ } /* }}} */ @@ -1739,6 +1836,7 @@ ssl_common_dissect_t name = { \ & name .ett.hs_ext_psk_identity, \ & name .ett.hs_ext_server_name, \ & name .ett.hs_ext_oid_filter, \ + & name .ett.hs_ext_quictp_parameter, \ & name .ett.hs_sig_hash_alg, \ & name .ett.hs_sig_hash_algs, \ & name .ett.urlhash, \ -- cgit v1.2.3