Skip to content

Commit 4b841ab

Browse files
committed
mbedtls_ssl_get_alert(): getter for fatal alerts
Even though the TLS RFCs do not mandate libraries to expose *Error Alerts* (as defined in RFC8446 6.2 for TLS 1.3 and in RFC5246 7.2.2 for TLS 1.2) to the user, there are use cases when it is handy to get the actual last received fatal error instead of a generic one. For instance this enables the user to differ between received fatal errors in case `mbedtls_ssl_handshake()`, `mbedtls_ssl_handshake_step()` or `mbedtls_ssl_read()` returned `MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE`. This changesets stores the last incoming fatal alert in `mbedtls_ssl_context` and provides `mbedtls_ssl_get_alert()` as a getter for retrieving it. Another option would be to provide a callback mechanisms for all kinds of alerts (not only fatals) but for simplicity I discarded this option. Signed-off-by: Nico Geyso <[email protected]>
1 parent 3a0868b commit 4b841ab

File tree

6 files changed

+86
-0
lines changed

6 files changed

+86
-0
lines changed

ChangeLog.d/alert-getter.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Features
2+
* Add the function mbedtls_ssl_get_alert() which returns the
3+
last received fatal error alert type for a more generic
4+
MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE return value from
5+
mbedtls_ssl_handshake(), mbedtls_ssl_handshake_step() or
6+
mbedtls_ssl_read().

include/mbedtls/ssl.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,13 @@ struct mbedtls_ssl_context {
17221722
int MBEDTLS_PRIVATE(keep_current_message); /*!< drop or reuse current message
17231723
on next call to record layer? */
17241724

1725+
unsigned char MBEDTLS_PRIVATE(in_alert_recv); /*!< Determines if a fatal alert has
1726+
been received. Values:
1727+
- \c 0 , no fatal alert received.
1728+
- \c 1 , a fatal alert has been received */
1729+
unsigned char MBEDTLS_PRIVATE(in_alert_type); /*!< Type of fatal alert if in_alert_recv
1730+
!= 0 */
1731+
17251732
/* The following three variables indicate if and, if yes,
17261733
* what kind of alert is pending to be sent.
17271734
*/
@@ -4918,6 +4925,22 @@ int mbedtls_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t
49184925
int mbedtls_ssl_send_alert_message(mbedtls_ssl_context *ssl,
49194926
unsigned char level,
49204927
unsigned char message);
4928+
4929+
/**
4930+
* \brief Get the received fatal alert
4931+
*
4932+
* \param ssl SSL context
4933+
*
4934+
* \return The alert description type (MBEDTLS_SSL_ALERT_MSG_*) if a fatal
4935+
* alert has been received or MBEDTLS_ERR_SSL_BAD_INPUT_DATA
4936+
*
4937+
* \note This function can be used in case mbedtls_ssl_handshake(),
4938+
* mbedtls_ssl_handshake_step() or mbedtls_ssl_read() returned
4939+
* MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE to get the actual alert
4940+
* description type.
4941+
*/
4942+
int mbedtls_ssl_get_alert(mbedtls_ssl_context *ssl);
4943+
49214944
/**
49224945
* \brief Notify the peer that the connection is being closed
49234946
*

library/ssl_msg.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4932,6 +4932,8 @@ int mbedtls_ssl_handle_message_type(mbedtls_ssl_context *ssl)
49324932
if (ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_FATAL) {
49334933
MBEDTLS_SSL_DEBUG_MSG(1, ("is a fatal alert message (msg %d)",
49344934
ssl->in_msg[1]));
4935+
ssl->in_alert_recv = 1;
4936+
ssl->in_alert_type = ssl->in_msg[1];
49354937
return MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE;
49364938
}
49374939

@@ -5016,6 +5018,14 @@ int mbedtls_ssl_send_alert_message(mbedtls_ssl_context *ssl,
50165018
return 0;
50175019
}
50185020

5021+
int mbedtls_ssl_get_alert(mbedtls_ssl_context *ssl)
5022+
{
5023+
if (ssl == NULL || ssl->in_alert_recv != 1) {
5024+
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
5025+
}
5026+
return ssl->in_alert_type;
5027+
}
5028+
50195029
int mbedtls_ssl_write_change_cipher_spec(mbedtls_ssl_context *ssl)
50205030
{
50215031
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

library/ssl_tls.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,8 @@ void mbedtls_ssl_session_reset_msg_layer(mbedtls_ssl_context *ssl,
12971297
memset(ssl->in_buf, 0, in_buf_len);
12981298
}
12991299

1300+
ssl->in_alert_recv = 0;
1301+
13001302
ssl->send_alert = 0;
13011303

13021304
/* Reset outgoing message writing */

tests/suites/test_suite_ssl.data

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,3 +3364,6 @@ ssl_tls_exporter_rejects_bad_parameters:MBEDTLS_SSL_VERSION_TLS1_3:24:250:10
33643364
TLS 1.3 Keying Material Exporter: Handshake not done
33653365
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:MBEDTLS_X509_RSASSA_PSS_SUPPORT
33663366
ssl_tls_exporter_too_early:MBEDTLS_SSL_VERSION_TLS1_3:1:MBEDTLS_SSL_SERVER_CERTIFICATE
3367+
3368+
TLS fatal alert getter
3369+
ssl_get_alert_after_fatal

tests/suites/test_suite_ssl.function

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5936,3 +5936,45 @@ exit:
59365936
MD_OR_USE_PSA_DONE();
59375937
}
59385938
/* END_CASE */
5939+
5940+
/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
5941+
void ssl_get_alert_after_fatal(void)
5942+
{
5943+
mbedtls_ssl_context ssl;
5944+
mbedtls_ssl_config conf;
5945+
5946+
/* prepapre ssl context to test on*/
5947+
mbedtls_ssl_init(&ssl);
5948+
mbedtls_ssl_config_init(&conf);
5949+
TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
5950+
MBEDTLS_SSL_IS_CLIENT,
5951+
MBEDTLS_SSL_TRANSPORT_STREAM,
5952+
MBEDTLS_SSL_PRESET_DEFAULT), 0);
5953+
5954+
mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
5955+
MD_OR_USE_PSA_INIT();
5956+
TEST_ASSERT(mbedtls_ssl_setup(&ssl, &conf) == 0);
5957+
5958+
/* No alert has been received yet */
5959+
TEST_ASSERT(mbedtls_ssl_get_alert(&ssl) == MBEDTLS_ERR_SSL_BAD_INPUT_DATA);
5960+
5961+
// prepare input message buffer with fatal alert
5962+
ssl.in_msglen = 2;
5963+
ssl.in_msgtype = MBEDTLS_SSL_MSG_ALERT;
5964+
ssl.in_msg[0] = MBEDTLS_SSL_ALERT_LEVEL_FATAL;
5965+
ssl.in_msg[1] = MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE;
5966+
5967+
/* import prepared fatal alert and test getter */
5968+
TEST_ASSERT(mbedtls_ssl_handle_message_type(&ssl) == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE );
5969+
TEST_ASSERT(mbedtls_ssl_get_alert(&ssl) == MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
5970+
5971+
/* Reset the session and check that no alert is present*/
5972+
mbedtls_ssl_session_reset_msg_layer( &ssl, 0 );
5973+
TEST_ASSERT(mbedtls_ssl_get_alert(&ssl) == MBEDTLS_ERR_SSL_BAD_INPUT_DATA);
5974+
5975+
exit:
5976+
mbedtls_ssl_free(&ssl);
5977+
mbedtls_ssl_config_free(&conf);
5978+
USE_PSA_DONE();
5979+
}
5980+
/* END_CASE */

0 commit comments

Comments
 (0)