]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Corrected bug which affected compressed records.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 22 Nov 2013 21:28:38 +0000 (22:28 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 22 Nov 2013 21:32:43 +0000 (22:32 +0100)
Less space was provided for decryption than the required
causing disconnection issues when compression was used.
The issue was pointed by Frank Zschockelt.

Also replaced the macros MAX_RECORD_RECV_SIZE and MAX_RECV_SIZE
with max_decrypted_size() and max_record_recv_size().

lib/gnutls_buffers.c
lib/gnutls_int.h
lib/gnutls_record.c
lib/gnutls_record.h

index 4ea0cc94b6d74b5d03f76b2d919351c21323e650..7f3b5a41478b1bc20e41aa2be558a2f1bae85071 100644 (file)
@@ -185,8 +185,8 @@ _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel,
        ssize_t i, ret;
        uint8_t *ptr;
        struct timespec t1, t2;
-       size_t max_size = get_max_decrypted_data(session);
-       size_t recv_size = MAX_RECV_SIZE(session);
+       size_t max_size = max_record_recv_size(session);
+       size_t recv_size = max_record_recv_size(session);
        gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
        unsigned int diff;
 
@@ -261,7 +261,7 @@ _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel,
 {
        size_t left;
        ssize_t i = 0;
-       size_t max_size = get_max_decrypted_data(session);
+       size_t max_size = max_record_recv_size(session);
        uint8_t *ptr;
        gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
        int ret;
@@ -436,7 +436,7 @@ _gnutls_writev(gnutls_session_t session, const giovec_t * giovec,
  * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
  * It does return gnutls_errno instead.
  * This function reads data from the socket and keeps them in a buffer, of up to
- * MAX_RECV_SIZE
+ * max_record_recv_size
  *
  * This is not a general purpose function. It returns EXACTLY the data requested,
  * which are stored in a local (in the session) buffer.
@@ -454,7 +454,7 @@ _gnutls_io_read_buffered(gnutls_session_t session, size_t total,
        mbuffer_st *bufel = NULL;
        size_t recvdata, readsize;
 
-       if (total > MAX_RECV_SIZE(session) || total == 0) {
+       if (total > max_record_recv_size(session) || total == 0) {
                gnutls_assert();        /* internal error */
                return GNUTLS_E_INVALID_REQUEST;
        }
@@ -483,7 +483,7 @@ _gnutls_io_read_buffered(gnutls_session_t session, size_t total,
         * receive are longer than the maximum receive buffer size.
         */
        if ((session->internals.record_recv_buffer.byte_length +
-            recvdata) > MAX_RECV_SIZE(session)) {
+            recvdata) > max_record_recv_size(session)) {
                gnutls_assert();        /* internal error */
                return GNUTLS_E_INVALID_REQUEST;
        }
index c1ce4b88a3ebc717d143139453329a58b4a120ea..21d2fc938b8938a84273f19c78df2ddae86daf27 100644 (file)
@@ -177,12 +177,14 @@ typedef enum record_flush_t {
 #define RECORD_HEADER_SIZE(session) (IS_DTLS(session) ? DTLS_RECORD_HEADER_SIZE : TLS_RECORD_HEADER_SIZE)
 #define MAX_RECORD_HEADER_SIZE DTLS_RECORD_HEADER_SIZE
 
-#define MAX_RECORD_SEND_SIZE(session) (IS_DTLS(session)?((size_t)gnutls_dtls_get_mtu(session)):(size_t)session->security_parameters.max_record_send_size+MAX_RECORD_OVERHEAD(session))
-#define MAX_RECORD_RECV_SIZE(session) ((size_t)session->security_parameters.max_record_recv_size)
+/* The following macro is used to calculate the overhead when sending.
+ * when receiving we use a different way as there are implementations that
+ * store more data than allowed.
+ */
+#define MAX_RECORD_SEND_OVERHEAD(session) (MAX_CIPHER_BLOCK_SIZE/*iv*/+MAX_PAD_SIZE+(gnutls_compression_get(session)!=GNUTLS_COMP_NULL)?EXTRA_COMP_SIZE:0+MAX_HASH_SIZE/*MAC*/)
+#define MAX_RECORD_SEND_SIZE(session) (IS_DTLS(session)?((size_t)gnutls_dtls_get_mtu(session)):(size_t)session->security_parameters.max_record_send_size+MAX_RECORD_SEND_OVERHEAD(session))
 #define MAX_PAD_SIZE 255
 #define EXTRA_COMP_SIZE 2048
-#define MAX_RECORD_OVERHEAD(session) (MAX_CIPHER_BLOCK_SIZE/*iv*/+MAX_PAD_SIZE+(gnutls_compression_get(session)!=GNUTLS_COMP_NULL)?EXTRA_COMP_SIZE:0+MAX_HASH_SIZE/*MAC*/)
-#define MAX_RECV_SIZE(session) (MAX_RECORD_OVERHEAD(session)+MAX_RECORD_RECV_SIZE(session)+RECORD_HEADER_SIZE(session))
 
 #define TLS_HANDSHAKE_HEADER_SIZE 4
 #define DTLS_HANDSHAKE_HEADER_SIZE (TLS_HANDSHAKE_HEADER_SIZE+8)
index b597637884aba69134e6aa844b4aefb5148c8431..68d868abad308a7cc405ce36e205c63fdc00c015 100644 (file)
@@ -1088,7 +1088,7 @@ static int recv_headers(gnutls_session_t session, content_type_t type,
             record_check_version(session, htype, record->version)) < 0)
                return gnutls_assert_val(ret);
 
-       if (record->length > MAX_RECV_SIZE(session)) {
+       if (record->length > max_record_recv_size(session)) {
                _gnutls_audit_log
                    (session, "Received packet with illegal length: %u\n",
                     (unsigned int) record->length);
@@ -1195,9 +1195,11 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type,
                return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
        /* We allocate the maximum possible to allow few compressed bytes to expand to a
-        * full record.
+        * full record. Moreover we add space for any pad and the MAC (in case
+        * they are encrypted).
         */
-       decrypted = _mbuffer_alloc(record.length, record.length);
+       ret = max_decrypted_size(session) + MAX_PAD_SIZE + MAX_HASH_SIZE;
+       decrypted = _mbuffer_alloc(ret, ret);
        if (decrypted == NULL)
                return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
 
index 1a515610b4f860afc6a8d2e80222a124c4bef8bb..12fcc9b36249b1f95062aa43b023b4cb58687a09 100644 (file)
@@ -47,17 +47,30 @@ ssize_t _gnutls_recv_int(gnutls_session_t session, content_type_t type,
                         gnutls_handshake_description_t, uint8_t * data,
                         size_t sizeofdata, void *seq, unsigned int ms);
 
-inline static int get_max_decrypted_data(gnutls_session_t session)
+inline static unsigned max_record_recv_size(gnutls_session_t session)
 {
-       int ret;
+       unsigned size;
 
-       ret = MAX_RECORD_RECV_SIZE(session) + MAX_RECORD_OVERHEAD(session);
+       size = MAX_CIPHER_BLOCK_SIZE /*iv*/ + MAX_PAD_SIZE + MAX_HASH_SIZE/*MAC*/;
+       
+       if (gnutls_compression_get(session)!=GNUTLS_COMP_NULL || session->internals.priorities.allow_large_records != 0)
+               size += EXTRA_COMP_SIZE;
 
-       if (session->internals.priorities.allow_large_records != 0 &&
-           gnutls_compression_get(session) == GNUTLS_COMP_NULL)
-               ret += EXTRA_COMP_SIZE;
+       size += session->security_parameters.max_record_recv_size + RECORD_HEADER_SIZE(session);
 
-       return ret;
+       return size;
+}
+
+inline static unsigned max_decrypted_size(gnutls_session_t session)
+{
+       unsigned size = 0;
+
+       if (session->internals.priorities.allow_large_records != 0)
+               size += EXTRA_COMP_SIZE;
+
+       size += session->security_parameters.max_record_recv_size;
+
+       return size;
 }
 
 #endif