Merge pull request #3910 from hanno-arm/post_handshake_handling
Introduce helper for handling of post-handshake handshake messages in TLS <=1.2
This commit is contained in:
commit
5b416e95b2
@ -5112,6 +5112,120 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl )
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_RENEGOTIATION */
|
||||
|
||||
/* This function is called from mbedtls_ssl_read() when a handshake message is
|
||||
* received after the initial handshake. In this context, handshake messages
|
||||
* may only be sent for the purpose of initiating renegotiations.
|
||||
*
|
||||
* This function is introduced as a separate helper since the handling
|
||||
* of post-handshake handshake messages changes significantly in TLS 1.3,
|
||||
* and having a helper function allows to distinguish between TLS <= 1.2 and
|
||||
* TLS 1.3 in the future without bloating the logic of mbedtls_ssl_read().
|
||||
*/
|
||||
static int ssl_handle_hs_message_post_handshake( mbedtls_ssl_context *ssl )
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
|
||||
/*
|
||||
* - For client-side, expect SERVER_HELLO_REQUEST.
|
||||
* - For server-side, expect CLIENT_HELLO.
|
||||
* - Fail (TLS) or silently drop record (DTLS) in other cases.
|
||||
*/
|
||||
|
||||
#if defined(MBEDTLS_SSL_CLI_C)
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
|
||||
( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST ||
|
||||
ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) );
|
||||
|
||||
/* With DTLS, drop the packet (probably from last handshake) */
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
|
||||
{
|
||||
return( 0 );
|
||||
}
|
||||
#endif
|
||||
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_CLI_C */
|
||||
|
||||
#if defined(MBEDTLS_SSL_SRV_C)
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
|
||||
ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) );
|
||||
|
||||
/* With DTLS, drop the packet (probably from last handshake) */
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
|
||||
{
|
||||
return( 0 );
|
||||
}
|
||||
#endif
|
||||
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_SRV_C */
|
||||
|
||||
#if defined(MBEDTLS_SSL_RENEGOTIATION)
|
||||
/* Determine whether renegotiation attempt should be accepted */
|
||||
if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
|
||||
( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION &&
|
||||
ssl->conf->allow_legacy_renegotiation ==
|
||||
MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) )
|
||||
{
|
||||
/*
|
||||
* Accept renegotiation request
|
||||
*/
|
||||
|
||||
/* DTLS clients need to know renego is server-initiated */
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
|
||||
ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
|
||||
{
|
||||
ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING;
|
||||
}
|
||||
#endif
|
||||
ret = mbedtls_ssl_start_renegotiation( ssl );
|
||||
if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO &&
|
||||
ret != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_start_renegotiation",
|
||||
ret );
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_SSL_RENEGOTIATION */
|
||||
{
|
||||
/*
|
||||
* Refuse renegotiation
|
||||
*/
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
|
||||
defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
|
||||
{
|
||||
if( ( ret = mbedtls_ssl_send_alert_message( ssl,
|
||||
MBEDTLS_SSL_ALERT_LEVEL_WARNING,
|
||||
MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 ||
|
||||
MBEDTLS_SSL_PROTO_TLS1_2 */
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
|
||||
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive application data decrypted from the SSL layer
|
||||
*/
|
||||
@ -5210,108 +5324,17 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
|
||||
|
||||
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "received handshake message" ) );
|
||||
|
||||
/*
|
||||
* - For client-side, expect SERVER_HELLO_REQUEST.
|
||||
* - For server-side, expect CLIENT_HELLO.
|
||||
* - Fail (TLS) or silently drop record (DTLS) in other cases.
|
||||
*/
|
||||
|
||||
#if defined(MBEDTLS_SSL_CLI_C)
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
|
||||
( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST ||
|
||||
ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) )
|
||||
ret = ssl_handle_hs_message_post_handshake( ssl );
|
||||
if( ret != 0)
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) );
|
||||
|
||||
/* With DTLS, drop the packet (probably from last handshake) */
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_CLI_C */
|
||||
|
||||
#if defined(MBEDTLS_SSL_SRV_C)
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
|
||||
ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) );
|
||||
|
||||
/* With DTLS, drop the packet (probably from last handshake) */
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_SRV_C */
|
||||
|
||||
#if defined(MBEDTLS_SSL_RENEGOTIATION)
|
||||
/* Determine whether renegotiation attempt should be accepted */
|
||||
if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
|
||||
( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION &&
|
||||
ssl->conf->allow_legacy_renegotiation ==
|
||||
MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) )
|
||||
{
|
||||
/*
|
||||
* Accept renegotiation request
|
||||
*/
|
||||
|
||||
/* DTLS clients need to know renego is server-initiated */
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
|
||||
ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
|
||||
{
|
||||
ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING;
|
||||
}
|
||||
#endif
|
||||
ret = mbedtls_ssl_start_renegotiation( ssl );
|
||||
if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO &&
|
||||
ret != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_start_renegotiation",
|
||||
ret );
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_SSL_RENEGOTIATION */
|
||||
{
|
||||
/*
|
||||
* Refuse renegotiation
|
||||
*/
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
|
||||
defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
|
||||
{
|
||||
if( ( ret = mbedtls_ssl_send_alert_message( ssl,
|
||||
MBEDTLS_SSL_ALERT_LEVEL_WARNING,
|
||||
MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 ||
|
||||
MBEDTLS_SSL_PROTO_TLS1_2 */
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
|
||||
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
|
||||
}
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_handle_hs_message_post_handshake",
|
||||
ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/* At this point, we don't know whether the renegotiation has been
|
||||
* completed or not. The cases to consider are the following:
|
||||
/* At this point, we don't know whether the renegotiation triggered
|
||||
* by the post-handshake message has been completed or not. The cases
|
||||
* to consider are the following:
|
||||
* 1) The renegotiation is complete. In this case, no new record
|
||||
* has been read yet.
|
||||
* 2) The renegotiation is incomplete because the client received
|
||||
@ -5319,7 +5342,8 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
|
||||
* 3) The renegotiation is incomplete because the client received
|
||||
* a non-handshake, non-application data message while awaiting
|
||||
* the ServerHello.
|
||||
* In each of these case, looping will be the proper action:
|
||||
*
|
||||
* In each of these cases, looping will be the proper action:
|
||||
* - For 1), the next iteration will read a new record and check
|
||||
* if it's application data.
|
||||
* - For 2), the loop condition isn't satisfied as application data
|
||||
@ -5328,6 +5352,7 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
|
||||
* will re-deliver the message that was held back by the client
|
||||
* when expecting the ServerHello.
|
||||
*/
|
||||
|
||||
continue;
|
||||
}
|
||||
#if defined(MBEDTLS_SSL_RENEGOTIATION)
|
||||
|
Loading…
Reference in New Issue
Block a user