|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Author: Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
4684c1 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
4684c1 |
* the License, or (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
4684c1 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
4684c1 |
* Lesser General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* This file holds all the buffering code used in gnutls.
|
|
Packit Service |
4684c1 |
* The buffering code works as:
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* RECORD LAYER:
|
|
Packit Service |
4684c1 |
* 1. uses a buffer to hold data (application/handshake),
|
|
Packit Service |
4684c1 |
* we got but they were not requested, yet.
|
|
Packit Service |
4684c1 |
* (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* 2. uses a buffer to hold data that were incomplete (ie the read/write
|
|
Packit Service |
4684c1 |
* was interrupted)
|
|
Packit Service |
4684c1 |
* (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* HANDSHAKE LAYER:
|
|
Packit Service |
4684c1 |
* 1. Uses buffer to hold the last received handshake message.
|
|
Packit Service |
4684c1 |
* (see _gnutls_handshake_hash_buffer_put() etc.)
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "gnutls_int.h"
|
|
Packit Service |
4684c1 |
#include "errors.h"
|
|
Packit Service |
4684c1 |
#include <num.h>
|
|
Packit Service |
4684c1 |
#include <record.h>
|
|
Packit Service |
4684c1 |
#include <buffers.h>
|
|
Packit Service |
4684c1 |
#include <mbuffers.h>
|
|
Packit Service |
4684c1 |
#include <state.h>
|
|
Packit Service |
4684c1 |
#include <dtls.h>
|
|
Packit Service |
4684c1 |
#include <system.h>
|
|
Packit Service |
4684c1 |
#include <constate.h> /* gnutls_epoch_get */
|
|
Packit Service |
4684c1 |
#include <handshake.h> /* remaining_time() */
|
|
Packit Service |
4684c1 |
#include <errno.h>
|
|
Packit Service |
4684c1 |
#include <system.h>
|
|
Packit Service |
4684c1 |
#include "debug.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef EAGAIN
|
|
Packit Service |
4684c1 |
#define EAGAIN EWOULDBLOCK
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* this is the maximum number of messages allowed to queue.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
#define MAX_QUEUE 32
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Buffers received packets of type APPLICATION DATA,
|
|
Packit Service |
4684c1 |
* HANDSHAKE DATA and HEARTBEAT.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
void
|
|
Packit Service |
4684c1 |
_gnutls_record_buffer_put(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
content_type_t type, uint64_t seq,
|
|
Packit Service |
4684c1 |
mbuffer_st * bufel)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
bufel->type = type;
|
|
Packit Service |
4684c1 |
bufel->record_sequence = seq;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_enqueue(&session->internals.record_buffer, bufel);
|
|
Packit Service |
4684c1 |
_gnutls_buffers_log("BUF[REC]: Inserted %d bytes of Data(%d)\n",
|
|
Packit Service |
4684c1 |
(int) bufel->msg.size, (int) type);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_record_check_pending:
|
|
Packit Service |
4684c1 |
* @session: is a #gnutls_session_t type.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function checks if there are unread data
|
|
Packit Service |
4684c1 |
* in the gnutls buffers. If the return value is
|
|
Packit Service |
4684c1 |
* non-zero the next call to gnutls_record_recv()
|
|
Packit Service |
4684c1 |
* is guaranteed not to block.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: Returns the size of the data or zero.
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
size_t gnutls_record_check_pending(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
return _gnutls_record_buffer_get_size(session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_record_check_corked:
|
|
Packit Service |
4684c1 |
* @session: is a #gnutls_session_t type.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function checks if there pending corked
|
|
Packit Service |
4684c1 |
* data in the gnutls buffers --see gnutls_record_cork().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: Returns the size of the corked data or zero.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.2.8
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
size_t gnutls_record_check_corked(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
return session->internals.record_presend_buffer.length;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
_gnutls_record_buffer_get(content_type_t type,
|
|
Packit Service |
4684c1 |
gnutls_session_t session, uint8_t * data,
|
|
Packit Service |
4684c1 |
size_t length, uint8_t seq[8])
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t msg;
|
|
Packit Service |
4684c1 |
mbuffer_st *bufel;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (length == 0 || data == NULL) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
bufel =
|
|
Packit Service |
4684c1 |
_mbuffer_head_get_first(&session->internals.record_buffer,
|
|
Packit Service |
4684c1 |
&msg;;
|
|
Packit Service |
4684c1 |
if (bufel == NULL)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (type != bufel->type) {
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session))
|
|
Packit Service |
4684c1 |
_gnutls_audit_log(session,
|
|
Packit Service |
4684c1 |
"Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
|
|
Packit Service |
4684c1 |
_gnutls_packet2str(bufel->type),
|
|
Packit Service |
4684c1 |
(int) bufel->type,
|
|
Packit Service |
4684c1 |
_gnutls_packet2str(type),
|
|
Packit Service |
4684c1 |
(int) type);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("received unexpected packet: %s(%d)\n",
|
|
Packit Service |
4684c1 |
_gnutls_packet2str(bufel->type), (int)bufel->type);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer, msg.size);
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (msg.size <= length)
|
|
Packit Service |
4684c1 |
length = msg.size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (seq)
|
|
Packit Service |
4684c1 |
_gnutls_write_uint64(bufel->record_sequence, seq);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memcpy(data, msg.data, length);
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(&session->internals.record_buffer,
|
|
Packit Service |
4684c1 |
length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return length;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
_gnutls_record_buffer_get_packet(content_type_t type, gnutls_session_t session, gnutls_packet_t *packet)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
mbuffer_st *bufel;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
bufel =
|
|
Packit Service |
4684c1 |
_mbuffer_head_pop_first(&session->internals.record_buffer);
|
|
Packit Service |
4684c1 |
if (bufel == NULL)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (type != bufel->type) {
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session))
|
|
Packit Service |
4684c1 |
_gnutls_audit_log(session,
|
|
Packit Service |
4684c1 |
"Discarded unexpected %s (%d) packet (expecting: %s)\n",
|
|
Packit Service |
4684c1 |
_gnutls_packet2str(bufel->type),
|
|
Packit Service |
4684c1 |
(int) bufel->type,
|
|
Packit Service |
4684c1 |
_gnutls_packet2str(type));
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer, bufel->msg.size);
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*packet = bufel;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return bufel->msg.size - bufel->mark;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline static void reset_errno(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
session->internals.errnum = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline static int get_errno(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->internals.errnum != 0)
|
|
Packit Service |
4684c1 |
ret = session->internals.errnum;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
session->internals.errno_func(session->internals.
|
|
Packit Service |
4684c1 |
transport_recv_ptr);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
inline static
|
|
Packit Service |
4684c1 |
int errno_to_gerr(int err, unsigned dtls)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
switch (err) {
|
|
Packit Service |
4684c1 |
case EAGAIN:
|
|
Packit Service |
4684c1 |
return GNUTLS_E_AGAIN;
|
|
Packit Service |
4684c1 |
case EINTR:
|
|
Packit Service |
4684c1 |
return GNUTLS_E_INTERRUPTED;
|
|
Packit Service |
4684c1 |
case EMSGSIZE:
|
|
Packit Service |
4684c1 |
if (dtls != 0)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_LARGE_PACKET;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return GNUTLS_E_PUSH_ERROR;
|
|
Packit Service |
4684c1 |
case ECONNRESET:
|
|
Packit Service |
4684c1 |
return GNUTLS_E_PREMATURE_TERMINATION;
|
|
Packit Service |
4684c1 |
default:
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_PUSH_ERROR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel,
|
|
Packit Service |
4684c1 |
gnutls_pull_func pull_func, unsigned int *ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
ssize_t i, ret;
|
|
Packit Service |
4684c1 |
uint8_t *ptr;
|
|
Packit Service |
4684c1 |
struct timespec t1, t2;
|
|
Packit Service |
4684c1 |
size_t max_size, recv_size;
|
|
Packit Service |
4684c1 |
gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
|
|
Packit Service |
4684c1 |
unsigned int diff;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
max_size = max_record_recv_size(session);
|
|
Packit Service |
4684c1 |
recv_size = max_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.direction = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ms && *ms > 0) {
|
|
Packit Service |
4684c1 |
ret = _gnutls_io_check_recv(session, *ms);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
gnutls_gettime(&t1;;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session));
|
|
Packit Service |
4684c1 |
if (*bufel == NULL)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ptr = (*bufel)->msg.data;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
reset_errno(session);
|
|
Packit Service |
4684c1 |
i = pull_func(fd, ptr, recv_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (i < 0) {
|
|
Packit Service |
4684c1 |
int err = get_errno(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_read_log("READ: %d returned from %p, errno=%d\n",
|
|
Packit Service |
4684c1 |
(int) i, fd, err);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = errno_to_gerr(err, 1);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
_gnutls_read_log("READ: Got %d bytes from %p\n", (int) i,
|
|
Packit Service |
4684c1 |
fd);
|
|
Packit Service |
4684c1 |
if (i == 0) {
|
|
Packit Service |
4684c1 |
/* If we get here, we likely have a stream socket.
|
|
Packit Service |
4684c1 |
* That assumption may not work on DCCP. */
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
ret = 0;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_set_udata_size(*bufel, i);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ms && *ms > 0) {
|
|
Packit Service |
4684c1 |
gnutls_gettime(&t2;;
|
|
Packit Service |
4684c1 |
diff = timespec_sub_ms(&t2, &t1;;
|
|
Packit Service |
4684c1 |
if (diff < *ms)
|
|
Packit Service |
4684c1 |
*ms -= diff;
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_read_log("READ: read %d bytes from %p\n", (int) i, fd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
_mbuffer_xfree(bufel);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel,
|
|
Packit Service |
4684c1 |
size_t size, gnutls_pull_func pull_func,
|
|
Packit Service |
4684c1 |
unsigned int *ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
size_t left;
|
|
Packit Service |
4684c1 |
ssize_t i = 0;
|
|
Packit Service |
4684c1 |
size_t max_size = max_record_recv_size(session);
|
|
Packit Service |
4684c1 |
uint8_t *ptr;
|
|
Packit Service |
4684c1 |
gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
struct timespec t1, t2;
|
|
Packit Service |
4684c1 |
unsigned int diff;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.direction = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*bufel = _mbuffer_alloc_align16(MAX(max_size, size), get_total_headers(session));
|
|
Packit Service |
4684c1 |
if (!*bufel) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
ptr = (*bufel)->msg.data;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
left = size;
|
|
Packit Service |
4684c1 |
while (left > 0) {
|
|
Packit Service |
4684c1 |
if (ms && *ms > 0) {
|
|
Packit Service |
4684c1 |
ret = _gnutls_io_check_recv(session, *ms);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_gettime(&t1;;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
reset_errno(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
i = pull_func(fd, &ptr[size - left], left);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (i < 0) {
|
|
Packit Service |
4684c1 |
int err = get_errno(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_read_log
|
|
Packit Service |
4684c1 |
("READ: %d returned from %p, errno=%d gerrno=%d\n",
|
|
Packit Service |
4684c1 |
(int) i, fd, errno,
|
|
Packit Service |
4684c1 |
session->internals.errnum);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (err == EAGAIN || err == EINTR) {
|
|
Packit Service |
4684c1 |
if (size - left > 0) {
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_read_log
|
|
Packit Service |
4684c1 |
("READ: returning %d bytes from %p\n",
|
|
Packit Service |
4684c1 |
(int) (size - left), fd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
goto finish;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = errno_to_gerr(err, 0);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_PULL_ERROR;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_read_log("READ: Got %d bytes from %p\n",
|
|
Packit Service |
4684c1 |
(int) i, fd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (i == 0)
|
|
Packit Service |
4684c1 |
break; /* EOF */
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
left -= i;
|
|
Packit Service |
4684c1 |
(*bufel)->msg.size += i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ms && *ms > 0 && *ms != GNUTLS_INDEFINITE_TIMEOUT) {
|
|
Packit Service |
4684c1 |
gnutls_gettime(&t2;;
|
|
Packit Service |
4684c1 |
diff = timespec_sub_ms(&t2, &t1;;
|
|
Packit Service |
4684c1 |
if (diff < *ms)
|
|
Packit Service |
4684c1 |
*ms -= diff;
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
finish:
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_read_log("READ: read %d bytes from %p\n",
|
|
Packit Service |
4684c1 |
(int) (size - left), fd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (size - left == 0)
|
|
Packit Service |
4684c1 |
_mbuffer_xfree(bufel);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return (size - left);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
_mbuffer_xfree(bufel);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This function is like read. But it does not return -1 on error.
|
|
Packit Service |
4684c1 |
* It does return gnutls_errno instead.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Flags are only used if the default recv() function is being used.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_read(gnutls_session_t session, mbuffer_st ** bufel,
|
|
Packit Service |
4684c1 |
size_t size, gnutls_pull_func pull_func, unsigned int *ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session))
|
|
Packit Service |
4684c1 |
/* Size is not passed, since a whole datagram will be read. */
|
|
Packit Service |
4684c1 |
return _gnutls_dgram_read(session, bufel, pull_func, ms);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return _gnutls_stream_read(session, bufel, size, pull_func,
|
|
Packit Service |
4684c1 |
ms);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* @vec: if non-zero then the vector function will be used to
|
|
Packit Service |
4684c1 |
* push the data.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_writev_emu(gnutls_session_t session, gnutls_transport_ptr_t fd,
|
|
Packit Service |
4684c1 |
const giovec_t * giovec, unsigned int giovec_cnt, unsigned vec)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned int j = 0;
|
|
Packit Service |
4684c1 |
size_t total = 0;
|
|
Packit Service |
4684c1 |
ssize_t ret = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (j = 0; j < giovec_cnt; j++) {
|
|
Packit Service |
4684c1 |
if (vec) {
|
|
Packit Service |
4684c1 |
ret = session->internals.vec_push_func(fd, &giovec[j], 1);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
size_t sent = 0;
|
|
Packit Service |
4684c1 |
ssize_t left = giovec[j].iov_len;
|
|
Packit Service |
4684c1 |
char *p = giovec[j].iov_base;
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
session->internals.push_func(fd, p,
|
|
Packit Service |
4684c1 |
left);
|
|
Packit Service |
4684c1 |
if (ret > 0) {
|
|
Packit Service |
4684c1 |
sent += ret;
|
|
Packit Service |
4684c1 |
left -= ret;
|
|
Packit Service |
4684c1 |
p += ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} while(ret > 0 && left > 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sent > 0)
|
|
Packit Service |
4684c1 |
ret = sent;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == -1) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
total += ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((size_t) ret != giovec[j].iov_len)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (total > 0)
|
|
Packit Service |
4684c1 |
return total;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* @total: The sum of the data in giovec
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_writev(gnutls_session_t session, const giovec_t * giovec,
|
|
Packit Service |
4684c1 |
unsigned giovec_cnt, unsigned total)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
bool is_dtls = IS_DTLS(session);
|
|
Packit Service |
4684c1 |
unsigned no_writev = 0;
|
|
Packit Service |
4684c1 |
gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
reset_errno(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->internals.vec_push_func != NULL) {
|
|
Packit Service |
4684c1 |
if (is_dtls && giovec_cnt > 1) {
|
|
Packit Service |
4684c1 |
if (total > session->internals.dtls.mtu) {
|
|
Packit Service |
4684c1 |
no_writev = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (no_writev == 0) {
|
|
Packit Service |
4684c1 |
i = session->internals.vec_push_func(fd, giovec, giovec_cnt);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else if (session->internals.push_func != NULL) {
|
|
Packit Service |
4684c1 |
i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 0);
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_PUSH_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (i == -1) {
|
|
Packit Service |
4684c1 |
int err = get_errno(session);
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("WRITE: %d returned from %p, errno: %d\n",
|
|
Packit Service |
4684c1 |
i, fd, err);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return errno_to_gerr(err, is_dtls);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return i;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
|
|
Packit Service |
4684c1 |
* It does return gnutls_errno instead.
|
|
Packit Service |
4684c1 |
* This function reads data from the socket and keeps them in a buffer, of up to
|
|
Packit Service |
4684c1 |
* max_record_recv_size.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This is not a general purpose function. It returns EXACTLY the data requested,
|
|
Packit Service |
4684c1 |
* which are stored in a local (in the session) buffer.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* If the @ms parameter is non zero then this function will return before
|
|
Packit Service |
4684c1 |
* the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_io_read_buffered(gnutls_session_t session, size_t total,
|
|
Packit Service |
4684c1 |
content_type_t recv_type, unsigned int *ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
ssize_t ret;
|
|
Packit Service |
4684c1 |
size_t min;
|
|
Packit Service |
4684c1 |
mbuffer_st *bufel = NULL;
|
|
Packit Service |
4684c1 |
size_t recvdata, readsize;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (total > max_record_recv_size(session) || total == 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_RECORD_OVERFLOW;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* calculate the actual size, ie. get the minimum of the
|
|
Packit Service |
4684c1 |
* buffered data and the requested data.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
min =
|
|
Packit Service |
4684c1 |
MIN(session->internals.record_recv_buffer.byte_length, total);
|
|
Packit Service |
4684c1 |
if (min > 0) {
|
|
Packit Service |
4684c1 |
/* if we have enough buffered data
|
|
Packit Service |
4684c1 |
* then just return them.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (min == total) {
|
|
Packit Service |
4684c1 |
return min;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* min is over zero. recvdata is the data we must
|
|
Packit Service |
4684c1 |
* receive in order to return the requested data.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
recvdata = total - min;
|
|
Packit Service |
4684c1 |
readsize = recvdata;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Check if the previously read data plus the new data to
|
|
Packit Service |
4684c1 |
* receive are longer than the maximum receive buffer size.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if ((session->internals.record_recv_buffer.byte_length +
|
|
Packit Service |
4684c1 |
recvdata) > max_record_recv_size(session)) {
|
|
Packit Service |
4684c1 |
gnutls_assert(); /* internal error */
|
|
Packit Service |
4684c1 |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* READ DATA
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (readsize > 0) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
_gnutls_read(session, &bufel, readsize,
|
|
Packit Service |
4684c1 |
session->internals.pull_func, ms);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* return immediately if we got an interrupt or eagain
|
|
Packit Service |
4684c1 |
* error.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == 0) /* EOF */
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* copy fresh data to our buffer.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
_gnutls_read_log
|
|
Packit Service |
4684c1 |
("RB: Have %d bytes into buffer. Adding %d bytes.\n",
|
|
Packit Service |
4684c1 |
(int) session->internals.record_recv_buffer.
|
|
Packit Service |
4684c1 |
byte_length, (int) ret);
|
|
Packit Service |
4684c1 |
_gnutls_read_log("RB: Requested %d bytes\n", (int) total);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_enqueue(&session->internals.record_recv_buffer,
|
|
Packit Service |
4684c1 |
bufel);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session))
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
MIN(total,
|
|
Packit Service |
4684c1 |
session->internals.record_recv_buffer.
|
|
Packit Service |
4684c1 |
byte_length);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
session->internals.record_recv_buffer.
|
|
Packit Service |
4684c1 |
byte_length;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((ret > 0) && ((size_t) ret < total)) /* Short Read */
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This function is like write. But it does not return -1 on error.
|
|
Packit Service |
4684c1 |
* It does return gnutls_errno instead.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function takes full responsibility of freeing msg->data.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* In case of E_AGAIN and E_INTERRUPTED errors, you must call
|
|
Packit Service |
4684c1 |
* gnutls_write_flush(), until it returns ok (0).
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* We need to push exactly the data in msg->size, since we cannot send
|
|
Packit Service |
4684c1 |
* less data. In TLS the peer must receive the whole packet in order
|
|
Packit Service |
4684c1 |
* to decrypt and verify the integrity.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_io_write_buffered(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
mbuffer_st * bufel, unsigned int mflag)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
mbuffer_head_st *const send_buffer =
|
|
Packit Service |
4684c1 |
&session->internals.record_send_buffer;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* to know where the procedure was interrupted.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
session->internals.direction = 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_enqueue(send_buffer, bufel);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_write_log
|
|
Packit Service |
4684c1 |
("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
|
|
Packit Service |
4684c1 |
(int) bufel->msg.size, session->internals.transport_recv_ptr,
|
|
Packit Service |
4684c1 |
(int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (mflag == MBUFFER_FLUSH)
|
|
Packit Service |
4684c1 |
return _gnutls_io_write_flush(session);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return bufel->msg.size;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
typedef ssize_t(*send_func) (gnutls_session_t, const giovec_t *, int);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This function writes the data that are left in the
|
|
Packit Service |
4684c1 |
* TLS write buffer (ie. because the previous write was
|
|
Packit Service |
4684c1 |
* interrupted.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ssize_t _gnutls_io_write_flush(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t msg;
|
|
Packit Service |
4684c1 |
mbuffer_head_st *send_buffer =
|
|
Packit Service |
4684c1 |
&session->internals.record_send_buffer;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
ssize_t sent = 0, tosend = 0;
|
|
Packit Service |
4684c1 |
giovec_t iovec[MAX_QUEUE];
|
|
Packit Service |
4684c1 |
int i = 0;
|
|
Packit Service |
4684c1 |
mbuffer_st *cur;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.direction = 1;
|
|
Packit Service |
4684c1 |
_gnutls_write_log("WRITE FLUSH: %d bytes in buffer.\n",
|
|
Packit Service |
4684c1 |
(int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (cur = _mbuffer_head_get_first(send_buffer, &msg;;
|
|
Packit Service |
4684c1 |
cur != NULL; cur = _mbuffer_head_get_next(cur, &msg)) {
|
|
Packit Service |
4684c1 |
iovec[i].iov_base = msg.data;
|
|
Packit Service |
4684c1 |
iovec[i++].iov_len = msg.size;
|
|
Packit Service |
4684c1 |
tosend += msg.size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* we buffer up to MAX_QUEUE messages */
|
|
Packit Service |
4684c1 |
if (i >= MAX_QUEUE) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_INTERNAL_ERROR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (tosend == 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls_writev(session, iovec, i, tosend);
|
|
Packit Service |
4684c1 |
if (ret >= 0) {
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(send_buffer, ret);
|
|
Packit Service |
4684c1 |
_gnutls_write_log
|
|
Packit Service |
4684c1 |
("WRITE: wrote %d bytes, %d bytes left.\n", ret,
|
|
Packit Service |
4684c1 |
(int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sent += ret;
|
|
Packit Service |
4684c1 |
} else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
|
|
Packit Service |
4684c1 |
_gnutls_write_log("WRITE interrupted: %d bytes left.\n",
|
|
Packit Service |
4684c1 |
(int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
} else if (ret == GNUTLS_E_LARGE_PACKET) {
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(send_buffer, tosend);
|
|
Packit Service |
4684c1 |
_gnutls_write_log
|
|
Packit Service |
4684c1 |
("WRITE cannot send large packet (%u bytes).\n",
|
|
Packit Service |
4684c1 |
(unsigned int) tosend);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
_gnutls_write_log("WRITE error: code %d, %d bytes left.\n",
|
|
Packit Service |
4684c1 |
ret, (int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sent < tosend) {
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return sent;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Checks whether there are received data within
|
|
Packit Service |
4684c1 |
* a timeframe.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns 0 if data were received, GNUTLS_E_TIMEDOUT
|
|
Packit Service |
4684c1 |
* on timeout and a negative error code on error.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
int _gnutls_io_check_recv(gnutls_session_t session, unsigned int ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
|
|
Packit Service |
4684c1 |
int ret = 0, err;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (NO_TIMEOUT_FUNC_SET(session)) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("The pull function has been replaced but not the pull timeout.\n");
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
reset_errno(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = session->internals.pull_timeout_func(fd, ms);
|
|
Packit Service |
4684c1 |
if (ret == -1) {
|
|
Packit Service |
4684c1 |
err = get_errno(session);
|
|
Packit Service |
4684c1 |
_gnutls_read_log
|
|
Packit Service |
4684c1 |
("READ_TIMEOUT: %d returned from %p, errno=%d (timeout: %u)\n",
|
|
Packit Service |
4684c1 |
(int) ret, fd, err, ms);
|
|
Packit Service |
4684c1 |
return errno_to_gerr(err, IS_DTLS(session));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret > 0)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return GNUTLS_E_TIMEDOUT;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* HANDSHAKE buffers part
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This function writes the data that are left in the
|
|
Packit Service |
4684c1 |
* Handshake write buffer (ie. because the previous write was
|
|
Packit Service |
4684c1 |
* interrupted.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ssize_t _gnutls_handshake_io_write_flush(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
mbuffer_head_st *const send_buffer =
|
|
Packit Service |
4684c1 |
&session->internals.handshake_send_buffer;
|
|
Packit Service |
4684c1 |
gnutls_datum_t msg;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
uint16_t epoch;
|
|
Packit Service |
4684c1 |
ssize_t total = 0;
|
|
Packit Service |
4684c1 |
mbuffer_st *cur;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_write_log("HWRITE FLUSH: %d bytes in buffer.\n",
|
|
Packit Service |
4684c1 |
(int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session))
|
|
Packit Service |
4684c1 |
return _dtls_transmit(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (cur = _mbuffer_head_get_first(send_buffer, &msg;;
|
|
Packit Service |
4684c1 |
cur != NULL; cur = _mbuffer_head_get_first(send_buffer, &msg))
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
epoch = cur->epoch;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls_send_int(session, cur->type,
|
|
Packit Service |
4684c1 |
cur->htype,
|
|
Packit Service |
4684c1 |
epoch, msg.data, msg.size, 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret >= 0) {
|
|
Packit Service |
4684c1 |
total += ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _mbuffer_head_remove_bytes(send_buffer, ret);
|
|
Packit Service |
4684c1 |
/* for each queued message we send, ensure that
|
|
Packit Service |
4684c1 |
* we drop the epoch refcount set in _gnutls_handshake_io_cache_int(). */
|
|
Packit Service |
4684c1 |
if (ret == 1)
|
|
Packit Service |
4684c1 |
_gnutls_epoch_refcount_dec(session, epoch);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_write_log
|
|
Packit Service |
4684c1 |
("HWRITE: wrote %d bytes, %d bytes left.\n",
|
|
Packit Service |
4684c1 |
ret, (int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
_gnutls_write_log
|
|
Packit Service |
4684c1 |
("HWRITE error: code %d, %d bytes left.\n",
|
|
Packit Service |
4684c1 |
ret, (int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return _gnutls_io_write_flush(session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This is a send function for the gnutls handshake
|
|
Packit Service |
4684c1 |
* protocol. Just makes sure that all data have been sent.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
_gnutls_handshake_io_cache_int(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
gnutls_handshake_description_t htype,
|
|
Packit Service |
4684c1 |
mbuffer_st * bufel)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
mbuffer_head_st *send_buffer;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session)) {
|
|
Packit Service |
4684c1 |
bufel->handshake_sequence =
|
|
Packit Service |
4684c1 |
session->internals.dtls.hsk_write_seq - 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
send_buffer = &session->internals.handshake_send_buffer;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* ensure that our epoch does not get garbage collected
|
|
Packit Service |
4684c1 |
* before we send all queued messages with it */
|
|
Packit Service |
4684c1 |
bufel->epoch =
|
|
Packit Service |
4684c1 |
(uint16_t) _gnutls_epoch_refcount_inc(session,
|
|
Packit Service |
4684c1 |
EPOCH_WRITE_CURRENT);
|
|
Packit Service |
4684c1 |
bufel->htype = htype;
|
|
Packit Service |
4684c1 |
if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
|
|
Packit Service |
4684c1 |
bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
bufel->type = GNUTLS_HANDSHAKE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_enqueue(send_buffer, bufel);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_write_log
|
|
Packit Service |
4684c1 |
("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
|
|
Packit Service |
4684c1 |
_gnutls_handshake2str(bufel->htype), (int) bufel->msg.size,
|
|
Packit Service |
4684c1 |
(int) send_buffer->byte_length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int handshake_compare(const void *_e1, const void *_e2)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const handshake_buffer_st *e1 = _e1;
|
|
Packit Service |
4684c1 |
const handshake_buffer_st *e2 = _e2;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (e1->sequence <= e2->sequence)
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define SSL2_HEADERS 1
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
|
Packit Service |
4684c1 |
handshake_buffer_st * hsk)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
uint8_t *dataptr = NULL; /* for realloc */
|
|
Packit Service |
4684c1 |
size_t handshake_header_size =
|
|
Packit Service |
4684c1 |
HANDSHAKE_HEADER_SIZE(session), data_size, frag_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Note: SSL2_HEADERS == 1 */
|
|
Packit Service |
4684c1 |
if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
dataptr = _mbuffer_get_udata_ptr(bufel);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* if reading a client hello of SSLv2 */
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SSL2
|
|
Packit Service |
4684c1 |
if (unlikely
|
|
Packit Service |
4684c1 |
(!IS_DTLS(session)
|
|
Packit Service |
4684c1 |
&& bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
|
|
Packit Service |
4684c1 |
handshake_header_size = SSL2_HEADERS; /* we've already read one byte */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
frag_size = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hsk->sequence = 0;
|
|
Packit Service |
4684c1 |
hsk->start_offset = 0;
|
|
Packit Service |
4684c1 |
hsk->length = frag_size;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
{ /* TLS or DTLS handshake headers */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hsk->rtype = hsk->htype = dataptr[0];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* we do not use DECR_LEN because we know
|
|
Packit Service |
4684c1 |
* that the packet has enough data.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
hsk->length = _gnutls_read_uint24(&dataptr[1]);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session)) {
|
|
Packit Service |
4684c1 |
hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
|
|
Packit Service |
4684c1 |
hsk->start_offset =
|
|
Packit Service |
4684c1 |
_gnutls_read_uint24(&dataptr[6]);
|
|
Packit Service |
4684c1 |
frag_size =
|
|
Packit Service |
4684c1 |
_gnutls_read_uint24(&dataptr[9]);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
hsk->sequence = 0;
|
|
Packit Service |
4684c1 |
hsk->start_offset = 0;
|
|
Packit Service |
4684c1 |
frag_size =
|
|
Packit Service |
4684c1 |
MIN((_mbuffer_get_udata_size(bufel) -
|
|
Packit Service |
4684c1 |
handshake_header_size), hsk->length);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* TLS1.3: distinguish server hello versus hello retry request.
|
|
Packit Service |
4684c1 |
* The epitome of slick protocol design. */
|
|
Packit Service |
4684c1 |
if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO && hsk->start_offset == 0 && !IS_DTLS(session)) {
|
|
Packit Service |
4684c1 |
if (_mbuffer_get_udata_size(bufel) > handshake_header_size+2+GNUTLS_RANDOM_SIZE &&
|
|
Packit Service |
4684c1 |
memcmp(dataptr+handshake_header_size+2, HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) {
|
|
Packit Service |
4684c1 |
hsk->htype = GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (frag_size > 0)
|
|
Packit Service |
4684c1 |
hsk->end_offset = hsk->start_offset + frag_size - 1;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
hsk->end_offset = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_log
|
|
Packit Service |
4684c1 |
("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
|
|
Packit Service |
4684c1 |
session, _gnutls_handshake2str(hsk->htype),
|
|
Packit Service |
4684c1 |
(unsigned) hsk->htype, (int) hsk->length, (int) data_size,
|
|
Packit Service |
4684c1 |
hsk->start_offset, (int) frag_size,
|
|
Packit Service |
4684c1 |
(int) hsk->sequence);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hsk->header_size = handshake_header_size;
|
|
Packit Service |
4684c1 |
memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
|
|
Packit Service |
4684c1 |
handshake_header_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hsk->length > 0 && (frag_size > data_size ||
|
|
Packit Service |
4684c1 |
(frag_size > 0 &&
|
|
Packit Service |
4684c1 |
hsk->end_offset >= hsk->length))) {
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
else if (hsk->length == 0 && hsk->end_offset != 0
|
|
Packit Service |
4684c1 |
&& hsk->start_offset != 0)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return handshake_header_size;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void _gnutls_handshake_buffer_move(handshake_buffer_st * dst,
|
|
Packit Service |
4684c1 |
handshake_buffer_st * src)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
memcpy(dst, src, sizeof(*dst));
|
|
Packit Service |
4684c1 |
memset(src, 0, sizeof(*src));
|
|
Packit Service |
4684c1 |
src->htype = -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* will merge the given handshake_buffer_st to the handshake_recv_buffer
|
|
Packit Service |
4684c1 |
* list. The given hsk packet will be released in any case (success or failure).
|
|
Packit Service |
4684c1 |
* Only used in DTLS.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static int merge_handshake_packet(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
handshake_buffer_st * hsk)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int exists = 0, i, pos = 0;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
|
|
Packit Service |
4684c1 |
if (session->internals.handshake_recv_buffer[i].htype ==
|
|
Packit Service |
4684c1 |
hsk->htype) {
|
|
Packit Service |
4684c1 |
exists = 1;
|
|
Packit Service |
4684c1 |
pos = i;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!exists)
|
|
Packit Service |
4684c1 |
pos = session->internals.handshake_recv_buffer_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (pos >= MAX_HANDSHAKE_MSGS)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!exists) {
|
|
Packit Service |
4684c1 |
if (hsk->length > 0 && hsk->end_offset > 0
|
|
Packit Service |
4684c1 |
&& hsk->end_offset - hsk->start_offset + 1 !=
|
|
Packit Service |
4684c1 |
hsk->length) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
_gnutls_buffer_resize(&hsk->data, hsk->length);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hsk->data.length = hsk->length;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memmove(&hsk->data.data[hsk->start_offset],
|
|
Packit Service |
4684c1 |
hsk->data.data,
|
|
Packit Service |
4684c1 |
hsk->end_offset - hsk->start_offset + 1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer_size++;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* rewrite headers to make them look as each packet came as a single fragment */
|
|
Packit Service |
4684c1 |
_gnutls_write_uint24(hsk->length, &hsk->header[1]);
|
|
Packit Service |
4684c1 |
_gnutls_write_uint24(0, &hsk->header[6]);
|
|
Packit Service |
4684c1 |
_gnutls_write_uint24(hsk->length, &hsk->header[9]);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_buffer_move(&session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer[pos],
|
|
Packit Service |
4684c1 |
hsk);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (hsk->start_offset <
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
start_offset
|
|
Packit Service |
4684c1 |
&& hsk->end_offset + 1 >=
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
start_offset) {
|
|
Packit Service |
4684c1 |
memcpy(&session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer[pos].data.data[hsk->
|
|
Packit Service |
4684c1 |
start_offset],
|
|
Packit Service |
4684c1 |
hsk->data.data, hsk->data.length);
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
start_offset = hsk->start_offset;
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
end_offset =
|
|
Packit Service |
4684c1 |
MIN(hsk->end_offset,
|
|
Packit Service |
4684c1 |
session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer[pos].end_offset);
|
|
Packit Service |
4684c1 |
} else if (hsk->end_offset >
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
end_offset
|
|
Packit Service |
4684c1 |
&& hsk->start_offset <=
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
end_offset + 1) {
|
|
Packit Service |
4684c1 |
memcpy(&session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer[pos].data.data[hsk->
|
|
Packit Service |
4684c1 |
start_offset],
|
|
Packit Service |
4684c1 |
hsk->data.data, hsk->data.length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
end_offset = hsk->end_offset;
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer[pos].
|
|
Packit Service |
4684c1 |
start_offset =
|
|
Packit Service |
4684c1 |
MIN(hsk->start_offset,
|
|
Packit Service |
4684c1 |
session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer[pos].start_offset);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
_gnutls_handshake_buffer_clear(hsk);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* returns non-zero on match and zero on mismatch
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
inline static int cmp_hsk_types(gnutls_handshake_description_t expected,
|
|
Packit Service |
4684c1 |
gnutls_handshake_description_t recvd)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (expected == GNUTLS_HANDSHAKE_ANY)
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SSL2
|
|
Packit Service |
4684c1 |
if (expected == GNUTLS_HANDSHAKE_CLIENT_HELLO
|
|
Packit Service |
4684c1 |
&& recvd == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
if (expected != recvd)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1)
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* returns the last stored handshake packet.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static int get_last_packet(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
gnutls_handshake_description_t htype,
|
|
Packit Service |
4684c1 |
handshake_buffer_st * hsk,
|
|
Packit Service |
4684c1 |
unsigned int optional)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
handshake_buffer_st *recv_buf =
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session)) {
|
|
Packit Service |
4684c1 |
if (session->internals.handshake_recv_buffer_size == 0 ||
|
|
Packit Service |
4684c1 |
(session->internals.dtls.hsk_read_seq !=
|
|
Packit Service |
4684c1 |
recv_buf[LAST_ELEMENT].sequence))
|
|
Packit Service |
4684c1 |
goto timeout;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (htype != recv_buf[LAST_ELEMENT].htype) {
|
|
Packit Service |
4684c1 |
if (optional == 0)
|
|
Packit Service |
4684c1 |
_gnutls_audit_log(session,
|
|
Packit Service |
4684c1 |
"Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
|
|
Packit Service |
4684c1 |
_gnutls_handshake2str
|
|
Packit Service |
4684c1 |
(recv_buf[0].htype),
|
|
Packit Service |
4684c1 |
(int) recv_buf[0].htype,
|
|
Packit Service |
4684c1 |
_gnutls_handshake2str
|
|
Packit Service |
4684c1 |
(htype), (int) htype);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
|
|
Packit Service |
4684c1 |
recv_buf[LAST_ELEMENT].end_offset ==
|
|
Packit Service |
4684c1 |
recv_buf[LAST_ELEMENT].length - 1)
|
|
Packit Service |
4684c1 |
|| recv_buf[LAST_ELEMENT].length == 0) {
|
|
Packit Service |
4684c1 |
session->internals.dtls.hsk_read_seq++;
|
|
Packit Service |
4684c1 |
_gnutls_handshake_buffer_move(hsk,
|
|
Packit Service |
4684c1 |
&recv_buf
|
|
Packit Service |
4684c1 |
[LAST_ELEMENT]);
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer_size--;
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
/* if we don't have a complete handshake message, but we
|
|
Packit Service |
4684c1 |
* have queued data waiting, try again to reconstruct the
|
|
Packit Service |
4684c1 |
* handshake packet, using the queued */
|
|
Packit Service |
4684c1 |
if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
|
|
Packit Service |
4684c1 |
record_check_unprocessed(session) > 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
goto timeout;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else { /* TLS */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->internals.handshake_recv_buffer_size > 0
|
|
Packit Service |
4684c1 |
&& recv_buf[0].length == recv_buf[0].data.length) {
|
|
Packit Service |
4684c1 |
if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) {
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer_size--;
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
timeout:
|
|
Packit Service |
4684c1 |
RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This is a receive function for the gnutls handshake
|
|
Packit Service |
4684c1 |
* protocol. Makes sure that we have received all data.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* htype is the next handshake packet expected.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t msg;
|
|
Packit Service |
4684c1 |
mbuffer_st *bufel = NULL, *prev = NULL;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
size_t data_size;
|
|
Packit Service |
4684c1 |
handshake_buffer_st *recv_buf =
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
bufel =
|
|
Packit Service |
4684c1 |
_mbuffer_head_get_first(&session->internals.record_buffer,
|
|
Packit Service |
4684c1 |
&msg;;
|
|
Packit Service |
4684c1 |
if (bufel == NULL)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!IS_DTLS(session)) {
|
|
Packit Service |
4684c1 |
ssize_t append, header_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
if (bufel->type != GNUTLS_HANDSHAKE)
|
|
Packit Service |
4684c1 |
return
|
|
Packit Service |
4684c1 |
gnutls_assert_val
|
|
Packit Service |
4684c1 |
(GNUTLS_E_UNEXPECTED_PACKET);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (unlikely
|
|
Packit Service |
4684c1 |
(session->internals.handshake_recv_buffer_size == 0 &&
|
|
Packit Service |
4684c1 |
msg.size < HANDSHAKE_HEADER_SIZE(session) &&
|
|
Packit Service |
4684c1 |
session->internals.handshake_header_recv_buffer.byte_length <
|
|
Packit Service |
4684c1 |
HANDSHAKE_HEADER_SIZE(session) - msg.size)) {
|
|
Packit Service |
4684c1 |
bufel = _mbuffer_head_pop_first(&session->internals.record_buffer);
|
|
Packit Service |
4684c1 |
_mbuffer_enqueue(&session->internals.handshake_header_recv_buffer,
|
|
Packit Service |
4684c1 |
bufel);
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
} else if (session->internals.handshake_recv_buffer_size >
|
|
Packit Service |
4684c1 |
0 && recv_buf[0].length > recv_buf[0].data.length) {
|
|
Packit Service |
4684c1 |
/* this is the rest of a previous message */
|
|
Packit Service |
4684c1 |
append = MIN(msg.size,
|
|
Packit Service |
4684c1 |
recv_buf[0].length -
|
|
Packit Service |
4684c1 |
recv_buf[0].data.length);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
_gnutls_buffer_append_data(&recv_buf
|
|
Packit Service |
4684c1 |
[0].data,
|
|
Packit Service |
4684c1 |
msg.data,
|
|
Packit Service |
4684c1 |
append);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(&session->
|
|
Packit Service |
4684c1 |
internals.
|
|
Packit Service |
4684c1 |
record_buffer,
|
|
Packit Service |
4684c1 |
append);
|
|
Packit Service |
4684c1 |
} else { /* received new message */
|
|
Packit Service |
4684c1 |
if (unlikely
|
|
Packit Service |
4684c1 |
(session->internals.
|
|
Packit Service |
4684c1 |
handshake_header_recv_buffer.length > 0)) {
|
|
Packit Service |
4684c1 |
bufel = _mbuffer_head_pop_first(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer);
|
|
Packit Service |
4684c1 |
_mbuffer_enqueue(&session->internals.
|
|
Packit Service |
4684c1 |
handshake_header_recv_buffer,
|
|
Packit Service |
4684c1 |
bufel);
|
|
Packit Service |
4684c1 |
ret = _mbuffer_linearize_align16(&session->internals.
|
|
Packit Service |
4684c1 |
handshake_header_recv_buffer,
|
|
Packit Service |
4684c1 |
get_total_headers(session));
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
bufel = _mbuffer_head_pop_first(&session->internals.
|
|
Packit Service |
4684c1 |
handshake_header_recv_buffer);
|
|
Packit Service |
4684c1 |
_mbuffer_head_push_first(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer,
|
|
Packit Service |
4684c1 |
bufel);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
parse_handshake_header(session, bufel,
|
|
Packit Service |
4684c1 |
&recv_buf[0]);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
header_size = ret;
|
|
Packit Service |
4684c1 |
session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer_size = 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_set_uhead_size(bufel,
|
|
Packit Service |
4684c1 |
header_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
data_size =
|
|
Packit Service |
4684c1 |
MIN(recv_buf[0].length,
|
|
Packit Service |
4684c1 |
_mbuffer_get_udata_size(bufel));
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
_gnutls_buffer_append_data(&recv_buf
|
|
Packit Service |
4684c1 |
[0].data,
|
|
Packit Service |
4684c1 |
_mbuffer_get_udata_ptr
|
|
Packit Service |
4684c1 |
(bufel),
|
|
Packit Service |
4684c1 |
data_size);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
_mbuffer_set_uhead_size(bufel, 0);
|
|
Packit Service |
4684c1 |
_mbuffer_head_remove_bytes(&session->
|
|
Packit Service |
4684c1 |
internals.
|
|
Packit Service |
4684c1 |
record_buffer,
|
|
Packit Service |
4684c1 |
data_size +
|
|
Packit Service |
4684c1 |
header_size);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* if packet is complete then return it
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (recv_buf[0].length == recv_buf[0].data.length) {
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
bufel =
|
|
Packit Service |
4684c1 |
_mbuffer_head_get_first(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer, &msg;;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (bufel != NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* if we are here it means that the received packets were not
|
|
Packit Service |
4684c1 |
* enough to complete the handshake packet.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
} else { /* DTLS */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
handshake_buffer_st tmp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
/* we now
|
|
Packit Service |
4684c1 |
* 0. parse headers
|
|
Packit Service |
4684c1 |
* 1. insert to handshake_recv_buffer
|
|
Packit Service |
4684c1 |
* 2. sort handshake_recv_buffer on sequence numbers
|
|
Packit Service |
4684c1 |
* 3. return first packet if completed or GNUTLS_E_AGAIN.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
if (bufel->type != GNUTLS_HANDSHAKE) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto next; /* ignore packet */
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_buffer_init(&tmp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
parse_handshake_header(session, bufel,
|
|
Packit Service |
4684c1 |
&tmp);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
_gnutls_audit_log(session,
|
|
Packit Service |
4684c1 |
"Invalid handshake packet headers. Discarding.\n");
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_consume(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer, bufel,
|
|
Packit Service |
4684c1 |
ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
data_size =
|
|
Packit Service |
4684c1 |
MIN(tmp.length,
|
|
Packit Service |
4684c1 |
tmp.end_offset - tmp.start_offset +
|
|
Packit Service |
4684c1 |
1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
_gnutls_buffer_append_data(&tmp.data,
|
|
Packit Service |
4684c1 |
_mbuffer_get_udata_ptr
|
|
Packit Service |
4684c1 |
(bufel),
|
|
Packit Service |
4684c1 |
data_size);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_consume(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer, bufel,
|
|
Packit Service |
4684c1 |
data_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
merge_handshake_packet(session, &tmp);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (_mbuffer_get_udata_size(bufel) > 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
prev = bufel;
|
|
Packit Service |
4684c1 |
bufel =
|
|
Packit Service |
4684c1 |
_mbuffer_dequeue(&session->internals.
|
|
Packit Service |
4684c1 |
record_buffer, bufel);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_xfree(&prev;;
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
next:
|
|
Packit Service |
4684c1 |
bufel = _mbuffer_head_get_next(bufel, NULL);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (bufel != NULL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* sort in descending order */
|
|
Packit Service |
4684c1 |
if (session->internals.handshake_recv_buffer_size > 1)
|
|
Packit Service |
4684c1 |
qsort(recv_buf,
|
|
Packit Service |
4684c1 |
session->internals.
|
|
Packit Service |
4684c1 |
handshake_recv_buffer_size,
|
|
Packit Service |
4684c1 |
sizeof(recv_buf[0]), handshake_compare);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
while (session->internals.handshake_recv_buffer_size > 0 &&
|
|
Packit Service |
4684c1 |
recv_buf[LAST_ELEMENT].sequence <
|
|
Packit Service |
4684c1 |
session->internals.dtls.hsk_read_seq) {
|
|
Packit Service |
4684c1 |
_gnutls_audit_log(session,
|
|
Packit Service |
4684c1 |
"Discarded replayed handshake packet with sequence %d\n",
|
|
Packit Service |
4684c1 |
recv_buf[LAST_ELEMENT].sequence);
|
|
Packit Service |
4684c1 |
_gnutls_handshake_buffer_clear(&recv_buf
|
|
Packit Service |
4684c1 |
[LAST_ELEMENT]);
|
|
Packit Service |
4684c1 |
session->internals.handshake_recv_buffer_size--;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This is a receive function for the gnutls handshake
|
|
Packit Service |
4684c1 |
* protocol. Makes sure that we have received all data.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_handshake_io_recv_int(gnutls_session_t session,
|
|
Packit Service |
4684c1 |
gnutls_handshake_description_t htype,
|
|
Packit Service |
4684c1 |
handshake_buffer_st * hsk,
|
|
Packit Service |
4684c1 |
unsigned int optional)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned int tleft = 0;
|
|
Packit Service |
4684c1 |
int retries = 7;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = get_last_packet(session, htype, hsk, optional);
|
|
Packit Service |
4684c1 |
if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED &&
|
|
Packit Service |
4684c1 |
ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE &&
|
|
Packit Service |
4684c1 |
ret != GNUTLS_E_INT_CHECK_AGAIN) {
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* try using the already existing records before
|
|
Packit Service |
4684c1 |
* trying to receive.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ret = _gnutls_parse_record_buffered_msgs(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == 0) {
|
|
Packit Service |
4684c1 |
ret = get_last_packet(session, htype, hsk, optional);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (IS_DTLS(session)) {
|
|
Packit Service |
4684c1 |
if (ret >= 0)
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
|
|
Packit Service |
4684c1 |
&& ret < 0) || ret >= 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (htype != (gnutls_handshake_description_t) -1) {
|
|
Packit Service |
4684c1 |
ret = handshake_remaining_time(session);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
tleft = ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
/* if we don't have a complete message waiting for us, try
|
|
Packit Service |
4684c1 |
* receiving more */
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
_gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
|
|
Packit Service |
4684c1 |
tleft);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val_fatal(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls_parse_record_buffered_msgs(session);
|
|
Packit Service |
4684c1 |
if (ret == 0) {
|
|
Packit Service |
4684c1 |
ret = get_last_packet(session, htype, hsk, optional);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
/* we put an upper limit (retries) to the number of partial handshake
|
|
Packit Service |
4684c1 |
* messages in a record packet. */
|
|
Packit Service |
4684c1 |
} while(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN && retries-- > 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|