ssl: fix decryption when session ticket is not used

Do not use the client-supplied session ticket for decryption when the
session is not resumed as the cached key (associated with that ticket)
is invalid for this new session. SSL Session IDs are unaffected by this
issue as only the server-issued Session ID is considered.

This fixes decryption of a SSL capture which uses the keylog file for
decryption, but where the session tickets are invalid because the server
was restarted.

Additionally, the session and session tickets stores are split to avoid
exporting session tickets via File -> Export SSL Session keys. Session
tickets should only be used internally, the CLIENT_RANDOM identifier is
shorter and is the preferred method to link secrets.

Change-Id: If96d7a4e89389825478e67e9a65401ce0607aa66
Reviewed-on: https://code.wireshark.org/review/13994
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Peter Wu 2016-02-18 18:24:29 +01:00 committed by Michael Mann
parent eb75ec1824
commit f4580ac9ed
2 changed files with 15 additions and 7 deletions

View File

@ -4344,6 +4344,7 @@ ssl_common_init(ssl_master_key_map_t *mk_map,
StringInfo *decrypted_data, StringInfo *compressed_data)
{
mk_map->session = g_hash_table_new(ssl_hash, ssl_equal);
mk_map->tickets = g_hash_table_new(ssl_hash, ssl_equal);
mk_map->crandom = g_hash_table_new(ssl_hash, ssl_equal);
mk_map->pre_master = g_hash_table_new(ssl_hash, ssl_equal);
mk_map->pms = g_hash_table_new(ssl_hash, ssl_equal);
@ -4356,6 +4357,7 @@ ssl_common_cleanup(ssl_master_key_map_t *mk_map, FILE **ssl_keylog_file,
StringInfo *decrypted_data, StringInfo *compressed_data)
{
g_hash_table_destroy(mk_map->session);
g_hash_table_destroy(mk_map->tickets);
g_hash_table_destroy(mk_map->crandom);
g_hash_table_destroy(mk_map->pre_master);
g_hash_table_destroy(mk_map->pms);
@ -4543,8 +4545,9 @@ ssl_finalize_decryption(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map)
if (!(ssl->state & (SSL_MASTER_SECRET | SSL_PRE_MASTER_SECRET)) &&
!ssl_restore_master_key(ssl, "Session ID", FALSE,
mk_map->session, &ssl->session_id) &&
!ssl_restore_master_key(ssl, "Session Ticket", FALSE,
mk_map->session, &ssl->session_ticket) &&
(!ssl->session.is_session_resumed ||
!ssl_restore_master_key(ssl, "Session Ticket", FALSE,
mk_map->tickets, &ssl->session_ticket)) &&
!ssl_restore_master_key(ssl, "Client Random", FALSE,
mk_map->crandom, &ssl->client_random)) {
if (ssl->cipher_suite.enc != ENC_NULL) {
@ -4566,8 +4569,12 @@ ssl_finalize_decryption(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map)
&ssl->client_random, &ssl->master_secret);
ssl_save_master_key("Session ID", mk_map->session,
&ssl->session_id, &ssl->master_secret);
ssl_save_master_key("Session Ticket", mk_map->session,
&ssl->session_ticket, &ssl->master_secret);
/* Only save the new secrets if the server sent the ticket. The client
* ticket might have become stale. */
if (ssl->state & SSL_NEW_SESSION_TICKET) {
ssl_save_master_key("Session Ticket", mk_map->tickets,
&ssl->session_ticket, &ssl->master_secret);
}
} /* }}} */
#endif /* HAVE_LIBGCRYPT */
@ -5906,6 +5913,7 @@ ssl_dissect_hnd_new_ses_ticket(ssl_common_dissect_t *hf, tvbuff_t *tvb,
* master key (from the first CCS), save the ticket here too. */
ssl_save_master_key("Session Ticket", session_hash,
&ssl->session_ticket, &ssl->master_secret);
ssl->state |= SSL_NEW_SESSION_TICKET;
}
#endif
} /* }}} */

View File

@ -230,6 +230,7 @@ typedef struct _StringInfo {
#define SSL_CLIENT_EXTENDED_MASTER_SECRET (1<<7)
#define SSL_SERVER_EXTENDED_MASTER_SECRET (1<<8)
#define SSL_SERVER_HELLO_DONE (1<<9)
#define SSL_NEW_SESSION_TICKET (1<<10)
#define SSL_EXTENDED_MASTER_SECRET_MASK (SSL_CLIENT_EXTENDED_MASTER_SECRET|SSL_SERVER_EXTENDED_MASTER_SECRET)
@ -424,9 +425,8 @@ typedef struct ssl_common_options {
/** Map from something to a (pre-)master secret */
typedef struct {
GHashTable *session; /* Session ID/Ticket to master secret. It uses the
observation that Session IDs are 1-32 bytes and
tickets are much longer */
GHashTable *session; /* Session ID (1-32 bytes) to master secret. */
GHashTable *tickets; /* Session Ticket to master secret. */
GHashTable *crandom; /* Client Random to master secret */
GHashTable *pre_master; /* First 8 bytes of encrypted pre-master secret to
pre-master secret */