_mbuffer_enqueue (send_buffer, bufel);
_gnutls_write_log
- ("HWRITE: enqueued %d. Total %d bytes.\n",
- (int) bufel->msg.size, (int) send_buffer->byte_length);
+ ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
+ _gnutls_handshake2str (bufel->htype), (int) bufel->msg.size, (int) send_buffer->byte_length);
+
+ return 0;
+}
+
+/* Skips a handshake packet
+ */
+int
+_gnutls_handshake_io_recv_skip (gnutls_session_t session,
+ content_type_t type,
+ gnutls_handshake_description_t htype,
+ size_t ptr_size)
+{
+ opaque * ptr;
+ int ret;
+
+ if (ptr_size == 0) return 0;
+
+ ptr = gnutls_malloc(ptr_size);
+ if (ptr == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ ret = _gnutls_handshake_io_recv_int(session, type, htype, ptr, ptr_size);
+ gnutls_free(ptr);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
return 0;
}
_gnutls_handshake_io_recv_int (gnutls_session_t session,
content_type_t type,
gnutls_handshake_description_t htype,
- void *iptr, size_t sizeOfPtr)
+ void *iptr, size_t ptr_size)
{
size_t left;
ssize_t i;
size_t dsize;
ptr = iptr;
- left = sizeOfPtr;
+ left = ptr_size;
- if (sizeOfPtr == 0 || iptr == NULL)
+ if (ptr_size == 0 || iptr == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
size_t tmp;
/* if we have already received some data */
- if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
+ if (ptr_size <= session->internals.handshake_recv_buffer.length)
{
/* if requested less data then return it.
*/
gnutls_assert ();
- tmp = sizeOfPtr;
+ tmp = ptr_size;
_gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
iptr, &tmp);
return tmp;
}
gnutls_assert ();
- tmp = sizeOfPtr;
+ tmp = ptr_size;
_gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
iptr, &tmp);
left -= tmp;
while (left > 0)
{
- dsize = sizeOfPtr - left;
+ dsize = ptr_size - left;
i = _gnutls_recv_int (session, type, htype, &ptr[dsize], left);
if (i < 0)
{
session->internals.handshake_recv_buffer.length = 0;
- return sizeOfPtr - left;
+ return ptr_size - left;
}
/* Buffer for handshake packets. Keeps the packets in order
int _gnutls_handshake_io_cache_int (gnutls_session_t,
gnutls_handshake_description_t,
mbuffer_st * bufel);
+int
+_gnutls_handshake_io_recv_skip (gnutls_session_t session,
+ content_type_t type,
+ gnutls_handshake_description_t htype,
+ size_t ptr_size);
+
ssize_t _gnutls_io_write_flush (gnutls_session_t session);
int
_gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, unsigned int ms);
if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC)
{
+ _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
+ "length: %u, offset: %u, fragment length: %u\n",
+ session, bufel->sequence,
+ _gnutls_handshake2str (bufel->htype),
+ bufel->htype, data_size, offset, frag_len);
+
return _gnutls_send_int (session, bufel->type, -1,
bufel->epoch,
_mbuffer_get_uhead_ptr(bufel),
return ret;
}
+#define _gnutls_handshake_header_buffer_clear( session) session->internals.handshake_header_buffer.header_size = 0; \
+ session->internals.handshake_header_buffer.sequence = -1; \
+ session->internals.handshake_header_buffer.frag_offset = 0; \
+ session->internals.handshake_header_buffer.frag_length = 0
+
/* This function will read the handshake header and return it to the caller. If the
* received handshake packet is not the one expected then it buffers the header, and
* returns UNEXPECTED_HANDSHAKE_PACKET.
length32 = _gnutls_read_uint24 (&dataptr[1]);
handshake_header_size = HANDSHAKE_HEADER_SIZE(session);
+ if (IS_DTLS(session))
+ {
+ session->internals.handshake_header_buffer.sequence = _gnutls_read_uint16 (&dataptr[4]);
+ session->internals.handshake_header_buffer.frag_offset = _gnutls_read_uint24 (&dataptr[6]);
+ session->internals.handshake_header_buffer.frag_length = _gnutls_read_uint24 (&dataptr[9]);
+ }
+
+
_gnutls_handshake_log ("HSK[%p]: %s was received [%ld bytes]\n",
session, _gnutls_handshake2str (dataptr[0]),
(long int) (length32 + HANDSHAKE_HEADER_SIZE(session)));
session, _gnutls_handshake2str (*recv_type),
(long int) (length32 + handshake_header_size));
- if (*recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO)
+ /* The IS_DTLS() check is redundant since the record layer will
+ * prevent us from reaching here.
+ */
+ if (IS_DTLS(session) || *recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO)
{ /* it should be one or nothing */
gnutls_assert ();
return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
session->internals.handshake_header_buffer.packet_length = length32;
session->internals.handshake_header_buffer.recv_type = *recv_type;
- if (_gnutls_is_dtls (session)
- && type == GNUTLS_HANDSHAKE_SERVER_HELLO
- && *recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST)
- return length32;
- else if (*recv_type != type)
+ if (IS_DTLS(session))
+ {
+ if ((int)session->internals.handshake_header_buffer.sequence <= session->internals.dtls.hsk_read_seq)
+ {
+ _gnutls_audit_log("Dropping replayed handshake packet with sequence %d\n", session->internals.handshake_header_buffer.sequence);
+ ret = _gnutls_handshake_io_recv_skip(session, GNUTLS_HANDSHAKE, *recv_type, length32);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ _gnutls_handshake_header_buffer_clear (session);
+ return GNUTLS_E_AGAIN;
+ }
+ session->internals.dtls.hsk_read_seq = session->internals.handshake_header_buffer.sequence;
+
+ if (type == GNUTLS_HANDSHAKE_SERVER_HELLO
+ && *recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST)
+ return length32;
+ }
+
+ if (*recv_type != type)
{
_gnutls_handshake_log ("HSK[%p]: %s was received, expected %s\n",
session, _gnutls_handshake2str (*recv_type),
return length32;
}
-#define _gnutls_handshake_header_buffer_clear( session) session->internals.handshake_header_buffer.header_size = 0
-
-
-
/* This function will hash the handshake headers and the
* handshake data.
*/
ret = _gnutls_recv_handshake_header (session, type, &recv_type);
if (ret < 0)
{
-
if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
&& optional == OPTIONAL_PACKET)
{
if (data != NULL && length32 > 0)
*data = dataptr;
-
ret = _gnutls_handshake_hash_add_recvd (session, recv_type,
session->
internals.handshake_header_buffer.
/* For DTLS handshake fragmentation and reassembly. */
uint16_t hsk_write_seq;
- uint16_t hsk_read_seq;
+ int hsk_read_seq;
uint16_t mtu;
unsigned int retrans_timeout;
/* this holds the length of the handshake packet */
size_t packet_length;
gnutls_handshake_description_t recv_type;
+
+ /* DTLS fields */
+ uint16_t sequence;
+ size_t frag_offset;
+ size_t frag_length;
} handshake_header_buffer_st;
typedef union
int
_gnutls_uint48pp (uint64 * x)
{
- int ret;
-
- ret = _gnutls_uint64pp(x);
- if (ret != 0)
- return ret;
-
- if (x->i[6] != 0)
- return -1;
-
+ register int i, y = 0;
+
+ for (i = 5; i >= 0; i--)
+ {
+ y = 0;
+ if (x->i[i] == 0xff)
+ {
+ x->i[i] = 0;
+ y = 1;
+ }
+ else
+ x->i[i]++;
+
+ if (y == 0)
+ break;
+ }
+ if (y != 0)
+ return -1; /* over 48 bits */
+
return 0;
}
session->internals.last_handshake_out = -1;
session->internals.resumable = RESUME_TRUE;
+
+ session->internals.dtls.hsk_read_seq = -1;
+ session->internals.dtls.hsk_write_seq = 0;
}
void
(*session)->internals.dtls.mtu = DTLS_DEFAULT_MTU;
(*session)->internals.transport = GNUTLS_DGRAM;
- (*session)->internals.dtls.retrans_timeout = 1000;
- (*session)->internals.dtls.total_timeout = 4000;
+ (*session)->internals.dtls.retrans_timeout = 300;
+ (*session)->internals.dtls.total_timeout = 6000;
return 0;
}