1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-08-01 10:06:53 +03:00

Send TLS alerts in many more cases

The TLS client and server code was usually closing the connection in
case of a fatal error without sending an alert. This commit adds
alerts in many cases.

Added one test case to detect that we send the alert, where a server
complains that the client's certificate is from an unknown CA (case
tracked internally as IOTSSL-1330).
This commit is contained in:
Gilles Peskine
2017-05-03 16:28:34 +02:00
parent 071db41627
commit 1cc8e3472a
4 changed files with 265 additions and 4 deletions

View File

@ -4030,6 +4030,7 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) );
MBEDTLS_SSL_DEBUG_MSG( 3, ( "send alert level=%u message=%u", level, message ));
ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT;
ssl->out_msglen = 2;
@ -4041,7 +4042,6 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) );
return( 0 );
@ -4262,6 +4262,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
{
/* mbedtls_ssl_read_record may have sent an alert already. We
let it decide whether to alert. */
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
}
@ -4283,6 +4285,9 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) );
/* The client was asked for a certificate but didn't send
one. The client should know what's going on, so we
don't send an alert. */
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
return( 0 );
@ -4304,6 +4309,9 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
/* The client was asked for a certificate but didn't send
one. The client should know what's going on, so we
don't send an alert. */
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
return( 0 );
@ -4318,6 +4326,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
@ -4325,6 +4335,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
@ -4339,6 +4351,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
@ -4354,6 +4368,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
{
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 );
}
@ -4366,6 +4382,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( ssl->in_msg[i] != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
@ -4376,13 +4394,35 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( n < 128 || i + n > ssl->in_hslen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert,
ssl->in_msg + i, n );
if( 0 != ret && ( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND ) != ret )
switch( ret )
{
uint8_t alert;
case 0: /*ok*/
case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND:
/* Ignore certificate with an unknown algorithm: maybe a
prior certificate was already trusted. */
break;
case MBEDTLS_ERR_X509_ALLOC_FAILED:
alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR;
goto crt_parse_der_failed;
case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
goto crt_parse_der_failed;
default:
alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
crt_parse_der_failed:
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
return( ret );
}
@ -4403,6 +4443,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
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 );
}
@ -4413,6 +4455,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
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 );
}
}
@ -4439,6 +4483,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( ca_chain == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_BAD_CERT );
return( MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED );
}
@ -4489,6 +4535,36 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
ret = 0;
if( ret != 0 )
{
/* The certificate may have been rejected for several reasons.
Pick one and send the corresponding alert. Which alert to send
may be a subject of debate in some cases. */
uint8_t alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER )
alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH )
alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED )
alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED )
alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED )
alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
alert );
}
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
@ -4541,12 +4617,16 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
if( ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC );
}
@ -4569,6 +4649,8 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
if( ++ssl->in_epoch == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) );
/* This is highly unlikely to happen for legitimate reasons, so
treat it as an attack and don't send an alert. */
return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
}
}
@ -4593,6 +4675,8 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_INBOUND ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
}
@ -5171,6 +5255,8 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl )
if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
@ -5186,6 +5272,8 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl )
ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + hash_len )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
}
@ -5193,6 +5281,8 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl )
buf, hash_len ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
}