aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2014-01-20 20:26:04 +0000
committerAnders Broman <anders.broman@ericsson.com>2014-01-20 20:26:04 +0000
commitf0fb43a6215f0845face2b5dd0df568012321ae1 (patch)
treef524a884c4a06a6ce2102c6126631861f6c59f30 /epan/dissectors
parent6402d8590ea0fe7bfb6fbc8d530cce64a0080183 (diff)
From alexeyv:
Add decryption for resumed TLS sessions with a session ticket. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5963 svn path=/trunk/; revision=54860
Diffstat (limited to 'epan/dissectors')
-rw-r--r--epan/dissectors/packet-dtls.c4
-rw-r--r--epan/dissectors/packet-ssl-utils.c80
-rw-r--r--epan/dissectors/packet-ssl-utils.h11
-rw-r--r--epan/dissectors/packet-ssl.c44
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