diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index c5087348a2..ad77270c32 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -224,7 +224,7 @@ #define SSL_INITIAL_HANDSHAKE 0 #define SSL_RENEGOTIATION 1 /* In progress */ -#define SSL_RENEGOTIATION_DONE 2 /* Done */ +#define SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ #define SSL_RENEGOTIATION_PENDING 3 /* Requested (server only) */ #define SSL_LEGACY_RENEGOTIATION 0 @@ -760,7 +760,9 @@ struct _ssl_context int state; /*!< SSL handshake: current state */ int transport; /*!< Transport: stream or datagram */ int renegotiation; /*!< Initial or renegotiation */ - int renego_records_seen; /*!< Records since renego request */ + int renego_records_seen; /*!< Records since renego request, or with DTLS, + number of retransmissions of request if + renego_max_records is < 0 */ int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */ int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ @@ -1816,7 +1818,7 @@ void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ); void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ); /** - * \brief Enforce server-requested renegotiation. + * \brief Enforce renegotiation requests. * (Default: enforced, max_records = 16) * * When we request a renegotiation, the peer can comply or @@ -1832,6 +1834,15 @@ void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ); * The optimal value is highly dependent on the specific usage * scenario. * + * \note With DTLS and server-initiated renegotiation, the + * HelloRequest is retransmited every time ssl_read() times + * out or receives Application Data, until: + * - max_records records have beens seen, if it is >= 0, or + * - the number of retransmits that would happen during an + * actual handshake has been reached. + * Please remember the request might be lost a few times + * if you consider setting max_records to a really low value. + * * \warning On client, the grace period can only happen during * ssl_read(), as opposed to ssl_write() and ssl_renegotiate() * which always behave as if max_record was 0. The reason is, diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 7c34d0f26a..f42a560582 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1891,6 +1891,33 @@ static int ssl_decompress_buf( ssl_context *ssl ) #if defined(POLARSSL_SSL_SRV_C) static int ssl_write_hello_request( ssl_context *ssl ); + +#if defined(POLARSSL_SSL_PROTO_DTLS) +static int ssl_resend_hello_request( ssl_context *ssl ) +{ + /* If renegotiation is not enforced, retransmit until we would reach max + * timeout if we were using the usual handshake doubling scheme */ + if( ssl->renego_max_records < 0 ) + { + uint32_t ratio = ssl->hs_timeout_max / ssl->hs_timeout_min + 1; + unsigned char doublings = 1; + + while( ratio != 0 ) + { + ++doublings; + ratio >>= 1; + } + + if( ++ssl->renego_records_seen > doublings ) + { + SSL_DEBUG_MSG( 0, ( "no longer retransmitting hello request" ) ); + return( 0 ); + } + } + + return( ssl_write_hello_request( ssl ) ); +} +#endif #endif /* @@ -2045,9 +2072,9 @@ int ssl_fetch_input( ssl_context *ssl, size_t nb_want ) else if( ssl->endpoint == SSL_IS_SERVER && ssl->renegotiation == SSL_RENEGOTIATION_PENDING ) { - if( ( ret = ssl_write_hello_request( ssl ) ) != 0 ) + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) { - SSL_DEBUG_RET( 1, "ssl_write_hello_request", ret ); + SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); return( ret ); } @@ -5900,14 +5927,15 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) } else if( ssl->renegotiation == SSL_RENEGOTIATION_PENDING ) { - ssl->renego_records_seen++; - if( ssl->renego_max_records >= 0 && - ssl->renego_records_seen > ssl->renego_max_records ) + if( ssl->renego_max_records >= 0 ) { - SSL_DEBUG_MSG( 1, ( "renegotiation requested, " - "but not honored by client" ) ); - return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + if( ++ssl->renego_records_seen > ssl->renego_max_records ) + { + SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by client" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } } } @@ -5939,9 +5967,9 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) if( ssl->endpoint == SSL_IS_SERVER && ssl->renegotiation == SSL_RENEGOTIATION_PENDING ) { - if( ( ret = ssl_write_hello_request( ssl ) ) != 0 ) + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) { - SSL_DEBUG_RET( 1, "ssl_write_hello_request", ret ); + SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); return( ret ); } }