(int) send_buffer->byte_length);
if (IS_DTLS(session))
- return _gnutls_dtls_transmit(session);
+ return _dtls_transmit(session);
for (cur = _mbuffer_get_first (send_buffer, &msg);
cur != NULL; cur = _mbuffer_get_first (send_buffer, &msg))
* record layer.
*/
int
-_gnutls_dtls_transmit (gnutls_session_t session)
+_dtls_transmit (gnutls_session_t session)
{
int ret;
return ret;
}
+#define window_table session->internals.dtls.record_sw
+#define window_size session->internals.dtls.record_sw_size
+
+/* FIXME: could we modify that code to avoid using
+ * uint64_t?
+ */
+
+static void rot_window(gnutls_session_t session, int places)
+{
+ window_size -= places;
+ memmove(window_table, &window_table[places], window_size*sizeof(window_table[0]));
+}
+
+#define MOVE_SIZE 20
+/* Checks if a sequence number is not replayed. If replayed
+ * returns a negative value, otherwise zero.
+ */
+int _dtls_record_check(gnutls_session_t session, uint64 * _seq)
+{
+uint64_t seq = 0, diff;
+int i, offset = 0;
+
+ for (i=0;i<8;i++)
+ {
+ seq |= _seq->i[i];
+ seq <<= 8;
+ }
+
+ if (window_size == 0)
+ {
+ window_size = 1;
+ window_table[0] = seq;
+ return 0;
+ }
+
+ if (seq <= window_table[0])
+ {
+ return -1;
+ }
+
+ if (window_size == DTLS_RECORD_WINDOW_SIZE) {
+ rot_window(session, MOVE_SIZE);
+ }
+
+ if (seq < window_table[window_size-1])
+ {
+ /* is between first and last */
+ diff = window_table[window_size-1] - seq;
+
+ if (diff >= window_size)
+ {
+ return -1;
+ }
+
+ offset = window_size-1-diff;
+
+ if (window_table[offset] == seq)
+ {
+ return -1;
+ }
+ else
+ {
+ window_table[offset] = seq;
+ }
+ }
+ else /* seq >= last */
+ {
+ if (seq == window_table[window_size-1])
+ {
+ return -1;
+ }
+
+ diff = seq - window_table[window_size-1];
+ if (diff <= DTLS_RECORD_WINDOW_SIZE - window_size)
+ { /* fits in our empty space */
+ offset = diff + window_size-1;
+
+ window_table[offset] = seq;
+ window_size = offset + 1;
+ }
+ else
+ {
+ if (diff > DTLS_RECORD_WINDOW_SIZE/2)
+ { /* difference is too big */
+ window_table[DTLS_RECORD_WINDOW_SIZE-1] = seq;
+ window_size = DTLS_RECORD_WINDOW_SIZE;
+ }
+ else
+ {
+ rot_window(session, diff);
+ offset = diff + window_size-1;
+ window_table[offset] = seq;
+ window_size = offset + 1;
+ }
+ }
+ }
+ return 0;
+}
+
/**
* gnutls_dtls_set_timeouts:
#include "gnutls_int.h"
-int _gnutls_dtls_transmit(gnutls_session_t session);
+int _dtls_transmit(gnutls_session_t session);
+int _dtls_record_check(gnutls_session_t session, uint64 * _seq);
#endif
int free_rsa_params;
} internal_params_st;
+#define DTLS_RECORD_WINDOW_SIZE 64
+
/* DTLS session state
*/
typedef struct
unsigned int total_timeout;
unsigned int hsk_hello_verify_requests;
+
+ uint64_t record_sw[DTLS_RECORD_WINDOW_SIZE];
+ int record_sw_size;
} dtls_st;
#include "gnutls_constate.h"
#include "ext_max_record.h"
#include <gnutls_state.h>
+#include <gnutls_dtls.h>
#include <gnutls_dh.h>
/**
sequence_write(&record_state->sequence_number, &headers[3]);
_gnutls_record_log
- ("REC[%p]: Sending Packet[%d] %s(%d) with length: %d\n", session,
- (int) _gnutls_uint64touint32 (&record_state->sequence_number),
+ ("REC[%p]: Preparing Packet %s(%d) with length: %d\n", session,
_gnutls_packet2str (type), type, (int) sizeofdata);
if (sizeofdata > MAX_RECORD_SEND_SIZE(session))
_gnutls_record_log ("REC[%p]: Sent Packet[%d] %s(%d) with length: %d\n",
session,
- (int)
+ (unsigned int)
_gnutls_uint64touint32
(&record_state->sequence_number),
_gnutls_packet2str (type), type, (int) cipher_size);
header_size + length);
decrypted_length = ret;
+ /* check for duplicates. We check after the message
+ * is processed an authenticated to avoid someone
+ * messing with our windows.
+ */
+ if (IS_DTLS(session))
+ {
+ ret = _dtls_record_check(session, decrypt_sequence);
+ if (ret < 0)
+ {
+ _gnutls_audit_log("Duplicate message with sequence %u\n",
+ (unsigned int) _gnutls_uint64touint32 (decrypt_sequence));
+ return GNUTLS_E_AGAIN;
+ }
+ }
+
/* Check if this is a CHANGE_CIPHER_SPEC
*/
if (type == GNUTLS_CHANGE_CIPHER_SPEC &&
_gnutls_record_log
("REC[%p]: ChangeCipherSpec Packet was received\n", session);
- if ((size_t) ret != sizeofdata)
+ if ((size_t) decrypted_length != sizeofdata)
{ /* sizeofdata should be 1 */
gnutls_assert ();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
memcpy (data, tmp.data, sizeofdata);
- return ret;
+ return decrypted_length;
}
_gnutls_record_log
("REC[%p]: Decrypted Packet[%d] %s(%d) with length: %d\n", session,
- (int) _gnutls_uint64touint32 (&record_state->sequence_number),
+ (int) _gnutls_uint64touint32 (decrypt_sequence),
_gnutls_packet2str (recv_type), recv_type, decrypted_length);
/* increase sequence number
(*session)->internals.dtls.retrans_timeout = 300;
(*session)->internals.dtls.total_timeout = 6000;
+ (*session)->internals.dtls.record_sw_size = 0;
+
return 0;
}