Add functions for replay protection

This commit is contained in:
Manuel Pégourié-Gonnard 2014-09-24 10:52:58 +02:00 committed by Paul Bakker
parent ea22ce577e
commit 7a7e140d4e
3 changed files with 103 additions and 0 deletions

View file

@ -913,6 +913,15 @@
*/
#define POLARSSL_SSL_PROTO_DTLS
/**
* \def POLARSSL_SSL_DTLS_ANTI_REPLAY
*
* Enable support for the anti-replay mechanism in DTLS.
*
* Comment this to disable anti-replay in DTLS.
*/
#define POLARSSL_SSL_DTLS_ANTI_REPLAY
/**
* \def POLARSSL_SSL_ALPN
*

View file

@ -822,6 +822,10 @@ struct _ssl_context
size_t next_record_offset; /*!< offset of the next record in datagram
(equal to in_left if none) */
#endif
#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
uint64_t in_window_top; /*!< last validated record seq_num */
uint64_t in_window; /*!< bitmask for replay detection */
#endif
size_t in_hslen; /*!< current handshake message length,
including the handshake header */
@ -2043,6 +2047,12 @@ void ssl_recv_flight_completed( ssl_context *ssl );
int ssl_resend( ssl_context *ssl );
#endif
/* Visible for testing purposes only */
#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
int ssl_dtls_replay_check( ssl_context *ssl );
void ssl_dtls_replay_update( ssl_context *ssl );
#endif
/* constant-time buffer comparison */
static inline int safer_memcmp( const void *a, const void *b, size_t n )
{

View file

@ -2694,6 +2694,90 @@ static int ssl_prepare_handshake_record( ssl_context *ssl )
return( 0 );
}
/*
* DTLS anti-replay: RFC 6347 4.1.2.6
*
* - in_window_top is the highest record sequence number seen
* - the lsb of in_window is set iff in_window_top - 1 has been seen
* ...
* the msb of in_window is set iff in_window_top - 64 has been seen
*/
#if defined(POLARSSL_SSL_DTLS_ANTI_REPLAY)
static void ssl_dtls_replay_reset( ssl_context *ssl )
{
ssl->in_window_top = 0;
ssl->in_window = 0;
}
static inline uint64_t ssl_load_six_bytes( unsigned char *buf )
{
return( ( (uint64_t) buf[0] << 40 ) |
( (uint64_t) buf[1] << 32 ) |
( (uint64_t) buf[2] << 24 ) |
( (uint64_t) buf[3] << 16 ) |
( (uint64_t) buf[4] << 8 ) |
( (uint64_t) buf[5] ) );
}
/*
* Return 0 if sequence number is acceptable, -1 otherwise
*/
int ssl_dtls_replay_check( ssl_context *ssl )
{
uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 );
uint64_t bit;
if( rec_seqnum > ssl->in_window_top )
return( 0 );
if( rec_seqnum == ssl->in_window_top )
return( -1 );
bit = ssl->in_window_top - rec_seqnum - 1;
if( bit >= 64 )
return( -1 );
if( ( ssl->in_window & ( (uint64_t) 1 << bit ) ) != 0 )
return( -1 );
return( 0 );
}
/*
* Update replay window on new validated record
*/
void ssl_dtls_replay_update( ssl_context *ssl )
{
uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 );
if( rec_seqnum > ssl->in_window_top )
{
/* Update window_top and the contents of the window */
uint64_t shift = rec_seqnum - ssl->in_window_top;
if( shift >= 64 )
ssl->in_window = 0;
else
ssl->in_window <<= shift;
ssl->in_window_top = rec_seqnum;
}
else if( rec_seqnum == ssl->in_window_top )
{
; /* Can't happen, but anyway, nothing to do if it happened */
}
else
{
/* Mark that number as seen in the current window */
uint64_t bit = ssl->in_window_top - rec_seqnum - 1;
if( bit < 64 ) /* Always true, but be extra sure */
ssl->in_window |= (uint64_t) 1 << bit;
}
}
#endif /* POLARSSL_SSL_DTLS_ANTI_REPLAY */
/*
* ContentType type;
* ProtocolVersion version;