From: Nikos Mavrogiannopoulos Date: Thu, 8 Jan 2015 08:35:59 +0000 (+0100) Subject: When receiving a TLS record with multiple handshake packets, parse them in one go X-Git-Tag: gnutls_3_4_0~376 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bb616582ea8cce9880067a292f7fc031b19d315f;p=thirdparty%2Fgnutls.git When receiving a TLS record with multiple handshake packets, parse them in one go That resolves: https://savannah.gnu.org/support/?108712 --- diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 9ec2a88edf..d5888a25c2 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -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; } 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 #define GNUTLS_E_INT_RET_0 -1251 +#define GNUTLS_E_INT_CHECK_AGAIN -1252 #ifdef __FILE__ #ifdef __LINE__