Merge branch 'configs' of bachp configs
diff --git a/ChangeLog b/ChangeLog
index 37c79f6..c9e48e2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,13 +1,30 @@
mbed TLS ChangeLog (Sorted per branch, date)
-= mbed TLS 2.1.1 released 2015-09-??
+= mbed TLS 2.1.1 released 2015-09-17
+
+Security
+ * Add countermeasure against Lenstra's RSA-CRT attack for PKCS#1 v1.5
+ signatures. (Found by Florian Weimer, Red Hat.)
+ https://securityblog.redhat.com/2015/09/02/factoring-rsa-keys-with-tls-perfect-forward-secrecy/
+ * Fix possible client-side NULL pointer dereference (read) when the client
+ tries to continue the handshake after it failed (a misuse of the API).
+ (Found and patch provided by Fabian Foerg, Gotham Digital Science using afl-fuzz.)
Bugfix
* Fix warning when using a 64bit platform. (found by embedthis) (#275)
-
+ * Fix off-by-one error in parsing Supported Point Format extension that
+ caused some handshakes to fail.
+
Changes
* Made X509 profile pointer const in mbedtls_ssl_conf_cert_profile() to allow
use of mbedtls_x509_crt_profile_next. (found by NWilson)
+ * When a client initiates a reconnect from the same port as a live
+ connection, if cookie verification is available
+ (MBEDTLS_SSL_DTLS_HELLO_VERIFY defined in config.h, and usable cookie
+ callbacks set with mbedtls_ssl_conf_dtls_cookies()), this will be
+ detected and mbedtls_ssl_read() will return
+ MBEDTLS_ERR_SSL_CLIENT_RECONNECT - it is then possible to start a new
+ handshake with the same context. (See RFC 6347 section 4.2.8.)
= mbed TLS 2.1.0 released 2015-09-04
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index ca7cd1d..076f24d 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -21,7 +21,7 @@
*/
/**
- * @mainpage mbed TLS v2.1.0 source code documentation
+ * @mainpage mbed TLS v2.1.1 source code documentation
*
* This documentation describes the internal structure of mbed TLS. It was
* automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index 6ca97c1..e5cd908 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@
# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
-PROJECT_NAME = "mbed TLS v2.1.0"
+PROJECT_NAME = "mbed TLS v2.1.1"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index cb707e9..8dadbe1 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -421,6 +421,11 @@
#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites"
#endif
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \
+ !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites"
+#endif
+
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites"
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 66657da..6e9d8f3 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1135,6 +1135,22 @@
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
/**
+ * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+ *
+ * Enable server-side support for clients that reconnect from the same port.
+ *
+ * Some clients unexpectedly close the connection and try to reconnect using the
+ * same source port. This needs special support from the server to handle the
+ * new connection securely, as described in section 4.2.8 of RFC 6347. This
+ * flag enables that support.
+ *
+ * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY
+ *
+ * Comment this to disable support for clients reusing the source port.
+ */
+#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+
+/**
* \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT
*
* Enable support for a limit of records with bad MAC.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 907bba1..2d7beb3 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -125,6 +125,7 @@
#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< Connection requires a read call. */
#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. */
/*
* Various constants
@@ -1169,6 +1170,11 @@
* the MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED that is expected
* on the first handshake attempt when this is enabled.
*
+ * \note This is also necessary to handle client reconnection from
+ * the same port as described in RFC 6347 section 4.2.8 (only
+ * the variant with cookies is supported currently). See
+ * comments on \c mbedtls_ssl_read() for details.
+ *
* \param conf SSL configuration
* \param f_cookie_write Cookie write callback
* \param f_cookie_check Cookie check callback
@@ -2089,29 +2095,35 @@
*
* \param ssl SSL context
*
- * \return 0 if successful, MBEDTLS_ERR_SSL_WANT_READ,
- * MBEDTLS_ERR_SSL_WANT_WRITE, or a specific SSL error code.
+ * \return 0 if successful, or
+ * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or
+ * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED (see below), or
+ * a specific SSL error code.
*
- * \note If this function returns non-zero, then the ssl context
+ * \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.
- * If DTLS is in use, then you may choose to handle
+ *
+ * \note If DTLS is in use, then you may choose to handle
* MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging
- * purposes, but you still need to reset/free the context.
+ * purposes, as it is an expected return value rather than an
+ * actual error, but you still need to reset/free the context.
*/
int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl );
/**
* \brief Perform a single step of the SSL handshake
*
- * Note: the state of the context (ssl->state) will be at
+ * \note The state of the context (ssl->state) will be at
* the following state after execution of this function.
* Do not call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER.
*
* \param ssl SSL context
*
- * \return 0 if successful, MBEDTLS_ERR_SSL_WANT_READ,
- * MBEDTLS_ERR_SSL_WANT_WRITE, or a specific SSL error code.
+ * \return 0 if successful, or
+ * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or
+ * a specific SSL error code.
*/
int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl );
@@ -2138,7 +2150,23 @@
*
* \return the number of bytes read, or
* 0 for EOF, or
- * a negative error code.
+ * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or
+ * MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or
+ * another negative error code.
+ *
+ * \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.
+ * You can either treat that as a connection close and wait
+ * for the client to resend a ClientHello, or directly
+ * continue with \c mbedtls_ssl_handshake() with the same
+ * context (as it has beeen reset internally). Either way, you
+ * should make sure this is seen by the application as a new
+ * connection: application state, if any, should be reset, and
+ * most importantly the identity of the client must be checked
+ * again. WARNING: not validating the identity of the client
+ * again, or not transmitting the new identity to the
+ * application layer, would allow authentication bypass!
*/
int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len );
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index da76e76..d097264 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -39,16 +39,16 @@
*/
#define MBEDTLS_VERSION_MAJOR 2
#define MBEDTLS_VERSION_MINOR 1
-#define MBEDTLS_VERSION_PATCH 0
+#define MBEDTLS_VERSION_PATCH 1
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x02010000
-#define MBEDTLS_VERSION_STRING "2.1.0"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.1.0"
+#define MBEDTLS_VERSION_NUMBER 0x02010100
+#define MBEDTLS_VERSION_STRING "2.1.1"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.1.1"
#if defined(MBEDTLS_VERSION_C)
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index c458117..ea43ccb 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -138,15 +138,15 @@
if(USE_SHARED_MBEDTLS_LIBRARY)
add_library(mbedcrypto SHARED ${src_crypto})
- set_target_properties(mbedcrypto PROPERTIES VERSION 2.1.0 SOVERSION 0)
+ set_target_properties(mbedcrypto PROPERTIES VERSION 2.1.1 SOVERSION 0)
target_link_libraries(mbedcrypto ${libs})
add_library(mbedx509 SHARED ${src_x509})
- set_target_properties(mbedx509 PROPERTIES VERSION 2.1.0 SOVERSION 0)
+ set_target_properties(mbedx509 PROPERTIES VERSION 2.1.1 SOVERSION 0)
target_link_libraries(mbedx509 ${libs} mbedcrypto)
add_library(mbedtls SHARED ${src_tls})
- set_target_properties(mbedtls PROPERTIES VERSION 2.1.0 SOVERSION 10)
+ set_target_properties(mbedtls PROPERTIES VERSION 2.1.1 SOVERSION 10)
target_link_libraries(mbedtls ${libs} mbedx509)
install(TARGETS mbedtls mbedx509 mbedcrypto
diff --git a/library/error.c b/library/error.c
index a7de110..a1cf83a 100644
--- a/library/error.c
+++ b/library/error.c
@@ -428,6 +428,8 @@
mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" );
if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) )
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" );
#endif /* MBEDTLS_SSL_TLS_C */
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
diff --git a/library/rsa.c b/library/rsa.c
index f4ab6b2a..3883d09 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -51,6 +51,8 @@
#else
#include <stdio.h>
#define mbedtls_printf printf
+#define mbedtls_calloc calloc
+#define mbedtls_free free
#endif
/*
@@ -1005,6 +1007,11 @@
size_t nb_pad, olen, oid_size = 0;
unsigned char *p = sig;
const char *oid = NULL;
+ unsigned char *sig_try = NULL, *verif = NULL;
+ size_t i;
+ unsigned char diff;
+ volatile unsigned char diff_no_optimize;
+ int ret;
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
@@ -1067,9 +1074,39 @@
memcpy( p, hash, hashlen );
}
- return( ( mode == MBEDTLS_RSA_PUBLIC )
- ? mbedtls_rsa_public( ctx, sig, sig )
- : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
+ if( mode == MBEDTLS_RSA_PUBLIC )
+ return( mbedtls_rsa_public( ctx, sig, sig ) );
+
+ /*
+ * In order to prevent Lenstra's attack, make the signature in a
+ * temporary buffer and check it before returning it.
+ */
+ sig_try = mbedtls_calloc( 1, ctx->len );
+ verif = mbedtls_calloc( 1, ctx->len );
+ if( sig_try == NULL || verif == NULL )
+ return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+ MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) );
+ MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) );
+
+ /* Compare in constant time just in case */
+ for( diff = 0, i = 0; i < ctx->len; i++ )
+ diff |= verif[i] ^ sig[i];
+ diff_no_optimize = diff;
+
+ if( diff_no_optimize != 0 )
+ {
+ ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
+ goto cleanup;
+ }
+
+ memcpy( sig, sig_try, ctx->len );
+
+cleanup:
+ mbedtls_free( sig_try );
+ mbedtls_free( verif );
+
+ return( ret );
}
#endif /* MBEDTLS_PKCS1_V15 */
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 5a9c432..c82e2e7 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1771,6 +1771,12 @@
ssl->handshake->pmslen = 48;
+ if( ssl->session_negotiate->peer_cert == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+ }
+
/*
* Now write it out, encrypted
*/
@@ -1873,6 +1879,12 @@
int ret;
const mbedtls_ecp_keypair *peer_key;
+ if( ssl->session_negotiate->peer_cert == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+ }
+
if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
MBEDTLS_PK_ECKEY ) )
{
@@ -2182,6 +2194,12 @@
MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen :
(unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) );
+ if( ssl->session_negotiate->peer_cert == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+ }
+
/*
* Verify signature
*/
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index ca1e7b8..b48a609 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -299,7 +299,7 @@
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
}
- p = buf + 2;
+ p = buf + 1;
while( list_size > 0 )
{
if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED ||
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index f1d2dd2..d9b05fd 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -3250,6 +3250,196 @@
}
#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
+/* Forward declaration */
+static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial );
+
+/*
+ * Without any SSL context, check if a datagram looks like a ClientHello with
+ * a valid cookie, and if it doesn't, generate a HelloVerifyRequest message.
+ * Both input and output include full DTLS headers.
+ *
+ * - if cookie is valid, return 0
+ * - if ClientHello looks superficially valid but cookie is not,
+ * fill obuf and set olen, then
+ * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED
+ * - otherwise return a specific error code
+ */
+static int ssl_check_dtls_clihlo_cookie(
+ mbedtls_ssl_cookie_write_t *f_cookie_write,
+ mbedtls_ssl_cookie_check_t *f_cookie_check,
+ void *p_cookie,
+ const unsigned char *cli_id, size_t cli_id_len,
+ const unsigned char *in, size_t in_len,
+ unsigned char *obuf, size_t buf_len, size_t *olen )
+{
+ size_t sid_len, cookie_len;
+ unsigned char *p;
+
+ if( f_cookie_write == NULL || f_cookie_check == NULL )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ /*
+ * Structure of ClientHello with record and handshake headers,
+ * and expected values. We don't need to check a lot, more checks will be
+ * done when actually parsing the ClientHello - skipping those checks
+ * avoids code duplication and does not make cookie forging any easier.
+ *
+ * 0-0 ContentType type; copied, must be handshake
+ * 1-2 ProtocolVersion version; copied
+ * 3-4 uint16 epoch; copied, must be 0
+ * 5-10 uint48 sequence_number; copied
+ * 11-12 uint16 length; (ignored)
+ *
+ * 13-13 HandshakeType msg_type; (ignored)
+ * 14-16 uint24 length; (ignored)
+ * 17-18 uint16 message_seq; copied
+ * 19-21 uint24 fragment_offset; copied, must be 0
+ * 22-24 uint24 fragment_length; (ignored)
+ *
+ * 25-26 ProtocolVersion client_version; (ignored)
+ * 27-58 Random random; (ignored)
+ * 59-xx SessionID session_id; 1 byte len + sid_len content
+ * 60+ opaque cookie<0..2^8-1>; 1 byte len + content
+ * ...
+ *
+ * Minimum length is 61 bytes.
+ */
+ if( in_len < 61 ||
+ in[0] != MBEDTLS_SSL_MSG_HANDSHAKE ||
+ in[3] != 0 || in[4] != 0 ||
+ in[19] != 0 || in[20] != 0 || in[21] != 0 )
+ {
+ return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ sid_len = in[59];
+ if( sid_len > in_len - 61 )
+ return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+
+ cookie_len = in[60 + sid_len];
+ if( cookie_len > in_len - 60 )
+ return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+
+ if( f_cookie_check( p_cookie, in + sid_len + 61, cookie_len,
+ cli_id, cli_id_len ) == 0 )
+ {
+ /* Valid cookie */
+ return( 0 );
+ }
+
+ /*
+ * If we get here, we've got an invalid cookie, let's prepare HVR.
+ *
+ * 0-0 ContentType type; copied
+ * 1-2 ProtocolVersion version; copied
+ * 3-4 uint16 epoch; copied
+ * 5-10 uint48 sequence_number; copied
+ * 11-12 uint16 length; olen - 13
+ *
+ * 13-13 HandshakeType msg_type; hello_verify_request
+ * 14-16 uint24 length; olen - 25
+ * 17-18 uint16 message_seq; copied
+ * 19-21 uint24 fragment_offset; copied
+ * 22-24 uint24 fragment_length; olen - 25
+ *
+ * 25-26 ProtocolVersion server_version; 0xfe 0xff
+ * 27-27 opaque cookie<0..2^8-1>; cookie_len = olen - 27, cookie
+ *
+ * Minimum length is 28.
+ */
+ if( buf_len < 28 )
+ return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+ /* Copy most fields and adapt others */
+ memcpy( obuf, in, 25 );
+ obuf[13] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST;
+ obuf[25] = 0xfe;
+ obuf[26] = 0xff;
+
+ /* Generate and write actual cookie */
+ p = obuf + 28;
+ if( f_cookie_write( p_cookie,
+ &p, obuf + buf_len, cli_id, cli_id_len ) != 0 )
+ {
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ *olen = p - obuf;
+
+ /* Go back and fill length fields */
+ obuf[27] = (unsigned char)( *olen - 28 );
+
+ obuf[14] = obuf[22] = (unsigned char)( ( *olen - 25 ) >> 16 );
+ obuf[15] = obuf[23] = (unsigned char)( ( *olen - 25 ) >> 8 );
+ obuf[16] = obuf[24] = (unsigned char)( ( *olen - 25 ) );
+
+ obuf[11] = (unsigned char)( ( *olen - 13 ) >> 8 );
+ obuf[12] = (unsigned char)( ( *olen - 13 ) );
+
+ return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED );
+}
+
+/*
+ * Handle possible client reconnect with the same UDP quadruplet
+ * (RFC 6347 Section 4.2.8).
+ *
+ * Called by ssl_parse_record_header() in case we receive an epoch 0 record
+ * that looks like a ClientHello.
+ *
+ * - if the input looks like a ClientHello without cookies,
+ * send back HelloVerifyRequest, then
+ * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED
+ * - if the input looks like a ClientHello with a valid cookie,
+ * reset the session of the current context, and
+ * return MBEDTLS_ERR_SSL_CLIENT_RECONNECT
+ * - if anything goes wrong, return a specific error code
+ *
+ * mbedtls_ssl_read_record() will ignore the record if anything else than
+ * MBEDTLS_ERR_SSL_CLIENT_RECONNECT or 0 is returned, although this function
+ * cannot not return 0.
+ */
+static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl )
+{
+ int ret;
+ size_t len;
+
+ ret = ssl_check_dtls_clihlo_cookie(
+ ssl->conf->f_cookie_write,
+ ssl->conf->f_cookie_check,
+ ssl->conf->p_cookie,
+ ssl->cli_id, ssl->cli_id_len,
+ ssl->in_buf, ssl->in_left,
+ ssl->out_buf, MBEDTLS_SSL_MAX_CONTENT_LEN, &len );
+
+ MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret );
+
+ if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
+ {
+ /* Dont check write errors as we can't do anything here.
+ * If the error is permanent we'll catch it later,
+ * if it's not, then hopefully it'll work next time. */
+ (void) ssl->f_send( ssl->p_bio, ssl->out_buf, len );
+
+ return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED );
+ }
+
+ if( ret == 0 )
+ {
+ /* Got a valid cookie, partially reset context */
+ if( ( ret = ssl_session_reset_int( ssl, 1 ) ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "reset", ret );
+ return( ret );
+ }
+
+ return( MBEDTLS_ERR_SSL_CLIENT_RECONNECT );
+ }
+
+ return( ret );
+}
+#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
+
/*
* ContentType type;
* ProtocolVersion version;
@@ -3341,13 +3531,36 @@
if( rec_epoch != ssl->in_epoch )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: "
- "expected %d, received %d",
- ssl->in_epoch, rec_epoch ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
+ "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)
- if( mbedtls_ssl_dtls_replay_check( ssl ) != 0 )
+ /* 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 );
@@ -3528,7 +3741,8 @@
if( ( ret = ssl_parse_record_header( ssl ) ) != 0 )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
- if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ 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
@@ -5123,8 +5337,11 @@
/*
* Reset an initialized and used SSL context for re-use while retaining
* all application-set variables, function pointers and data.
+ *
+ * If partial is non-zero, keep data in the input buffer and client ID.
+ * (Use when a DTLS client reconnects from the same port.)
*/
-int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl )
+static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
{
int ret;
@@ -5148,7 +5365,8 @@
ssl->in_msg = ssl->in_buf + 13;
ssl->in_msgtype = 0;
ssl->in_msglen = 0;
- ssl->in_left = 0;
+ if( partial == 0 )
+ ssl->in_left = 0;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
ssl->next_record_offset = 0;
ssl->in_epoch = 0;
@@ -5174,7 +5392,8 @@
ssl->transform_out = NULL;
memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN );
- memset( ssl->in_buf, 0, MBEDTLS_SSL_BUFFER_LEN );
+ if( partial == 0 )
+ memset( ssl->in_buf, 0, MBEDTLS_SSL_BUFFER_LEN );
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_reset != NULL )
@@ -5207,9 +5426,12 @@
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
- mbedtls_free( ssl->cli_id );
- ssl->cli_id = NULL;
- ssl->cli_id_len = 0;
+ if( partial == 0 )
+ {
+ mbedtls_free( ssl->cli_id );
+ ssl->cli_id = NULL;
+ ssl->cli_id_len = 0;
+ }
#endif
if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
@@ -5219,6 +5441,15 @@
}
/*
+ * Reset an initialized and used SSL context for re-use while retaining
+ * all application-set variables, function pointers and data.
+ */
+int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl )
+{
+ return( ssl_session_reset_int( ssl, 0 ) );
+}
+
+/*
* SSL set accessors
*/
void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint )
diff --git a/library/version_features.c b/library/version_features.c
index c2f30f2..196b93c 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -369,6 +369,9 @@
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
"MBEDTLS_SSL_DTLS_HELLO_VERIFY",
#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE)
+ "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE",
+#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE */
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
"MBEDTLS_SSL_DTLS_BADMAC_LIMIT",
#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
diff --git a/programs/pkey/pk_sign.c b/programs/pkey/pk_sign.c
index 606fc93..322e8af 100644
--- a/programs/pkey/pk_sign.c
+++ b/programs/pkey/pk_sign.c
@@ -40,7 +40,7 @@
int main( void )
{
mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
- "MBEDTLS_SHA256_C and/or MBEDLTS_MD_C and/or "
+ "MBEDTLS_SHA256_C and/or MBEDTLS_MD_C and/or "
"MBEDTLS_PK_PARSE_C and/or MBEDTLS_FS_IO and/or "
"MBEDTLS_CTR_DRBG_C not defined.\n");
return( 0 );
diff --git a/programs/pkey/rsa_sign.c b/programs/pkey/rsa_sign.c
index 469ad9f..e897c65 100644
--- a/programs/pkey/rsa_sign.c
+++ b/programs/pkey/rsa_sign.c
@@ -40,7 +40,7 @@
int main( void )
{
mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_RSA_C and/or "
- "MBEDLTS_MD_C and/or "
+ "MBEDTLS_MD_C and/or "
"MBEDTLS_SHA256_C and/or MBEDTLS_FS_IO not defined.\n");
return( 0 );
}
diff --git a/programs/pkey/rsa_verify.c b/programs/pkey/rsa_verify.c
index 9d48a18..ade36dc 100644
--- a/programs/pkey/rsa_verify.c
+++ b/programs/pkey/rsa_verify.c
@@ -39,7 +39,7 @@
int main( void )
{
mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_RSA_C and/or "
- "MBEDLTS_MD_C and/or "
+ "MBEDTLS_MD_C and/or "
"MBEDTLS_SHA256_C and/or MBEDTLS_FS_IO not defined.\n");
return( 0 );
}
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 99c2d2a..c090db9 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -90,6 +90,7 @@
#define DFL_DHMLEN -1
#define DFL_RECONNECT 0
#define DFL_RECO_DELAY 0
+#define DFL_RECONNECT_HARD 0
#define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED
#define DFL_ALPN_STRING NULL
#define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM
@@ -222,7 +223,7 @@
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
- " read_timeout=%%d default: 0 (no timeout)\n" \
+ " read_timeout=%%d default: 0 ms (no timeout)\n" \
" max_resend=%%d default: 0 (no resend on timeout)\n" \
"\n" \
USAGE_DTLS \
@@ -238,6 +239,7 @@
" exchanges=%%d default: 1\n" \
" reconnect=%%d default: 0 (disabled)\n" \
" reco_delay=%%d default: 0 seconds\n" \
+ " reconnect_hard=%%d default: 0 (disabled)\n" \
USAGE_TICKETS \
USAGE_MAX_FRAG_LEN \
USAGE_TRUNC_HMAC \
@@ -293,6 +295,7 @@
int dhmlen; /* minimum DHM params len in bits */
int reconnect; /* attempt to resume session */
int reco_delay; /* delay in seconds before resuming session */
+ int reconnect_hard; /* unexpectedly reconnect from the same port */
int tickets; /* enable / disable session tickets */
const char *alpn_string; /* ALPN supported protocols */
int transport; /* TLS or DTLS? */
@@ -481,6 +484,7 @@
opt.dhmlen = DFL_DHMLEN;
opt.reconnect = DFL_RECONNECT;
opt.reco_delay = DFL_RECO_DELAY;
+ opt.reconnect_hard = DFL_RECONNECT_HARD;
opt.tickets = DFL_TICKETS;
opt.alpn_string = DFL_ALPN_STRING;
opt.transport = DFL_TRANSPORT;
@@ -603,6 +607,12 @@
if( opt.reco_delay < 0 )
goto usage;
}
+ else if( strcmp( p, "reconnect_hard" ) == 0 )
+ {
+ opt.reconnect_hard = atoi( q );
+ if( opt.reconnect_hard < 0 || opt.reconnect_hard > 1 )
+ goto usage;
+ }
else if( strcmp( p, "tickets" ) == 0 )
{
opt.tickets = atoi( q );
@@ -1479,7 +1489,38 @@
}
/*
- * 7b. Continue doing data exchanges?
+ * 7b. Simulate hard reset and reconnect from same port?
+ */
+ if( opt.reconnect_hard != 0 )
+ {
+ opt.reconnect_hard = 0;
+
+ mbedtls_printf( " . Restarting connection from same port..." );
+ fflush( stdout );
+
+ if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n", -ret );
+ goto exit;
+ }
+
+ while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
+ {
+ if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret );
+ goto exit;
+ }
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ goto send_request;
+ }
+
+ /*
+ * 7c. Continue doing data exchanges?
*/
if( --opt.exchanges > 0 )
goto send_request;
@@ -1489,6 +1530,7 @@
*/
close_notify:
mbedtls_printf( " . Closing the connection..." );
+ fflush( stdout );
/* No error checking, the connection might be closed already */
do ret = mbedtls_ssl_close_notify( &ssl );
@@ -1513,7 +1555,6 @@
#endif
mbedtls_printf( " . Reconnecting with saved session..." );
- fflush( stdout );
if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
{
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index f169291..bd4d1d1 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -301,7 +301,7 @@
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
- " read_timeout=%%d default: 0 (no timeout)\n" \
+ " read_timeout=%%d default: 0 ms (no timeout)\n" \
"\n" \
USAGE_DTLS \
USAGE_COOKIES \
@@ -1838,6 +1838,12 @@
}
#endif
+ if( ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
+ {
+ mbedtls_printf( " ! Client initiated reconnection from same port\n" );
+ goto handshake;
+ }
+
#ifdef MBEDTLS_ERROR_C
if( ret != 0 )
{
@@ -1903,6 +1909,7 @@
/*
* 4. Handshake
*/
+handshake:
mbedtls_printf( " . Performing the SSL/TLS handshake..." );
fflush( stdout );
diff --git a/tests/scripts/yotta-build.sh b/tests/scripts/yotta-build.sh
index 59cedf4..2648d3e 100755
--- a/tests/scripts/yotta-build.sh
+++ b/tests/scripts/yotta-build.sh
@@ -6,7 +6,7 @@
yotta/create-module.sh
cd yotta/module
-# yt update # needs network
+yt update || true # needs network
yotta_build()
{
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 77db588..e494413 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -2867,6 +2867,40 @@
-s "hello verification requested" \
-S "SSL - The requested feature is not available"
+# Tests for client reconnecting from the same port with DTLS
+
+not_with_valgrind # spurious resend
+run_test "DTLS client reconnect from same port: reference" \
+ "$P_SRV dtls=1 exchanges=2 read_timeout=1000" \
+ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-1000" \
+ 0 \
+ -C "resend" \
+ -S "The operation timed out" \
+ -S "Client initiated reconnection from same port"
+
+not_with_valgrind # spurious resend
+run_test "DTLS client reconnect from same port: reconnect" \
+ "$P_SRV dtls=1 exchanges=2 read_timeout=1000" \
+ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-1000 reconnect_hard=1" \
+ 0 \
+ -C "resend" \
+ -S "The operation timed out" \
+ -s "Client initiated reconnection from same port"
+
+run_test "DTLS client reconnect from same port: reconnect, nbio" \
+ "$P_SRV dtls=1 exchanges=2 read_timeout=1000 nbio=2" \
+ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-1000 reconnect_hard=1" \
+ 0 \
+ -S "The operation timed out" \
+ -s "Client initiated reconnection from same port"
+
+run_test "DTLS client reconnect from same port: no cookies" \
+ "$P_SRV dtls=1 exchanges=2 read_timeout=1000 cookies=0" \
+ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-8000 reconnect_hard=1" \
+ 0 \
+ -s "The operation timed out" \
+ -S "Client initiated reconnection from same port"
+
# Tests for various cases of client authentication with DTLS
# (focused on handshake flows and message parsing)
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index 29ea2d2..ef8a579 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
Check compiletime library version
-check_compiletime_version:"2.1.0"
+check_compiletime_version:"2.1.1"
Check runtime library version
-check_runtime_version:"2.1.0"
+check_runtime_version:"2.1.1"
Check for MBEDTLS_VERSION_C
check_feature:"MBEDTLS_VERSION_C":0
diff --git a/yotta/data/example-authcrypt/main.cpp b/yotta/data/example-authcrypt/main.cpp
index 2f49aa9..257a1ad 100644
--- a/yotta/data/example-authcrypt/main.cpp
+++ b/yotta/data/example-authcrypt/main.cpp
@@ -187,7 +187,7 @@
}
void app_start(int, char*[]) {
- minar::Scheduler::postCallback(FunctionPointer0<void>(run).bind());
+ minar::Scheduler::postCallback(mbed::util::FunctionPointer0<void>(run).bind());
}
#else
diff --git a/yotta/data/example-benchmark/main.cpp b/yotta/data/example-benchmark/main.cpp
index 6ac2a29..1a6c7ae 100644
--- a/yotta/data/example-benchmark/main.cpp
+++ b/yotta/data/example-benchmark/main.cpp
@@ -947,7 +947,7 @@
}
void app_start(int, char*[]) {
- minar::Scheduler::postCallback(FunctionPointer0<void>(run).bind());
+ minar::Scheduler::postCallback(mbed::util::FunctionPointer0<void>(run).bind());
}
#endif /* TARGET_LIKE_MBED */
diff --git a/yotta/data/example-hashing/main.cpp b/yotta/data/example-hashing/main.cpp
index 4ef3665..7603cbe 100644
--- a/yotta/data/example-hashing/main.cpp
+++ b/yotta/data/example-hashing/main.cpp
@@ -167,7 +167,7 @@
}
void app_start(int, char*[]) {
- minar::Scheduler::postCallback(FunctionPointer0<void>(run).bind());
+ minar::Scheduler::postCallback(mbed::util::FunctionPointer0<void>(run).bind());
}
#else
diff --git a/yotta/data/example-selftest/main.cpp b/yotta/data/example-selftest/main.cpp
index 22fd466..046a548 100644
--- a/yotta/data/example-selftest/main.cpp
+++ b/yotta/data/example-selftest/main.cpp
@@ -258,7 +258,7 @@
}
void app_start(int, char*[]) {
- minar::Scheduler::postCallback(FunctionPointer0<void>(run).bind());
+ minar::Scheduler::postCallback(mbed::util::FunctionPointer0<void>(run).bind());
}
#else
diff --git a/yotta/data/example-tls-client/main.cpp b/yotta/data/example-tls-client/main.cpp
index 684f1c1..907cfb6 100644
--- a/yotta/data/example-tls-client/main.cpp
+++ b/yotta/data/example-tls-client/main.cpp
@@ -513,7 +513,7 @@
printf("Client IP Address is %s\r\n", eth.getIPAddress());
- mbed::FunctionPointer1<void, const char*> fp(hello, &HelloHTTPS::startTest);
+ mbed::util::FunctionPointer1<void, const char*> fp(hello, &HelloHTTPS::startTest);
minar::Scheduler::postCallback(fp.bind(HTTPS_PATH));
}
diff --git a/yotta/data/module.json b/yotta/data/module.json
index 5b57cc2..9a9e8a1 100644
--- a/yotta/data/module.json
+++ b/yotta/data/module.json
@@ -1,6 +1,6 @@
{
"name": "mbedtls",
- "version": "2.1.0",
+ "version": "2.1.2",
"description": "The mbed TLS crypto/SSL/TLS library",
"licenses": [
{
@@ -13,6 +13,6 @@
"mbed": { "cmsis-core": "~0.2.3" }
},
"testTargetDependencies": {
- "mbed": { "sockets": "~0.3.0" }
+ "mbed": { "sockets": "~0.4.0" }
}
}