Merge branch 'iotssl-541-2.1-pathlen-bugfix'
diff --git a/ChangeLog b/ChangeLog
index 7c1c264..b4cf598 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12 +1,21 @@
mbed TLS ChangeLog (Sorted per branch, date)
-= mbed TLS 2.1.4 released 2015-11-xx
+= mbed TLS 2.1.4 released 2015-12-xx
Bugfix
+ * Fix over-restrictive length limit in GCM. Found by Andreas-N. #362
* Fix bug in certificate validation that caused valid chains to be rejected
when the first intermediate certificate has pathLenConstraint=0. Found by
Nicholas Wilson. Introduced in mbed TLS 2.1.4. #280
+Changes
+ * To avoid dropping an entire DTLS datagram if a single record in a datagram
+ is invalid, we now only drop the record and look at subsequent records (if
+ any are present) in the same datagram to avoid interoperability issues.
+ Previously the library was dropping the entire datagram, Where a record is
+ unexpected, the function mbedtls_ssl_read_record() will now return
+ MBEDTLS_ERR_SSL_UNEXPECTED_RECORD.
+
= mbed TLS 2.1.3 released 2015-11-04
Security
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index a182713..5e549f6 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -79,7 +79,7 @@
* ECP 4 8 (Started from top)
* MD 5 4
* CIPHER 6 6
- * SSL 6 16 (Started from top)
+ * SSL 6 17 (Started from top)
* SSL 7 31
*
* Module dependent error code (5 bits 0x.00.-0x.F8.)
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 7ab9600..73e96dd 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -106,6 +106,7 @@
#define MBEDTLS_ERR_SSL_WANT_WRITE -0x6880 /**< Connection requires a write call. */
#define MBEDTLS_ERR_SSL_TIMEOUT -0x6800 /**< The operation timed out. */
#define MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780 /**< The client initiated a reconnect from the same port. */
+#define MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700 /**< Record header looks valid but is not expected. */
/*
* Various constants
@@ -2087,7 +2088,8 @@
* \note If this function returns something other than 0 or
* MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context
* becomes unusable, and you should either free it or call
- * \c mbedtls_ssl_session_reset() on it before re-using it.
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
*
* \note If DTLS is in use, then you may choose to handle
* MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging
@@ -2103,6 +2105,12 @@
* the following state after execution of this function.
* Do not call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER.
*
+ * \note If this function returns something other than 0 or
+ * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context
+ * becomes unusable, and you should either free it or call
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
+ *
* \param ssl SSL context
*
* \return 0 if successful, or
@@ -2121,6 +2129,12 @@
* \param ssl SSL context
*
* \return 0 if successful, or any mbedtls_ssl_handshake() return value.
+ *
+ * \note If this function returns something other than 0 or
+ * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context
+ * becomes unusable, and you should either free it or call
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
*/
int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl );
#endif /* MBEDTLS_SSL_RENEGOTIATION */
@@ -2138,6 +2152,13 @@
* MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or
* another negative error code.
*
+ * \note If this function returns something other than a positive
+ * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE or
+ * MBEDTLS_ERR_SSL_CLIENT_RECONNECT, then the ssl context
+ * becomes unusable, and you should either free it or call
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
+ *
* \note When this function return MBEDTLS_ERR_SSL_CLIENT_RECONNECT
* (which can only happen server-side), it means that a client
* is initiating a new connection using the same source port.
@@ -2171,6 +2192,12 @@
* or MBEDTLS_ERR_SSL_WANT_WRITE of MBEDTLS_ERR_SSL_WANT_READ,
* or another negative error code.
*
+ * \note If this function returns something other than a positive
+ * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE, the ssl context
+ * becomes unusable, and you should either free it or call
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
+ *
* \note When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ,
* it must be called later with the *same* arguments,
* until it returns a positive value.
@@ -2194,6 +2221,12 @@
* \param message The alert message (SSL_ALERT_MSG_*)
*
* \return 0 if successful, or a specific SSL error code.
+ *
+ * \note If this function returns something other than 0 or
+ * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context
+ * becomes unusable, and you should either free it or call
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
*/
int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
unsigned char level,
@@ -2202,6 +2235,14 @@
* \brief Notify the peer that the connection is being closed
*
* \param ssl SSL context
+ *
+ * \return 0 if successful, or a specific SSL error code.
+ *
+ * \note If this function returns something other than 0 or
+ * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context
+ * becomes unusable, and you should either free it or call
+ * \c mbedtls_ssl_session_reset() on it before re-using it for
+ * a new connection; the current connection must be closed.
*/
int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl );
diff --git a/library/bignum.c b/library/bignum.c
index 58a4cd2..ca05f77 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -18,13 +18,22 @@
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
+
/*
- * This MPI implementation is based on:
+ * The following sources were referenced in the design of this Multi-precision
+ * Integer library:
*
- * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
- * http://www.stillhq.com/extracted/gnupg-api/mpi/
- * http://math.libtomcrypt.com/files/tommath.pdf
- */
+ * [1] Handbook of Applied Cryptography - 1997
+ * Menezes, van Oorschot and Vanstone
+ *
+ * [2] Multi-Precision Math
+ * Tom St Denis
+ * https://github.com/libtom/libtommath/blob/develop/tommath.pdf
+ *
+ * [3] GNU Multi-Precision Arithmetic Library
+ * https://gmplib.org/manual/index.html
+ *
+*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
@@ -348,6 +357,24 @@
}
/*
+ * Count leading zero bits in a given integer
+ */
+static size_t mbedtls_clz( const mbedtls_mpi_uint x )
+{
+ size_t j;
+ mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
+
+ for( j = 0; j < biL; j++ )
+ {
+ if( x & mask ) break;
+
+ mask >>= 1;
+ }
+
+ return j;
+}
+
+/*
* Return the number of bits
*/
size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
@@ -361,9 +388,7 @@
if( X->p[i] != 0 )
break;
- for( j = biL; j > 0; j-- )
- if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 )
- break;
+ j = biL - mbedtls_clz( X->p[i] );
return( ( i * biL ) + j );
}
@@ -1187,6 +1212,99 @@
}
/*
+ * Unsigned integer divide - 64bit dividend and 32bit divisor
+ */
+static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
+ mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r)
+{
+#if defined(MBEDTLS_HAVE_UDBL)
+ mbedtls_t_udbl dividend, quotient;
+#endif
+
+ /*
+ * Check for overflow
+ */
+ if(( 0 == d ) || ( u1 >= d ))
+ {
+ if (r != NULL) *r = (~0);
+
+ return (~0);
+ }
+
+#if defined(MBEDTLS_HAVE_UDBL)
+ dividend = (mbedtls_t_udbl) u1 << biL;
+ dividend |= (mbedtls_t_udbl) u0;
+ quotient = dividend / d;
+ if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
+ quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
+
+ if( r != NULL )
+ *r = dividend - (quotient * d);
+
+ return (mbedtls_mpi_uint) quotient;
+#else
+ const mbedtls_mpi_uint radix = 1 << biH;
+ mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
+ mbedtls_mpi_uint u0_msw, u0_lsw;
+ int s;
+
+ /*
+ * Algorithm D, Section 4.3.1 - The Art of Computer Programming
+ * Vol. 2 - Seminumerical Algorithms, Knuth
+ */
+
+ /*
+ * Normalize the divisor, d, and dividend, u0, u1
+ */
+ s = mbedtls_clz( d );
+ d = d << s;
+
+ u1 = u1 << s;
+ u1 |= (u0 >> (32 - s)) & ( (-s) >> 31);
+ u0 = u0 << s;
+
+ d1 = d >> biH;
+ d0 = d & 0xffff;
+
+ u0_msw = u0 >> biH;
+ u0_lsw = u0 & 0xffff;
+
+ /*
+ * Find the first quotient and remainder
+ */
+ q1 = u1 / d1;
+ r0 = u1 - d1 * q1;
+
+ while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
+ {
+ q1 -= 1;
+ r0 += d1;
+
+ if ( r0 >= radix ) break;
+ }
+
+ rAX = (u1 * radix) + (u0_msw - q1 * d);
+ q0 = rAX / d1;
+ r0 = rAX - q0 * d1;
+
+ while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
+ {
+ q0 -= 1;
+ r0 += d1;
+
+ if ( r0 >= radix ) break;
+ }
+
+ if (r != NULL)
+ *r = (rAX * radix + u0_lsw - q0 * d) >> s;
+
+ quotient = q1 * radix + q0;
+
+ return quotient;
+#endif
+}
+
+/*
* Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
*/
int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
@@ -1243,57 +1361,8 @@
Z.p[i - t - 1] = ~0;
else
{
-#if defined(MBEDTLS_HAVE_UDBL)
- mbedtls_t_udbl r;
-
- r = (mbedtls_t_udbl) X.p[i] << biL;
- r |= (mbedtls_t_udbl) X.p[i - 1];
- r /= Y.p[t];
- if( r > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
- r = ( (mbedtls_t_udbl) 1 << biL ) - 1;
-
- Z.p[i - t - 1] = (mbedtls_mpi_uint) r;
-#else
- /*
- * __udiv_qrnnd_c, from gmp/longlong.h
- */
- mbedtls_mpi_uint q0, q1, r0, r1;
- mbedtls_mpi_uint d0, d1, d, m;
-
- d = Y.p[t];
- d0 = ( d << biH ) >> biH;
- d1 = ( d >> biH );
-
- q1 = X.p[i] / d1;
- r1 = X.p[i] - d1 * q1;
- r1 <<= biH;
- r1 |= ( X.p[i - 1] >> biH );
-
- m = q1 * d0;
- if( r1 < m )
- {
- q1--, r1 += d;
- while( r1 >= d && r1 < m )
- q1--, r1 += d;
- }
- r1 -= m;
-
- q0 = r1 / d1;
- r0 = r1 - d1 * q0;
- r0 <<= biH;
- r0 |= ( X.p[i - 1] << biH ) >> biH;
-
- m = q0 * d0;
- if( r0 < m )
- {
- q0--, r0 += d;
- while( r0 >= d && r0 < m )
- q0--, r0 += d;
- }
- r0 -= m;
-
- Z.p[i - t - 1] = ( q1 << biH ) | q0;
-#endif /* MBEDTLS_HAVE_UDBL && !64-bit Apple with Clang 5.0 */
+ Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
+ Y.p[t], NULL);
}
Z.p[i - t - 1]++;
diff --git a/library/error.c b/library/error.c
index a1cf83a..debda1d 100644
--- a/library/error.c
+++ b/library/error.c
@@ -430,6 +430,8 @@
mbedtls_snprintf( buf, buflen, "SSL - The operation timed out" );
if( use_ret == -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT) )
mbedtls_snprintf( buf, buflen, "SSL - The client initiated a reconnect from the same port" );
+ if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) )
+ mbedtls_snprintf( buf, buflen, "SSL - Record header looks valid but is not expected" );
#endif /* MBEDTLS_SSL_TLS_C */
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
diff --git a/library/gcm.c b/library/gcm.c
index 4298254..aaacf97 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -362,7 +362,7 @@
/* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes
* Also check for possible overflow */
if( ctx->len + length < ctx->len ||
- (uint64_t) ctx->len + length > 0x03FFFFE0ull )
+ (uint64_t) ctx->len + length > 0xFFFFFFFE0ull )
{
return( MBEDTLS_ERR_GCM_BAD_INPUT );
}
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 1bda53c..938ca7a 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -2474,7 +2474,9 @@
{
dn_size = crt->subject_raw.len;
- if( end < p || (size_t)( end - p ) < 2 + dn_size )
+ if( end < p ||
+ (size_t)( end - p ) < dn_size ||
+ (size_t)( end - p ) < 2 + dn_size )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) );
break;
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 04d6981..ddc7bdc 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -3455,6 +3455,18 @@
* uint16 epoch; // DTLS only
* uint48 sequence_number; // DTLS only
* uint16 length;
+ *
+ * Return 0 if header looks sane (and, for DTLS, the record is expected)
+ * MBEDTLS_ERR_SSL_INVALID_RECORD if the header looks bad,
+ * MBEDTLS_ERR_SSL_UNEXPECTED_RECORD (DTLS only) if sane but unexpected.
+ *
+ * With DTLS, mbedtls_ssl_read_record() will:
+ * 1. proceed with the record if this function returns 0
+ * 2. drop only the current record if this function returns UNEXPECTED_RECORD
+ * 3. return CLIENT_RECONNECT if this function returns that value
+ * 4. drop the whole datagram if this function returns anything else.
+ * Point 2 is needed when the peer is resending, and we have already received
+ * the first record from a datagram but are still waiting for the others.
*/
static int ssl_parse_record_header( mbedtls_ssl_context *ssl )
{
@@ -3490,34 +3502,6 @@
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
- if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
- {
- /* Drop unexpected ChangeCipherSpec messages */
- if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC &&
- ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC &&
- ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
-
- /* Drop unexpected ApplicationData records,
- * except at the beginning of renegotiations */
- if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA &&
- ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
- && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS &&
- ssl->state == MBEDTLS_SSL_SERVER_HELLO )
-#endif
- )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
- }
-#endif
-
/* Check version */
if( major_ver != ssl->major_ver )
{
@@ -3531,53 +3515,6 @@
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
- /* Check epoch (and sequence number) with DTLS */
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
- if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
- {
- unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1];
-
- if( rec_epoch != ssl->in_epoch )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: "
- "expected %d, received %d",
- ssl->in_epoch, rec_epoch ) );
-
-#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
- /*
- * Check for an epoch 0 ClientHello. We can't use in_msg here to
- * access the first byte of record content (handshake type), as we
- * have an active transform (possibly iv_len != 0), so use the
- * fact that the record header len is 13 instead.
- */
- if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
- ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER &&
- rec_epoch == 0 &&
- ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
- ssl->in_left > 13 &&
- ssl->in_buf[13] == MBEDTLS_SSL_HS_CLIENT_HELLO )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "possible client reconnect "
- "from the same port" ) );
- return( ssl_handle_possible_reconnect( ssl ) );
- }
- else
-#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
-
-#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
- /* Replay detection only works for the current epoch */
- if( rec_epoch == ssl->in_epoch &&
- mbedtls_ssl_dtls_replay_check( ssl ) != 0 )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record" ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
-#endif
- }
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-
/* Check length against the size of our buffer */
if( ssl->in_msglen > MBEDTLS_SSL_BUFFER_LEN
- (size_t)( ssl->in_msg - ssl->in_buf ) )
@@ -3627,6 +3564,82 @@
#endif
}
+ /*
+ * DTLS-related tests done last, because most of them may result in
+ * silently dropping the record (but not the whole datagram), and we only
+ * want to consider that after ensuring that the "basic" fields (type,
+ * version, length) are sane.
+ */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ {
+ unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1];
+
+ /* Drop unexpected ChangeCipherSpec messages */
+ if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC &&
+ ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC &&
+ ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
+ }
+
+ /* Drop unexpected ApplicationData records,
+ * except at the beginning of renegotiations */
+ if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA &&
+ ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS &&
+ ssl->state == MBEDTLS_SSL_SERVER_HELLO )
+#endif
+ )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
+ }
+
+ /* Check epoch (and sequence number) with DTLS */
+ if( rec_epoch != ssl->in_epoch )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: "
+ "expected %d, received %d",
+ ssl->in_epoch, rec_epoch ) );
+
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
+ /*
+ * Check for an epoch 0 ClientHello. We can't use in_msg here to
+ * access the first byte of record content (handshake type), as we
+ * have an active transform (possibly iv_len != 0), so use the
+ * fact that the record header len is 13 instead.
+ */
+ if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
+ ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER &&
+ rec_epoch == 0 &&
+ ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
+ ssl->in_left > 13 &&
+ ssl->in_buf[13] == MBEDTLS_SSL_HS_CLIENT_HELLO )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "possible client reconnect "
+ "from the same port" ) );
+ return( ssl_handle_possible_reconnect( ssl ) );
+ }
+ else
+#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
+ }
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+ /* Replay detection only works for the current epoch */
+ if( rec_epoch == ssl->in_epoch &&
+ mbedtls_ssl_dtls_replay_check( ssl ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
+ }
+#endif
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
return( 0 );
}
@@ -3752,13 +3765,26 @@
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
{
- /* Ignore bad record and get next one; drop the whole datagram
- * since current header cannot be trusted to find the next record
- * in current datagram */
- ssl->next_record_offset = 0;
- ssl->in_left = 0;
+ if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD )
+ {
+ /* Skip unexpected record (but not whole datagram) */
+ ssl->next_record_offset = ssl->in_msglen
+ + mbedtls_ssl_hdr_len( ssl );
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record (header)" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding unexpected record "
+ "(header)" ) );
+ }
+ else
+ {
+ /* Skip invalid record and the rest of the datagram */
+ ssl->next_record_offset = 0;
+ ssl->in_left = 0;
+
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record "
+ "(header)" ) );
+ }
+
+ /* Get next record */
goto read_record_header;
}
#endif