diff --git a/ChangeLog.d/workaround_gnutls_anti_replay_fail.txt b/ChangeLog.d/workaround_gnutls_anti_replay_fail.txt new file mode 100644 index 000000000..cebc2b7ef --- /dev/null +++ b/ChangeLog.d/workaround_gnutls_anti_replay_fail.txt @@ -0,0 +1,7 @@ +Bugfix + * In TLS 1.3, when using a ticket for session resumption, tweak its age + calculation on the client side. It prevents a server with more accurate + ticket timestamps (typically timestamps in milliseconds) compared to the + Mbed TLS ticket timestamps (in seconds) to compute a ticket age smaller + than the age computed and transmitted by the client and thus potentially + reject the ticket. Fix #6623. diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index f07c8b698..025183d44 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -946,6 +946,21 @@ int mbedtls_ssl_tls13_write_identities_of_pre_shared_key_ext( uint32_t obfuscated_ticket_age = (uint32_t)( now - session->ticket_received ); + /* + * The ticket timestamp is in seconds but the ticket age is in + * milliseconds. If the ticket was received at the end of a second and + * re-used here just at the beginning of the next second, the computed + * age `now - session->ticket_received` is equal to 1s thus 1000 ms + * while the actual age could be just a few milliseconds or tens of + * milliseconds. If the server has more accurate ticket timestamps + * (typically timestamps in milliseconds), as part of the processing of + * the ClientHello, it may compute a ticket lifetime smaller than the + * one computed here and potentially reject the ticket. To avoid that, + * remove one second to the ticket age if possible. + */ + if( obfuscated_ticket_age > 0 ) + obfuscated_ticket_age -= 1; + obfuscated_ticket_age *= 1000; obfuscated_ticket_age += session->ticket_age_add; diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 02ee7cf69..304d10c0c 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -424,7 +424,7 @@ int main( void ) " reconnect=%%d number of reconnections using session resumption\n" \ " default: 0 (disabled)\n" \ " reco_server_name=%%s default: NULL\n" \ - " reco_delay=%%d default: 0 seconds\n" \ + " reco_delay=%%d default: 0 millionseconds\n" \ " reco_mode=%%d 0: copy session, 1: serialize session\n" \ " default: 1\n" \ " reconnect_hard=%%d default: 0 (disabled)\n" \ @@ -3184,7 +3184,7 @@ reconnect: #if defined(MBEDTLS_TIMING_C) if( opt.reco_delay > 0 ) - mbedtls_net_usleep( 1000000 * opt.reco_delay ); + mbedtls_net_usleep( 1000 * opt.reco_delay ); #endif mbedtls_printf( " . Reconnecting with saved session..." ); diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh index 710fb3433..3aaf3f330 100755 --- a/tests/opt-testcases/tls13-misc.sh +++ b/tests/opt-testcases/tls13-misc.sh @@ -264,9 +264,6 @@ run_test "TLS 1.3: G->m: PSK: configured ephemeral only, good." \ 0 \ -s "key exchange mode: ephemeral$" -# skip the basic check now cause it will randomly trigger the anti-replay protection in gnutls_server -# Add it back once we fix the issue -skip_next_test requires_gnutls_tls1_3 requires_config_enabled MBEDTLS_DEBUG_C requires_config_enabled MBEDTLS_SSL_CLI_C @@ -277,7 +274,7 @@ requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED run_test "TLS 1.3 m->G: EarlyData: basic check, good" \ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --earlydata --disable-client-cert" \ - "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=2" \ + "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=900" \ 1 \ -c "Reconnecting with saved session" \ -c "NewSessionTicket: early_data(42) extension received." \ @@ -298,7 +295,7 @@ requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED run_test "TLS 1.3 m->G: EarlyData: no early_data in NewSessionTicket, good" \ "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --disable-client-cert" \ - "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=2" \ + "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1" \ 0 \ -c "Reconnecting with saved session" \ -C "NewSessionTicket: early_data(42) extension received." \ diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index fdd366201..c206283a2 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -3643,7 +3643,7 @@ run_test "Session resume using tickets: cache disabled" \ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 run_test "Session resume using tickets: timeout" \ "$P_SRV debug_level=3 tickets=1 cache_max=0 ticket_timeout=1" \ - "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_delay=2" \ + "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_delay=2000" \ 0 \ -c "client hello, adding session ticket extension" \ -s "found session ticket extension" \ @@ -3953,7 +3953,7 @@ run_test "Session resume using tickets, DTLS: cache disabled" \ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 run_test "Session resume using tickets, DTLS: timeout" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0 ticket_timeout=1" \ - "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1 reco_delay=2" \ + "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1 reco_delay=2000" \ 0 \ -c "client hello, adding session ticket extension" \ -s "found session ticket extension" \ @@ -4077,7 +4077,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_SSL_CACHE_C run_test "Session resume using cache: timeout < delay" \ "$P_SRV debug_level=3 tickets=0 cache_timeout=1" \ - "$P_CLI debug_level=3 tickets=0 reconnect=1 reco_delay=2" \ + "$P_CLI debug_level=3 tickets=0 reconnect=1 reco_delay=2000" \ 0 \ -S "session successfully restored from cache" \ -S "session successfully restored from ticket" \ @@ -4088,7 +4088,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_SSL_CACHE_C run_test "Session resume using cache: no timeout" \ "$P_SRV debug_level=3 tickets=0 cache_timeout=0" \ - "$P_CLI debug_level=3 tickets=0 reconnect=1 reco_delay=2" \ + "$P_CLI debug_level=3 tickets=0 reconnect=1 reco_delay=2000" \ 0 \ -s "session successfully restored from cache" \ -S "session successfully restored from ticket" \ @@ -4224,7 +4224,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_SSL_CACHE_C run_test "Session resume using cache, DTLS: timeout < delay" \ "$P_SRV dtls=1 debug_level=3 tickets=0 cache_timeout=1" \ - "$P_CLI dtls=1 debug_level=3 tickets=0 reconnect=1 skip_close_notify=1 reco_delay=2" \ + "$P_CLI dtls=1 debug_level=3 tickets=0 reconnect=1 skip_close_notify=1 reco_delay=2000" \ 0 \ -S "session successfully restored from cache" \ -S "session successfully restored from ticket" \ @@ -4235,7 +4235,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_SSL_CACHE_C run_test "Session resume using cache, DTLS: no timeout" \ "$P_SRV dtls=1 debug_level=3 tickets=0 cache_timeout=0" \ - "$P_CLI dtls=1 debug_level=3 tickets=0 reconnect=1 skip_close_notify=1 reco_delay=2" \ + "$P_CLI dtls=1 debug_level=3 tickets=0 reconnect=1 skip_close_notify=1 reco_delay=2000" \ 0 \ -s "session successfully restored from cache" \ -S "session successfully restored from ticket" \ @@ -9891,7 +9891,7 @@ run_test "DTLS fragmenting: proxy MTU, resumed handshake" \ key_file=data_files/server8.key \ hs_timeout=10000-60000 \ force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ - mtu=1450 reconnect=1 skip_close_notify=1 reco_delay=1" \ + mtu=1450 reconnect=1 skip_close_notify=1 reco_delay=1000" \ 0 \ -S "autoreduction" \ -s "found fragmented DTLS handshake message" \