Merge remote-tracking branch 'origin/pr/2391' into development

This commit is contained in:
Jaeden Amero 2019-02-21 12:04:13 +00:00
commit 9f47f82218
3 changed files with 123 additions and 69 deletions

View file

@ -33,6 +33,8 @@ Bugfix
(e.g. config.h.bak). Fixed by Peter Kolbus (Garmin) #2407. (e.g. config.h.bak). Fixed by Peter Kolbus (Garmin) #2407.
Changes Changes
* Reduce RAM consumption during session renegotiation by not storing
the peer CRT chain and session ticket twice.
* Include configuration file in all header files that use configuration, * Include configuration file in all header files that use configuration,
instead of relying on other header files that they include. instead of relying on other header files that they include.
Inserted as an enhancement for #1371 Inserted as an enhancement for #1371

View file

@ -3541,6 +3541,15 @@ static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl )
if( ticket_len == 0 ) if( ticket_len == 0 )
return( 0 ); return( 0 );
if( ssl->session != NULL && ssl->session->ticket != NULL )
{
mbedtls_platform_zeroize( ssl->session->ticket,
ssl->session->ticket_len );
mbedtls_free( ssl->session->ticket );
ssl->session->ticket = NULL;
ssl->session->ticket_len = 0;
}
mbedtls_platform_zeroize( ssl->session_negotiate->ticket, mbedtls_platform_zeroize( ssl->session_negotiate->ticket,
ssl->session_negotiate->ticket_len ); ssl->session_negotiate->ticket_len );
mbedtls_free( ssl->session_negotiate->ticket ); mbedtls_free( ssl->session_negotiate->ticket );

View file

@ -5724,6 +5724,23 @@ write_msg:
return( ret ); return( ret );
} }
#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
unsigned char *crt_buf,
size_t crt_buf_len )
{
mbedtls_x509_crt const * const peer_crt = ssl->session->peer_cert;
if( peer_crt == NULL )
return( -1 );
if( peer_crt->raw.len != crt_buf_len )
return( -1 );
return( memcmp( peer_crt->raw.p, crt_buf, crt_buf_len ) );
}
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
/* /*
* Once the certificate message is read, parse it into a cert chain and * Once the certificate message is read, parse it into a cert chain and
* perform basic checks, but leave actual verification to the caller * perform basic checks, but leave actual verification to the caller
@ -5814,43 +5831,40 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
} }
/* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */
i += 3;
/* In case we tried to reuse a session but it failed */ /* In case we tried to reuse a session but it failed */
if( ssl->session_negotiate->peer_cert != NULL ) if( ssl->session_negotiate->peer_cert != NULL )
{ {
mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert );
mbedtls_free( ssl->session_negotiate->peer_cert ); mbedtls_free( ssl->session_negotiate->peer_cert );
ssl->session_negotiate->peer_cert = NULL;
} }
if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, /* Iterate through and parse the CRTs in the provided chain. */
sizeof( mbedtls_x509_crt ) ) ) == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
sizeof( mbedtls_x509_crt ) ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}
mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert );
i += 3;
while( i < ssl->in_hslen ) while( i < ssl->in_hslen )
{ {
/* Check that there's room for the next CRT's length fields. */
if ( i + 3 > ssl->in_hslen ) { if ( i + 3 > ssl->in_hslen ) {
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
} }
/* In theory, the CRT can be up to 2**24 Bytes, but we don't support
* anything beyond 2**16 ~ 64K. */
if( ssl->in_msg[i] != 0 ) if( ssl->in_msg[i] != 0 )
{ {
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
} }
/* Read length of the next CRT in the chain. */
n = ( (unsigned int) ssl->in_msg[i + 1] << 8 ) n = ( (unsigned int) ssl->in_msg[i + 1] << 8 )
| (unsigned int) ssl->in_msg[i + 2]; | (unsigned int) ssl->in_msg[i + 2];
i += 3; i += 3;
@ -5858,11 +5872,71 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
if( n < 128 || i + n > ssl->in_hslen ) if( n < 128 || i + n > ssl->in_hslen )
{ {
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
} }
/* Check if we're handling the first CRT in the chain. */
if( ssl->session_negotiate->peer_cert == NULL )
{
/* During client-side renegotiation, check that the server's
* end-CRTs hasn't changed compared to the initial handshake,
* mitigating the triple handshake attack. On success, reuse
* the original end-CRT instead of parsing it again. */
#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) );
if( ssl_check_peer_crt_unchanged( ssl,
&ssl->in_msg[i],
n ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
/* Move CRT chain structure to new session instance. */
ssl->session_negotiate->peer_cert = ssl->session->peer_cert;
ssl->session->peer_cert = NULL;
/* Delete all remaining CRTs from the original CRT chain. */
mbedtls_x509_crt_free(
ssl->session_negotiate->peer_cert->next );
mbedtls_free( ssl->session_negotiate->peer_cert->next );
ssl->session_negotiate->peer_cert->next = NULL;
i += n;
continue;
}
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
/* Outside of client-side renegotiation, create a fresh X.509 CRT
* instance to parse the end-CRT into. */
ssl->session_negotiate->peer_cert =
mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
if( ssl->session_negotiate->peer_cert == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
sizeof( mbedtls_x509_crt ) ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}
mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert );
/* Intentional fall through */
}
/* Parse the next certificate in the chain. */
ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert,
ssl->in_msg + i, n ); ssl->in_msg + i, n );
switch( ret ) switch( ret )
@ -5893,37 +5967,6 @@ static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
} }
MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert );
/*
* On client, make sure the server cert doesn't change during renego to
* avoid "triple handshake" attack: https://secure-resumption.com/
*/
#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
{
if( ssl->session->peer_cert == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
if( ssl->session->peer_cert->raw.len !=
ssl->session_negotiate->peer_cert->raw.len ||
memcmp( ssl->session->peer_cert->raw.p,
ssl->session_negotiate->peer_cert->raw.p,
ssl->session->peer_cert->raw.len ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "server cert changed during renegotiation" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
}
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
return( 0 ); return( 0 );
} }