From: Nikos Mavrogiannopoulos Date: Sun, 20 Feb 2011 20:07:29 +0000 (+0100) Subject: Implemented a sliding window-like thing to discard replayed packets. X-Git-Tag: gnutls_2_99_0~204 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b44dc60baf7b9e5df7f905e6adcf2206fc039b4a;p=thirdparty%2Fgnutls.git Implemented a sliding window-like thing to discard replayed packets. --- diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 0cd367f964..9a44af76d4 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -826,7 +826,7 @@ _gnutls_handshake_io_write_flush (gnutls_session_t session) (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)) diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c index 1f3d9bd108..db598b97a6 100644 --- a/lib/gnutls_dtls.c +++ b/lib/gnutls_dtls.c @@ -144,7 +144,7 @@ static int drop_usage_count(gnutls_session_t session) * record layer. */ int -_gnutls_dtls_transmit (gnutls_session_t session) +_dtls_transmit (gnutls_session_t session) { int ret; @@ -215,6 +215,105 @@ cleanup: 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: diff --git a/lib/gnutls_dtls.h b/lib/gnutls_dtls.h index d3a4870bbb..ab4e4da6fa 100644 --- a/lib/gnutls_dtls.h +++ b/lib/gnutls_dtls.h @@ -27,6 +27,7 @@ #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 diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 47978e6e19..56324140ad 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -539,6 +539,8 @@ typedef struct int free_rsa_params; } internal_params_st; +#define DTLS_RECORD_WINDOW_SIZE 64 + /* DTLS session state */ typedef struct @@ -558,6 +560,9 @@ 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; diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 950579a786..2ac4ce98e5 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -45,6 +45,7 @@ #include "gnutls_constate.h" #include "ext_max_record.h" #include +#include #include /** @@ -427,8 +428,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type, 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)) @@ -518,7 +518,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type, _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); @@ -1094,6 +1094,21 @@ begin: 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 && @@ -1103,19 +1118,19 @@ begin: _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 diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 6ba5dd153c..c679c24b19 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -412,6 +412,8 @@ gnutls_init_dtls (gnutls_session_t * session, (*session)->internals.dtls.retrans_timeout = 300; (*session)->internals.dtls.total_timeout = 6000; + (*session)->internals.dtls.record_sw_size = 0; + return 0; }