Merge pull request #7887 from ronald-cron-arm/fix-hrr-in-psk-kem

tls13: server: Fix spurious HRR
diff --git a/ChangeLog.d/fix-hrr-in-psk-kem.txt b/ChangeLog.d/fix-hrr-in-psk-kem.txt
new file mode 100644
index 0000000..0377711
--- /dev/null
+++ b/ChangeLog.d/fix-hrr-in-psk-kem.txt
@@ -0,0 +1,5 @@
+Bugfix
+   * In TLS 1.3, fix handshake failure when a client in its ClientHello
+     proposes an handshake based on PSK only key exchange mode or at least
+     one of the key exchange modes using ephemeral keys to a server that
+     supports only the PSK key exchange mode.
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 196d09a..5aeb358 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -1262,6 +1262,7 @@
     const unsigned char *supported_versions_data_end;
     mbedtls_ssl_handshake_params *handshake = ssl->handshake;
     int hrr_required = 0;
+    int no_usable_share_for_key_agreement = 0;
 
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
     const unsigned char *pre_shared_key_ext = NULL;
@@ -1577,8 +1578,8 @@
                 ret = ssl_tls13_parse_key_shares_ext(
                     ssl, p, extension_data_end);
                 if (ret == SSL_TLS1_3_PARSE_KEY_SHARES_EXT_NO_MATCH) {
-                    MBEDTLS_SSL_DEBUG_MSG(2, ("HRR needed "));
-                    hrr_required = 1;
+                    MBEDTLS_SSL_DEBUG_MSG(2, ("No usable share for key agreement."));
+                    no_usable_share_for_key_agreement = 1;
                 }
 
                 if (ret < 0) {
@@ -1736,6 +1737,11 @@
         return ret;
     }
 
+    if (ssl->handshake->key_exchange_mode !=
+        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) {
+        hrr_required = (no_usable_share_for_key_agreement != 0);
+    }
+
     mbedtls_ssl_optimize_checksum(ssl, handshake->ciphersuite_info);
 
     return hrr_required ? SSL_CLIENT_HELLO_HRR_REQUIRED : SSL_CLIENT_HELLO_OK;
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 1e52dbe..cc1695d 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -13362,6 +13362,19 @@
          -c "Verifying peer X.509 certificate... ok" \
          -C "received HelloRetryRequest message"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
+requires_config_enabled MBEDTLS_SSL_SRV_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+run_test    "TLS 1.3: no HRR in case of PSK key exchange mode" \
+            "$P_SRV nbio=2 psk=010203 psk_identity=0a0b0c tls13_kex_modes=psk curves=none" \
+            "$P_CLI nbio=2 debug_level=3 psk=010203 psk_identity=0a0b0c tls13_kex_modes=all" \
+            0 \
+            -C "received HelloRetryRequest message" \
+            -c "Selected key exchange mode: psk$" \
+            -c "HTTP/1.0 200 OK"
+
 # Test heap memory usage after handshake
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_MEMORY_DEBUG