Merge remote-tracking branch 'origin/development'

This commit is contained in:
Simon Butcher 2015-09-16 23:25:25 +01:00
commit ac58c53ab1
17 changed files with 420 additions and 35 deletions

View File

@ -1,6 +1,6 @@
mbed TLS ChangeLog (Sorted per branch, date) mbed TLS ChangeLog (Sorted per branch, date)
= mbed TLS 2.1.1 released 2015-09-?? = mbed TLS 2.1.1 released 2015-09-16
Security Security
* Add countermeasure against Lenstra's RSA-CRT attack for PKCS#1 v1.5 * Add countermeasure against Lenstra's RSA-CRT attack for PKCS#1 v1.5
@ -10,6 +10,22 @@ Security
tries to continue the handshake after it failed (a misuse of the API). tries to continue the handshake after it failed (a misuse of the API).
(Found by GDS Labs using afl-fuzz, patch provided by GDS Labs.) (Found by GDS Labs using afl-fuzz, patch provided by GDS Labs.)
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 = mbed TLS 2.1.0 released 2015-09-04
Features Features

View File

@ -29,7 +29,7 @@ The Make and CMake build systems create three libraries: libmbedcrypto, libmbedx
### Yotta ### Yotta
[yotta](http://yottabuild.org) is a package manager and build system developped by mbed; it is the build system of mbed OS. To install it on your platform, please follow the yotta [installation instructions](http://docs.yottabuild.org/#installing). [yotta](http://yottabuild.org) is a package manager and build system developed by mbed; it is the build system of mbed OS. To install it on your platform, please follow the yotta [installation instructions](http://docs.yottabuild.org/#installing).
Once yotta is installed, you can use it to download the latest version of mbed TLS form the yotta registry with: Once yotta is installed, you can use it to download the latest version of mbed TLS form the yotta registry with:
@ -64,7 +64,7 @@ In order to run the tests, enter:
make check make check
The tests need Perl to be built and run. If you don't have Perl installed, you can skip buiding the tests with: The tests need Perl to be built and run. If you don't have Perl installed, you can skip building the tests with:
make no_test make no_test
@ -122,7 +122,7 @@ To list other available CMake options, use:
cmake -LH cmake -LH
Note that, with CMake, if you want to change the compiler or its options after you already ran CMake, you need to clear its cache first, eg (using GNU find): Note that, with CMake, if you want to change the compiler or its options after you already ran CMake, you need to clear its cache first, e.g. (using GNU find):
find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} + find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} +
CC=gcc CFLAGS='-fstack-protector-strong -Wa,--noexecstack' cmake . CC=gcc CFLAGS='-fstack-protector-strong -Wa,--noexecstack' cmake .

View File

@ -421,6 +421,11 @@
#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" #error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites"
#endif #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) && \ #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites" #error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites"

View File

@ -1134,6 +1134,22 @@
*/ */
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY #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 * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT
* *

View File

@ -125,6 +125,7 @@
#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< Connection requires a read call. */ #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_WANT_WRITE -0x6880 /**< Connection requires a write call. */
#define MBEDTLS_ERR_SSL_TIMEOUT -0x6800 /**< The operation timed out. */ #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 * Various constants
@ -1169,6 +1170,11 @@ typedef int mbedtls_ssl_cookie_check_t( void *ctx,
* the MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED that is expected * the MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED that is expected
* on the first handshake attempt when this is enabled. * 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 conf SSL configuration
* \param f_cookie_write Cookie write callback * \param f_cookie_write Cookie write callback
* \param f_cookie_check Cookie check callback * \param f_cookie_check Cookie check callback
@ -1381,7 +1387,7 @@ void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf,
* \param profile Profile to use * \param profile Profile to use
*/ */
void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf,
mbedtls_x509_crt_profile *profile ); const mbedtls_x509_crt_profile *profile );
/** /**
* \brief Set the data required to verify peer certificate * \brief Set the data required to verify peer certificate
@ -2089,29 +2095,35 @@ int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session
* *
* \param ssl SSL context * \param ssl SSL context
* *
* \return 0 if successful, MBEDTLS_ERR_SSL_WANT_READ, * \return 0 if successful, or
* MBEDTLS_ERR_SSL_WANT_WRITE, or a specific SSL error code. * 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 * 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.
* 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 * 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 ); int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl );
/** /**
* \brief Perform a single step of the SSL handshake * \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. * the following state after execution of this function.
* Do not call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER. * Do not call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER.
* *
* \param ssl SSL context * \param ssl SSL context
* *
* \return 0 if successful, MBEDTLS_ERR_SSL_WANT_READ, * \return 0 if successful, or
* MBEDTLS_ERR_SSL_WANT_WRITE, or a specific SSL error code. * 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 ); int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl );
@ -2138,7 +2150,23 @@ int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl );
* *
* \return the number of bytes read, or * \return the number of bytes read, or
* 0 for EOF, 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 ); int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len );

View File

@ -428,6 +428,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" );
if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) )
mbedtls_snprintf( buf, buflen, "SSL - The operation timed out" ); 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 */ #endif /* MBEDTLS_SSL_TLS_C */
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)

View File

@ -319,7 +319,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
/* UDP: wait for a message, but keep it in the queue */ /* UDP: wait for a message, but keep it in the queue */
char buf[1] = { 0 }; char buf[1] = { 0 };
ret = recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK,
(struct sockaddr *) &client_addr, &n ); (struct sockaddr *) &client_addr, &n );
#if defined(_WIN32) #if defined(_WIN32)

View File

@ -299,7 +299,7 @@ static int ssl_parse_supported_point_formats( mbedtls_ssl_context *ssl,
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
} }
p = buf + 2; p = buf + 1;
while( list_size > 0 ) while( list_size > 0 )
{ {
if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED ||

View File

@ -3250,6 +3250,196 @@ void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl )
} }
#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ #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; * ContentType type;
* ProtocolVersion version; * ProtocolVersion version;
@ -3341,13 +3531,36 @@ static int ssl_parse_record_header( mbedtls_ssl_context *ssl )
if( rec_epoch != ssl->in_epoch ) if( rec_epoch != ssl->in_epoch )
{ {
MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: " MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: "
"expected %d, received %d", "expected %d, received %d",
ssl->in_epoch, rec_epoch ) ); ssl->in_epoch, rec_epoch ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
#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 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" ) ); MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record" ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD ); return( MBEDTLS_ERR_SSL_INVALID_RECORD );
@ -3528,7 +3741,8 @@ read_record_header:
if( ( ret = ssl_parse_record_header( ssl ) ) != 0 ) if( ( ret = ssl_parse_record_header( ssl ) ) != 0 )
{ {
#if defined(MBEDTLS_SSL_PROTO_DTLS) #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 /* Ignore bad record and get next one; drop the whole datagram
* since current header cannot be trusted to find the next record * since current header cannot be trusted to find the next record
@ -5123,8 +5337,11 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl,
/* /*
* Reset an initialized and used SSL context for re-use while retaining * Reset an initialized and used SSL context for re-use while retaining
* all application-set variables, function pointers and data. * 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; int ret;
@ -5148,7 +5365,8 @@ int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl )
ssl->in_msg = ssl->in_buf + 13; ssl->in_msg = ssl->in_buf + 13;
ssl->in_msgtype = 0; ssl->in_msgtype = 0;
ssl->in_msglen = 0; ssl->in_msglen = 0;
ssl->in_left = 0; if( partial == 0 )
ssl->in_left = 0;
#if defined(MBEDTLS_SSL_PROTO_DTLS) #if defined(MBEDTLS_SSL_PROTO_DTLS)
ssl->next_record_offset = 0; ssl->next_record_offset = 0;
ssl->in_epoch = 0; ssl->in_epoch = 0;
@ -5174,7 +5392,8 @@ int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl )
ssl->transform_out = NULL; ssl->transform_out = NULL;
memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); 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 defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_reset != NULL ) if( mbedtls_ssl_hw_record_reset != NULL )
@ -5207,9 +5426,12 @@ int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl )
#endif #endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
mbedtls_free( ssl->cli_id ); if( partial == 0 )
ssl->cli_id = NULL; {
ssl->cli_id_len = 0; mbedtls_free( ssl->cli_id );
ssl->cli_id = NULL;
ssl->cli_id_len = 0;
}
#endif #endif
if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
@ -5218,6 +5440,15 @@ int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl )
return( 0 ); return( 0 );
} }
/*
* 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 * SSL set accessors
*/ */
@ -5372,7 +5603,7 @@ void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf,
#if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_X509_CRT_PARSE_C)
void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf,
mbedtls_x509_crt_profile *profile ) const mbedtls_x509_crt_profile *profile )
{ {
conf->cert_profile = profile; conf->cert_profile = profile;
} }

View File

@ -369,6 +369,9 @@ static const char *features[] = {
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
"MBEDTLS_SSL_DTLS_HELLO_VERIFY", "MBEDTLS_SSL_DTLS_HELLO_VERIFY",
#endif /* 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) #if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
"MBEDTLS_SSL_DTLS_BADMAC_LIMIT", "MBEDTLS_SSL_DTLS_BADMAC_LIMIT",
#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ #endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */

View File

@ -40,7 +40,7 @@
int main( void ) int main( void )
{ {
mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or " 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_PK_PARSE_C and/or MBEDTLS_FS_IO and/or "
"MBEDTLS_CTR_DRBG_C not defined.\n"); "MBEDTLS_CTR_DRBG_C not defined.\n");
return( 0 ); return( 0 );

View File

@ -40,7 +40,7 @@
int main( void ) int main( void )
{ {
mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_RSA_C and/or " 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"); "MBEDTLS_SHA256_C and/or MBEDTLS_FS_IO not defined.\n");
return( 0 ); return( 0 );
} }

View File

@ -39,7 +39,7 @@
int main( void ) int main( void )
{ {
mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_RSA_C and/or " 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"); "MBEDTLS_SHA256_C and/or MBEDTLS_FS_IO not defined.\n");
return( 0 ); return( 0 );
} }

View File

@ -90,6 +90,7 @@ int main( void )
#define DFL_DHMLEN -1 #define DFL_DHMLEN -1
#define DFL_RECONNECT 0 #define DFL_RECONNECT 0
#define DFL_RECO_DELAY 0 #define DFL_RECO_DELAY 0
#define DFL_RECONNECT_HARD 0
#define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED #define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED
#define DFL_ALPN_STRING NULL #define DFL_ALPN_STRING NULL
#define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM #define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM
@ -222,7 +223,7 @@ int main( void )
" debug_level=%%d default: 0 (disabled)\n" \ " debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \ " nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\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" \ " max_resend=%%d default: 0 (no resend on timeout)\n" \
"\n" \ "\n" \
USAGE_DTLS \ USAGE_DTLS \
@ -238,6 +239,7 @@ int main( void )
" exchanges=%%d default: 1\n" \ " exchanges=%%d default: 1\n" \
" reconnect=%%d default: 0 (disabled)\n" \ " reconnect=%%d default: 0 (disabled)\n" \
" reco_delay=%%d default: 0 seconds\n" \ " reco_delay=%%d default: 0 seconds\n" \
" reconnect_hard=%%d default: 0 (disabled)\n" \
USAGE_TICKETS \ USAGE_TICKETS \
USAGE_MAX_FRAG_LEN \ USAGE_MAX_FRAG_LEN \
USAGE_TRUNC_HMAC \ USAGE_TRUNC_HMAC \
@ -293,6 +295,7 @@ struct options
int dhmlen; /* minimum DHM params len in bits */ int dhmlen; /* minimum DHM params len in bits */
int reconnect; /* attempt to resume session */ int reconnect; /* attempt to resume session */
int reco_delay; /* delay in seconds before resuming 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 */ int tickets; /* enable / disable session tickets */
const char *alpn_string; /* ALPN supported protocols */ const char *alpn_string; /* ALPN supported protocols */
int transport; /* TLS or DTLS? */ int transport; /* TLS or DTLS? */
@ -481,6 +484,7 @@ int main( int argc, char *argv[] )
opt.dhmlen = DFL_DHMLEN; opt.dhmlen = DFL_DHMLEN;
opt.reconnect = DFL_RECONNECT; opt.reconnect = DFL_RECONNECT;
opt.reco_delay = DFL_RECO_DELAY; opt.reco_delay = DFL_RECO_DELAY;
opt.reconnect_hard = DFL_RECONNECT_HARD;
opt.tickets = DFL_TICKETS; opt.tickets = DFL_TICKETS;
opt.alpn_string = DFL_ALPN_STRING; opt.alpn_string = DFL_ALPN_STRING;
opt.transport = DFL_TRANSPORT; opt.transport = DFL_TRANSPORT;
@ -603,6 +607,12 @@ int main( int argc, char *argv[] )
if( opt.reco_delay < 0 ) if( opt.reco_delay < 0 )
goto usage; 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 ) else if( strcmp( p, "tickets" ) == 0 )
{ {
opt.tickets = atoi( q ); opt.tickets = atoi( q );
@ -1479,7 +1489,38 @@ send_request:
} }
/* /*
* 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 ) if( --opt.exchanges > 0 )
goto send_request; goto send_request;
@ -1489,6 +1530,7 @@ send_request:
*/ */
close_notify: close_notify:
mbedtls_printf( " . Closing the connection..." ); mbedtls_printf( " . Closing the connection..." );
fflush( stdout );
/* No error checking, the connection might be closed already */ /* No error checking, the connection might be closed already */
do ret = mbedtls_ssl_close_notify( &ssl ); do ret = mbedtls_ssl_close_notify( &ssl );
@ -1513,7 +1555,6 @@ reconnect:
#endif #endif
mbedtls_printf( " . Reconnecting with saved session..." ); mbedtls_printf( " . Reconnecting with saved session..." );
fflush( stdout );
if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 ) if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
{ {

View File

@ -301,7 +301,7 @@ int main( void )
" debug_level=%%d default: 0 (disabled)\n" \ " debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \ " nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\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" \ "\n" \
USAGE_DTLS \ USAGE_DTLS \
USAGE_COOKIES \ USAGE_COOKIES \
@ -1838,6 +1838,12 @@ reset:
} }
#endif #endif
if( ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
{
mbedtls_printf( " ! Client initiated reconnection from same port\n" );
goto handshake;
}
#ifdef MBEDTLS_ERROR_C #ifdef MBEDTLS_ERROR_C
if( ret != 0 ) if( ret != 0 )
{ {
@ -1903,6 +1909,7 @@ reset:
/* /*
* 4. Handshake * 4. Handshake
*/ */
handshake:
mbedtls_printf( " . Performing the SSL/TLS handshake..." ); mbedtls_printf( " . Performing the SSL/TLS handshake..." );
fflush( stdout ); fflush( stdout );

View File

@ -52,6 +52,8 @@ do_config()
scripts/config.pl unset $FLAG scripts/config.pl unset $FLAG
done done
grep -F SSL_MAX_CONTENT_LEN $CONFIG_H || echo 'SSL_MAX_CONTENT_LEN=16384'
printf " Executable size... " printf " Executable size... "
make clean make clean

View File

@ -2867,6 +2867,40 @@ run_test "DTLS cookie: enabled, nbio" \
-s "hello verification requested" \ -s "hello verification requested" \
-S "SSL - The requested feature is not available" -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 # Tests for various cases of client authentication with DTLS
# (focused on handshake flows and message parsing) # (focused on handshake flows and message parsing)