]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
1. Fix for memory leaks on interrupted handshake.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 22 Oct 2009 16:33:44 +0000 (19:33 +0300)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 22 Oct 2009 21:07:06 +0000 (00:07 +0300)
2. Fixes issue where a TLS 1.2 client will wrongly calculate hashes if the server will select a different than 1.2 protocol.

3. In TLS 1.2 when a certificate request is sent, support is not complete. In that case abort the handshake. By checking
TLS 1.2 it seems that the algorithms to be used for the signature in the certificate verify message are negotiated not at
the client/server hello messages but rather selected by the server at the certificate request. This might not look as bad, but
since in this message we have to sign all previous handshake messages, it forces us to keep all the handshake messages into a
buffer until this point... I don't know who proposed this change to the TLS WG, but it seems it wasn't really thought of.

lib/gnutls_buffers.c
lib/gnutls_buffers.h
lib/gnutls_cipher.c
lib/gnutls_handshake.c
lib/gnutls_handshake.h
lib/gnutls_hash_int.c
lib/gnutls_hash_int.h
lib/gnutls_int.h
lib/gnutls_sig.c
lib/gnutls_state.c

index 4e54df631c2ea66dce208b8336eaec0342dcd8a6..75c3287e48a71e8c114b36ced3b43055005bb4b3 100644 (file)
@@ -1064,7 +1064,6 @@ _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
     }
 
   _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", (int)length);
-
   if (_gnutls_buffer_append (&session->internals.handshake_hash_buffer,
                             data, length) < 0)
     {
@@ -1082,24 +1081,6 @@ _gnutls_handshake_buffer_get_size (gnutls_session_t session)
   return session->internals.handshake_hash_buffer.length;
 }
 
-/* this function does not touch the buffer
- * and returns data from it (peek mode!)
- */
-int
-_gnutls_handshake_buffer_peek (gnutls_session_t session, opaque * data,
-                              size_t length)
-{
-  if (length > session->internals.handshake_hash_buffer.length)
-    {
-      length = session->internals.handshake_hash_buffer.length;
-    }
-
-  _gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n", (int)length);
-
-  memcpy (data, session->internals.handshake_hash_buffer.data, length);
-  return length;
-}
-
 /* this function does not touch the buffer
  * and returns data from it (peek mode!)
  */
@@ -1137,7 +1118,6 @@ _gnutls_handshake_buffer_clear (gnutls_session_t session)
 {
 
   _gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n");
-
   _gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
 
   return 0;
index b21ac5be93017930258be84620139e6e27a1e64a..a8ffa7d6796c227b1407db7af48012c109e1fbad 100644 (file)
@@ -41,8 +41,6 @@ ssize_t _gnutls_io_write_buffered2 (gnutls_session_t, const void *iptr,
                                    size_t n, const void *iptr2, size_t n2);
 
 int _gnutls_handshake_buffer_get_size (gnutls_session_t session);
-int _gnutls_handshake_buffer_peek (gnutls_session_t session, opaque * data,
-                                  size_t length);
 int _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
                                  size_t length);
 int _gnutls_handshake_buffer_clear (gnutls_session_t session);
index 0d8c5e1da0ffbacb8acecdd76b320c32385b639b..5f2ed62060581b74eaac9bab0765430f9eb7074f 100644 (file)
@@ -418,6 +418,10 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
   return length;
 }
 
+#define DEINIT_MAC(td, ver, algo) \
+          if (algo != GNUTLS_MAC_NULL) \
+            mac_deinit (&td, NULL, ver);
+
 /* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
  * Returns the actual compressed packet size.
  */
@@ -473,6 +477,9 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
                                   ciphertext.size)) < 0)
        {
          gnutls_assert ();
+         DEINIT_MAC(td, ver, session->security_parameters.write_mac_algorithm);
+
+
          return ret;
        }
 
@@ -483,6 +490,7 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
       if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
        {
          gnutls_assert ();
+         DEINIT_MAC(td, ver, session->security_parameters.write_mac_algorithm);
          return GNUTLS_E_DECRYPTION_FAILED;
        }
 
@@ -492,6 +500,7 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
                                   ciphertext.size)) < 0)
        {
          gnutls_assert ();
+         DEINIT_MAC(td, ver, session->security_parameters.write_mac_algorithm);
          return ret;
        }
 
@@ -505,6 +514,7 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
          if (ciphertext.size == 0)
            {
              gnutls_assert ();
+              DEINIT_MAC(td, ver, session->security_parameters.write_mac_algorithm);
              return GNUTLS_E_DECRYPTION_FAILED;
            }
        }
@@ -537,6 +547,7 @@ _gnutls_ciphertext2compressed (gnutls_session_t session,
       break;
     default:
       gnutls_assert ();
+      DEINIT_MAC(td, ver, session->security_parameters.write_mac_algorithm);
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
index 83dc54e78cd1e8454e112607d3211a5dac2b5bd9..93e0553b401719f06438e14abd13f9f74531d544 100644 (file)
 #define TRUE 1
 #define FALSE 0
 
-int _gnutls_server_select_comp_method (gnutls_session_t session,
+static int _gnutls_handshake_hash_init (gnutls_session_t session);
+static int _gnutls_server_select_comp_method (gnutls_session_t session,
                                       opaque * data, int datalen);
+static int
+_gnutls_handshake_hash_add_recvd (gnutls_session_t session,
+                                 gnutls_handshake_description_t recv_type,
+                                 opaque * header, uint16_t header_size,
+                                 opaque * dataptr, uint32_t datalen);
 
 
 /* Clears the handshake hash buffers and handles.
  */
-static void
+void
 _gnutls_handshake_hash_buffers_clear (gnutls_session_t session)
 {
-  _gnutls_hash_deinit (&session->internals.handshake_mac_handle_md5, NULL);
-  _gnutls_hash_deinit (&session->internals.handshake_mac_handle_sha, NULL);
+  if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_10) 
+    {
+      _gnutls_hash_deinit (&session->internals.handshake_mac_handle.tls10.md5, NULL);
+      _gnutls_hash_deinit (&session->internals.handshake_mac_handle.tls10.sha, NULL);
+    }
+  else if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12)
+    {
+      _gnutls_hash_deinit (&session->internals.handshake_mac_handle.tls12.mac, NULL);
+    }
+  session->security_parameters.handshake_mac_handle_type = 0;
   session->internals.handshake_mac_handle_init = 0;
   _gnutls_handshake_buffer_clear (session);
 }
@@ -150,23 +164,33 @@ _gnutls_ssl3_finished (gnutls_session_t session, int type, opaque * ret)
   const char *mesg;
   int rc;
 
-  rc =
-    _gnutls_hash_copy (&td_md5, &session->internals.handshake_mac_handle_md5);
-  if (rc < 0)
+  if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_10) 
     {
-      gnutls_assert ();
-      return rc;
-    }
+      rc =
+        _gnutls_hash_copy (&td_md5, &session->internals.handshake_mac_handle.tls10.md5);
+      if (rc < 0)
+        {
+          gnutls_assert ();
+          return rc;
+        }
+
+      rc =
+        _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls10.sha);
+      if (rc < 0)
+        {
+          gnutls_assert ();
+          _gnutls_hash_deinit (&td_md5, NULL);
+          return rc;
+        }
 
-  rc =
-    _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle_sha);
-  if (rc < 0)
+    }
+  else
     {
-      gnutls_assert ();
-      _gnutls_hash_deinit (&td_md5, NULL);
-      return rc;
+      gnutls_assert();
+      return GNUTLS_E_INTERNAL_ERROR;
     }
 
+
   if (type == GNUTLS_SERVER)
     {
       mesg = SSL3_SERVER_MSG;
@@ -198,7 +222,7 @@ static int
 _gnutls_finished (gnutls_session_t session, int type, void *ret)
 {
   const int siz = TLS_MSG_LEN;
-  opaque concat[36];
+  opaque concat[MAX_HASH_SIZE+16/*MD5*/];
   size_t len;
   const char *mesg;
   digest_hd_st td_md5;
@@ -206,39 +230,45 @@ _gnutls_finished (gnutls_session_t session, int type, void *ret)
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
   int rc;
 
-  if (!_gnutls_version_has_selectable_prf(ver))
+  if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_10) 
     {
       rc =
        _gnutls_hash_copy (&td_md5,
-                          &session->internals.handshake_mac_handle_md5);
+                          &session->internals.handshake_mac_handle.tls10.md5);
       if (rc < 0)
        {
          gnutls_assert ();
          return rc;
        }
-    }
 
-  rc =
-    _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle_sha);
-  if (rc < 0)
-    {
-      gnutls_assert ();
-      _gnutls_hash_deinit (&td_md5, NULL);
-      return rc;
-    }
+      rc =
+        _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls10.sha);
+      if (rc < 0)
+        {
+          gnutls_assert ();
+          _gnutls_hash_deinit (&td_md5, NULL);
+          return rc;
+        }
 
-  if (!_gnutls_version_has_selectable_prf(ver))
-    {
-      _gnutls_hash_deinit (&td_md5, concat);
-      _gnutls_hash_deinit (&td_sha, &concat[16]);
-      len = 20 + 16;
+        _gnutls_hash_deinit (&td_md5, concat);
+        _gnutls_hash_deinit (&td_sha, &concat[16]);
+        len = 20 + 16;
     }
-  else
+  else if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12) 
     {
-      _gnutls_hash_deinit (&td_sha, concat);
-      len = _gnutls_hash_get_algo_len (td_sha.algorithm);
+      rc =
+        _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls12.mac);
+      if (rc < 0)
+        {
+          gnutls_assert ();
+          return rc;
+        }
+
+        _gnutls_hash_deinit (&td_sha, concat);
+        len = _gnutls_hash_get_algo_len (td_sha.algorithm);
     }
 
+
   if (type == GNUTLS_SERVER)
     {
       mesg = SERVER_MSG;
@@ -534,8 +564,15 @@ _gnutls_handshake_hash_pending (gnutls_session_t session)
 
   if (siz > 0)
     {
-      _gnutls_hash (&session->internals.handshake_mac_handle_sha, data, siz);
-      _gnutls_hash (&session->internals.handshake_mac_handle_md5, data, siz);
+      if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_10) 
+        {
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls10.sha, data, siz);
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls10.md5, data, siz);
+        } 
+      else if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12)
+        {
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.mac, data, siz);
+        }
     }
 
   _gnutls_handshake_buffer_empty (session);
@@ -836,7 +873,7 @@ finish:
 
 /* This selects the best supported compression method from the ones provided 
  */
-int
+static int
 _gnutls_server_select_comp_method (gnutls_session_t session,
                                   opaque * data, int datalen)
 {
@@ -915,6 +952,18 @@ _gnutls_handshake_hash_add_sent (gnutls_session_t session,
 {
   int ret;
 
+  if (session->security_parameters.entity == GNUTLS_CLIENT && type == GNUTLS_HANDSHAKE_CLIENT_HELLO)
+    {
+      /* do not hash immediatelly since the hash has not yet been initialized */
+      if ((ret =
+          _gnutls_handshake_buffer_put (session, dataptr, datalen)) < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+      return 0;
+    }
+
   if ((ret = _gnutls_handshake_hash_pending (session)) < 0)
     {
       gnutls_assert ();
@@ -923,10 +972,18 @@ _gnutls_handshake_hash_add_sent (gnutls_session_t session,
 
   if (type != GNUTLS_HANDSHAKE_HELLO_REQUEST)
     {
-      _gnutls_hash (&session->internals.handshake_mac_handle_sha, dataptr,
+      if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_10) 
+        {
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls10.sha, dataptr,
                    datalen);
-      _gnutls_hash (&session->internals.handshake_mac_handle_md5, dataptr,
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls10.md5, dataptr,
                    datalen);
+        }
+      else if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12) 
+        { 
+          _gnutls_hash (&session->internals.handshake_mac_handle.tls12.mac, dataptr,
+                   datalen);
+        }
     }
 
   return 0;
@@ -1165,11 +1222,14 @@ _gnutls_handshake_hash_add_recvd (gnutls_session_t session,
   /* The idea here is to hash the previous message we received,
    * and add the one we just received into the handshake_hash_buffer.
    */
-
-  if ((ret = _gnutls_handshake_hash_pending (session)) < 0)
+  if ((session->security_parameters.entity == GNUTLS_SERVER || recv_type != GNUTLS_HANDSHAKE_SERVER_HELLO) && 
+      (session->security_parameters.entity == GNUTLS_CLIENT || recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO))
     {
-      gnutls_assert ();
-      return ret;
+      if ((ret = _gnutls_handshake_hash_pending (session)) < 0)
+        {
+          gnutls_assert ();
+          return ret;
+        }
     }
 
   /* here we buffer the handshake messages - needed at Finished message */
@@ -1292,11 +1352,23 @@ _gnutls_recv_handshake (gnutls_session_t session, uint8_t ** data,
     case GNUTLS_HANDSHAKE_CLIENT_HELLO:
     case GNUTLS_HANDSHAKE_SERVER_HELLO:
       ret = _gnutls_recv_hello (session, dataptr, length32);
+      
       /* dataptr is freed because the caller does not
        * need it */
       gnutls_free (dataptr);
       if (data != NULL)
        *data = NULL;
+      
+      if (ret < 0)
+        break;
+
+      /* initialize the hashes for both - (client will know server's version
+       * and server as well at this point) */
+      if ((ret = _gnutls_handshake_hash_init (session)) < 0) {
+        gnutls_assert();
+        return ret;
+      }
+
       break;
     case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
       if (length32 == 0)
@@ -2167,38 +2239,60 @@ _gnutls_abort_handshake (gnutls_session_t session, int ret)
 /* This function initialized the handshake hash session.
  * required for finished messages.
  */
-inline static int
+static int
 _gnutls_handshake_hash_init (gnutls_session_t session)
 {
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
-  gnutls_digest_algorithm_t hash_algo = GNUTLS_MAC_SHA1;
 
   if (session->internals.handshake_mac_handle_init == 0)
     {
-      int ret =
-       _gnutls_hash_init (&session->internals.handshake_mac_handle_md5,
+      int ret;
+
+      /* set the hash type for handshake message hashing */
+      if (_gnutls_version_has_selectable_prf (ver))
+        session->security_parameters.handshake_mac_handle_type = HANDSHAKE_MAC_TYPE_12;
+      else
+        session->security_parameters.handshake_mac_handle_type = HANDSHAKE_MAC_TYPE_10;
+
+
+      if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_10) 
+        {
+          ret =
+           _gnutls_hash_init (&session->internals.handshake_mac_handle.tls10.md5,
                           GNUTLS_MAC_MD5);
 
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
+          if (ret < 0)
+           {
+             gnutls_assert ();
+             return ret;
+           }
 
-      /* The algorithm to compute hash over handshake messages must be
-        same as the one used as the basis for PRF.  By now we use
-        SHA256. */
-      if (_gnutls_version_has_selectable_prf (ver))
-       hash_algo = GNUTLS_MAC_SHA256;
+          ret =
+            _gnutls_hash_init (&session->internals.handshake_mac_handle.tls10.sha,
+                          GNUTLS_MAC_SHA1);
+          if (ret < 0)
+           {
+             gnutls_assert ();
+             _gnutls_hash_deinit (&session->internals.handshake_mac_handle.tls10.md5, NULL);
+             return GNUTLS_E_MEMORY_ERROR;
+           }
+        }
+      else if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12)
+        {
+        /* The algorithm to compute hash over handshake messages must be
+          same as the one used as the basis for PRF.  By now we use
+          SHA256. */
+          gnutls_digest_algorithm_t hash_algo = GNUTLS_MAC_SHA256;
 
-      ret =
-       _gnutls_hash_init (&session->internals.handshake_mac_handle_sha,
+          ret =
+           _gnutls_hash_init (&session->internals.handshake_mac_handle.tls12.mac,
                           hash_algo);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_MEMORY_ERROR;
-       }
+           if (ret < 0)
+            {
+              gnutls_assert ();
+              return GNUTLS_E_MEMORY_ERROR;
+            }
+        }
 
       session->internals.handshake_mac_handle_init = 1;
     }
@@ -2300,12 +2394,6 @@ gnutls_handshake (gnutls_session_t session)
 {
   int ret;
 
-  if ((ret = _gnutls_handshake_hash_init (session)) < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
   if (session->security_parameters.entity == GNUTLS_CLIENT)
     {
       ret = _gnutls_handshake_client (session);
@@ -2343,9 +2431,9 @@ gnutls_handshake (gnutls_session_t session)
   return 0;
 }
 
-#define IMED_RET( str, ret) do { \
+#define IMED_RET( str, ret, check_fatal) do { \
        if (ret < 0) { \
-               if (gnutls_error_is_fatal(ret)==0) return ret; \
+               if (check_fatal != 0 && gnutls_error_is_fatal(ret)==0) return ret; \
                gnutls_assert(); \
                ERR( str, ret); \
                _gnutls_handshake_hash_buffers_clear(session); \
@@ -2383,7 +2471,7 @@ _gnutls_handshake_client (gnutls_session_t session)
     case STATE1:
       ret = _gnutls_send_hello (session, AGAIN (STATE1));
       STATE = STATE1;
-      IMED_RET ("send hello", ret);
+      IMED_RET ("send hello", ret, 0);
 
     case STATE2:
       /* receive the server hello */
@@ -2392,14 +2480,14 @@ _gnutls_handshake_client (gnutls_session_t session)
                                GNUTLS_HANDSHAKE_SERVER_HELLO,
                                MANDATORY_PACKET);
       STATE = STATE2;
-      IMED_RET ("recv hello", ret);
+      IMED_RET ("recv hello", ret, 1);
 
     case STATE70:
       if (session->security_parameters.extensions.do_recv_supplemental)
        {
          ret = _gnutls_recv_supplemental (session);
          STATE = STATE70;
-         IMED_RET ("recv supplemental", ret);
+         IMED_RET ("recv supplemental", ret, 1);
        }
 
     case STATE3:
@@ -2407,14 +2495,14 @@ _gnutls_handshake_client (gnutls_session_t session)
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_recv_server_certificate (session);
       STATE = STATE3;
-      IMED_RET ("recv server certificate", ret);
+      IMED_RET ("recv server certificate", ret, 1);
 
     case STATE4:
       /* receive the server key exchange */
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_recv_server_kx_message (session);
       STATE = STATE4;
-      IMED_RET ("recv server kx message", ret);
+      IMED_RET ("recv server kx message", ret, 1);
 
     case STATE5:
       /* receive the server certificate request - if any 
@@ -2423,7 +2511,7 @@ _gnutls_handshake_client (gnutls_session_t session)
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_recv_server_certificate_request (session);
       STATE = STATE5;
-      IMED_RET ("recv server certificate request message", ret);
+      IMED_RET ("recv server certificate request message", ret, 1);
 
     case STATE6:
       /* receive the server hello done */
@@ -2433,14 +2521,14 @@ _gnutls_handshake_client (gnutls_session_t session)
                                  GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
                                  MANDATORY_PACKET);
       STATE = STATE6;
-      IMED_RET ("recv server hello done", ret);
+      IMED_RET ("recv server hello done", ret, 1);
 
     case STATE71:
       if (session->security_parameters.extensions.do_send_supplemental)
        {
          ret = _gnutls_send_supplemental (session, AGAIN (STATE71));
          STATE = STATE71;
-         IMED_RET ("send supplemental", ret);
+         IMED_RET ("send supplemental", ret, 0);
        }
 
     case STATE7:
@@ -2449,13 +2537,13 @@ _gnutls_handshake_client (gnutls_session_t session)
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_send_client_certificate (session, AGAIN (STATE7));
       STATE = STATE7;
-      IMED_RET ("send client certificate", ret);
+      IMED_RET ("send client certificate", ret, 0);
 
     case STATE8:
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_send_client_kx_message (session, AGAIN (STATE8));
       STATE = STATE8;
-      IMED_RET ("send client kx", ret);
+      IMED_RET ("send client kx", ret, 0);
 
     case STATE9:
       /* send client certificate verify */
@@ -2463,7 +2551,7 @@ _gnutls_handshake_client (gnutls_session_t session)
        ret =
          _gnutls_send_client_certificate_verify (session, AGAIN (STATE9));
       STATE = STATE9;
-      IMED_RET ("send client certificate verify", ret);
+      IMED_RET ("send client certificate verify", ret, 0);
 
       STATE = STATE0;
     default:
@@ -2612,19 +2700,19 @@ _gnutls_handshake_server (gnutls_session_t session)
                                GNUTLS_HANDSHAKE_CLIENT_HELLO,
                                MANDATORY_PACKET);
       STATE = STATE1;
-      IMED_RET ("recv hello", ret);
+      IMED_RET ("recv hello", ret, 1);
 
     case STATE2:
       ret = _gnutls_send_hello (session, AGAIN (STATE2));
       STATE = STATE2;
-      IMED_RET ("send hello", ret);
+      IMED_RET ("send hello", ret, 0);
 
     case STATE70:
       if (session->security_parameters.extensions.do_send_supplemental)
        {
          ret = _gnutls_send_supplemental (session, AGAIN (STATE70));
          STATE = STATE70;
-         IMED_RET ("send supplemental data", ret);
+         IMED_RET ("send supplemental data", ret, 0);
        }
 
       /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
@@ -2634,14 +2722,14 @@ _gnutls_handshake_server (gnutls_session_t session)
       if (session->internals.resumed == RESUME_FALSE)
        ret = _gnutls_send_server_certificate (session, AGAIN (STATE3));
       STATE = STATE3;
-      IMED_RET ("send server certificate", ret);
+      IMED_RET ("send server certificate", ret, 0);
 
     case STATE4:
       /* send server key exchange (A) */
       if (session->internals.resumed == RESUME_FALSE)
        ret = _gnutls_send_server_kx_message (session, AGAIN (STATE4));
       STATE = STATE4;
-      IMED_RET ("send server kx", ret);
+      IMED_RET ("send server kx", ret, 0);
 
     case STATE5:
       /* Send certificate request - if requested to */
@@ -2649,7 +2737,7 @@ _gnutls_handshake_server (gnutls_session_t session)
        ret =
          _gnutls_send_server_certificate_request (session, AGAIN (STATE5));
       STATE = STATE5;
-      IMED_RET ("send server cert request", ret);
+      IMED_RET ("send server cert request", ret, 0);
 
     case STATE6:
       /* send the server hello done */
@@ -2659,14 +2747,14 @@ _gnutls_handshake_server (gnutls_session_t session)
                                        GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
                                        AGAIN (STATE6));
       STATE = STATE6;
-      IMED_RET ("send server hello done", ret);
+      IMED_RET ("send server hello done", ret, 0);
 
     case STATE71:
       if (session->security_parameters.extensions.do_recv_supplemental)
        {
          ret = _gnutls_recv_supplemental (session);
          STATE = STATE71;
-         IMED_RET ("recv client supplemental", ret);
+         IMED_RET ("recv client supplemental", ret, 1);
        }
 
       /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
@@ -2675,21 +2763,21 @@ _gnutls_handshake_server (gnutls_session_t session)
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_recv_client_certificate (session);
       STATE = STATE7;
-      IMED_RET ("recv client certificate", ret);
+      IMED_RET ("recv client certificate", ret, 1);
 
     case STATE8:
       /* receive the client key exchange message */
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_recv_client_kx_message (session);
       STATE = STATE8;
-      IMED_RET ("recv client kx", ret);
+      IMED_RET ("recv client kx", ret, 1);
 
     case STATE9:
       /* receive the client certificate verify message */
       if (session->internals.resumed == RESUME_FALSE)  /* if we are not resuming */
        ret = _gnutls_recv_client_certificate_verify_message (session);
       STATE = STATE9;
-      IMED_RET ("recv client certificate verify", ret);
+      IMED_RET ("recv client certificate verify", ret, 1);
 
       STATE = STATE0;          /* finished thus clear session */
     default:
@@ -2713,7 +2801,7 @@ _gnutls_handshake_common (gnutls_session_t session)
       /* if we are a client resuming - or we are a server not resuming */
 
       ret = _gnutls_recv_handshake_final (session, TRUE);
-      IMED_RET ("recv handshake final", ret);
+      IMED_RET ("recv handshake final", ret, 1);
 
 #ifdef ENABLE_SESSION_TICKET
       switch (STATE)
@@ -2724,7 +2812,7 @@ _gnutls_handshake_common (gnutls_session_t session)
            {
              ret = _gnutls_send_new_session_ticket (session, AGAIN(STATE40));
              STATE = STATE40;
-             IMED_RET ("send handshake new session ticket", ret);
+             IMED_RET ("send handshake new session ticket", ret, 0);
            }
          STATE = STATE0;
        default:
@@ -2733,13 +2821,13 @@ _gnutls_handshake_common (gnutls_session_t session)
 #endif
 
       ret = _gnutls_send_handshake_final (session, FALSE);
-      IMED_RET ("send handshake final", ret);
+      IMED_RET ("send handshake final", ret, 0);
     }
   else
     {                          /* if we are a client not resuming - or we are a server resuming */
 
       ret = _gnutls_send_handshake_final (session, TRUE);
-      IMED_RET ("send handshake final 2", ret);
+      IMED_RET ("send handshake final 2", ret, 0);
 
 #ifdef ENABLE_SESSION_TICKET
       switch (STATE)
@@ -2750,7 +2838,7 @@ _gnutls_handshake_common (gnutls_session_t session)
            {
              ret = _gnutls_recv_new_session_ticket (session);
              STATE = STATE41;
-             IMED_RET ("recv handshake new session ticket", ret);
+             IMED_RET ("recv handshake new session ticket", ret, 1);
            }
          STATE = STATE0;
        default:
@@ -2759,7 +2847,7 @@ _gnutls_handshake_common (gnutls_session_t session)
 #endif
 
       ret = _gnutls_recv_handshake_final (session, FALSE);
-      IMED_RET ("recv handshake final 2", ret);
+      IMED_RET ("recv handshake final 2", ret, 1);
     }
 
   if (session->security_parameters.entity == GNUTLS_SERVER)
index f1b1bd66cc3a6af3de001f9f5acda92ce8a18fee..2f484f5a7f116646607c956a1480a6c15a7c4868 100644 (file)
@@ -55,6 +55,8 @@ int _gnutls_negotiate_version (gnutls_session_t session,
 int _gnutls_user_hello_func (gnutls_session_t session,
                             gnutls_protocol_t adv_version);
 
+void _gnutls_handshake_hash_buffers_clear (gnutls_session_t session);
+
 #define STATE session->internals.handshake_state
 /* This returns true if we have got there
  * before (and not finished due to an interrupt).
index e55ae541e2c7600f8c6da9a2bb4dd032b7dee132..5e5b2aa6e1a305178d55b5c3d9fb32054a10218f 100644 (file)
@@ -77,6 +77,7 @@ _gnutls_hash_init (digest_hd_st * dig, gnutls_digest_algorithm_t algorithm)
          gnutls_assert ();
          return GNUTLS_E_HASH_FAILED;
        }
+      dig->active = 1;
       return 0;
     }
 
@@ -89,6 +90,7 @@ _gnutls_hash_init (digest_hd_st * dig, gnutls_digest_algorithm_t algorithm)
       return result;
     }
 
+  dig->active = 1;
   return 0;
 }
 
@@ -119,10 +121,10 @@ _gnutls_hash_copy (digest_hd_st * dst, digest_hd_st * src)
 {
   int result;
 
+  memset(dst, 0, sizeof(*dst));
   dst->algorithm = src->algorithm;
-  dst->key = NULL;             /* it's a hash anyway */
-  dst->keysize = 0;
   dst->registered = src->registered;
+  dst->active = 1;
 
   if (src->registered)
     {
@@ -165,7 +167,14 @@ _gnutls_hash_output (digest_hd_st * handle, void *digest)
 void
 _gnutls_hash_deinit (digest_hd_st * handle, void *digest)
 {
-  _gnutls_hash_output (handle, digest);
+  if (handle->active != 1) {
+    return;
+  }
+
+  if (digest != NULL)
+    _gnutls_hash_output (handle, digest);
+
+  handle->active = 0;
 
   if (handle->registered && handle->hd.rh.ctx != NULL)
     {
@@ -269,6 +278,7 @@ _gnutls_hmac_init (digest_hd_st * dig, gnutls_mac_algorithm_t algorithm,
          return GNUTLS_E_HASH_FAILED;
        }
 
+      dig->active = 1;
       return 0;
     }
 
@@ -283,6 +293,7 @@ _gnutls_hmac_init (digest_hd_st * dig, gnutls_mac_algorithm_t algorithm,
 
   _gnutls_mac_ops.setkey (dig->hd.gc, key, keylen);
 
+  dig->active = 1;
   return 0;
 }
 
@@ -323,8 +334,14 @@ _gnutls_hmac_output (digest_hd_st * handle, void *digest)
 void
 _gnutls_hmac_deinit (digest_hd_st * handle, void *digest)
 {
-  _gnutls_hmac_output (handle, digest);
+  if (handle->active != 1) {
+    return;
+  }
+
+  if (digest)
+    _gnutls_hmac_output (handle, digest);
 
+  handle->active = 0;
   if (handle->registered && handle->hd.rh.ctx != NULL)
     {
       handle->hd.rh.cc->deinit (handle->hd.rh.ctx);
@@ -398,6 +415,7 @@ _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest)
   if (padsize == 0)
     {
       gnutls_assert ();
+      _gnutls_hash_deinit (handle, NULL);
       return;
     }
 
@@ -407,6 +425,7 @@ _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest)
   if (rc < 0)
     {
       gnutls_assert ();
+      _gnutls_hash_deinit (handle, NULL);
       return;
     }
 
index 8017d12f9af3b141f0167f0281fbf065cf3a3937..d915af587b9185178db64d161d3d36aa8d3b7113 100644 (file)
@@ -52,6 +52,7 @@ typedef struct
   gnutls_mac_algorithm_t algorithm;
   const void *key;
   int keysize;
+  int active;
 } digest_hd_st;
 
 int _gnutls_hmac_init (digest_hd_st*, gnutls_mac_algorithm_t algorithm,
index 100ad374871b3fba99129866d64914b9c3e8564a..ac1da9df3ef5f785d89b7037d51123301a937d5f 100644 (file)
@@ -200,6 +200,12 @@ typedef enum content_type_t
 #define GNUTLS_PK_ANY (gnutls_pk_algorithm_t)-1
 #define GNUTLS_PK_NONE (gnutls_pk_algorithm_t)-2
 
+typedef enum
+{
+  HANDSHAKE_MAC_TYPE_10=1,
+  HANDSHAKE_MAC_TYPE_12
+} handshake_mac_type_t;
+
 /* Store & Retrieve functions defines: 
  */
 
@@ -213,7 +219,6 @@ typedef struct auth_cred_st
   struct auth_cred_st *next;
 } auth_cred_st;
 
-
 struct gnutls_key_st
 {
   /* For DH KX */
@@ -361,6 +366,7 @@ typedef struct
   gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
   gnutls_mac_algorithm_t write_mac_algorithm;
   gnutls_compression_method_t write_compression_algorithm;
+  handshake_mac_type_t handshake_mac_handle_type; /* one of HANDSHAKE_TYPE_10 and HANDSHAKE_TYPE_12 */
 
   /* this is the ciphersuite we are going to use 
    * moved here from internals in order to be restored
@@ -468,14 +474,25 @@ typedef struct
   gnutls_handshake_description_t recv_type;
 } handshake_header_buffer_st;
 
+
 typedef struct
 {
   gnutls_buffer application_data_buffer;       /* holds data to be delivered to application layer */
   gnutls_buffer handshake_hash_buffer; /* used to keep the last received handshake 
                                         * message */
-  digest_hd_st handshake_mac_handle_sha;       /* hash of the handshake messages */
-  digest_hd_st handshake_mac_handle_md5;       /* hash of the handshake messages */
-  int handshake_mac_handle_init; /* 1 when the previous two were initialized */
+  union
+    {
+      struct 
+        {
+          digest_hd_st sha;    /* hash of the handshake messages */
+          digest_hd_st md5;    /* hash of the handshake messages */
+        } tls10;
+      struct
+        {
+          digest_hd_st mac;    /* hash of the handshake messages for TLS 1.2+ */
+        } tls12;
+    } handshake_mac_handle;
+  int handshake_mac_handle_init; /* 1 when the previous union and type were initialized */
 
   gnutls_buffer handshake_data_buffer; /* this is a buffer that holds the current handshake message */
   gnutls_buffer ia_data_buffer;        /* holds inner application data (TLS/IA) */
index 04d61541d81b76844d00c81e85a84b7e334134de..c49f2eda2ae775be89fda274eb0b4f4ad3f59773 100644 (file)
@@ -132,8 +132,17 @@ _gnutls_tls_sign_hdata (gnutls_session_t session,
   digest_hd_st td_sha;
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
 
+  /* FIXME: This is not compliant to TLS 1.2. We should use an algorithm from the
+   * SignatureAndHashAlgorithm field of Certificate Request.
+   */
+  if (session->security_parameters.handshake_mac_handle_type != HANDSHAKE_MAC_TYPE_10)
+    {
+      gnutls_assert();
+      return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+    }
+  
   ret =
-    _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle_sha);
+    _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls10.sha);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -161,7 +170,7 @@ _gnutls_tls_sign_hdata (gnutls_session_t session,
     case GNUTLS_PK_RSA:
       ret =
        _gnutls_hash_copy (&td_md5,
-                          &session->internals.handshake_mac_handle_md5);
+                          &session->internals.handshake_mac_handle.tls10.md5);
       if (ret < 0)
        {
          gnutls_assert ();
@@ -464,8 +473,14 @@ _gnutls_verify_sig_hdata (gnutls_session_t session, gnutls_cert * cert,
   gnutls_datum_t dconcat;
   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
 
+  if (session->security_parameters.handshake_mac_handle_type != HANDSHAKE_MAC_TYPE_10)
+    {
+      gnutls_assert();
+      return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+    }
+
   ret =
-    _gnutls_hash_copy (&td_md5, &session->internals.handshake_mac_handle_md5);
+    _gnutls_hash_copy (&td_md5, &session->internals.handshake_mac_handle.tls10.md5);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -473,7 +488,7 @@ _gnutls_verify_sig_hdata (gnutls_session_t session, gnutls_cert * cert,
     }
 
   ret =
-    _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle_sha);
+    _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls10.sha);
   if (ret < 0)
     {
       gnutls_assert ();
index fede2a001146531eb12a88dab8df9e897dc4bd04..cd08f44a88c4f184b8343e28276c88638decdfc2 100644 (file)
@@ -201,6 +201,8 @@ deinit_internal_params (gnutls_session_t session)
   if (session->internals.params.free_rsa_params)
     gnutls_rsa_params_deinit (session->internals.params.rsa_params);
 
+  _gnutls_handshake_hash_buffers_clear(session);
+
   memset (&session->internals.params, 0, sizeof (session->internals.params));
 }
 
@@ -208,8 +210,8 @@ deinit_internal_params (gnutls_session_t session)
  * structure within the session, which depend on the current handshake.
  * This is used to allow further handshakes.
  */
-void
-_gnutls_handshake_internal_state_clear (gnutls_session_t session)
+static void
+_gnutls_handshake_internal_state_init (gnutls_session_t session)
 {
   session->internals.extensions_sent_size = 0;
 
@@ -231,6 +233,13 @@ _gnutls_handshake_internal_state_clear (gnutls_session_t session)
   session->internals.last_handshake_out = -1;
 
   session->internals.resumable = RESUME_TRUE;
+}
+
+void
+_gnutls_handshake_internal_state_clear (gnutls_session_t session)
+{
+  _gnutls_handshake_internal_state_init(session);
+
   _gnutls_free_datum (&session->internals.recv_buffer);
 
   deinit_internal_params (session);
@@ -336,7 +345,7 @@ gnutls_init (gnutls_session_t * session, gnutls_connection_end_t con_end)
    * as NULL or 0. This is why calloc is used.
    */
 
-  _gnutls_handshake_internal_state_clear (*session);
+  _gnutls_handshake_internal_state_init (*session);
 
   return 0;
 }