summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2015-01-08 09:35:59 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2015-01-08 10:47:28 +0100
commitaab0c663471aa709f9e51d547a83e3eddefb47d2 (patch)
tree0486eb2df6c9a42ac96f2223b0c8111abde6f484
parentce27325e1706595e34f36a934a1042bdf1337e0f (diff)
downloadgnutls-aab0c663471aa709f9e51d547a83e3eddefb47d2.tar.gz
When receiving a TLS record with multiple handshake packets, parse them in one go
That resolves: https://savannah.gnu.org/support/?108712
-rw-r--r--lib/gnutls_buffers.c42
-rw-r--r--lib/gnutls_errors.h1
2 files changed, 31 insertions, 12 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 967fa41f13..7cde45c46f 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -1110,8 +1110,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
@@ -1342,6 +1350,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
@@ -1373,17 +1382,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;
}
diff --git a/lib/gnutls_errors.h b/lib/gnutls_errors.h
index dbc1dfd82f..a810834fb4 100644
--- a/lib/gnutls_errors.h
+++ b/lib/gnutls_errors.h
@@ -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__