TLS: fix RSA decryption with EMS and renegotiation

The handshake hash is used to derive TLS decryption keys when the
Extended Master Secret (EMS) extension is in use.
ssl_calculate_handshake_hash updates this hash only when the master
secret has not been determined yet.

During TLS renegotiation, there are two master secrets: one before, and
one after. Before this fix, the second calculated master secret is
wrong because the second Client Hello is missing in the handshake hash.
It was missing because the handshake hash was not being updated since
the master secret for the first handshake was still present, and the
decryption state was only reset after that hash update.

To fix this, make sure to clear the SSL_MASTER_SECRET flag before
updating the handshake hash when needed. Additionally, clear the
handshake hash when processing the Client Hello just to make sure that
any previous state is gone.

Fixes #18059
This commit is contained in:
Peter Wu 2022-04-25 03:00:44 +02:00 committed by A Wireshark GitLab Utility
parent b1ba667acc
commit 62100da7f4
4 changed files with 22 additions and 5 deletions

View File

@ -1400,6 +1400,11 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
sub_tvb = tvb_new_subset_length(tvb, offset, fragment_length);
}
if ((msg_type == SSL_HND_CLIENT_HELLO || msg_type == SSL_HND_SERVER_HELLO)) {
/* Prepare for renegotiation by resetting the state. */
ssl_reset_session(session, ssl, msg_type == SSL_HND_CLIENT_HELLO);
}
/*
* Add handshake message (including type, length, etc.) to hash (for
* Extended Master Secret). The computation must however happen as if

View File

@ -5308,8 +5308,7 @@ ssl_get_session(conversation_t *conversation, dissector_handle_t tls_handle)
return ssl_session;
}
/* Resets the decryption parameters for the next decoder. */
static void ssl_reset_session(SslSession *session, SslDecryptSession *ssl, gboolean is_client)
void ssl_reset_session(SslSession *session, SslDecryptSession *ssl, gboolean is_client)
{
if (ssl) {
/* Ensure that secrets are not restored using stale identifiers. Split
@ -5323,6 +5322,13 @@ static void ssl_reset_session(SslSession *session, SslDecryptSession *ssl, gbool
ssl->master_secret.data_len = 0;
ssl->client_random.data_len = 0;
ssl->has_early_data = FALSE;
if (ssl->handshake_data.data_len > 0) {
// The EMS handshake hash starts with at the Client Hello,
// ensure that any messages before it are forgotten.
wmem_free(wmem_file_scope(), ssl->handshake_data.data);
ssl->handshake_data.data = NULL;
ssl->handshake_data.data_len = 0;
}
} else {
clear_flags |= SSL_SERVER_EXTENDED_MASTER_SECRET | SSL_NEW_SESSION_TICKET;
ssl->server_random.data_len = 0;
@ -8000,9 +8006,6 @@ ssl_dissect_hnd_hello_common(ssl_common_dissect_t *hf, tvbuff_t *tvb,
proto_tree *ti_rnd;
guint8 draft_version = session->tls13_draft_version;
/* Prepare for renegotiation by resetting the state. */
ssl_reset_session(session, ssl, !from_server);
if (ssl) {
StringInfo *rnd;
if (from_server)

View File

@ -592,6 +592,10 @@ SslDecryptSession *ssl_get_session_by_cid(tvbuff_t *tvb, guint32 offset);
extern SslDecryptSession *
ssl_get_session(conversation_t *conversation, dissector_handle_t tls_handle);
/** Resets the decryption parameters for the next decoder. */
extern void
ssl_reset_session(SslSession *session, SslDecryptSession *ssl, gboolean is_client);
/** Set server address and port */
extern void
ssl_set_server(SslSession *session, address *addr, port_type ptype, guint32 port);

View File

@ -2600,6 +2600,11 @@ dissect_tls_handshake_full(tvbuff_t *tvb, packet_info *pinfo,
tvb, offset, 3, length);
offset += 3;
if ((msg_type == SSL_HND_CLIENT_HELLO || msg_type == SSL_HND_SERVER_HELLO)) {
/* Prepare for renegotiation by resetting the state. */
ssl_reset_session(session, ssl, msg_type == SSL_HND_CLIENT_HELLO);
}
/*
* Add handshake message (including type, length, etc.) to hash (for
* Extended Master Secret).