]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
When receiving a TLS record with multiple handshake packets, parse them in one go
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 8 Jan 2015 08:35:59 +0000 (09:35 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 8 Jan 2015 08:38:25 +0000 (09:38 +0100)
That resolves:
https://savannah.gnu.org/support/?108712

lib/gnutls_buffers.c
lib/gnutls_errors.h

index 9ec2a88edf7699efc60181a00bbd4bce569b1959..d5888a25c20f71abd150b10bb821406291637fb2 100644 (file)
@@ -1113,8 +1113,16 @@ static int get_last_packet(gnutls_session_t session,
                                                      [LAST_ELEMENT]);
                        session->internals.handshake_recv_buffer_size--;
                        return 0;
-               } else
-                       goto timeout;
+               } else {
+                       /* if we don't have a complete handshake message, but we
+                        * have queued data waiting, try again to reconstruct the
+                        * handshake packet, using the queued */
+                       if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
+                           record_check_unprocessed(session) > 0)
+                               return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
+                       else
+                               goto timeout;
+               }
        } else {                /* TLS */
 
                if (session->internals.handshake_recv_buffer_size > 0
@@ -1345,6 +1353,7 @@ _gnutls_handshake_io_recv_int(gnutls_session_t session,
 {
        int ret;
        unsigned int tleft = 0;
+       int retries = 7;
 
        ret = get_last_packet(session, htype, hsk, optional);
        if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED
@@ -1376,17 +1385,26 @@ _gnutls_handshake_io_recv_int(gnutls_session_t session,
                tleft = ret;
        }
 
-       /* if we don't have a complete message waiting for us, try 
-        * receiving more */
-       ret =
-           _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
-                                   tleft);
-       if (ret < 0)
-               return gnutls_assert_val_fatal(ret);
+       do {
+               /* if we don't have a complete message waiting for us, try 
+                * receiving more */
+               ret =
+                   _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
+                                           tleft);
+               if (ret < 0)
+                       return gnutls_assert_val_fatal(ret);
+
+               ret = _gnutls_parse_record_buffered_msgs(session);
+               if (ret == 0) {
+                       ret = get_last_packet(session, htype, hsk, optional);
+               }
+               /* we put an upper limit (retries) to the number of partial handshake
+                * messages in a record packet. */
+       } while(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN && retries-- > 0);
 
-       ret = _gnutls_parse_record_buffered_msgs(session);
-       if (ret == 0)
-               ret = get_last_packet(session, htype, hsk, optional);
+       if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
+               ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
+       }
 
        return ret;
 }
index dbc1dfd82fd171a7f5b257c694f56d21ca4cb175..a810834fb4a53d0ae5fe0dd64ea0d341567c40ca 100644 (file)
@@ -27,6 +27,7 @@
 #include <gnutls_global.h>
 
 #define GNUTLS_E_INT_RET_0 -1251
+#define GNUTLS_E_INT_CHECK_AGAIN -1252
 
 #ifdef __FILE__
 #ifdef __LINE__