Merge pull request #6498 from yuhaoth/pr/fix-session-resumption-fail-when-hostname-is-not-localhost

BUG: Fix session resumption fail when hostname is not localhost
diff --git a/ChangeLog.d/fix_tls13_session_resumption_fail_when_hostname_is_not_localhost.txt b/ChangeLog.d/fix_tls13_session_resumption_fail_when_hostname_is_not_localhost.txt
new file mode 100644
index 0000000..5797f48
--- /dev/null
+++ b/ChangeLog.d/fix_tls13_session_resumption_fail_when_hostname_is_not_localhost.txt
@@ -0,0 +1,4 @@
+Bugfix
+    * Fix TLS 1.3 session resumption fail. Fixes #6488.
+    * Add configuration check to exclude TLS 1.3 optional authentication of
+      client.
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 3c91b45..5200d90 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1012,6 +1012,30 @@
     if( ret != 0 )
         return( ret );
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    /* RFC 8446 section 4.4.3
+     *
+     * If the verification fails, the receiver MUST terminate the handshake with
+     * a "decrypt_error" alert.
+     *
+     * If the client is configured as TLS 1.3 only with optional verify, return
+     * bad config.
+     *
+     */
+    if( mbedtls_ssl_conf_tls13_ephemeral_enabled(
+            (mbedtls_ssl_context *)ssl )                            &&
+        ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT                &&
+        ssl->conf->max_tls_version == MBEDTLS_SSL_VERSION_TLS1_3    &&
+        ssl->conf->min_tls_version == MBEDTLS_SSL_VERSION_TLS1_3    &&
+        ssl->conf->authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG(
+            1, ( "Optional verify auth mode "
+                 "is not available for TLS 1.3 client" ) );
+        return( MBEDTLS_ERR_SSL_BAD_CONFIG );
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
     /* Space for further checks */
 
     return( 0 );
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 80862f9..86a9c1e 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -83,6 +83,7 @@
 #define DFL_RECSPLIT            -1
 #define DFL_DHMLEN              -1
 #define DFL_RECONNECT           0
+#define DFL_RECO_SERVER_NAME    NULL
 #define DFL_RECO_DELAY          0
 #define DFL_RECO_MODE           1
 #define DFL_CID_ENABLED         0
@@ -403,8 +404,8 @@
     USAGE_RENEGO                                            \
     "    exchanges=%%d        default: 1\n"                 \
     "    reconnect=%%d        number of reconnections using session resumption\n" \
-    "                        default: 0 (disabled)\n"      \
-    "    reco_server_name=%%s  default: localhost\n"         \
+    "                        default: 0 (disabled)\n"       \
+    "    reco_server_name=%%s  default: NULL\n"             \
     "    reco_delay=%%d       default: 0 seconds\n"         \
     "    reco_mode=%%d        0: copy session, 1: serialize session\n" \
     "                        default: 1\n"      \
@@ -921,7 +922,7 @@
     opt.recsplit            = DFL_RECSPLIT;
     opt.dhmlen              = DFL_DHMLEN;
     opt.reconnect           = DFL_RECONNECT;
-    opt.reco_server_name    = DFL_SERVER_NAME;
+    opt.reco_server_name    = DFL_RECO_SERVER_NAME;
     opt.reco_delay          = DFL_RECO_DELAY;
     opt.reco_mode           = DFL_RECO_MODE;
     opt.reconnect_hard      = DFL_RECONNECT_HARD;
@@ -1118,7 +1119,7 @@
             if( opt.reconnect < 0 || opt.reconnect > 2 )
                 goto usage;
         }
-        else if( strcmp( p, "rec_server_name" ) == 0 )
+        else if( strcmp( p, "reco_server_name" ) == 0 )
             opt.reco_server_name = q;
         else if( strcmp( p, "reco_delay" ) == 0 )
         {
@@ -2239,7 +2240,10 @@
                     "    or you didn't set ca_file or ca_path "
                         "to an appropriate value.\n"
                     "    Alternatively, you may want to use "
-                        "auth_mode=optional for testing purposes.\n" );
+                        "auth_mode=optional for testing purposes if "
+                        "not using TLS 1.3.\n"
+                    "    For TLS 1.3 server, try `ca_path=/etc/ssl/certs/`"
+                        "or other folder that has root certificates\n" );
             mbedtls_printf( "\n" );
             goto exit;
         }
@@ -3113,7 +3117,8 @@
         }
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
-        if( ( ret = mbedtls_ssl_set_hostname( &ssl,
+        if( opt.reco_server_name != NULL &&
+            ( ret = mbedtls_ssl_set_hostname( &ssl,
                                               opt.reco_server_name ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n",
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index a75b3f5..fc892a1 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -13018,7 +13018,7 @@
 run_test    "TLS 1.3: NewSessionTicket: servername negative check, m->m" \
             "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=4 \
             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \
-            "$P_CLI debug_level=4 server_name=localhost rec_server_name=remote reco_mode=1 reconnect=1" \
+            "$P_CLI debug_level=4 server_name=localhost reco_server_name=remote reco_mode=1 reconnect=1" \
             1 \
             -c "Protocol is TLSv1.3" \
             -c "got new session ticket." \