forked from osmocom/wireshark
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:
parent
b8a330d2d5
commit
7bf8a87429
|
@ -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")
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue