From alexeyv:
authorAnders Broman <anders.broman@ericsson.com>
Mon, 20 Jan 2014 20:26:04 +0000 (20:26 -0000)
committerAnders Broman <anders.broman@ericsson.com>
Mon, 20 Jan 2014 20:26:04 +0000 (20:26 -0000)
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

epan/dissectors/packet-dtls.c
epan/dissectors/packet-ssl-utils.c
epan/dissectors/packet-ssl-utils.h
epan/dissectors/packet-ssl.c

index bedee5efcaeb8adffb22e74c2a95ece44b53919f..9d4acb614007e7757af78f57b3e7354643be6b5c 100644 (file)
@@ -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;
index 240839c529d4e8f5f1e53687124cffc59f7588bf..4dc89c8d832888b3a317e1ad35489a272319e541 100644 (file)
@@ -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,
index 471b7713533cd059409afea4542d19736b48b5d7..7bbd3a4365743eb00d809fcfd8c91db0925e698b 100644 (file)
 #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,
index 290f237b35e43872661fab9638421ad7b765189a..64bfb5fba1a4700442e1be9bc434b6d2656a72d1 100644 (file)
@@ -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