Merge branch 'mbedtls-3.6-restricted' into mbedtls-3.6.1rc0-pr

Signed-off-by: David Horstmann <david.horstmann@arm.com>
diff --git a/ChangeLog.d/disable-new-session-tickets.txt b/ChangeLog.d/disable-new-session-tickets.txt
new file mode 100644
index 0000000..bb13b4b
--- /dev/null
+++ b/ChangeLog.d/disable-new-session-tickets.txt
@@ -0,0 +1,14 @@
+Bugfix
+   * Fix TLS connection failure in applications using an Mbed TLS client in
+     the default configuration connecting to a TLS 1.3 server sending tickets.
+     See the documentation of
+     mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets() for more
+     information.
+     Fixes #8749.
+
+Changes
+   * By default, the handling of TLS 1.3 tickets by the Mbed TLS client is now
+     disabled at runtime. Applications that were using TLS 1.3 tickets
+     signalled by MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET return values now
+     need to enable the handling of TLS 1.3 tickets through the new
+     mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets() API.
diff --git a/ChangeLog.d/tls13-psa_crypto_init.txt b/ChangeLog.d/tls13-psa_crypto_init.txt
new file mode 100644
index 0000000..311db65
--- /dev/null
+++ b/ChangeLog.d/tls13-psa_crypto_init.txt
@@ -0,0 +1,9 @@
+Bugfix
+   * Fix TLS connections failing when the handshake selects TLS 1.3
+     in an application that does not call psa_crypto_init().
+     Fixes #9072.
+
+Changes
+   * A TLS handshake may now call psa_crypto_init() if TLS 1.3 is enabled.
+     This can happen even if TLS 1.3 is offered but eventually not selected
+     in the protocol version negotiation.
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index f500a4a..bd3f71d 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1798,8 +1798,9 @@
  * Requires: MBEDTLS_PSA_CRYPTO_C
  *
  * \note TLS 1.3 uses PSA crypto for cryptographic operations that are
- *       directly performed by TLS 1.3 code. As a consequence, you must
- *       call psa_crypto_init() before the first TLS 1.3 handshake.
+ *       directly performed by TLS 1.3 code. As a consequence, when TLS 1.3
+ *       is enabled, a TLS handshake may call psa_crypto_init(), even
+ *       if it ends up negotiating a different TLS version.
  *
  * \note Cryptographic operations performed indirectly via another module
  *       (X.509, PK) or by code shared with TLS 1.2 (record protection,
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 4b59e78..42fffbf 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -83,10 +83,7 @@
 /** Processing of the Certificate handshake message failed. */
 #define MBEDTLS_ERR_SSL_BAD_CERTIFICATE                   -0x7A00
 /* Error space gap */
-/**
- * Received NewSessionTicket Post Handshake Message.
- * This error code is experimental and may be changed or removed without notice.
- */
+/** A TLS 1.3 NewSessionTicket message has been received. */
 #define MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET       -0x7B00
 /** Not possible to read early data */
 #define MBEDTLS_ERR_SSL_CANNOT_READ_EARLY_DATA            -0x7B80
@@ -324,6 +321,9 @@
 #define MBEDTLS_SSL_SESSION_TICKETS_DISABLED     0
 #define MBEDTLS_SSL_SESSION_TICKETS_ENABLED      1
 
+#define MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_DISABLED  0
+#define MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED   1
+
 #define MBEDTLS_SSL_PRESET_DEFAULT              0
 #define MBEDTLS_SSL_PRESET_SUITEB               2
 
@@ -1446,6 +1446,12 @@
 #endif
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
     defined(MBEDTLS_SSL_CLI_C)
+    /** Encodes two booleans, one stating whether TLS 1.2 session tickets are
+     *  enabled or not, the other one whether the handling of TLS 1.3
+     *  NewSessionTicket messages is enabled or not. They are respectively set
+     *  by mbedtls_ssl_conf_session_tickets() and
+     *  mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets().
+     */
     uint8_t MBEDTLS_PRIVATE(session_tickets);   /*!< use session tickets? */
 #endif
 
@@ -4465,21 +4471,50 @@
 void mbedtls_ssl_conf_preference_order(mbedtls_ssl_config *conf, int order);
 #endif /* MBEDTLS_SSL_SRV_C */
 
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
-    defined(MBEDTLS_SSL_CLI_C)
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
 /**
- * \brief          Enable / Disable session tickets (client only).
- *                 (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.)
+ * \brief          Enable / Disable TLS 1.2 session tickets (client only,
+ *                 TLS 1.2 only). Enabled by default.
  *
  * \note           On server, use \c mbedtls_ssl_conf_session_tickets_cb().
  *
  * \param conf     SSL configuration
- * \param use_tickets   Enable or disable (MBEDTLS_SSL_SESSION_TICKETS_ENABLED or
- *                                         MBEDTLS_SSL_SESSION_TICKETS_DISABLED)
+ * \param use_tickets   Enable or disable (#MBEDTLS_SSL_SESSION_TICKETS_ENABLED or
+ *                                         #MBEDTLS_SSL_SESSION_TICKETS_DISABLED)
  */
 void mbedtls_ssl_conf_session_tickets(mbedtls_ssl_config *conf, int use_tickets);
-#endif /* MBEDTLS_SSL_SESSION_TICKETS &&
-          MBEDTLS_SSL_CLI_C */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/**
+ * \brief Enable / Disable handling of TLS 1.3 NewSessionTicket messages
+ *        (client only, TLS 1.3 only).
+ *
+ *        The handling of TLS 1.3 NewSessionTicket messages is disabled by
+ *        default.
+ *
+ *        In TLS 1.3, servers may send a NewSessionTicket message at any time,
+ *        and may send multiple NewSessionTicket messages. By default, TLS 1.3
+ *        clients ignore NewSessionTicket messages.
+ *
+ *        To support session tickets in TLS 1.3 clients, call this function
+ *        with #MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED. When
+ *        this is enabled, when a client receives a NewSessionTicket message,
+ *        the next call to a message processing functions (notably
+ *        mbedtls_ssl_handshake() and mbedtls_ssl_read()) will return
+ *        #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET. The client should then
+ *        call mbedtls_ssl_get_session() to retrieve the session ticket before
+ *        calling the same message processing function again.
+ *
+ * \param conf  SSL configuration
+ * \param signal_new_session_tickets Enable or disable
+ *                                   (#MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED or
+ *                                    #MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_DISABLED)
+ */
+void mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(
+    mbedtls_ssl_config *conf, int signal_new_session_tickets);
+
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && \
     defined(MBEDTLS_SSL_SRV_C) && \
@@ -4887,6 +4922,10 @@
  * \return         #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED if DTLS is in use
  *                 and the client did not demonstrate reachability yet - in
  *                 this case you must stop using the context (see below).
+ * \return         #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET if a TLS 1.3
+ *                 NewSessionTicket message has been received. See the
+ *                 documentation of mbedtls_ssl_read() for more information
+ *                 about this error code.
  * \return         #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA if early data, as
  *                 defined in RFC 8446 (TLS 1.3 specification), has been
  *                 received as part of the handshake. This is server specific
@@ -4903,6 +4942,7 @@
  *                 #MBEDTLS_ERR_SSL_WANT_WRITE,
  *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or
  *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET or
  *                 #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA,
  *                 you must stop using the SSL context for reading or writing,
  *                 and either free it or call \c mbedtls_ssl_session_reset()
@@ -4923,10 +4963,13 @@
  *                 currently being processed might or might not contain further
  *                 DTLS records.
  *
- * \note           If the context is configured to allow TLS 1.3, or if
- *                 #MBEDTLS_USE_PSA_CRYPTO is enabled, the PSA crypto
+ * \note           If #MBEDTLS_USE_PSA_CRYPTO is enabled, the PSA crypto
  *                 subsystem must have been initialized by calling
  *                 psa_crypto_init() before calling this function.
+ *                 Otherwise, the handshake may call psa_crypto_init()
+ *                 if a negotiation involving TLS 1.3 takes place (this may
+ *                 be the case even if TLS 1.3 is offered but eventually
+ *                 not selected).
  */
 int mbedtls_ssl_handshake(mbedtls_ssl_context *ssl);
 
@@ -4974,6 +5017,7 @@
  *                 #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE,
  *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS,
  *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET or
  *                 #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA, you must stop using
  *                 the SSL context for reading or writing, and either free it
  *                 or call \c mbedtls_ssl_session_reset() on it before
@@ -5042,6 +5086,17 @@
  * \return         #MBEDTLS_ERR_SSL_CLIENT_RECONNECT if we're at the server
  *                 side of a DTLS connection and the client is initiating a
  *                 new connection using the same source port. See below.
+ * \return         #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET if a TLS 1.3
+ *                 NewSessionTicket message has been received.
+ *                 This error code is only returned on the client side. It is
+ *                 only returned if handling of TLS 1.3 NewSessionTicket
+ *                 messages has been enabled through
+ *                 mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets().
+ *                 This error code indicates that a TLS 1.3 NewSessionTicket
+ *                 message has been received and parsed successfully by the
+ *                 client. The ticket data can be retrieved from the SSL
+ *                 context by calling mbedtls_ssl_get_session(). It remains
+ *                 available until the next call to mbedtls_ssl_read().
  * \return         #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA if early data, as
  *                 defined in RFC 8446 (TLS 1.3 specification), has been
  *                 received as part of the handshake. This is server specific
@@ -5059,6 +5114,7 @@
  *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS,
  *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS,
  *                 #MBEDTLS_ERR_SSL_CLIENT_RECONNECT or
+ *                 #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET or
  *                 #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA,
  *                 you must stop using the SSL context for reading or writing,
  *                 and either free it or call \c mbedtls_ssl_session_reset()
@@ -5124,6 +5180,10 @@
  *                 operation is in progress (see mbedtls_ecp_set_max_ops()) -
  *                 in this case you must call this function again to complete
  *                 the handshake when you're done attending other tasks.
+ * \return         #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET if a TLS 1.3
+ *                 NewSessionTicket message has been received. See the
+ *                 documentation of mbedtls_ssl_read() for more information
+ *                 about this error code.
  * \return         #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA if early data, as
  *                 defined in RFC 8446 (TLS 1.3 specification), has been
  *                 received as part of the handshake. This is server specific
@@ -5140,6 +5200,7 @@
  *                 #MBEDTLS_ERR_SSL_WANT_WRITE,
  *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS,
  *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET or
  *                 #MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA,
  *                 you must stop using the SSL context for reading or writing,
  *                 and either free it or call \c mbedtls_ssl_session_reset()
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index f31ce11..9866879 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -1926,6 +1926,26 @@
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 && MBEDTLS_SSL_PROTO_TLS1_3 */
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+
+/** \brief Initialize the PSA crypto subsystem if necessary.
+ *
+ * Call this function before doing any cryptography in a TLS 1.3 handshake.
+ *
+ * This is necessary in Mbed TLS 3.x for backward compatibility.
+ * Up to Mbed TLS 3.5, in the default configuration, you could perform
+ * a TLS connection with default parameters without having called
+ * psa_crypto_init(), since the TLS layer only supported TLS 1.2 and
+ * did not use PSA crypto. (TLS 1.2 only uses PSA crypto if
+ * MBEDTLS_USE_PSA_CRYPTO is enabled, which is not the case in the default
+ * configuration.) Starting with Mbed TLS 3.6.0, TLS 1.3 is enabled
+ * by default, and the TLS 1.3 layer uses PSA crypto. This means that
+ * applications that are not otherwise using PSA crypto and that worked
+ * with Mbed TLS 3.5 started failing in TLS 3.6.0 if they connected to
+ * a peer that supports TLS 1.3. See
+ * https://github.com/Mbed-TLS/mbedtls/issues/9072
+ */
+int mbedtls_ssl_tls13_crypto_init(mbedtls_ssl_context *ssl);
+
 extern const uint8_t mbedtls_ssl_tls13_hello_retry_request_magic[
     MBEDTLS_SERVER_HELLO_RANDOM_LEN];
 MBEDTLS_CHECK_RETURN_CRITICAL
@@ -2949,8 +2969,37 @@
 {
     session->ticket_flags &= ~(flags & MBEDTLS_SSL_TLS1_3_TICKET_FLAGS_MASK);
 }
+
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
 
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+#define MBEDTLS_SSL_SESSION_TICKETS_TLS1_2_BIT 0
+#define MBEDTLS_SSL_SESSION_TICKETS_TLS1_3_BIT 1
+
+#define MBEDTLS_SSL_SESSION_TICKETS_TLS1_2_MASK \
+    (1 << MBEDTLS_SSL_SESSION_TICKETS_TLS1_2_BIT)
+#define MBEDTLS_SSL_SESSION_TICKETS_TLS1_3_MASK \
+    (1 << MBEDTLS_SSL_SESSION_TICKETS_TLS1_3_BIT)
+
+static inline int mbedtls_ssl_conf_get_session_tickets(
+    const mbedtls_ssl_config *conf)
+{
+    return conf->session_tickets & MBEDTLS_SSL_SESSION_TICKETS_TLS1_2_MASK ?
+           MBEDTLS_SSL_SESSION_TICKETS_ENABLED :
+           MBEDTLS_SSL_SESSION_TICKETS_DISABLED;
+}
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+static inline int mbedtls_ssl_conf_is_signal_new_session_tickets_enabled(
+    const mbedtls_ssl_config *conf)
+{
+    return conf->session_tickets & MBEDTLS_SSL_SESSION_TICKETS_TLS1_3_MASK ?
+           MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED :
+           MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_DISABLED;
+}
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
 #if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3)
 int mbedtls_ssl_tls13_finalize_client_hello(mbedtls_ssl_context *ssl);
 #endif
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index 2bdad84..ef722d7 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -5595,13 +5595,19 @@
         if (ssl_tls13_is_new_session_ticket(ssl)) {
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
             MBEDTLS_SSL_DEBUG_MSG(3, ("NewSessionTicket received"));
-            ssl->keep_current_message = 1;
+            if (mbedtls_ssl_conf_is_signal_new_session_tickets_enabled(ssl->conf) ==
+                MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED) {
+                ssl->keep_current_message = 1;
 
-            mbedtls_ssl_handshake_set_state(ssl,
-                                            MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET);
-            return MBEDTLS_ERR_SSL_WANT_READ;
+                mbedtls_ssl_handshake_set_state(ssl,
+                                                MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET);
+                return MBEDTLS_ERR_SSL_WANT_READ;
+            } else {
+                MBEDTLS_SSL_DEBUG_MSG(3, ("Ignoring NewSessionTicket, handling disabled."));
+                return 0;
+            }
 #else
-            MBEDTLS_SSL_DEBUG_MSG(3, ("Ignore NewSessionTicket, not supported."));
+            MBEDTLS_SSL_DEBUG_MSG(3, ("Ignoring NewSessionTicket, not supported."));
             return 0;
 #endif
         }
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 8f5c37a..c773365 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2986,11 +2986,24 @@
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 #if defined(MBEDTLS_SSL_CLI_C)
+
 void mbedtls_ssl_conf_session_tickets(mbedtls_ssl_config *conf, int use_tickets)
 {
-    conf->session_tickets = use_tickets;
+    conf->session_tickets &= ~MBEDTLS_SSL_SESSION_TICKETS_TLS1_2_MASK;
+    conf->session_tickets |= (use_tickets != 0) <<
+                             MBEDTLS_SSL_SESSION_TICKETS_TLS1_2_BIT;
 }
-#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+void mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(
+    mbedtls_ssl_config *conf, int signal_new_session_tickets)
+{
+    conf->session_tickets &= ~MBEDTLS_SSL_SESSION_TICKETS_TLS1_3_MASK;
+    conf->session_tickets |= (signal_new_session_tickets != 0) <<
+                             MBEDTLS_SSL_SESSION_TICKETS_TLS1_3_BIT;
+}
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+#endif /* MBEDTLS_SSL_CLI_C */
 
 #if defined(MBEDTLS_SSL_SRV_C)
 
@@ -5855,7 +5868,33 @@
     if (endpoint == MBEDTLS_SSL_IS_CLIENT) {
         conf->authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-        conf->session_tickets = MBEDTLS_SSL_SESSION_TICKETS_ENABLED;
+        mbedtls_ssl_conf_session_tickets(conf, MBEDTLS_SSL_SESSION_TICKETS_ENABLED);
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+        /* Contrary to TLS 1.2 tickets, TLS 1.3 NewSessionTicket message
+         * handling is disabled by default in Mbed TLS 3.6.x for backward
+         * compatibility with client applications developed using Mbed TLS 3.5
+         * or earlier with the default configuration.
+         *
+         * Up to Mbed TLS 3.5, in the default configuration TLS 1.3 was
+         * disabled, and a Mbed TLS client with the default configuration would
+         * establish a TLS 1.2 connection with a TLS 1.2 and TLS 1.3 capable
+         * server.
+         *
+         * Starting with Mbed TLS 3.6.0, TLS 1.3 is enabled by default, and thus
+         * an Mbed TLS client with the default configuration establishes a
+         * TLS 1.3 connection with a TLS 1.2 and TLS 1.3 capable server. If
+         * following the handshake the TLS 1.3 server sends NewSessionTicket
+         * messages and the Mbed TLS client processes them, this results in
+         * Mbed TLS high level APIs (mbedtls_ssl_read(),
+         * mbedtls_ssl_handshake(), ...) to eventually return an
+         * #MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET non fatal error code
+         * (see the documentation of mbedtls_ssl_read() for more information on
+         * that error code). Applications unaware of that TLS 1.3 specific non
+         * fatal error code are then failing.
+         */
+        mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(
+            conf, MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_DISABLED);
+#endif
 #endif
     }
 #endif
diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c
index eac6a3a..9b2da5a 100644
--- a/library/ssl_tls12_client.c
+++ b/library/ssl_tls12_client.c
@@ -364,7 +364,8 @@
 
     *olen = 0;
 
-    if (ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED) {
+    if (mbedtls_ssl_conf_get_session_tickets(ssl->conf) ==
+        MBEDTLS_SSL_SESSION_TICKETS_DISABLED) {
         return 0;
     }
 
@@ -787,7 +788,8 @@
                                         const unsigned char *buf,
                                         size_t len)
 {
-    if (ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED ||
+    if ((mbedtls_ssl_conf_get_session_tickets(ssl->conf) ==
+         MBEDTLS_SSL_SESSION_TICKETS_DISABLED) ||
         len != 0) {
         MBEDTLS_SSL_DEBUG_MSG(1,
                               ("non-matching session ticket extension"));
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index 162e3a3..b63b5e6 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -1141,6 +1141,11 @@
 
     *out_len = 0;
 
+    ret = mbedtls_ssl_tls13_crypto_init(ssl);
+    if (ret != 0) {
+        return ret;
+    }
+
     /* Write supported_versions extension
      *
      * Supported Versions Extension is mandatory with TLS 1.3.
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index 3f1f551..b6d0978 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -27,7 +27,6 @@
 #include "psa/crypto.h"
 #include "psa_util_internal.h"
 
-#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED)
 /* Define a local translating function to save code size by not using too many
  * arguments in each translating place. */
 static int local_err_translation(psa_status_t status)
@@ -37,7 +36,16 @@
                                  psa_generic_status_to_mbedtls);
 }
 #define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
-#endif
+
+int mbedtls_ssl_tls13_crypto_init(mbedtls_ssl_context *ssl)
+{
+    psa_status_t status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        (void) ssl; // unused when debugging is disabled
+        MBEDTLS_SSL_DEBUG_RET(1, "psa_crypto_init", status);
+    }
+    return PSA_TO_MBEDTLS_ERR(status);
+}
 
 const uint8_t mbedtls_ssl_tls13_hello_retry_request_magic[
     MBEDTLS_SERVER_HELLO_RANDOM_LEN] =
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 9c949bd..693edc7 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -1412,6 +1412,12 @@
     ssl->session_negotiate->tls_version = MBEDTLS_SSL_VERSION_TLS1_3;
     ssl->session_negotiate->endpoint = ssl->conf->endpoint;
 
+    /* Before doing any crypto, make sure we can. */
+    ret = mbedtls_ssl_tls13_crypto_init(ssl);
+    if (ret != 0) {
+        return ret;
+    }
+
     /*
      * We are negotiating the version 1.3 of the protocol. Do what we have
      * postponed: copy of the client random bytes, copy of the legacy session
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 501ac61..025f3c5 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -82,6 +82,7 @@
 #define DFL_CID_VALUE_RENEGO    NULL
 #define DFL_RECONNECT_HARD      0
 #define DFL_TICKETS             MBEDTLS_SSL_SESSION_TICKETS_ENABLED
+#define DFL_NEW_SESSION_TICKETS MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED
 #define DFL_ALPN_STRING         NULL
 #define DFL_GROUPS              NULL
 #define DFL_SIG_ALGS            NULL
@@ -198,7 +199,8 @@
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 #define USAGE_TICKETS                                       \
-    "    tickets=%%d          default: 1 (enabled)\n"
+    "    tickets=%%d              default: 1 (enabled)\n"    \
+    "    new_session_tickets=%%d  default: 1 (enabled)\n"
 #else
 #define USAGE_TICKETS ""
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
@@ -514,7 +516,8 @@
     int reco_delay;             /* delay in seconds before resuming session */
     int reco_mode;              /* how to keep the session around           */
     int reconnect_hard;         /* unexpectedly reconnect from the same port */
-    int tickets;                /* enable / disable session tickets         */
+    int tickets;                /* enable / disable session tickets (TLS 1.2) */
+    int new_session_tickets;    /* enable / disable new session tickets (TLS 1.3) */
     const char *groups;         /* list of supported groups                 */
     const char *sig_algs;       /* supported TLS 1.3 signature algorithms   */
     const char *alpn_string;    /* ALPN supported protocols                 */
@@ -818,8 +821,6 @@
     psa_key_attributes_t key_attributes;
 #endif
     psa_status_t status;
-#elif defined(MBEDTLS_SSL_PROTO_TLS1_3)
-    psa_status_t status;
 #endif
 
     rng_context_t rng;
@@ -894,7 +895,15 @@
     memset((void *) alpn_list, 0, sizeof(alpn_list));
 #endif
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    /* For builds with TLS 1.3 enabled but not MBEDTLS_USE_PSA_CRYPTO,
+     * we deliberately do not call psa_crypto_init() here, to test that
+     * the library is backward-compatible with versions prior to 3.6.0
+     * where calling psa_crypto_init() was not required to open a TLS
+     * connection in the default configuration. See
+     * https://github.com/Mbed-TLS/mbedtls/issues/9072 and
+     * mbedtls_ssl_tls13_crypto_init().
+     */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
     status = psa_crypto_init();
     if (status != PSA_SUCCESS) {
         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
@@ -963,6 +972,7 @@
     opt.reco_mode           = DFL_RECO_MODE;
     opt.reconnect_hard      = DFL_RECONNECT_HARD;
     opt.tickets             = DFL_TICKETS;
+    opt.new_session_tickets = DFL_NEW_SESSION_TICKETS;
     opt.alpn_string         = DFL_ALPN_STRING;
     opt.groups              = DFL_GROUPS;
     opt.sig_algs            = DFL_SIG_ALGS;
@@ -1220,6 +1230,11 @@
             if (opt.tickets < 0) {
                 goto usage;
             }
+        } else if (strcmp(p, "new_session_tickets") == 0) {
+            opt.new_session_tickets = atoi(q);
+            if (opt.new_session_tickets < 0) {
+                goto usage;
+            }
         } else if (strcmp(p, "alpn") == 0) {
             opt.alpn_string = q;
         } else if (strcmp(p, "extended_ms") == 0) {
@@ -1930,7 +1945,11 @@
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
     mbedtls_ssl_conf_session_tickets(&conf, opt.tickets);
-#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(
+        &conf, opt.new_session_tickets);
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
     if (opt.force_ciphersuite[0] != DFL_FORCE_CIPHER) {
         mbedtls_ssl_conf_ciphersuites(&conf, opt.force_ciphersuite);
@@ -3200,6 +3219,9 @@
 
     /* For builds with MBEDTLS_TEST_USE_PSA_CRYPTO_RNG psa crypto
      * resources are freed by rng_free(). */
+    /* For builds with MBEDTLS_SSL_PROTO_TLS1_3, PSA may have been
+     * initialized under the hood by the TLS layer. See
+     * mbedtls_ssl_tls13_crypto_init(). */
 #if (defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)) && \
     !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
     mbedtls_psa_crypto_free();
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index bc9bc5c..ed69590 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1594,7 +1594,7 @@
     int i;
     char *p, *q;
     const int *list;
-#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_status_t status;
 #endif
     unsigned char eap_tls_keymaterial[16];
@@ -1660,7 +1660,15 @@
     mbedtls_ssl_cookie_init(&cookie_ctx);
 #endif
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    /* For builds with TLS 1.3 enabled but not MBEDTLS_USE_PSA_CRYPTO,
+     * we deliberately do not call psa_crypto_init() here, to test that
+     * the library is backward-compatible with versions prior to 3.6.0
+     * where calling psa_crypto_init() was not required to open a TLS
+     * connection in the default configuration. See
+     * https://github.com/Mbed-TLS/mbedtls/issues/9072 and
+     * mbedtls_ssl_tls13_crypto_init().
+     */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
     status = psa_crypto_init();
     if (status != PSA_SUCCESS) {
         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
@@ -4310,6 +4318,9 @@
 
     /* For builds with MBEDTLS_TEST_USE_PSA_CRYPTO_RNG psa crypto
      * resources are freed by rng_free(). */
+    /* For builds with MBEDTLS_SSL_PROTO_TLS1_3, PSA may have been
+     * initialized under the hood by the TLS layer. See
+     * mbedtls_ssl_tls13_crypto_init(). */
 #if (defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)) \
     && !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
     mbedtls_psa_crypto_free();
diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h
index 71ba0fc..1039712 100644
--- a/tests/include/test/psa_crypto_helpers.h
+++ b/tests/include/test/psa_crypto_helpers.h
@@ -334,9 +334,18 @@
  * This is like #PSA_DONE except it does nothing under the same conditions as
  * #USE_PSA_INIT.
  */
-#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
 #define USE_PSA_INIT() PSA_INIT()
 #define USE_PSA_DONE() PSA_DONE()
+#elif defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/* TLS 1.3 must work without having called psa_crypto_init(), for backward
+ * compatibility with Mbed TLS <= 3.5 when connecting with a peer that
+ * supports both TLS 1.2 and TLS 1.3. See mbedtls_ssl_tls13_crypto_init()
+ * and https://github.com/Mbed-TLS/mbedtls/issues/9072 . */
+#define USE_PSA_INIT() ((void) 0)
+/* TLS 1.3 may have initialized the PSA subsystem. Shut it down cleanly,
+ * otherwise Asan and Valgrind would notice a resource leak. */
+#define USE_PSA_DONE() PSA_DONE()
 #else /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */
 /* Define empty macros so that we can use them in the preamble and teardown
  * of every test function that uses PSA conditionally based on
@@ -408,13 +417,12 @@
  * This is like #PSA_DONE except it does nothing under the same conditions as
  * #MD_OR_USE_PSA_INIT.
  */
-#if defined(MBEDTLS_MD_SOME_PSA) || \
-    defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#if defined(MBEDTLS_MD_SOME_PSA)
 #define MD_OR_USE_PSA_INIT()   PSA_INIT()
 #define MD_OR_USE_PSA_DONE()   PSA_DONE()
 #else
-#define MD_OR_USE_PSA_INIT() ((void) 0)
-#define MD_OR_USE_PSA_DONE() ((void) 0)
+#define MD_OR_USE_PSA_INIT()   USE_PSA_INIT()
+#define MD_OR_USE_PSA_DONE()   USE_PSA_DONE()
 #endif
 
 /** \def AES_PSA_INIT
diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh
index 9d5870d..90ae3b2 100755
--- a/tests/opt-testcases/tls13-misc.sh
+++ b/tests/opt-testcases/tls13-misc.sh
@@ -839,7 +839,21 @@
             -c "Protocol is TLSv1.3" \
             -C "Saving session for reuse... ok" \
             -C "Reconnecting with saved session... ok" \
-            -c "Ignore NewSessionTicket, not supported."
+            -c "Ignoring NewSessionTicket, not supported."
+
+requires_openssl_tls1_3_with_compatible_ephemeral
+requires_all_configs_enabled MBEDTLS_SSL_CLI_C \
+                             MBEDTLS_SSL_SESSION_TICKETS \
+                             MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+run_test    "TLS 1.3 m->O: resumption fails, ticket handling disabled" \
+            "$O_NEXT_SRV -msg -tls1_3 -no_resume_ephemeral -no_cache --num_tickets 1" \
+            "$P_CLI debug_level=3 new_session_tickets=0 reco_mode=1 reconnect=1" \
+            1 \
+            -c "Protocol is TLSv1.3" \
+            -C "Saving session for reuse... ok" \
+            -C "Reconnecting with saved session... ok" \
+            -c "Ignoring NewSessionTicket, handling disabled."
 
 # No early data m->O tests for the time being. The option -early_data is needed
 # to enable early data on OpenSSL server and it is not compatible with the
@@ -899,7 +913,21 @@
             -c "Protocol is TLSv1.3" \
             -C "Saving session for reuse... ok" \
             -C "Reconnecting with saved session... ok" \
-            -c "Ignore NewSessionTicket, not supported."
+            -c "Ignoring NewSessionTicket, not supported."
+
+requires_gnutls_tls1_3
+requires_all_configs_enabled MBEDTLS_SSL_CLI_C \
+                             MBEDTLS_SSL_SESSION_TICKETS \
+                             MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+run_test    "TLS 1.3 m->G: resumption fails, ticket handling disabled" \
+            "$G_NEXT_SRV -d 5 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3 --disable-client-cert" \
+            "$P_CLI debug_level=3 new_session_tickets=0 reco_mode=1 reconnect=1" \
+            1 \
+            -c "Protocol is TLSv1.3" \
+            -C "Saving session for reuse... ok" \
+            -C "Reconnecting with saved session... ok" \
+            -c "Ignoring NewSessionTicket, handling disabled."
 
 requires_gnutls_tls1_3
 requires_all_configs_enabled MBEDTLS_SSL_CLI_C \
diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c
index f546e76..3cb6175 100644
--- a/tests/src/test_helpers/ssl_helpers.c
+++ b/tests/src/test_helpers/ssl_helpers.c
@@ -2543,6 +2543,9 @@
                                          server_options, NULL, NULL, NULL);
     TEST_EQUAL(ret, 0);
 
+    mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(
+        &client_ep.conf, MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED);
+
     mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
                                         mbedtls_test_ticket_write,
                                         mbedtls_test_ticket_parse,