Fix SSL decryption failure if client and server have the same TCP port
authorTomas Kukosa <tomas.kukosa@siemens.com>
Thu, 13 Aug 2009 09:07:03 +0000 (09:07 -0000)
committerTomas Kukosa <tomas.kukosa@siemens.com>
Thu, 13 Aug 2009 09:07:03 +0000 (09:07 -0000)
svn path=/trunk/; revision=29400

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

index 8f47e45a9f7725bbfaa22c4250f3bcf240f9cde7..7aae624cebcc405c79bbdb28cf545dbd748d516a 100644 (file)
@@ -368,7 +368,7 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     conversation_add_proto_data(conversation, proto_dtls, ssl_session);
 
     /* we need to know witch side of conversation is speaking */
-    if (ssl_packet_from_server(dtls_associations, pinfo->srcport, pinfo->ptype == PT_TCP)) {
+    if (ssl_packet_from_server(ssl_session, dtls_associations, pinfo)) {
       dummy.addr = pinfo->src;
       dummy.port = pinfo->srcport;
     }
@@ -486,7 +486,7 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
   }
 
   /* retrive decoder for this packet direction */
-  if ((direction = ssl_packet_from_server(dtls_associations, pinfo->srcport, pinfo->ptype == PT_TCP)) != 0) {
+  if ((direction = ssl_packet_from_server(ssl, dtls_associations, pinfo)) != 0) {
     ssl_debug_printf("decrypt_dtls_record: using server decoder\n");
     decoder = ssl->server;
   }
@@ -586,7 +586,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
   record_length = tvb_get_ntohs(tvb, offset + 11);
 
   if(ssl){
-    if(ssl_packet_from_server(dtls_associations, pinfo->srcport, pinfo->ptype == PT_TCP)){
+    if(ssl_packet_from_server(ssl, dtls_associations, pinfo)){
      if (ssl->server) {
       ssl->server->seq=(guint32)sequence_number;
       ssl->server->epoch=epoch;
index 84c4b9e535ee5fc675785d7c2ecd73cad4aa6224..bcf1baf97f800bf43efda66bdd0a0dfc5f332ec1 100644 (file)
@@ -1112,7 +1112,7 @@ ssl_private_decrypt(guint len, guchar* encr_data, SSL_PRIVATE_KEY* pk)
         }
     }
 
-    ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %zd\n",
+    ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %d\n",
         rc, decr_len);
     ssl_print_data("decrypted_unstrip_pre_master", decr_data_ptr, decr_len);
     g_memmove(decr_data_ptr, &decr_data_ptr[rc], decr_len - rc);
@@ -1574,6 +1574,9 @@ ssl_generate_keyring_material(SslDecryptSession*ssl_session)
     /* if master_key is not yet generate, create it now*/
     if (!(ssl_session->state & SSL_MASTER_SECRET)) {
         ssl_debug_printf("ssl_generate_keyring_material:PRF(pre_master_secret)\n");
+        ssl_print_string("pre master secret",&ssl_session->pre_master_secret);
+        ssl_print_string("client random",&ssl_session->client_random);
+        ssl_print_string("server random",&ssl_session->server_random);
         if (PRF(ssl_session,&ssl_session->pre_master_secret,"master secret",
                 &ssl_session->client_random,
                 &ssl_session->server_random, &ssl_session->master_secret)) {
@@ -2487,6 +2490,60 @@ void ssl_free_key(Ssl_private_key_t* key)
   g_free((Ssl_private_key_t*)key);
 }
 
+gint
+ssl_find_private_key(SslDecryptSession *ssl_session, GHashTable *key_hash, GTree* associations, packet_info *pinfo) {
+  SslService dummy;
+  char ip_addr_any[] = {0,0,0,0};
+  guint32 port = 0;
+  Ssl_private_key_t * private_key;
+
+  /* we need to know which side of the conversation is speaking */
+  if (ssl_packet_from_server(ssl_session, associations, pinfo)) {
+      dummy.addr = pinfo->src;
+      dummy.port = port = pinfo->srcport;
+  } else {
+      dummy.addr = pinfo->dst;
+      dummy.port = port = pinfo->destport;
+  }
+  ssl_debug_printf("ssl_find_private_key server %s:%u\n",
+      address_to_str(&dummy.addr),dummy.port);
+
+  /* try to retrieve private key for this service. Do it now 'cause pinfo
+   * is not always available
+   * Note that with HAVE_LIBGNUTLS undefined private_key is allways 0
+   * and thus decryption never engaged*/
+
+
+  ssl_session->private_key = 0;
+  private_key = g_hash_table_lookup(key_hash, &dummy);
+
+  if (!private_key) {
+      ssl_debug_printf("ssl_find_private_key can't find private key for this server! Try it again with universal port 0\n");
+
+      dummy.port = 0;
+      private_key = g_hash_table_lookup(key_hash, &dummy);
+  }
+
+  if (!private_key) {
+      ssl_debug_printf("ssl_find_private_key can't find private key for this server (universal port)! Try it again with universal address 0.0.0.0\n");
+
+      dummy.addr.type = AT_IPv4;
+      dummy.addr.len = 4;
+      dummy.addr.data = ip_addr_any;
+
+      dummy.port = port;
+      private_key = g_hash_table_lookup(key_hash, &dummy);
+  }
+
+  if (!private_key) {
+      ssl_debug_printf("ssl_find_private_key can't find any private key!\n");
+  } else {
+      ssl_session->private_key = private_key->sexp_pkey;
+  }
+
+  return 0;
+}
+
 void
 ssl_lib_init(void)
 {
@@ -2524,6 +2581,11 @@ ssl_free_key(Ssl_private_key_t* key _U_)
 {
 }
 
+gint
+ssl_find_private_key(SslDecryptSession *ssl_session _U_, GHashTable *key_hash _U_, GTree* associations _U_, packet_info *pinfo _U_)
+{
+}
+
 int
 ssl_find_cipher(int num,SslCipherSuite* cs)
 {
@@ -2592,6 +2654,17 @@ ssl_session_init(SslDecryptSession* ssl_session)
     ssl_session->client_data_for_iv.data = ssl_session->_client_data_for_iv;
     ssl_session->app_data_segment.data=NULL;
     ssl_session->app_data_segment.data_len=0;
+    SET_ADDRESS(&ssl_session->srv_addr, AT_NONE, 0, NULL);
+    ssl_session->srv_ptype = PT_NONE;
+    ssl_session->srv_port = 0;
+}
+
+void
+ssl_set_server(SslDecryptSession* ssl, address *addr, port_type ptype, guint32 port)
+{
+    SE_COPY_ADDRESS(&ssl->srv_addr, addr);
+    ssl->srv_ptype = ptype;
+    ssl->srv_port = port;
 }
 
 /* Hash Functions for TLS/DTLS sessions table and private keys table*/
@@ -2754,10 +2827,14 @@ ssl_assoc_from_key_list(gpointer key _U_, gpointer data, gpointer user_data)
 }
 
 int
-ssl_packet_from_server(GTree* associations, guint port, gboolean tcp)
+ssl_packet_from_server(SslDecryptSession* ssl, GTree* associations, packet_info *pinfo)
 {
-  register gint ret;
-  ret = ssl_association_find(associations, port, tcp) != 0;
+  gint ret;
+  if (ssl && (ssl->srv_ptype != PT_NONE)) {
+    ret = (ssl->srv_ptype == pinfo->ptype) && (ssl->srv_port == pinfo->srcport) && ADDRESSES_EQUAL(&ssl->srv_addr, &pinfo->src);
+  } else {
+    ret = ssl_association_find(associations, pinfo->srcport, pinfo->ptype == PT_TCP) != 0;
+  }
 
   ssl_debug_printf("packet_from_server: is from server - %s\n", (ret)?"TRUE":"FALSE");
   return ret;
index 67b48b254267552834c889cc649c90ad0e926cde..a6556faf7d529ad3f5aa3fb65f4047422260f517 100644 (file)
@@ -307,6 +307,10 @@ typedef struct _SslDecryptSession {
     guint16 version_netorder;
     StringInfo app_data_segment;
 
+    address srv_addr;
+    port_type srv_ptype;
+    guint srv_port;
+
 } SslDecryptSession;
 
 typedef struct _SslAssociation {
@@ -339,6 +343,10 @@ ssl_lib_init(void);
 extern void
 ssl_session_init(SslDecryptSession* ssl);
 
+/** Set server address and port */
+extern void
+ssl_set_server(SslDecryptSession* ssl, address *addr, port_type ptype, guint32 port);
+
 /** set the data and len for the stringInfo buffer. buf should be big enough to
  * contain the provided data
  @param buf the buffer to update
@@ -364,6 +372,10 @@ ssl_load_pkcs12(FILE* fp, const gchar *cert_passwd);
 extern void
 ssl_free_key(Ssl_private_key_t* key);
 
+/* Find private key in associations */
+extern gint
+ssl_find_private_key(SslDecryptSession *ssl_session, GHashTable *key_hash, GTree* associations, packet_info *pinfo);
+
 /* Search for the specified cipher souite id
  @param num the id of the cipher suite to be searched
  @param cs pointer to the cipher suite struct to be filled
@@ -440,7 +452,7 @@ extern gint
 ssl_assoc_from_key_list(gpointer key _U_, gpointer data, gpointer user_data);
 
 extern gint
-ssl_packet_from_server(GTree* associations, guint port, gboolean tcp);
+ssl_packet_from_server(SslDecryptSession* ssl, GTree* associations, packet_info *pinfo);
 
 /* add to packet data a newly allocated tvb with the specified real data*/
 extern void
index 9797e056e3572c9c7872ec97b93bbcb1e3582f4e..0da783c1ba42da69acfa90e6f0e24bd83eb8b030 100644 (file)
@@ -507,15 +507,12 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     gboolean need_desegmentation;
     SslDecryptSession* ssl_session;
     guint* conv_version;
-    Ssl_private_key_t * private_key;
-    guint32 port;
 
     ti = NULL;
     ssl_tree   = NULL;
     offset = 0;
     first_record_in_frame = TRUE;
     ssl_session = NULL;
-    port = 0;
 
 
     ssl_debug_printf("\ndissect_ssl enter frame #%u (%s)\n", pinfo->fd->num, (pinfo->fd->flags.visited)?"already visited":"first time");
@@ -549,64 +546,15 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     if (conv_data != NULL)
         ssl_session = conv_data;
     else {
-        SslService dummy;
-        char ip_addr_any[] = {0,0,0,0};
-
         ssl_session = se_alloc0(sizeof(SslDecryptSession));
         ssl_session_init(ssl_session);
         ssl_session->version = SSL_VER_UNKNOWN;
         conversation_add_proto_data(conversation, proto_ssl, ssl_session);
-
-        /* we need to know which side of the conversation is speaking */
-        if (ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP)) {
-            dummy.addr = pinfo->src;
-            dummy.port = port = pinfo->srcport;
-        } else {
-            dummy.addr = pinfo->dst;
-            dummy.port = port = pinfo->destport;
-        }
-        ssl_debug_printf("dissect_ssl server %s:%u\n",
-            address_to_str(&dummy.addr),dummy.port);
-
-        /* try to retrieve private key for this service. Do it now 'cause pinfo
-         * is not always available
-         * Note that with HAVE_LIBGNUTLS undefined private_key is allways 0
-         * and thus decryption never engaged*/
-
-
-        ssl_session->private_key = 0;
-        private_key = g_hash_table_lookup(ssl_key_hash, &dummy);
-
-        if (!private_key) {
-            ssl_debug_printf("dissect_ssl can't find private key for this server! Try it again with universal port 0\n");
-
-            dummy.port = 0;
-            private_key = g_hash_table_lookup(ssl_key_hash, &dummy);
-        }
-
-        if (!private_key) {
-            ssl_debug_printf("dissect_ssl can't find private key for this server (universal port)! Try it again with universal address 0.0.0.0\n");
-
-            dummy.addr.type = AT_IPv4;
-            dummy.addr.len = 4;
-            dummy.addr.data = ip_addr_any;
-
-            dummy.port = port;
-            private_key = g_hash_table_lookup(ssl_key_hash, &dummy);
-        }
-
-        if (!private_key) {
-            ssl_debug_printf("dissect_ssl can't find any private key!\n");
-        } else {
-            ssl_session->private_key = private_key->sexp_pkey;
-        }
-
     }
     conv_version =& ssl_session->version;
 
     /* try decryption only the first time we see this packet
-     * (to keep cipher synchronized) and only if we have
-     * the server private key*/
+     * (to keep cipher synchronized) */
     if (pinfo->fd->flags.visited)
          ssl_session = NULL;
 
@@ -767,7 +715,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
      * add decrypted data to this packet info */
     ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl, state 0x%02X\n",
         record_length, ssl->state);
-    direction = ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
+    direction = ssl_packet_from_server(ssl, ssl_associations, pinfo);
 
     /* retrieve decoder for this packet direction */
     if (direction != 0) {
@@ -1505,7 +1453,7 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
             col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
         dissect_ssl3_change_cipher_spec(tvb, ssl_record_tree,
                                         offset, conv_version, content_type);
-        if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP));
+        if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl, ssl_associations, pinfo));
         break;
     case SSL_ID_ALERT:
     {
@@ -2087,6 +2035,11 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo,
     compression_methods_length = 0;
     start_offset = offset;
 
+    if (ssl) {
+      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 */
@@ -2808,6 +2761,11 @@ dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, packet_info *pinfo,
         return;
     }
 
+    if (ssl) {
+      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 version */
@@ -2919,7 +2877,7 @@ dissect_ssl2_hnd_client_hello(tvbuff_t *tvb, packet_info *pinfo,
                 tvb_memcpy(tvb, &ssl->client_random.data[32 - max], offset, max);
                 ssl->client_random.data_len = 32;
                 ssl->state |= SSL_CLIENT_RANDOM;
-
+                ssl_debug_printf("dissect_ssl2_hnd_client_hello found CLIENT RANDOM -> state 0x%02X\n", ssl->state);
             }
             offset += challenge_length;
         }
@@ -3499,6 +3457,8 @@ void ssl_set_master_secret(guint32 frame_num, address *addr_srv, address *addr_c
 
   ssl_debug_printf("  conversation = %p, ssl_session = %p\n", (void *)conversation, (void *)ssl);
 
+  ssl_set_server(ssl, addr_srv, ptype, port_srv);
+
   /* version */
   if ((ssl->version==SSL_VER_UNKNOWN) && (version!=SSL_VER_UNKNOWN)) {
     switch (version) {