diff options
Diffstat (limited to 'lib/buffers.c')
-rw-r--r-- | lib/buffers.c | 75 |
1 files changed, 48 insertions, 27 deletions
diff --git a/lib/buffers.c b/lib/buffers.c index 100390b5dc..cee0d5fc59 100644 --- a/lib/buffers.c +++ b/lib/buffers.c @@ -882,7 +882,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, { uint8_t *dataptr = NULL; /* for realloc */ size_t handshake_header_size = - HANDSHAKE_HEADER_SIZE(session), data_size; + HANDSHAKE_HEADER_SIZE(session), data_size, frag_size; /* Note: SSL2_HEADERS == 1 */ if (_mbuffer_get_udata_size(bufel) < handshake_header_size) @@ -898,7 +898,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) { handshake_header_size = SSL2_HEADERS; /* we've already read one byte */ - hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */ + frag_size = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */ if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO) return @@ -908,7 +908,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, hsk->sequence = 0; hsk->start_offset = 0; - hsk->end_offset = hsk->length; + hsk->length = frag_size; } else #endif { /* TLS or DTLS handshake headers */ @@ -925,13 +925,12 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, hsk->sequence = _gnutls_read_uint16(&dataptr[4]); hsk->start_offset = _gnutls_read_uint24(&dataptr[6]); - hsk->end_offset = - hsk->start_offset + + frag_size = _gnutls_read_uint24(&dataptr[9]); } else { hsk->sequence = 0; hsk->start_offset = 0; - hsk->end_offset = + frag_size = MIN((_mbuffer_get_udata_size(bufel) - handshake_header_size), hsk->length); } @@ -947,25 +946,25 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, } data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size; - /* make the length offset */ - if (hsk->end_offset > 0) - hsk->end_offset--; + if (frag_size > 0) + hsk->end_offset = hsk->start_offset + frag_size - 1; + else + hsk->end_offset = 0; _gnutls_handshake_log ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n", session, _gnutls_handshake2str(hsk->htype), (unsigned) hsk->htype, (int) hsk->length, (int) data_size, - hsk->start_offset, hsk->end_offset - hsk->start_offset + 1, + hsk->start_offset, (int) frag_size, (int) hsk->sequence); hsk->header_size = handshake_header_size; memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel), handshake_header_size); - if (hsk->length > 0 && (hsk->start_offset > hsk->end_offset || - hsk->end_offset - hsk->start_offset >= - data_size - || hsk->end_offset >= hsk->length)) { + if (hsk->length > 0 && (frag_size > data_size || + (frag_size > 0 && + hsk->end_offset >= hsk->length))) { return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } @@ -1197,7 +1196,7 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; if (!IS_DTLS(session)) { - ssize_t remain, append, header_size; + ssize_t append, header_size; do { if (bufel->type != GNUTLS_HANDSHAKE) @@ -1205,18 +1204,21 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session) gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET); - /* if we have a half received message then complete it. - */ - remain = recv_buf[0].length - - recv_buf[0].data.length; - - /* this is the rest of a previous message */ - if (session->internals.handshake_recv_buffer_size > - 0 && recv_buf[0].length > 0 && remain > 0) { - if ((ssize_t) msg.size <= remain) - append = msg.size; - else - append = remain; + if (unlikely + (session->internals.handshake_recv_buffer_size == 0 && + msg.size < HANDSHAKE_HEADER_SIZE(session) && + session->internals.handshake_header_recv_buffer.byte_length < + HANDSHAKE_HEADER_SIZE(session) - msg.size)) { + bufel = _mbuffer_head_pop_first(&session->internals.record_buffer); + _mbuffer_enqueue(&session->internals.handshake_header_recv_buffer, + bufel); + break; + } else if (session->internals.handshake_recv_buffer_size > + 0 && recv_buf[0].length > recv_buf[0].data.length) { + /* this is the rest of a previous message */ + append = MIN(msg.size, + recv_buf[0].length - + recv_buf[0].data.length); ret = _gnutls_buffer_append_data(&recv_buf @@ -1231,6 +1233,25 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session) record_buffer, append); } else { /* received new message */ + if (unlikely + (session->internals. + handshake_header_recv_buffer.length > 0)) { + bufel = _mbuffer_head_pop_first(&session->internals. + record_buffer); + _mbuffer_enqueue(&session->internals. + handshake_header_recv_buffer, + bufel); + ret = _mbuffer_linearize_align16(&session->internals. + handshake_header_recv_buffer, + get_total_headers(session)); + if (ret < 0) + return gnutls_assert_val(ret); + bufel = _mbuffer_head_pop_first(&session->internals. + handshake_header_recv_buffer); + _mbuffer_head_push_first(&session->internals. + record_buffer, + bufel); + } ret = parse_handshake_header(session, bufel, |