diff options
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-dtls.c | 4 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.c | 80 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.h | 11 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl.c | 44 |
4 files changed, 117 insertions, 22 deletions
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c index bedee5efca..9d4acb6140 100644 --- a/epan/dissectors/packet-dtls.c +++ b/epan/dissectors/packet-dtls.c @@ -1822,7 +1822,7 @@ dissect_dtls_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo, { ssl_dissect_hnd_hello_ext(&dissect_dtls_hf, tvb, tree, offset, length - - (offset - start_offset), TRUE); + (offset - start_offset), TRUE, ssl); } } } @@ -1909,7 +1909,7 @@ dissect_dtls_hnd_srv_hello(tvbuff_t *tvb, { offset = ssl_dissect_hnd_hello_ext(&dissect_dtls_hf, tvb, tree, offset, length - - (offset - start_offset), FALSE); + (offset - start_offset), FALSE, ssl); } } return offset; diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c index 240839c529..4dc89c8d83 100644 --- a/epan/dissectors/packet-ssl-utils.c +++ b/epan/dissectors/packet-ssl-utils.c @@ -1043,7 +1043,7 @@ const value_string tls_hello_extension_types[] = { { SSL_HND_HELLO_EXT_HEARTBEAT, "Heartbeat" }, /* RFC 6520 */ { SSL_HND_HELLO_EXT_ALPN, "Application Layer Protocol Negotiation" }, /* draft-ietf-tls-applayerprotoneg-01 */ { SSL_HND_HELLO_EXT_STATUS_REQUEST_V2, "status_request_v2" }, /* RFC 6961 */ - { 35, "SessionTicket TLS" }, /* RFC 4507 */ + { SSL_HND_HELLO_EXT_SESSION_TICKET, "SessionTicket TLS" }, /* RFC 4507 */ { SSL_HND_HELLO_EXT_NPN, "next_protocol_negotiation"}, /* http://technotes.googlecode.com/git/nextprotoneg.html */ { SSL_HND_HELLO_EXT_RENEG_INFO, "renegotiation_info" }, /* RFC 5746 */ { 0, NULL } @@ -3668,6 +3668,8 @@ ssl_session_init(SslDecryptSession* ssl_session) ssl_session->session_id.data = ssl_session->_session_id; ssl_session->client_random.data = ssl_session->_client_random; ssl_session->server_random.data = ssl_session->_server_random; + ssl_session->session_ticket.data = ssl_session->_session_ticket; + ssl_session->session_ticket.data_len = 0; ssl_session->master_secret.data_len = 48; ssl_session->server_data_for_iv.data_len = 0; ssl_session->server_data_for_iv.data = ssl_session->_server_data_for_iv; @@ -4126,6 +4128,58 @@ ssl_restore_session(SslDecryptSession* ssl, GHashTable *session_hash) return TRUE; } +/* store master secret into session data cache */ +void +ssl_save_session_ticket(SslDecryptSession* ssl, GHashTable *session_hash) +{ + /* allocate stringinfo chunks for session id and master secret data*/ + StringInfo* session_ticket; + StringInfo* master_secret; + + if (ssl->session_ticket.data_len == 0) { + ssl_debug_printf("ssl_save_session_ticket - session ticket is empty!\n"); + return; + } + + session_ticket = (StringInfo *)wmem_alloc0(wmem_file_scope(), sizeof(StringInfo) + ssl->session_ticket.data_len); + master_secret = (StringInfo *)wmem_alloc0(wmem_file_scope(), 48 + sizeof(StringInfo)); + + master_secret->data = ((guchar*)master_secret+sizeof(StringInfo)); + + /* ssl_hash() depends on session_id->data being aligned for guint access + * so be careful in changing how it is allocated. + */ + session_ticket->data = ((guchar*)session_ticket+sizeof(StringInfo)); + + ssl_data_set(session_ticket, ssl->session_ticket.data, ssl->session_ticket.data_len); + ssl_data_set(master_secret, ssl->master_secret.data, ssl->master_secret.data_len); + g_hash_table_insert(session_hash, session_ticket, master_secret); + ssl_print_string("ssl_save_session_ticket stored session_ticket", session_ticket); + ssl_print_string("ssl_save_session_ticket stored master secret", master_secret); +} + +gboolean +ssl_restore_session_ticket(SslDecryptSession* ssl, GHashTable *session_hash) +{ + StringInfo* ms; + + if (ssl->session_ticket.data_len == 0) { + ssl_debug_printf("ssl_restore_session_ticket Cannot restore using an empty session ticket\n"); + return FALSE; + } + + ms = (StringInfo *)g_hash_table_lookup(session_hash, &ssl->session_ticket); + + if (!ms) { + ssl_debug_printf("ssl_restore_session_ticket can't find stored session ticket\n"); + return FALSE; + } + ssl_data_set(&ssl->master_secret, ms->data, ms->data_len); + ssl->state |= SSL_MASTER_SECRET; + ssl_debug_printf("ssl_restore_session_ticket master key retrieved\n"); + return TRUE; +} + int ssl_is_valid_content_type(guint8 type) { @@ -4747,6 +4801,23 @@ ssl_dissect_hnd_hello_ext_server_name(ssl_common_dissect_t *hf, tvbuff_t *tvb, return offset; } +static gint +ssl_dissect_hnd_hello_ext_session_ticket(ssl_common_dissect_t *hf, tvbuff_t *tvb, + proto_tree *tree, guint32 offset, guint32 ext_len, gboolean is_client, SslDecryptSession *ssl) +{ + if(is_client && ssl && ext_len != 0) + { + /*save the ticket on the ssl opaque so that we can use it as key on server hello */ + tvb_memcpy(tvb,ssl->session_ticket.data, offset, ext_len); + ssl->session_ticket.data_len = ext_len; + } + proto_tree_add_bytes_format(tree, hf->hf.hs_ext_data, + tvb, offset, ext_len, NULL, + "Data (%u byte%s)", + ext_len, plurality(ext_len, "", "s")); + return offset + ext_len; +} + void ssl_dissect_hnd_cert_url(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree, guint32 offset) { @@ -4950,14 +5021,14 @@ ssl_dissect_hnd_hello_ext_ec_point_formats(ssl_common_dissect_t *hf, tvbuff_t *t gint ssl_dissect_hnd_hello_ext(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 left, gboolean is_client) + guint32 offset, guint32 left, gboolean is_client, SslDecryptSession *ssl) { guint16 extension_length; guint16 ext_type; guint16 ext_len; proto_item *pi; proto_tree *ext_tree; - + if (left < 2) return offset; @@ -5027,6 +5098,9 @@ ssl_dissect_hnd_hello_ext(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t tvb, offset, 1, ENC_BIG_ENDIAN); offset += ext_len; break; + case SSL_HND_HELLO_EXT_SESSION_TICKET: + offset = ssl_dissect_hnd_hello_ext_session_ticket(hf, tvb, ext_tree, offset, ext_len, is_client, ssl); + break; default: proto_tree_add_bytes_format(ext_tree, hf->hf.hs_ext_data, tvb, offset, ext_len, NULL, diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h index 471b771353..7bbd3a4365 100644 --- a/epan/dissectors/packet-ssl-utils.h +++ b/epan/dissectors/packet-ssl-utils.h @@ -162,6 +162,7 @@ #define SSL_HND_HELLO_EXT_HEARTBEAT 0x000f #define SSL_HND_HELLO_EXT_ALPN 0x0010 #define SSL_HND_HELLO_EXT_STATUS_REQUEST_V2 0x0011 +#define SSL_HND_HELLO_EXT_SESSION_TICKET 0x0023 #define SSL_HND_HELLO_EXT_RENEG_INFO 0xff01 #define SSL_HND_HELLO_EXT_NPN 0x3374 #define SSL_HND_CERT_URL_TYPE_INDIVIDUAL_CERT 1 @@ -333,9 +334,11 @@ typedef struct { typedef struct _SslDecryptSession { guchar _master_secret[48]; guchar _session_id[256]; + guchar _session_ticket[1024]; guchar _client_random[32]; guchar _server_random[32]; StringInfo session_id; + StringInfo session_ticket; StringInfo server_random; StringInfo client_random; StringInfo master_secret; @@ -567,6 +570,12 @@ ssl_save_session(SslDecryptSession* ssl, GHashTable *session_hash); extern gboolean ssl_restore_session(SslDecryptSession* ssl, GHashTable *session_hash); +extern void +ssl_save_session_ticket(SslDecryptSession* ssl, GHashTable *session_hash); + +extern gboolean +ssl_restore_session_ticket(SslDecryptSession* ssl, GHashTable *session_hash); + extern gint ssl_is_valid_content_type(guint8 type); @@ -629,7 +638,7 @@ typedef struct ssl_common_dissect { extern gint ssl_dissect_hnd_hello_ext(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 left, gboolean is_client); + guint32 offset, guint32 left, gboolean is_client, SslDecryptSession *ssl); extern gint ssl_dissect_hash_alg_list(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree, diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c index 290f237b35..64bfb5fba1 100644 --- a/epan/dissectors/packet-ssl.c +++ b/epan/dissectors/packet-ssl.c @@ -535,7 +535,8 @@ static void dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb, static void dissect_ssl3_hnd_new_ses_ticket(tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 length); + guint32 offset, guint32 length, + SslDecryptSession *ssl); static void dissect_ssl3_hnd_cert(tvbuff_t *tvb, proto_tree *tree, guint32 offset, packet_info *pinfo); @@ -2023,7 +2024,7 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, break; case SSL_HND_NEWSESSION_TICKET: - dissect_ssl3_hnd_new_ses_ticket(tvb, ssl_hand_tree, offset, length); + dissect_ssl3_hnd_new_ses_ticket(tvb, ssl_hand_tree, offset, length, ssl); break; case SSL_HND_CERTIFICATE: @@ -2255,6 +2256,11 @@ dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, ssl_debug_printf(" found master secret in keylog file\n"); } } + /* if the session_ids match, then there is a chance that we need to restore a session_ticket */ + if(ssl->session_ticket.data_len != 0) + { + ssl_restore_session_ticket(ssl, ssl_session_hash); + } } else { tvb_memcpy(tvb,ssl->session_id.data, offset+33, session_id_length); ssl->session_id.data_len = session_id_length; @@ -2323,7 +2329,6 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo, ssl_set_server(ssl, &pinfo->dst, pinfo->ptype, pinfo->destport); ssl_find_private_key(ssl, ssl_key_hash, ssl_associations, pinfo); } - if (tree || ssl) { /* show the client version */ @@ -2331,18 +2336,17 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo, proto_tree_add_item(tree, hf_ssl_handshake_client_version, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; - /* show the fields in common with server hello */ offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 0); - /* tell the user how many cipher suites there are */ cipher_suite_length = tvb_get_ntohs(tvb, offset); - if (!tree) - return; + + /* even if there's no tree, we'll have to dissect the whole record to get to the extensions. + * we will continue with tree==NULL */ + proto_tree_add_uint(tree, hf_ssl_handshake_cipher_suites_len, tvb, offset, 2, cipher_suite_length); offset += 2; /* skip opaque length */ - if (cipher_suite_length > 0) { tvb_ensure_bytes_exist(tvb, offset, cipher_suite_length); @@ -2376,13 +2380,11 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo, cipher_suite_length -= 2; } } - /* tell the user how many compression methods there are */ compression_methods_length = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_ssl_handshake_comp_methods_len, tvb, offset, 1, compression_methods_length); offset += 1; - if (compression_methods_length > 0) { tvb_ensure_bytes_exist(tvb, offset, compression_methods_length); @@ -2419,11 +2421,10 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo, compression_methods_length--; } } - if (length > offset - start_offset) { ssl_dissect_hnd_hello_ext(&dissect_ssl3_hf, tvb, tree, offset, - length - (offset - start_offset), TRUE); + length - (offset - start_offset), TRUE, ssl); } } } @@ -2498,19 +2499,19 @@ no_cipher: if (length > offset - start_offset) { ssl_dissect_hnd_hello_ext(&dissect_ssl3_hf, tvb, tree, offset, - length - (offset - start_offset), FALSE); + length - (offset - start_offset), FALSE, ssl); } } } static void dissect_ssl3_hnd_new_ses_ticket(tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 length) + guint32 offset, guint32 length, SslDecryptSession *ssl) { guint nst_len; proto_item *ti; proto_tree *subtree; - + guint16 session_ticket_length = 0; nst_len = tvb_get_ntohs(tvb, offset+4); if (6 + nst_len != length) { @@ -2524,11 +2525,22 @@ dissect_ssl3_hnd_new_ses_ticket(tvbuff_t *tvb, proto_tree *tree, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; + + session_ticket_length = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(subtree, hf_ssl_handshake_session_ticket_len, tvb, offset, 2, nst_len); + offset += 2; + + /* save the session ticket to cache */ + if(ssl){ + tvb_memcpy(tvb,ssl->session_ticket.data, offset, session_ticket_length); + ssl->session_ticket.data_len = session_ticket_length; + ssl_save_session_ticket(ssl, ssl_session_hash); + } + /* Content depends on implementation, so just show data! */ proto_tree_add_item(subtree, hf_ssl_handshake_session_ticket, - tvb, offset + 2, nst_len, ENC_NA); + tvb, offset, nst_len, ENC_NA); } static void |