DTLS: Add connection ID extension support

* Add DTLS connection ID extension based on
draft-ietf-tls-dtls-connection-id-07, excerpt:

A CID is an identifier carried in the record layer header that gives the
recipient additional information for selecting the appropriate security
association.

* Support session tracking based on connection ID, i.e. a connection ID
list is built then looked up to retrieve the session of a packet, then
the related conversation is updated with this session.

Bug: 16600
Change-Id: I050d7b5b09dad33eb39d506aca67ee839b3b7181
Reviewed-on: https://code.wireshark.org/review/37351
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Ludovic Cintrat 2020-05-29 10:21:12 +02:00 committed by Anders Broman
parent b8a330d2d5
commit 7bf8a87429
4 changed files with 342 additions and 30 deletions

View File

@ -90,11 +90,14 @@ static gint exported_pdu_tap = -1;
static gint proto_dtls = -1;
static gint hf_dtls_record = -1;
static gint hf_dtls_record_content_type = -1;
static gint hf_dtls_record_special_type = -1;
static gint hf_dtls_record_version = -1;
static gint hf_dtls_record_epoch = -1;
static gint hf_dtls_record_sequence_number = -1;
static gint hf_dtls_record_connection_id = -1;
static gint hf_dtls_record_length = -1;
static gint hf_dtls_record_appdata = -1;
static gint hf_dtls_record_encrypted_content = -1;
static gint hf_dtls_alert_message = -1;
static gint hf_dtls_alert_message_level = -1;
static gint hf_dtls_alert_message_description = -1;
@ -146,6 +149,8 @@ static expert_field ei_dtls_handshake_fragment_length_zero = EI_INIT;
static expert_field ei_dtls_handshake_fragment_past_end_msg = EI_INIT;
static expert_field ei_dtls_msg_len_diff_fragment = EI_INIT;
static expert_field ei_dtls_heartbeat_payload_length = EI_INIT;
static expert_field ei_dtls_cid_invalid_content_type = EI_INIT;
static expert_field ei_dtls_cid_invalid_enc_content = EI_INIT;
#ifdef HAVE_LIBGNUTLS
static GHashTable *dtls_key_hash = NULL;
@ -207,11 +212,15 @@ dtls_init(void)
prefs_set_preference_obsolete(keys_list_pref);
}
}
ssl_init_cid_list();
}
static void
dtls_cleanup(void)
{
ssl_cleanup_cid_list();
#ifdef HAVE_LIBGNUTLS
if (key_list_stack != NULL) {
wmem_destroy_stack(key_list_stack);
@ -363,8 +372,8 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
proto_item *ti;
proto_tree *dtls_tree;
guint32 offset;
SslDecryptSession *ssl_session;
SslSession *session;
SslDecryptSession *ssl_session = NULL;
SslSession *session = NULL;
gint is_from_server;
guint8 curr_layer_num_ssl = pinfo->curr_layer_num;
@ -385,7 +394,29 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
* in addition to conv_version
*/
conversation = find_or_create_conversation(pinfo);
ssl_session = ssl_get_session(conversation, dtls_handle);
guint8 record_type = tvb_get_guint8(tvb, offset);
/* try to get decrypt session from the connection ID only for the first pass,
* it should be available from the conversation in the second pass
*/
if (record_type == SSL_ID_TLS12_CID && !PINFO_FD_VISITED(pinfo)) {
// CID length is not embedded in the packet
ssl_session = ssl_get_session_by_cid(tvb, offset+11);
if (ssl_session) {
// update conversation
conversation_add_proto_data(conversation,
dissector_handle_get_protocol_index(dtls_handle),
ssl_session);
}
}
/* if session cannot be retrieved from connection ID, get or create it from conversation */
if (ssl_session == NULL) {
ssl_session = ssl_get_session(conversation, dtls_handle);
}
session = &ssl_session->session;
if (session->last_nontls_frame != 0 &&
@ -550,9 +581,42 @@ dtls_is_null_cipher(guint cipher )
}
}
static void
dtls_save_decrypted_record(packet_info *pinfo, gint record_id, guint8 content_type, guint8 curr_layer_num_ssl)
{
const guchar *data = dtls_decrypted_data.data;
guint datalen = dtls_decrypted_data_avail;
if (datalen == 0) {
return;
}
if (content_type == SSL_ID_TLS12_CID) {
/*
* The actual data is followed by the content type and then zero or
* more padding. Scan backwards for content type, skipping padding.
*/
while (datalen > 0 && data[datalen - 1] == 0) {
datalen--;
}
ssl_debug_printf("%s found %d padding bytes\n", G_STRFUNC, dtls_decrypted_data_avail - datalen);
if (datalen == 0) {
ssl_debug_printf("%s there is no room for content type!\n", G_STRFUNC);
return;
}
content_type = data[--datalen];
if (datalen == 0) {
return;
}
}
ssl_add_record_info(proto_dtls, pinfo, data, datalen, record_id, NULL, (ContentType)content_type, curr_layer_num_ssl);
}
static gboolean
decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryptSession *ssl,
guint8 content_type, guint16 record_version, guint16 record_length, guint8 curr_layer_num_ssl)
guint8 content_type, guint16 record_version, guint16 record_length, guint8 curr_layer_num_ssl,
const guchar *cid, guint8 cid_length)
{
gboolean success;
SslDecoder *decoder;
@ -601,7 +665,7 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
return FALSE;
}
success = ssl_decrypt_record(ssl, decoder, content_type, record_version, FALSE,
tvb_get_ptr(tvb, offset, record_length), record_length,
tvb_get_ptr(tvb, offset, record_length), record_length, cid, cid_length,
&dtls_compressed_data, &dtls_decrypted_data, &dtls_decrypted_data_avail) == 0;
}
else if (dtls_is_null_cipher(ssl->session.cipher)) {
@ -613,13 +677,8 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
success = FALSE;
}
if (success && dtls_decrypted_data_avail > 0) {
const guchar *data = dtls_decrypted_data.data;
guint datalen = dtls_decrypted_data_avail;
ssl_add_record_info(proto_dtls, pinfo, data, datalen,
tvb_raw_offset(tvb)+offset,
NULL, (ContentType)content_type, curr_layer_num_ssl);
if (success) {
dtls_save_decrypted_record(pinfo, tvb_raw_offset(tvb)+offset, content_type, curr_layer_num_ssl);
}
return success;
}
@ -669,20 +728,41 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
* uint16 length;
* opaque fragment[TLSPlaintext.length];
* } DTLSPlaintext;
*
*
* draft-ietf-tls-dtls-connection-id-07:
*
* struct {
* ContentType special_type = tls12_cid;
* ProtocolVersion version;
* uint16 epoch;
* uint48 sequence_number;
* opaque cid[cid_length]; // New field
* uint16 length;
* opaque enc_content[DTLSCiphertext.length];
* } DTLSCiphertext;
*
*/
guint32 dtls_record_length;
guint32 record_length;
guint16 version;
guint16 epoch;
guint64 sequence_number;
guint8 content_type;
guint content_type_offset;
guint8 next_byte;
proto_tree *ti;
proto_tree *dtls_record_tree;
proto_item *length_pi;
proto_item *length_pi, *ct_pi;
tvbuff_t *decrypted;
SslRecordInfo *record = NULL;
heur_dtbl_entry_t *hdtbl_entry;
guint8 cid[DTLS_MAX_CID_LENGTH];
guint8 cid_length;
/* Connection ID length to use if any */
cid_length = is_from_server ? session->client_cid_len : session->server_cid_len;
/*
* Get the record layer fields of interest
@ -691,7 +771,15 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
version = tvb_get_ntohs(tvb, offset + 1);
epoch = tvb_get_ntohs(tvb, offset + 3);
sequence_number = tvb_get_ntoh48(tvb, offset + 5);
record_length = tvb_get_ntohs(tvb, offset + 11);
if (content_type == SSL_ID_TLS12_CID && cid_length > 0) {
tvb_memcpy(tvb, cid, offset + 11, cid_length);
record_length = tvb_get_ntohs(tvb, offset + cid_length + 11);
dtls_record_length = 13 + cid_length + record_length;
} else {
record_length = tvb_get_ntohs(tvb, offset + 11);
dtls_record_length = 13 + record_length;
}
if (!ssl_is_valid_content_type(content_type)) {
@ -702,7 +790,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/* Set the protocol column */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "DTLS");
return offset + 13 + record_length;
return offset + dtls_record_length;
}
if (ssl) {
@ -725,12 +813,18 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/* add the record layer subtree header */
ti = proto_tree_add_item(tree, hf_dtls_record, tvb,
offset, 13 + record_length, ENC_NA);
offset, dtls_record_length, ENC_NA);
dtls_record_tree = proto_item_add_subtree(ti, ett_dtls_record);
/* show the one-byte content type */
proto_tree_add_item(dtls_record_tree, hf_dtls_record_content_type,
tvb, offset, 1, ENC_BIG_ENDIAN);
if (content_type == SSL_ID_TLS12_CID) {
ct_pi = proto_tree_add_item(dtls_record_tree, hf_dtls_record_special_type,
tvb, offset, 1, ENC_BIG_ENDIAN);
} else {
ct_pi = proto_tree_add_item(dtls_record_tree, hf_dtls_record_content_type,
tvb, offset, 1, ENC_BIG_ENDIAN);
}
content_type_offset = offset;
offset++;
/* add the version */
@ -746,6 +840,12 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
proto_tree_add_uint64(dtls_record_tree, hf_dtls_record_sequence_number, tvb, offset, 6, sequence_number);
offset += 6;
if (content_type == SSL_ID_TLS12_CID) {
/* add connection ID */
proto_tree_add_item(dtls_record_tree, hf_dtls_record_connection_id, tvb, offset, cid_length, ENC_NA);
offset += cid_length;
}
/* add the length */
length_pi = proto_tree_add_uint(dtls_record_tree, hf_dtls_record_length, tvb,
offset, 2, record_length);
@ -771,14 +871,35 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
/* try to decrypt record on the first pass, if possible. Store decrypted
* record for later usage (without having to decrypt again). */
if (ssl) {
decrypt_dtls_record(tvb, pinfo, offset, ssl, content_type, version, record_length, curr_layer_num_ssl);
decrypt_dtls_record(tvb, pinfo, offset, ssl, content_type, version, record_length, curr_layer_num_ssl, cid, cid_length);
}
decrypted = ssl_get_record_info(tvb, proto_dtls, pinfo, tvb_raw_offset(tvb)+offset, curr_layer_num_ssl, &record);
if (decrypted) {
add_new_data_source(pinfo, decrypted, "Decrypted DTLS");
if (content_type == SSL_ID_TLS12_CID) {
content_type = record->type;
ti = proto_tree_add_uint(dtls_record_tree, hf_dtls_record_content_type,
tvb, content_type_offset, 1, record->type);
proto_item_set_generated(ti);
}
}
ssl_check_record_length(&dissect_dtls_hf, pinfo, (ContentType)content_type, record_length, length_pi, session->version, decrypted);
/* extract the real record from the connection ID record */
if (content_type == SSL_ID_TLS12_CID) {
proto_item_set_text(dtls_record_tree, "%s Record Layer: Connection ID",
val_to_str_const(session->version, ssl_version_short_names, "DTLS"));
/* if content cannot be deciphered or the content is invalid */
if (decrypted == NULL) {
col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Connection ID");
proto_tree_add_item(dtls_record_tree, hf_dtls_record_encrypted_content, tvb,
offset, record_length, ENC_NA);
offset += record_length; /* skip to end of record */
return offset;
}
}
switch ((ContentType) content_type) {
case SSL_ID_CHG_CIPHER_SPEC:
@ -900,6 +1021,10 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
session, record_length, FALSE);
}
break;
case SSL_ID_TLS12_CID:
expert_add_info_format(pinfo, ct_pi, &ei_dtls_cid_invalid_content_type,
"Invalid content type (%d)", content_type);
break;
}
offset += record_length; /* skip to end of record */
@ -1741,6 +1866,11 @@ proto_register_dtls(void)
FT_UINT8, BASE_DEC, VALS(ssl_31_content_type), 0x0,
NULL, HFILL}
},
{ &hf_dtls_record_special_type,
{ "Special Type", "dtls.record.special_type",
FT_UINT8, BASE_DEC, VALS(ssl_31_content_type), 0x0,
"Always set to value 25, actual content type is known after decryption", HFILL}
},
{ &hf_dtls_record_version,
{ "Version", "dtls.record.version",
FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0,
@ -1756,6 +1886,11 @@ proto_register_dtls(void)
FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_dtls_record_connection_id,
{ "Connection ID", "dtls.record.connection_id",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_dtls_record_length,
{ "Length", "dtls.record.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
@ -1766,6 +1901,11 @@ proto_register_dtls(void)
FT_BYTES, BASE_NONE, NULL, 0x0,
"Payload is encrypted application data", HFILL }
},
{ &hf_dtls_record_encrypted_content,
{ "Encrypted Record Content", "dtls.enc_content",
FT_BYTES, BASE_NONE, NULL, 0x0,
"Encrypted record data", HFILL }
},
{ & hf_dtls_alert_message,
{ "Alert Message", "dtls.alert_message",
FT_NONE, BASE_NONE, NULL, 0x0,
@ -1923,6 +2063,8 @@ proto_register_dtls(void)
{ &ei_dtls_handshake_fragment_past_end_msg, { "dtls.handshake.fragment_past_end_msg", PI_PROTOCOL, PI_ERROR, "Fragment runs past the end of the message", EXPFILL }},
{ &ei_dtls_msg_len_diff_fragment, { "dtls.msg_len_diff_fragment", PI_PROTOCOL, PI_ERROR, "Message length differs from value in earlier fragment", EXPFILL }},
{ &ei_dtls_heartbeat_payload_length, { "dtls.heartbeat_message.payload_length.invalid", PI_MALFORMED, PI_ERROR, "Invalid heartbeat payload length", EXPFILL }},
{ &ei_dtls_cid_invalid_content_type, { "dtls.cid.content_type.invalid", PI_MALFORMED, PI_ERROR, "Invalid real content type", EXPFILL }},
{ &ei_dtls_cid_invalid_enc_content, { "dtls.cid.enc_content.invalid", PI_MALFORMED, PI_ERROR, "Invalid encrypted content", EXPFILL }},
SSL_COMMON_EI_LIST(dissect_dtls_hf, "dtls")
};

View File

@ -507,6 +507,7 @@ const value_string ssl_31_content_type[] = {
{ 22, "Handshake" },
{ 23, "Application Data" },
{ 24, "Heartbeat" },
{ 25, "Connection ID" },
{ 0x00, NULL }
};
@ -1166,6 +1167,7 @@ const value_string tls_hello_extension_types[] = {
{ SSL_HND_HELLO_EXT_POST_HANDSHAKE_AUTH, "post_handshake_auth" }, /* RFC 8446 */
{ SSL_HND_HELLO_EXT_SIGNATURE_ALGORITHMS_CERT, "signature_algorithms_cert" }, /* RFC 8446 */
{ SSL_HND_HELLO_EXT_KEY_SHARE, "key_share" }, /* RFC 8446 */
{ SSL_HND_HELLO_EXT_CONNECTION_ID, "connection_id" }, /* draft-ietf-tls-dtls-connection-id-07 */
{ SSL_HND_HELLO_EXT_GREASE_0A0A, "Reserved (GREASE)" }, /* RFC 8701 */
{ SSL_HND_HELLO_EXT_GREASE_1A1A, "Reserved (GREASE)" }, /* RFC 8701 */
{ SSL_HND_HELLO_EXT_GREASE_2A2A, "Reserved (GREASE)" }, /* RFC 8701 */
@ -1955,6 +1957,52 @@ gint ssl_get_keyex_alg(gint cipher)
/* }}} */
}
static wmem_list_t *connection_id_session_list = NULL;
void
ssl_init_cid_list(void) {
connection_id_session_list = wmem_list_new(wmem_file_scope());
}
void
ssl_cleanup_cid_list(void) {
wmem_destroy_list(connection_id_session_list);
}
void
ssl_add_session_by_cid(SslDecryptSession *session)
{
wmem_list_append(connection_id_session_list, session);
}
SslDecryptSession *
ssl_get_session_by_cid(tvbuff_t *tvb, guint32 offset)
{
SslDecryptSession * ssl_cid = NULL;
wmem_list_frame_t *it = wmem_list_head(connection_id_session_list);
while (it != NULL && ssl_cid == NULL) {
SslDecryptSession * ssl = (SslDecryptSession *)wmem_list_frame_data(it);
DISSECTOR_ASSERT(ssl != NULL);
SslSession *session = &ssl->session;
if (session->client_cid_len > 0 && tvb_bytes_exist(tvb, offset, session->client_cid_len)) {
if (tvb_memeql(tvb, offset, session->client_cid, session->client_cid_len) == 0) {
ssl_cid = ssl;
}
}
if (session->server_cid_len > 0) {
if (tvb_memeql(tvb, offset, session->server_cid, session->server_cid_len) == 0) {
ssl_cid = ssl;
}
}
it = wmem_list_frame_next(it);
}
return ssl_cid;
}
/* StringInfo structure (len + data) functions {{{ */
@ -4069,7 +4117,9 @@ tls_decrypt_aead_record(SslDecryptSession *ssl, SslDecoder *decoder,
_U_
#endif
,
const guchar *in, guint16 inl, StringInfo *out_str, guint *outl)
const guchar *in, guint16 inl,
const guchar *cid, guint8 cidl,
StringInfo *out_str, guint *outl)
{
/* RFC 5246 (TLS 1.2) 6.2.3.3 defines the TLSCipherText.fragment as:
* GenericAEADCipher: { nonce_explicit, [content] }
@ -4079,6 +4129,7 @@ tls_decrypt_aead_record(SslDecryptSession *ssl, SslDecoder *decoder,
*/
const guint16 version = ssl->session.version;
const gboolean is_v12 = version == TLSV1DOT2_VERSION || version == DTLSV1DOT2_VERSION;
const gboolean is_cid = ct == SSL_ID_TLS12_CID && version == DTLSV1DOT2_VERSION;
gcry_error_t err;
const guchar *explicit_nonce = NULL, *ciphertext;
guint ciphertext_len, auth_tag_len;
@ -4186,11 +4237,30 @@ tls_decrypt_aead_record(SslDecryptSession *ssl, SslDecoder *decoder,
if (decoder->cipher_suite->mode == MODE_CCM || decoder->cipher_suite->mode == MODE_CCM_8) {
/* size of plaintext, additional authenticated data and auth tag. */
guint64 lengths[3] = { ciphertext_len, is_v12 ? 13 : 0, auth_tag_len };
if (is_cid) {
lengths[1] = 13 + 1 + cidl; /* cid length (1 byte) + cid (cidl bytes)*/
}
gcry_cipher_ctl(decoder->evp, GCRYCTL_SET_CCM_LENGTHS, lengths, sizeof(lengths));
}
/* (D)TLS 1.2 needs specific AAD, TLS 1.3 (before -25) uses empty AAD. */
if (is_v12) {
if (is_cid) { /* if connection ID */
guchar aad[14+DTLS_MAX_CID_LENGTH];
guint aad_len = 14 + cidl;
phton64(aad, decoder->seq); /* record sequence number */
phton16(aad, decoder->epoch); /* DTLS 1.2 includes epoch. */
aad[8] = ct; /* TLSCompressed.type */
phton16(aad + 9, record_version); /* TLSCompressed.version */
memcpy(aad + 11, cid, cidl); /* cid */
aad[11 + cidl] = cidl; /* cid_length */
phton16(aad + 12 + cidl, ciphertext_len); /* TLSCompressed.length */
ssl_print_data("AAD", aad, aad_len);
err = gcry_cipher_authenticate(decoder->evp, aad, aad_len);
if (err) {
ssl_debug_printf("%s failed to set AAD: %s\n", G_STRFUNC, gcry_strerror(err));
return FALSE;
}
} else if (is_v12) {
guchar aad[13];
phton64(aad, decoder->seq); /* record sequence number */
if (version == DTLSV1DOT2_VERSION) {
@ -4272,10 +4342,11 @@ tls_decrypt_aead_record(SslDecryptSession *ssl, SslDecoder *decoder,
/* Record decryption glue based on security parameters {{{ */
/* Assume that we are called only for a non-NULL decoder which also means that
* we have a non-NULL decoder->cipher_suite. */
int
gint
ssl_decrypt_record(SslDecryptSession *ssl, SslDecoder *decoder, guint8 ct, guint16 record_version,
gboolean ignore_mac_failed,
const guchar *in, guint16 inl, StringInfo *comp_str, StringInfo *out_str, guint *outl)
const guchar *in, guint16 inl, const guchar *cid, guint8 cidl,
StringInfo *comp_str, StringInfo *out_str, guint *outl)
{
guint pad, worklen, uncomplen, maclen, mac_fraglen = 0;
guint8 *mac = NULL, *mac_frag = NULL;
@ -4304,7 +4375,7 @@ ssl_decrypt_record(SslDecryptSession *ssl, SslDecoder *decoder, guint8 ct, guint
decoder->cipher_suite->mode == MODE_POLY1305 ||
ssl->session.version == TLSV1DOT3_VERSION) {
if (!tls_decrypt_aead_record(ssl, decoder, ct, record_version, ignore_mac_failed, in, inl, out_str, &worklen)) {
if (!tls_decrypt_aead_record(ssl, decoder, ct, record_version, ignore_mac_failed, in, inl, cid, cidl, out_str, &worklen)) {
/* decryption failed */
return -1;
}
@ -7563,6 +7634,53 @@ ssl_dissect_hnd_hello_ext_esni(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_i
}
/** TLS Extensions (in Client Hello and Server Hello). }}} */
/* Connection ID dissection. {{{ */
static guint32
ssl_dissect_ext_connection_id(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, guint32 offset, SslDecryptSession *ssl,
guint8 cidl, guint8 **session_cid, guint8 *session_cidl)
{
/* keep track of the decrypt session only for the first pass */
if (cidl > 0 && !PINFO_FD_VISITED(pinfo)) {
tvb_ensure_bytes_exist(tvb, offset + 1, cidl);
*session_cidl = cidl;
*session_cid = (guint8*)wmem_alloc0(wmem_file_scope(), cidl);
tvb_memcpy(tvb, *session_cid, offset + 1, cidl);
if (ssl) {
ssl_add_session_by_cid(ssl);
}
}
proto_tree_add_item(tree, hf->hf.hs_ext_connection_id_length,
tvb, offset, 1, ENC_NA);
offset++;
proto_tree_add_item(tree, hf->hf.hs_ext_connection_id,
tvb, offset, cidl, ENC_NA);
offset += cidl;
return offset;
}
static guint32
ssl_dissect_hnd_hello_ext_connection_id(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, guint32 offset, guint8 hnd_type,
SslSession *session, SslDecryptSession *ssl)
{
guint8 cidl = tvb_get_guint8(tvb, offset);
switch (hnd_type) {
case SSL_HND_CLIENT_HELLO:
return ssl_dissect_ext_connection_id(hf, tvb, pinfo, tree, offset, ssl,
cidl, &session->client_cid, &session->client_cid_len);
case SSL_HND_SERVER_HELLO:
return ssl_dissect_ext_connection_id(hf, tvb, pinfo, tree, offset, ssl,
cidl, &session->server_cid, &session->server_cid_len);
default:
return offset;
}
} /* }}} */
/* Whether the Content and Handshake Types are valid; handle Protocol Version. {{{ */
gboolean
ssl_is_valid_content_type(guint8 type)
@ -7573,6 +7691,7 @@ ssl_is_valid_content_type(guint8 type)
case SSL_ID_HANDSHAKE:
case SSL_ID_APP_DATA:
case SSL_ID_HEARTBEAT:
case SSL_ID_TLS12_CID:
return TRUE;
}
return FALSE;
@ -8758,6 +8877,9 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
case SSL_HND_HELLO_EXT_ENCRYPTED_SERVER_NAME:
offset = ssl_dissect_hnd_hello_ext_esni(hf, tvb, pinfo, ext_tree, offset, next_offset, hnd_type, ssl);
break;
case SSL_HND_HELLO_EXT_CONNECTION_ID:
offset = ssl_dissect_hnd_hello_ext_connection_id(hf, tvb, pinfo, ext_tree, offset, hnd_type, session, ssl);
break;
default:
proto_tree_add_item(ext_tree, hf->hf.hs_ext_data,
tvb, offset, ext_len, ENC_NA);

View File

@ -39,7 +39,8 @@ typedef enum {
SSL_ID_ALERT = 0x15,
SSL_ID_HANDSHAKE = 0x16,
SSL_ID_APP_DATA = 0x17,
SSL_ID_HEARTBEAT = 0x18
SSL_ID_HEARTBEAT = 0x18,
SSL_ID_TLS12_CID = 0x19
} ContentType;
typedef enum {
@ -121,6 +122,7 @@ typedef enum {
#define SSL_HND_HELLO_EXT_POST_HANDSHAKE_AUTH 49
#define SSL_HND_HELLO_EXT_SIGNATURE_ALGORITHMS_CERT 50
#define SSL_HND_HELLO_EXT_KEY_SHARE 51
#define SSL_HND_HELLO_EXT_CONNECTION_ID 53
#define SSL_HND_HELLO_EXT_GREASE_0A0A 2570
#define SSL_HND_HELLO_EXT_GREASE_1A1A 6682
#define SSL_HND_HELLO_EXT_GREASE_2A2A 10794
@ -430,6 +432,19 @@ typedef struct _SslSession {
/* First pass only: track an in-progress handshake reassembly (>0) */
guint32 client_hs_reassembly_id;
guint32 server_hs_reassembly_id;
/* Connection ID extension
struct {
opaque cid<0..2^8-1>;
} ConnectionId;
*/
#define DTLS_MAX_CID_LENGTH 256
guint8 *client_cid;
guint8 *server_cid;
guint8 client_cid_len;
guint8 server_cid_len;
} SslSession;
/* RFC 5246, section 8.1 says that the master secret is always 48 bytes */
@ -515,6 +530,22 @@ gboolean ssldecrypt_uat_fld_fileopen_chk_cb(void*, const char*, unsigned, const
gboolean ssldecrypt_uat_fld_password_chk_cb(void*, const char*, unsigned, const void*, const void*, char** err);
gchar* ssl_association_info(const char* dissector_table_name, const char* table_protocol);
/** Initialize the list of sessions with connection ID */
void ssl_init_cid_list(void);
/** Release resource allocated for the list of sessions with connection ID */
void ssl_cleanup_cid_list(void);
/** Add a session to the list of sessions using connection ID */
void ssl_add_session_by_cid(SslDecryptSession *ssl);
/**
* Return a session with a matching connection ID
* @param tvb a buffer containing a connection ID
* @param offset offset of the connection ID in tvb
*/
SslDecryptSession *ssl_get_session_by_cid(tvbuff_t *tvb, guint32 offset);
/** Retrieve a SslSession, creating it if it did not already exist.
* @param conversation The SSL conversation.
* @param tls_handle The dissector handle for SSL or DTLS.
@ -627,6 +658,8 @@ ssl_change_cipher(SslDecryptSession *ssl_session, gboolean server);
@param ignore_mac_failed whether to ignore MAC or authenticity failures
@param in a pointer to the ssl record to be decrypted
@param inl the record length
@param cid a pointer to the connection ID to use in AEAD or NULL
@param cidl the connection ID length or 0 if cid is NULL
@param comp_str a pointer to the store the compression data
@param out_str a pointer to the store for the decrypted data
@param outl the decrypted data len
@ -634,7 +667,8 @@ ssl_change_cipher(SslDecryptSession *ssl_session, gboolean server);
extern gint
ssl_decrypt_record(SslDecryptSession *ssl, SslDecoder *decoder, guint8 ct, guint16 record_version,
gboolean ignore_mac_failed,
const guchar *in, guint16 inl, StringInfo *comp_str, StringInfo *out_str, guint *outl);
const guchar *in, guint16 inl, const guchar *cid, guint8 cidl,
StringInfo *comp_str, StringInfo *out_str, guint *outl);
/**
* Given a cipher algorithm and its mode, a hash algorithm and the secret (with
@ -801,6 +835,8 @@ typedef struct ssl_common_dissect {
gint hs_ext_max_fragment_length;
gint hs_ext_padding_data;
gint hs_ext_type;
gint hs_ext_connection_id_length;
gint hs_ext_connection_id;
gint hs_sig_hash_alg;
gint hs_sig_hash_alg_len;
gint hs_sig_hash_algs;
@ -1170,7 +1206,7 @@ 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, \
}, \
/* ett */ { \
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \
@ -2146,6 +2182,16 @@ ssl_common_dissect_t name = { \
FT_UINT64, BASE_DEC, NULL, 0x00, \
NULL, HFILL } \
}, \
{ & name .hf.hs_ext_connection_id_length, \
{ "Connection ID length", prefix ".connection_id_length", \
FT_UINT8, BASE_DEC, NULL, 0x00, \
NULL, HFILL } \
}, \
{ & name .hf.hs_ext_connection_id, \
{ "Connection ID", prefix ".connection_id", \
FT_BYTES, BASE_NONE, NULL, 0x00, \
NULL, HFILL } \
}, \
{ & name .hf.esni_suite, \
{ "Cipher Suite", prefix ".esni.suite", \
FT_UINT16, BASE_HEX|BASE_EXT_STRING, &ssl_31_ciphersuite_ext, 0x0, \

View File

@ -1080,7 +1080,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset, SslDecryp
* is successful*/
ssl_decrypted_data_avail = ssl_decrypted_data.data_len;
success = ssl_decrypt_record(ssl, decoder, content_type, record_version, tls_ignore_mac_failed,
tvb_get_ptr(tvb, offset, record_length), record_length,
tvb_get_ptr(tvb, offset, record_length), record_length, NULL, 0,
&ssl_compressed_data, &ssl_decrypted_data, &ssl_decrypted_data_avail) == 0;
/* */
if (!success) {
@ -1119,7 +1119,7 @@ decrypt_tls13_early_data(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
ssl_decrypted_data_avail = ssl_decrypted_data.data_len;
success = ssl_decrypt_record(ssl, ssl->client, SSL_ID_APP_DATA, 0x303, FALSE,
tvb_get_ptr(tvb, offset, record_length), record_length,
tvb_get_ptr(tvb, offset, record_length), record_length, NULL, 0,
&ssl_compressed_data, &ssl_decrypted_data, &ssl_decrypted_data_avail) == 0;
if (success) {
tls_save_decrypted_record(pinfo, tvb_raw_offset(tvb)+offset, ssl, SSL_ID_APP_DATA, ssl->client, TRUE, curr_layer_num_ssl);
@ -1157,7 +1157,7 @@ decrypt_tls13_early_data(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
}
ssl_decrypted_data_avail = ssl_decrypted_data.data_len;
success = ssl_decrypt_record(ssl, ssl->client, SSL_ID_APP_DATA, 0x303, FALSE, record, record_length,
success = ssl_decrypt_record(ssl, ssl->client, SSL_ID_APP_DATA, 0x303, FALSE, record, record_length, NULL, 0,
&ssl_compressed_data, &ssl_decrypted_data, &ssl_decrypted_data_avail) == 0;
if (success) {
ssl_debug_printf("Early data decryption succeeded, cipher = %#x\n", cipher);
@ -2077,6 +2077,8 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
dissect_ssl3_heartbeat(tvb, pinfo, ssl_record_tree, offset, session, record_length, plaintext);
}
break;
case SSL_ID_TLS12_CID:
break;
}
offset += record_length; /* skip to end of record */