From: Nikos Mavrogiannopoulos Date: Sat, 26 Feb 2011 10:27:13 +0000 (+0100) Subject: internal buffering for record and handshake data changed from gnutls_buffers to gnutl... X-Git-Tag: gnutls_2_99_0~157 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5d1ef73207befe4d46e6666dda5a698faa7f7ab9;p=thirdparty%2Fgnutls.git internal buffering for record and handshake data changed from gnutls_buffers to gnutls_mbuffers. --- diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index a5b7eedd22..490b40cc7a 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -72,38 +72,29 @@ * HANDSHAKE DATA. */ int -_gnutls_record_buffer_put (content_type_t type, - gnutls_session_t session, opaque * data, - size_t length) +_gnutls_record_buffer_put (gnutls_session_t session, + content_type_t type, uint64* seq, mbuffer_st* bufel) { - gnutls_buffer_st *buf; - if (length == 0) - return 0; + bufel->type = type; + memcpy(&bufel->record_sequence, seq, sizeof(*seq)); switch (type) { case GNUTLS_APPLICATION_DATA: - buf = &session->internals.application_data_buffer; + _mbuffer_enqueue(&session->internals.application_data_buffer, bufel); _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n", - (int) length, (int) type); + (int) bufel->msg.size, (int) type); break; case GNUTLS_HANDSHAKE: - buf = &session->internals.handshake_data_buffer; + _mbuffer_enqueue(&session->internals.handshake_data_buffer, bufel); _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n", - (int) length, (int) type); + (int) bufel->msg.size, (int) type); break; default: - gnutls_assert (); - return GNUTLS_E_INVALID_REQUEST; - } - - if (_gnutls_buffer_append_data (buf, data, length) < 0) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } return 0; @@ -115,10 +106,10 @@ _gnutls_record_buffer_get_size (content_type_t type, gnutls_session_t session) switch (type) { case GNUTLS_APPLICATION_DATA: - return session->internals.application_data_buffer.length; + return session->internals.application_data_buffer.byte_length; case GNUTLS_HANDSHAKE: - return session->internals.handshake_data_buffer.length; + return session->internals.handshake_data_buffer.byte_length; default: return GNUTLS_E_INVALID_REQUEST; @@ -149,8 +140,12 @@ gnutls_record_check_pending (gnutls_session_t session) int _gnutls_record_buffer_get (content_type_t type, gnutls_session_t session, opaque * data, - size_t length) + size_t length, opaque seq[8]) { +gnutls_datum_t msg; +mbuffer_head_st* head; +mbuffer_st* bufel; + if (length == 0 || data == NULL) { gnutls_assert (); @@ -160,17 +155,11 @@ _gnutls_record_buffer_get (content_type_t type, switch (type) { case GNUTLS_APPLICATION_DATA: - _gnutls_buffer_pop_data (&session->internals.application_data_buffer, - data, &length); - _gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n", - (int) length, (int) type); + head = &session->internals.application_data_buffer; break; case GNUTLS_HANDSHAKE: - _gnutls_buffer_pop_data (&session->internals.handshake_data_buffer, - data, &length); - _gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n", - (int) length, (int) type); + head = &session->internals.handshake_data_buffer; break; default: @@ -178,7 +167,19 @@ _gnutls_record_buffer_get (content_type_t type, return GNUTLS_E_INVALID_REQUEST; } + bufel = _mbuffer_get_first(head, &msg); + if (bufel == NULL) + return gnutls_assert_val(GNUTLS_E_AGAIN); + + if (msg.size <= length) + length = msg.size; + + if (seq) + memcpy(seq, bufel->record_sequence.i, 8); + memcpy(data, msg.data, length); + _mbuffer_remove_bytes(head, length); + return length; } @@ -205,23 +206,24 @@ _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel, { ssize_t i, ret; char *ptr; + size_t max_size = _gnutls_get_max_decrypted_data(session); + size_t recv_size = MAX_RECV_SIZE(session); gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr; - if (!bufel) - { - gnutls_assert (); - return GNUTLS_E_INTERNAL_ERROR; - } + if (recv_size > max_size) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - ptr = gnutls_malloc(MAX_RECV_SIZE(session)); - if (ptr == NULL) + *bufel = _mbuffer_alloc (0, _gnutls_get_max_decrypted_data(session)); + if (*bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + ptr = (*bufel)->msg.data; + session->internals.direction = 0; reset_errno (session); - i = pull_func (fd, ptr, MAX_RECV_SIZE(session)); + i = pull_func (fd, ptr, recv_size); if (i < 0) { @@ -232,49 +234,42 @@ _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel, if (err == EAGAIN) { - ret = GNUTLS_E_AGAIN; - goto cleanup; + ret = GNUTLS_E_AGAIN; + goto cleanup; } else if (err == EINTR) { - ret = GNUTLS_E_INTERRUPTED; - goto cleanup; + ret = GNUTLS_E_INTERRUPTED; + goto cleanup; } else - { - gnutls_assert (); - ret = GNUTLS_E_PULL_ERROR; - goto cleanup; - } + { + gnutls_assert (); + ret = GNUTLS_E_PULL_ERROR; + goto cleanup; + } } else { _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd); - if (i == 0) { - /* If we get here, we likely have a stream socket. - * FIXME: this probably breaks DCCP. */ - gnutls_assert (); - ret = GNUTLS_E_INTERNAL_ERROR; - goto cleanup; - } - - *bufel = _mbuffer_alloc (0, i); - if (!*bufel) - { - gnutls_assert (); - ret = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - _mbuffer_append_data (*bufel, ptr, i); + if (i == 0) + { + /* If we get here, we likely have a stream socket. + * FIXME: this probably breaks DCCP. */ + gnutls_assert (); + ret = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; + } + + _mbuffer_set_udata_size (*bufel, i); } _gnutls_read_log ("READ: read %d bytes from %p\n", (int) i, fd); - ret = i; + return i; cleanup: - gnutls_free(ptr); + _mbuffer_xfree(bufel); return ret; } @@ -284,16 +279,11 @@ _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel, { size_t left; ssize_t i = 0; + size_t max_size = _gnutls_get_max_decrypted_data(session); char *ptr; gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr; - if (!bufel) - { - gnutls_assert (); - return GNUTLS_E_INTERNAL_ERROR; - } - - *bufel = _mbuffer_alloc (0, size); + *bufel = _mbuffer_alloc (0, GMAX(max_size, size)); if (!*bufel) { gnutls_assert (); @@ -861,7 +851,7 @@ _gnutls_handshake_io_cache_int (gnutls_session_t session, if (IS_DTLS(session)) { - bufel->sequence = session->internals.dtls.hsk_write_seq-1; + bufel->handshake_sequence = session->internals.dtls.hsk_write_seq-1; } send_buffer = diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h index 6e1b901272..ff762c31f1 100644 --- a/lib/gnutls_buffers.h +++ b/lib/gnutls_buffers.h @@ -27,14 +27,15 @@ #define MBUFFER_FLUSH 1 -int _gnutls_record_buffer_put (content_type_t type, - gnutls_session_t session, opaque * data, - size_t length); +int +_gnutls_record_buffer_put (gnutls_session_t session, + content_type_t type, uint64* seq, mbuffer_st* bufel); + int _gnutls_record_buffer_get_size (content_type_t type, gnutls_session_t session); int _gnutls_record_buffer_get (content_type_t type, gnutls_session_t session, opaque * data, - size_t length); + size_t length, opaque seq[8]); ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t); int _gnutls_io_clear_peeked_data (gnutls_session_t session); diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c index a1cbcf1004..f5d6929613 100644 --- a/lib/gnutls_dtls.c +++ b/lib/gnutls_dtls.c @@ -52,7 +52,7 @@ transmit_message (gnutls_session_t session, { _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with " "length: %u, offset: %u, fragment length: %u\n", - session, bufel->sequence, + session, bufel->handshake_sequence, _gnutls_handshake2str (bufel->htype), bufel->htype, data_size, offset, frag_len); @@ -79,7 +79,7 @@ transmit_message (gnutls_session_t session, _gnutls_write_uint24 (data_size, &mtu_data[1]); /* Handshake sequence */ - _gnutls_write_uint16 (bufel->sequence, &mtu_data[4]); + _gnutls_write_uint16 (bufel->handshake_sequence, &mtu_data[4]); /* Chop up and send handshake message into mtu-size pieces. */ for (offset=0; offset <= data_size; offset += mtu) @@ -100,7 +100,7 @@ transmit_message (gnutls_session_t session, _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with " "length: %u, offset: %u, fragment length: %u\n", - session, bufel->sequence, + session, bufel->handshake_sequence, _gnutls_handshake2str (bufel->htype), bufel->htype, data_size, offset, frag_len); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 2969124664..92696bf632 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -71,6 +71,8 @@ typedef struct #define DEBUG */ +#define GMAX(x,y) ((x>y)?(x):(y)) + /* The size of a handshake message should not * be larger than this value. */ @@ -127,12 +129,6 @@ typedef struct } gnutls_ext_parse_type_t; -/* The initial size of the receive - * buffer size. This will grow if larger - * packets are received. - */ -#define INITIAL_RECV_BUFFER_SIZE 256 - /* the default for TCP */ #define DEFAULT_LOWAT 0 @@ -263,16 +259,19 @@ typedef struct mbuffer_st size_t mark; unsigned int user_mark; /* only used during fill in */ size_t maximum_size; - + /* record layer content type */ content_type_t type; /* Record layer epoch of message */ uint16_t epoch; + /* record layer sequence */ + uint64 record_sequence; + /* Handshake layer type and sequence of message */ gnutls_handshake_description_t htype; - uint16_t sequence; + uint16_t handshake_sequence; } mbuffer_st; typedef struct mbuffer_head_st @@ -587,7 +586,9 @@ typedef union typedef struct { - gnutls_buffer_st application_data_buffer; /* holds data to be delivered to application layer */ + mbuffer_head_st application_data_buffer; /* holds data to be delivered to application layer */ + mbuffer_head_st handshake_data_buffer; /* this is a buffer that holds the current handshake message */ + gnutls_buffer_st handshake_hash_buffer; /* used to keep the last received handshake * message */ union @@ -605,7 +606,6 @@ typedef struct } handshake_mac_handle; int handshake_mac_handle_init; /* 1 when the previous union and type were initialized */ - gnutls_buffer_st handshake_data_buffer; /* this is a buffer that holds the current handshake message */ int resumable:1; /* TRUE or FALSE - if we can resume that session */ handshake_state_t handshake_state; /* holds * a number which indicates where @@ -780,11 +780,6 @@ typedef struct */ internal_params_st params; - /* This buffer is used by the record recv functions, - * as a temporary store buffer. - */ - gnutls_datum_t recv_buffer; - /* To avoid using global variables, and especially on Windows where * the application may use a different errno variable than GnuTLS, * it is possible to use gnutls_transport_set_errno to set a diff --git a/lib/gnutls_mbuffers.c b/lib/gnutls_mbuffers.c index e58a3c3165..297c9b286f 100644 --- a/lib/gnutls_mbuffers.c +++ b/lib/gnutls_mbuffers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Free Software Foundation + * Copyright (C) 2009,2011 Free Software Foundation * * Author: Jonathan Bastien-Filiatrault * @@ -98,6 +98,29 @@ _mbuffer_enqueue (mbuffer_head_st * buf, mbuffer_st * bufel) buf->tail = &bufel->next; } +/* Get a reference to the first segment of the buffer and + * remove it from the list. + * + * Used to start iteration. + * + * Cost: O(1) + */ +mbuffer_st * +_mbuffer_pop_first (mbuffer_head_st * buf) +{ + mbuffer_st *bufel = buf->head; + + buf->head = bufel->next; + + buf->byte_length -= (bufel->msg.size - bufel->mark); + buf->length -= 1; + + if (!buf->head) + buf->tail = &buf->head; + + return bufel; +} + /* Get a reference to the first segment of the buffer and its data. * * Used to start iteration or to peek at the data. @@ -109,15 +132,18 @@ _mbuffer_get_first (mbuffer_head_st * buf, gnutls_datum_t * msg) { mbuffer_st *bufel = buf->head; - if (bufel) + if (msg) { - msg->data = bufel->msg.data + bufel->mark; - msg->size = bufel->msg.size - bufel->mark; - } - else - { - msg->data = NULL; - msg->size = 0; + if (bufel) + { + msg->data = bufel->msg.data + bufel->mark; + msg->size = bufel->msg.size - bufel->mark; + } + else + { + msg->data = NULL; + msg->size = 0; + } } return bufel; } diff --git a/lib/gnutls_mbuffers.h b/lib/gnutls_mbuffers.h index 571e46729e..8330acb7cb 100644 --- a/lib/gnutls_mbuffers.h +++ b/lib/gnutls_mbuffers.h @@ -37,6 +37,9 @@ mbuffer_st *_mbuffer_alloc (size_t payload_size, size_t maximum_size); mbuffer_st *_mbuffer_get_first (mbuffer_head_st * buf, gnutls_datum_t * msg); mbuffer_st *_mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t * msg); +mbuffer_st * +_mbuffer_pop_first (mbuffer_head_st * buf); + /* This is dangerous since it will replace bufel with a new * one. */ @@ -52,6 +55,7 @@ inline static void _mbuffer_set_udata (mbuffer_st * bufel, void *data, size_t data_size) { memcpy (bufel->msg.data + bufel->user_mark, data, data_size); + bufel->msg.size = data_size + bufel->user_mark; } inline static void * diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 409420867f..b85cef3f42 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -535,14 +535,14 @@ check_recv_type (content_type_t recv_type) */ static int check_buffers (gnutls_session_t session, content_type_t type, - opaque * data, int data_size) + opaque * data, int data_size, void* seq) { if ((type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE) && _gnutls_record_buffer_get_size (type, session) > 0) { int ret, ret2; - ret = _gnutls_record_buffer_get (type, session, data, data_size); + ret = _gnutls_record_buffer_get (type, session, data, data_size, seq); if (ret < 0) { gnutls_assert (); @@ -607,13 +607,15 @@ record_check_version (gnutls_session_t session, /* This function will check if the received record type is * the one we actually expect and adds it to the proper - * buffer. + * buffer. The bufel will be deinitialized after calling + * this function, even if it fails. */ static int record_add_to_buffers (gnutls_session_t session, content_type_t recv_type, content_type_t type, gnutls_handshake_description_t htype, - gnutls_datum_t* data) + uint64* seq, + mbuffer_st* bufel) { int ret; @@ -622,7 +624,7 @@ record_add_to_buffers (gnutls_session_t session, && (type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE)) { - _gnutls_record_buffer_put (type, session, (void *) data->data, data->size); + _gnutls_record_buffer_put (session, type, seq, bufel); } else { @@ -631,42 +633,45 @@ record_add_to_buffers (gnutls_session_t session, switch (recv_type) { case GNUTLS_ALERT: - if (data->size < 2) - return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + if (bufel->msg.size < 2) + { + ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + goto cleanup; + } _gnutls_record_log ("REC[%p]: Alert[%d|%d] - %s - was received\n", session, - data->data[0], data->data[1], gnutls_alert_get_name ((int) data->data[1])); + bufel->msg.data[0], bufel->msg.data[1], gnutls_alert_get_name ((int) bufel->msg.data[1])); - session->internals.last_alert = data->data[1]; + session->internals.last_alert = bufel->msg.data[1]; /* if close notify is received and * the alert is not fatal */ - if (data->data[1] == GNUTLS_A_CLOSE_NOTIFY && data->data[0] != GNUTLS_AL_FATAL) + if (bufel->msg.data[1] == GNUTLS_A_CLOSE_NOTIFY && bufel->msg.data[0] != GNUTLS_AL_FATAL) { /* If we have been expecting for an alert do */ session->internals.read_eof = 1; - return GNUTLS_E_INT_RET_0; /* EOF */ + ret = GNUTLS_E_INT_RET_0; /* EOF */ + goto cleanup; } else { - /* if the alert is FATAL or WARNING * return the apropriate message */ gnutls_assert (); ret = GNUTLS_E_WARNING_ALERT_RECEIVED; - if (data->data[0] == GNUTLS_AL_FATAL) + if (bufel->msg.data[0] == GNUTLS_AL_FATAL) { session_unresumable (session); session_invalidate (session); ret = GNUTLS_E_FATAL_ALERT_RECEIVED; } - return ret; + goto cleanup; } break; @@ -681,11 +686,11 @@ record_add_to_buffers (gnutls_session_t session, case GNUTLS_APPLICATION_DATA: /* even if data is unexpected put it into the buffer */ if ((ret = - _gnutls_record_buffer_put (recv_type, session, - (void *) data->data, data->size)) < 0) + _gnutls_record_buffer_put (session, recv_type, seq, + bufel)) < 0) { gnutls_assert (); - return ret; + goto cleanup; } /* the got_application data is only returned @@ -694,11 +699,15 @@ record_add_to_buffers (gnutls_session_t session, */ if (type == GNUTLS_ALERT || (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && type == GNUTLS_HANDSHAKE)) - return GNUTLS_E_GOT_APPLICATION_DATA; + { + ret = GNUTLS_E_GOT_APPLICATION_DATA; + goto cleanup; + } else { gnutls_assert (); - return GNUTLS_E_UNEXPECTED_PACKET; + ret = GNUTLS_E_UNEXPECTED_PACKET; + goto cleanup; } break; @@ -710,12 +719,11 @@ record_add_to_buffers (gnutls_session_t session, { gnutls_assert (); ret = - _gnutls_record_buffer_put (recv_type, session, (void *) data->data, - data->size); + _gnutls_record_buffer_put (session, recv_type, seq, bufel); if (ret < 0) { gnutls_assert (); - return ret; + goto cleanup; } return GNUTLS_E_REHANDSHAKE; } @@ -726,7 +734,8 @@ record_add_to_buffers (gnutls_session_t session, */ /* So we accept it */ - return _gnutls_recv_hello_request (session, data->data, data->size); + ret = _gnutls_recv_hello_request (session, bufel->msg.data, bufel->msg.size); + goto cleanup; break; default: @@ -736,56 +745,30 @@ record_add_to_buffers (gnutls_session_t session, session, recv_type, type); gnutls_assert (); - return GNUTLS_E_INTERNAL_ERROR; + ret = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; } } return 0; -} +cleanup: + _mbuffer_xfree(&bufel); + return ret; +} -/* This function will return the internal (per session) temporary - * recv buffer. If the buffer was not initialized before it will - * also initialize it. - */ -inline static int -get_temp_recv_buffer (gnutls_session_t session, gnutls_datum_t ** tmp) +int _gnutls_get_max_decrypted_data(gnutls_session_t session) { - size_t max_record_size; +int ret; if (gnutls_compression_get (session) != GNUTLS_COMP_NULL || session->internals.priorities.allow_large_records != 0) - max_record_size = MAX_RECORD_RECV_SIZE(session) + EXTRA_COMP_SIZE; + ret = MAX_RECORD_RECV_SIZE(session) + EXTRA_COMP_SIZE; else - max_record_size = MAX_RECORD_RECV_SIZE(session); - - /* We allocate MAX_RECORD_RECV_SIZE length - * because we cannot predict the output data by the record - * packet length (due to compression). - */ - - if (max_record_size > session->internals.recv_buffer.size || - session->internals.recv_buffer.data == NULL) - { - - /* Initialize the internal buffer. - */ - session->internals.recv_buffer.data = - gnutls_realloc (session->internals.recv_buffer.data, max_record_size); - - if (session->internals.recv_buffer.data == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } - - session->internals.recv_buffer.size = max_record_size; - } - - *tmp = &session->internals.recv_buffer; + ret = MAX_RECORD_RECV_SIZE(session); - return 0; + return ret; } struct tls_record_st { @@ -796,7 +779,6 @@ struct tls_record_st { uint16_t packet_size; /* header_size + length */ content_type_t type; /* the data */ - gnutls_datum_t data; }; /* Checks the record headers and returns the length, version and @@ -864,6 +846,7 @@ static int recv_headers( gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, struct tls_record_st* record) { int ret; +gnutls_datum_t raw; /* raw headers */ /* Read the headers. */ record->header_size = record->packet_size = RECORD_HEADER_SIZE(session); @@ -882,9 +865,9 @@ int ret; return ret; } - _mbuffer_get_first (&session->internals.record_recv_buffer, &record->data); + _mbuffer_get_first (&session->internals.record_recv_buffer, &raw); - record_read_headers (session, record->data.data, type, htype, record); + record_read_headers (session, raw.data, type, htype, record); /* Check if the DTLS epoch is valid */ if (IS_DTLS(session)) @@ -955,9 +938,9 @@ _gnutls_recv_int (gnutls_session_t session, content_type_t type, { uint64 *packet_sequence; uint8_t *ciphertext; + mbuffer_st* bufel = NULL; int ret, ret2; int empty_packet = 0; - gnutls_datum_t *decrypted; record_parameters_st *record_params; record_state_st *record_state; struct tls_record_st record; @@ -993,7 +976,7 @@ begin: /* If we have enough data in the cache do not bother receiving * a new packet. (in order to flush the cache) */ - ret = check_buffers (session, type, data, data_size); + ret = check_buffers (session, type, data, data_size, seq); if (ret != 0) return ret; @@ -1021,9 +1004,6 @@ begin: else packet_sequence = &record_state->sequence_number; - if (seq) - memcpy(seq, packet_sequence, 8); - /* Read the packet data and insert it to record_recv_buffer. */ ret = @@ -1044,22 +1024,15 @@ begin: gnutls_assert (); return ret; } - _mbuffer_get_first (&session->internals.record_recv_buffer, &record.data); - ciphertext = &record.data.data[record.header_size]; - - ret = get_temp_recv_buffer (session, &decrypted); - if (ret < 0) - { - gnutls_assert (); - return ret; - } + bufel = _mbuffer_pop_first (&session->internals.record_recv_buffer); + ciphertext = &bufel->msg.data[record.header_size]; /* decrypt the data we got. */ ret = - _gnutls_decrypt (session, ciphertext, record.length, decrypted->data, decrypted->size, + _gnutls_decrypt (session, ciphertext, record.length, bufel->msg.data, bufel->maximum_size, record.type, record_params, packet_sequence); - decrypted->size = ret; + bufel->msg.size = ret; if (ret < 0) { @@ -1067,9 +1040,8 @@ begin: goto sanity_check_error; } - /* remove the decrypted packet from buffers */ - _mbuffer_remove_bytes (&session->internals.record_recv_buffer, - record.packet_size); + /* bufel now holds the decrypted data + */ /* check for duplicates. We check after the message * is processed and authenticated to avoid someone @@ -1082,7 +1054,7 @@ begin: { _gnutls_audit_log("Discarded duplicate message[%u]\n", (unsigned int) _gnutls_uint64touint32 (packet_sequence)); - goto discard2; + goto sanity_check_error; } } @@ -1094,21 +1066,22 @@ begin: _gnutls_record_log ("REC[%p]: ChangeCipherSpec Packet was received\n", session); - if ((size_t) decrypted->size != data_size) + if ((size_t) bufel->msg.size != data_size) { /* data_size should be 1 */ gnutls_assert (); ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto sanity_check_error; } - data[0] = decrypted->data[0]; + data[0] = bufel->msg.data[0]; - return 1; + ret = 1; + goto cleanup; } _gnutls_record_log ("REC[%p]: Decrypted Packet[%d] %s(%d) with length: %d\n", session, (int) _gnutls_uint64touint32 (packet_sequence), - _gnutls_packet2str (record.type), record.type, decrypted->size); + _gnutls_packet2str (record.type), record.type, bufel->msg.size); /* increase sequence number */ @@ -1116,15 +1089,22 @@ begin: { session_invalidate (session); gnutls_assert (); - return GNUTLS_E_RECORD_LIMIT_REACHED; + ret = GNUTLS_E_RECORD_LIMIT_REACHED; + goto sanity_check_error; } ret = - record_add_to_buffers (session, record.type, type, htype, decrypted); + record_add_to_buffers (session, record.type, type, htype, + packet_sequence, bufel); + + /* bufel is now either deinitialized or buffered somewhere else */ + if (ret < 0) { if (ret == GNUTLS_E_INT_RET_0) - return 0; + { + return 0; + } gnutls_assert (); return ret; } @@ -1136,7 +1116,7 @@ begin: type == GNUTLS_HANDSHAKE)) { - ret = _gnutls_record_buffer_get (type, session, data, data_size); + ret = _gnutls_record_buffer_get (type, session, data, data_size, seq); if (ret < 0) { gnutls_assert (); @@ -1178,9 +1158,8 @@ begin: return ret; discard: - _mbuffer_remove_bytes (&session->internals.record_recv_buffer, - record.packet_size); -discard2: + bufel = _mbuffer_pop_first(&session->internals.record_recv_buffer); + _mbuffer_xfree(&bufel); return GNUTLS_E_AGAIN; sanity_check_error: @@ -1188,10 +1167,15 @@ sanity_check_error: { _gnutls_audit_log("Discarded message[%u] due to invalid decryption\n", (unsigned int)_gnutls_uint64touint32 (packet_sequence)); - goto discard2; + ret = GNUTLS_E_AGAIN; + goto cleanup; } + session_unresumable (session); session_invalidate (session); + +cleanup: + _mbuffer_xfree(&bufel); return ret; recv_error: diff --git a/lib/gnutls_record.h b/lib/gnutls_record.h index f413471704..d1099ea28e 100644 --- a/lib/gnutls_record.h +++ b/lib/gnutls_record.h @@ -37,4 +37,6 @@ ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t, opaque * data, size_t sizeofdata, void* seq); +int _gnutls_get_max_decrypted_data(gnutls_session_t session); + #endif diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 18c9479d32..bcb32717c8 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -268,8 +268,6 @@ _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); _gnutls_epoch_gc(session); @@ -318,10 +316,10 @@ gnutls_init (gnutls_session_t * session, gnutls_connection_end_t con_end) (*session)->security_parameters.cert_type = DEFAULT_CERT_TYPE; /* Initialize buffers */ - _gnutls_buffer_init (&(*session)->internals.application_data_buffer); - _gnutls_buffer_init (&(*session)->internals.handshake_data_buffer); _gnutls_buffer_init (&(*session)->internals.handshake_hash_buffer); + _mbuffer_init (&(*session)->internals.application_data_buffer); + _mbuffer_init (&(*session)->internals.handshake_data_buffer); _mbuffer_init (&(*session)->internals.record_send_buffer); _mbuffer_init (&(*session)->internals.record_recv_buffer); @@ -456,8 +454,8 @@ gnutls_deinit (gnutls_session_t session) } _gnutls_buffer_clear (&session->internals.handshake_hash_buffer); - _gnutls_buffer_clear (&session->internals.handshake_data_buffer); - _gnutls_buffer_clear (&session->internals.application_data_buffer); + _mbuffer_clear (&session->internals.handshake_data_buffer); + _mbuffer_clear (&session->internals.application_data_buffer); _mbuffer_clear (&session->internals.record_recv_buffer); _mbuffer_clear (&session->internals.record_send_buffer);