Merge pull request #9385 from eleuzi01/replace-ecdsa-some

Replace MBEDTLS_PK_HAVE_ECDSA* with PSA_WANT counterparts
diff --git a/CMakeLists.txt b/CMakeLists.txt
index df4bf6b..b1af566 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,12 +40,12 @@
 if(TEST_CPP)
     project("Mbed TLS"
         LANGUAGES C CXX
-        VERSION 3.6.0
+        VERSION 4.0.0
     )
 else()
     project("Mbed TLS"
         LANGUAGES C
-        VERSION 3.6.0
+        VERSION 4.0.0
     )
 endif()
 
@@ -458,7 +458,7 @@
     write_basic_package_version_file(
         "cmake/MbedTLSConfigVersion.cmake"
             COMPATIBILITY SameMajorVersion
-            VERSION 3.6.0)
+            VERSION 4.0.0)
 
     install(
         FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
diff --git a/ChangeLog.d/fix-rsa-performance-regression.txt b/ChangeLog.d/fix-rsa-performance-regression.txt
new file mode 100644
index 0000000..603612a
--- /dev/null
+++ b/ChangeLog.d/fix-rsa-performance-regression.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix unintended performance regression when using short RSA public keys.
+     Fixes #9232.
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index 3eb5f75..fb4439a 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -10,7 +10,7 @@
  */
 
 /**
- * @mainpage Mbed TLS v3.6.0 API Documentation
+ * @mainpage Mbed TLS v4.0.0 API Documentation
  *
  * This documentation describes the internal structure of Mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index 1e494a0..917b88d 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -1,4 +1,4 @@
-PROJECT_NAME           = "Mbed TLS v3.6.0"
+PROJECT_NAME           = "Mbed TLS v4.0.0"
 OUTPUT_DIRECTORY       = ../apidoc/
 FULL_PATH_NAMES        = NO
 OPTIMIZE_OUTPUT_FOR_C  = YES
diff --git a/framework b/framework
index 94599c0..071831e 160000
--- a/framework
+++ b/framework
@@ -1 +1 @@
-Subproject commit 94599c0e3b5036e086446a51a3f79640f70f22f6
+Subproject commit 071831e25bd336baa58bbdf65e985283f56e1b86
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index cf38f90..2b48e50 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -24,8 +24,8 @@
  * The version number x.y.z is split into three parts.
  * Major, Minor, Patchlevel
  */
-#define MBEDTLS_VERSION_MAJOR  3
-#define MBEDTLS_VERSION_MINOR  6
+#define MBEDTLS_VERSION_MAJOR  4
+#define MBEDTLS_VERSION_MINOR  0
 #define MBEDTLS_VERSION_PATCH  0
 
 /**
@@ -33,9 +33,9 @@
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x03060000
-#define MBEDTLS_VERSION_STRING         "3.6.0"
-#define MBEDTLS_VERSION_STRING_FULL    "Mbed TLS 3.6.0"
+#define MBEDTLS_VERSION_NUMBER         0x04000000
+#define MBEDTLS_VERSION_STRING         "4.0.0"
+#define MBEDTLS_VERSION_STRING_FULL    "Mbed TLS 4.0.0"
 
 /* Macros for build-time platform detection */
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 2e18d2b..0f75822 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -304,7 +304,7 @@
 if(USE_SHARED_MBEDTLS_LIBRARY)
     set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
     add_library(${mbedcrypto_target} SHARED ${src_crypto})
-    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.6.0 SOVERSION 16)
+    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 4.0.0 SOVERSION 16)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
     if(TARGET ${everest_target})
@@ -316,11 +316,11 @@
     endif()
 
     add_library(${mbedx509_target} SHARED ${src_x509})
-    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.6.0 SOVERSION 7)
+    set_target_properties(${mbedx509_target} PROPERTIES VERSION 4.0.0 SOVERSION 7)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
 
     add_library(${mbedtls_target} SHARED ${src_tls})
-    set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.6.0 SOVERSION 21)
+    set_target_properties(${mbedtls_target} PROPERTIES VERSION 4.0.0 SOVERSION 21)
     target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
 endif(USE_SHARED_MBEDTLS_LIBRARY)
 
diff --git a/tests/include/test/bignum_codepath_check.h b/tests/include/test/bignum_codepath_check.h
new file mode 100644
index 0000000..3d72be1
--- /dev/null
+++ b/tests/include/test/bignum_codepath_check.h
@@ -0,0 +1,94 @@
+/** Support for path tracking in optionally safe bignum functions
+ *
+ * The functions are called when an optionally safe path is taken and logs it with a single
+ * variable. This variable is at any time in one of three states:
+ *      - MBEDTLS_MPI_IS_TEST: No optionally safe path has been taken since the last reset
+ *      - MBEDTLS_MPI_IS_SECRET: Only safe paths were teken since the last reset
+ *      - MBEDTLS_MPI_IS_PUBLIC: At least one unsafe path has been taken since the last reset
+ *
+ * Use a simple global variable to track execution path. Making it work with multithreading
+ * isn't worth the effort as multithreaded tests add little to no value here.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef BIGNUM_CODEPATH_CHECK_H
+#define BIGNUM_CODEPATH_CHECK_H
+
+#include "bignum_core.h"
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+
+extern int mbedtls_codepath_check;
+
+/**
+ * \brief         Setup the codepath test hooks used by optionally safe bignum functions to signal
+ *                the path taken.
+ */
+void mbedtls_codepath_test_hooks_setup(void);
+
+/**
+ * \brief         Teardown the codepath test hooks used by optionally safe bignum functions to
+ *                signal the path taken.
+ */
+void mbedtls_codepath_test_hooks_teardown(void);
+
+/**
+ * \brief         Reset the state of the codepath to the initial state.
+ */
+static inline void mbedtls_codepath_reset(void)
+{
+    mbedtls_codepath_check = MBEDTLS_MPI_IS_TEST;
+}
+
+/** Check the codepath taken and fail if it doesn't match.
+ *
+ * When a function returns with an error, it can do so before reaching any interesting codepath. The
+ * same can happen if a parameter to the function is zero. In these cases we need to allow
+ * the codepath tracking variable to still have its initial "not set" value.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param path      The expected codepath.
+ *                  This expression may be evaluated multiple times.
+ * \param ret       The expected return value.
+ * \param E         The MPI parameter that can cause shortcuts.
+ */
+#define ASSERT_BIGNUM_CODEPATH(path, ret, E)                            \
+    do {                                                                \
+        if ((ret) != 0 || (E).n == 0) {                                 \
+            TEST_ASSERT(mbedtls_codepath_check == (path) ||             \
+                        mbedtls_codepath_check == MBEDTLS_MPI_IS_TEST); \
+        } else {                                                        \
+            TEST_EQUAL(mbedtls_codepath_check, (path));                 \
+        }                                                               \
+    } while (0)
+
+/** Check the codepath taken and fail if it doesn't match.
+ *
+ * When a function returns with an error, it can do so before reaching any interesting codepath. In
+ * this case we need to allow the codepath tracking variable to still have its
+ * initial "not set" value.
+ *
+ * This macro expands to an instruction, not an expression.
+ * It may jump to the \c exit label.
+ *
+ * \param path      The expected codepath.
+ *                  This expression may be evaluated multiple times.
+ * \param ret       The expected return value.
+ */
+#define ASSERT_RSA_CODEPATH(path, ret)                                  \
+    do {                                                                \
+        if ((ret) != 0) {                                               \
+            TEST_ASSERT(mbedtls_codepath_check == (path) ||             \
+                        mbedtls_codepath_check == MBEDTLS_MPI_IS_TEST); \
+        } else {                                                        \
+            TEST_EQUAL(mbedtls_codepath_check, (path));                 \
+        }                                                               \
+    } while (0)
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
+
+#endif /* BIGNUM_CODEPATH_CHECK_H */
diff --git a/tests/scripts/components-build-system.sh b/tests/scripts/components-build-system.sh
index 4bb41ae..2c2d460 100644
--- a/tests/scripts/components-build-system.sh
+++ b/tests/scripts/components-build-system.sh
@@ -65,7 +65,7 @@
     mkdir "$OUT_OF_SOURCE_DIR"
     cd "$OUT_OF_SOURCE_DIR"
     # Note: Explicitly generate files as these are turned off in releases
-    cmake -D CMAKE_BUILD_TYPE:String=Check -D GEN_FILES=ON _D TEST_CPP=1 "$MBEDTLS_ROOT_DIR"
+    cmake -D CMAKE_BUILD_TYPE:String=Check -D GEN_FILES=ON -D TEST_CPP=1 "$MBEDTLS_ROOT_DIR"
     make
 
     msg "test: cmake 'out-of-source' build"
@@ -108,10 +108,15 @@
     make neat
 
     msg "build: cmake 'as-package' build"
+    root_dir="$(pwd)"
     cd programs/test/cmake_package
+    build_variant_dir="$(pwd)"
     cmake .
     make
     ./cmake_package
+    if [[ "$OSTYPE" == linux* ]]; then
+        PKG_CONFIG_PATH="${build_variant_dir}/mbedtls/pkgconfig" ${root_dir}/tests/scripts/pkgconfig.sh
+    fi
 }
 
 support_test_cmake_as_package () {
diff --git a/tests/scripts/components-configuration-crypto.sh b/tests/scripts/components-configuration-crypto.sh
index 2a770f5..d3741de 100644
--- a/tests/scripts/components-configuration-crypto.sh
+++ b/tests/scripts/components-configuration-crypto.sh
@@ -2288,11 +2288,19 @@
     # MBEDTLS_BLOCK_CIPHER_NO_DECRYPT is incompatible with ECB in PSA, CBC/XTS/NIST_KW/DES,
     # manually set or unset those configurations to check
     # MBEDTLS_BLOCK_CIPHER_NO_DECRYPT with various combinations in aes.o.
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
     scripts/config.py set MBEDTLS_BLOCK_CIPHER_NO_DECRYPT
-    scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
     scripts/config.py unset MBEDTLS_CIPHER_MODE_XTS
-    scripts/config.py unset MBEDTLS_DES_C
     scripts/config.py unset MBEDTLS_NIST_KW_C
+
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CBC_NO_PADDING
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CBC_PKCS7
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECB_NO_PADDING
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DES
+    # Note: The two unsets below are to be removed for Mbed TLS 4.0
+    scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
+    scripts/config.py unset MBEDTLS_DES_C
+
     build_test_config_combos ${BUILTIN_SRC_PATH}/aes.o validate_aes_config_variations \
         "MBEDTLS_AES_ROM_TABLES" \
         "MBEDTLS_AES_FEWER_TABLES" "MBEDTLS_AES_USE_HARDWARE_ONLY" \
@@ -2303,9 +2311,21 @@
     msg "sha3 loop unroll variations"
 
     # define minimal config sufficient to test SHA3
-    cat > include/mbedtls/mbedtls_config.h << END
-        #define MBEDTLS_SELF_TEST
-        #define MBEDTLS_SHA3_C
+     cat > include/mbedtls/mbedtls_config.h << END
+         #define MBEDTLS_AES_C
+         #define MBEDTLS_CTR_DRBG_C
+         #define MBEDTLS_ENTROPY_C
+         #define MBEDTLS_PSA_CRYPTO_C
+         #define MBEDTLS_PSA_CRYPTO_CONFIG
+         #define MBEDTLS_SELF_TEST
+END
+
+    cat > tf-psa-crypto/include/psa/crypto_config.h << END
+        #define PSA_WANT_ALG_SHA_256   1
+        #define PSA_WANT_ALG_SHA3_224  1
+        #define PSA_WANT_ALG_SHA3_256  1
+        #define PSA_WANT_ALG_SHA3_384  1
+        #define PSA_WANT_ALG_SHA3_512  1
 END
 
     msg "all loops unrolled"
@@ -2427,7 +2447,7 @@
     make test
 }
 
-# helper for common_block_cipher_no_decrypt() which:
+# helper for component_test_block_cipher_no_decrypt_aesni() which:
 # - enable/disable the list of config options passed from -s/-u respectively.
 # - build
 # - test for tests_suite_xxx
@@ -2481,13 +2501,32 @@
     programs/test/selftest
 }
 
-# This is a common configuration function used in:
-# - component_test_block_cipher_no_decrypt_aesni_legacy()
-# - component_test_block_cipher_no_decrypt_aesni_use_psa()
-# in order to test BLOCK_CIPHER_NO_DECRYPT with AESNI intrinsics,
-# AESNI assembly and AES C implementation on x86_64 and with AESNI intrinsics
-# on x86.
-common_block_cipher_no_decrypt () {
+# This is a configuration function used in component_test_block_cipher_no_decrypt_xxx:
+config_block_cipher_no_decrypt () {
+    scripts/config.py set MBEDTLS_BLOCK_CIPHER_NO_DECRYPT
+    scripts/config.py unset MBEDTLS_CIPHER_MODE_XTS
+    scripts/config.py unset MBEDTLS_NIST_KW_C
+
+    # Enable support for cryptographic mechanisms through the PSA API.
+    # Note: XTS, KW are not yet supported via the PSA API in Mbed TLS.
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CBC_NO_PADDING
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CBC_PKCS7
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_ECB_NO_PADDING
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_DES
+    # Note: The two unsets below are to be removed for Mbed TLS 4.0
+    scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
+    scripts/config.py unset MBEDTLS_DES_C
+}
+
+component_test_block_cipher_no_decrypt_aesni () {
+    # Test BLOCK_CIPHER_NO_DECRYPT with AESNI intrinsics, AESNI assembly and
+    # AES C implementation on x86_64 and with AESNI intrinsics on x86.
+
+    # This consistently causes an llvm crash on clang 3.8, so use gcc
+    export CC=gcc
+    config_block_cipher_no_decrypt
+
     # test AESNI intrinsics
     helper_block_cipher_no_decrypt_build_test \
         -s "MBEDTLS_AESNI_C" \
@@ -2509,43 +2548,6 @@
         -l "-m32"
 }
 
-# This is a configuration function used in component_test_block_cipher_no_decrypt_xxx:
-# usage: 0: no PSA crypto configuration
-#        1: use PSA crypto configuration
-config_block_cipher_no_decrypt () {
-    use_psa=$1
-
-    scripts/config.py set MBEDTLS_BLOCK_CIPHER_NO_DECRYPT
-    scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
-    scripts/config.py unset MBEDTLS_CIPHER_MODE_XTS
-    scripts/config.py unset MBEDTLS_DES_C
-    scripts/config.py unset MBEDTLS_NIST_KW_C
-
-    if [ "$use_psa" -eq 1 ]; then
-        # Enable support for cryptographic mechanisms through the PSA API.
-        # Note: XTS, KW are not yet supported via the PSA API in Mbed TLS.
-        scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
-        scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CBC_NO_PADDING
-        scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CBC_PKCS7
-        scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_ECB_NO_PADDING
-        scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_DES
-    fi
-}
-
-component_test_block_cipher_no_decrypt_aesni () {
-    # This consistently causes an llvm crash on clang 3.8, so use gcc
-    export CC=gcc
-    config_block_cipher_no_decrypt 0
-    common_block_cipher_no_decrypt
-}
-
-component_test_block_cipher_no_decrypt_aesni_use_psa () {
-    # This consistently causes an llvm crash on clang 3.8, so use gcc
-    export CC=gcc
-    config_block_cipher_no_decrypt 1
-    common_block_cipher_no_decrypt
-}
-
 support_test_block_cipher_no_decrypt_aesce_armcc () {
     support_build_armcc
 }
@@ -2565,7 +2567,7 @@
     scripts/config.py unset MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
     scripts/config.py set MBEDTLS_HAVE_ASM
 
-    config_block_cipher_no_decrypt 1
+    config_block_cipher_no_decrypt
 
     # test AESCE baremetal build
     scripts/config.py set MBEDTLS_AESCE_C
diff --git a/tests/scripts/components-configuration-tls.sh b/tests/scripts/components-configuration-tls.sh
index f936042..d81303b 100644
--- a/tests/scripts/components-configuration-tls.sh
+++ b/tests/scripts/components-configuration-tls.sh
@@ -404,15 +404,35 @@
     msg "build: TLS 1.3 only from default, only PSK key exchange mode"
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
-    scripts/config.py unset MBEDTLS_ECDH_C
-    scripts/config.py unset MBEDTLS_DHM_C
     scripts/config.py unset MBEDTLS_X509_CRT_PARSE_C
     scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
-    scripts/config.py unset MBEDTLS_ECDSA_C
-    scripts/config.py unset MBEDTLS_PKCS1_V21
     scripts/config.py unset MBEDTLS_PKCS7_C
     scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDH
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_OAEP
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_PSS
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_FFDH
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_DH_RFC7919_2048
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_DH_RFC7919_3072
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_DH_RFC7919_4096
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_DH_RFC7919_6144
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_DH_RFC7919_8192
+    # Note: The four unsets below are to be removed for Mbed TLS 4.0
+    scripts/config.py unset MBEDTLS_ECDH_C
+    scripts/config.py unset MBEDTLS_ECDSA_C
+    scripts/config.py unset MBEDTLS_PKCS1_V21
+    scripts/config.py unset MBEDTLS_DHM_C
+
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, only PSK key exchange mode enabled"
@@ -441,6 +461,10 @@
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
     scripts/config.py unset MBEDTLS_SSL_EARLY_DATA
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDH
+    # Note: The unset below is to be removed for Mbed TLS 4.0
     scripts/config.py unset MBEDTLS_ECDH_C
 
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
@@ -459,10 +483,18 @@
     scripts/config.py unset MBEDTLS_X509_CRT_PARSE_C
     scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
-    scripts/config.py unset MBEDTLS_ECDSA_C
-    scripts/config.py unset MBEDTLS_PKCS1_V21
     scripts/config.py unset MBEDTLS_PKCS7_C
     scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_OAEP
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_PSS
+    # Note: The two unsets below are to be removed for Mbed TLS 4.0
+    scripts/config.py unset MBEDTLS_ECDSA_C
+    scripts/config.py unset MBEDTLS_PKCS1_V21
+
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, only PSK ephemeral key exchange mode"
@@ -479,11 +511,20 @@
     scripts/config.py unset MBEDTLS_X509_CRT_PARSE_C
     scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
-    scripts/config.py unset MBEDTLS_ECDSA_C
-    scripts/config.py unset MBEDTLS_PKCS1_V21
     scripts/config.py unset MBEDTLS_PKCS7_C
     scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDH
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_OAEP
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_PSS
+    # Note: The three unsets below are to be removed for Mbed TLS 4.0
     scripts/config.py unset MBEDTLS_ECDH_C
+    scripts/config.py unset MBEDTLS_ECDSA_C
+    scripts/config.py unset MBEDTLS_PKCS1_V21
+
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, only PSK ephemeral ffdh key exchange mode"
@@ -499,10 +540,18 @@
     scripts/config.py unset MBEDTLS_X509_CRT_PARSE_C
     scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
-    scripts/config.py unset MBEDTLS_ECDSA_C
-    scripts/config.py unset MBEDTLS_PKCS1_V21
     scripts/config.py unset MBEDTLS_PKCS7_C
     scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_OAEP
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_RSA_PSS
+    # Note: The two unsets below are to be removed for Mbed TLS 4.0
+    scripts/config.py unset MBEDTLS_ECDSA_C
+    scripts/config.py unset MBEDTLS_PKCS1_V21
+
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, PSK and PSK ephemeral key exchange modes"
diff --git a/tests/scripts/pkgconfig.sh b/tests/scripts/pkgconfig.sh
new file mode 100755
index 0000000..2702bfa
--- /dev/null
+++ b/tests/scripts/pkgconfig.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Purpose
+#
+# Test pkgconfig files.
+#
+# For each of the build pkg-config files, .pc files, check that
+# they validate and do some basic sanity testing on the output,
+# i.e. that the strings are non-empty.
+#
+# NOTE: This requires the built pc files to be on the pkg-config
+# search path, this can be controlled with env variable
+# PKG_CONFIG_PATH. See man(1) pkg-config for details.
+#
+
+set -e -u
+
+# These are the EXPECTED package names. Renaming these could break
+# consumers of pkg-config, consider carefully.
+all_pcs="mbedtls mbedx509 mbedcrypto"
+
+for pc in $all_pcs; do
+    printf "testing package config file: ${pc} ... "
+    pkg-config --validate "${pc}"
+    version="$(pkg-config --modversion "${pc}")"
+    test -n "$version"
+    cflags="$(pkg-config --cflags "${pc}")"
+    test -n "$cflags"
+    libs="$(pkg-config --libs "${pc}")"
+    test -n "$libs"
+    printf "passed\n"
+done
+
+exit 0
diff --git a/tests/src/bignum_codepath_check.c b/tests/src/bignum_codepath_check.c
new file mode 100644
index 0000000..b752d13
--- /dev/null
+++ b/tests/src/bignum_codepath_check.c
@@ -0,0 +1,38 @@
+/** Support for path tracking in optionally safe bignum functions
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "test/bignum_codepath_check.h"
+#include "bignum_core_invasive.h"
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+int mbedtls_codepath_check = MBEDTLS_MPI_IS_TEST;
+
+void mbedtls_codepath_take_safe(void)
+{
+    if (mbedtls_codepath_check == MBEDTLS_MPI_IS_TEST) {
+        mbedtls_codepath_check = MBEDTLS_MPI_IS_SECRET;
+    }
+}
+
+void mbedtls_codepath_take_unsafe(void)
+{
+    mbedtls_codepath_check = MBEDTLS_MPI_IS_PUBLIC;
+}
+
+void mbedtls_codepath_test_hooks_setup(void)
+{
+    mbedtls_safe_codepath_hook = mbedtls_codepath_take_safe;
+    mbedtls_unsafe_codepath_hook = mbedtls_codepath_take_unsafe;
+}
+
+void mbedtls_codepath_test_hooks_teardown(void)
+{
+    mbedtls_safe_codepath_hook = NULL;
+    mbedtls_unsafe_codepath_hook = NULL;
+}
+
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index 065d17d..db50296 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -16,6 +16,9 @@
 #if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C)
 #include <test/psa_memory_poisoning_wrappers.h>
 #endif
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+#include <test/bignum_codepath_check.h>
+#endif
 #if defined(MBEDTLS_THREADING_C)
 #include "mbedtls/threading.h"
 #endif
@@ -342,6 +345,11 @@
     mbedtls_mutex_init(&mbedtls_test_info_mutex);
 #endif /* MBEDTLS_THREADING_C */
 
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_test_hooks_setup();
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
+
     return ret;
 }
 
@@ -359,6 +367,10 @@
 #if defined(MBEDTLS_PLATFORM_C)
     mbedtls_platform_teardown(&platform_ctx);
 #endif /* MBEDTLS_PLATFORM_C */
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_test_hooks_teardown();
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
 }
 
 int mbedtls_test_ascii2uc(const char c, unsigned char *uc)
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 6afc26a..beb9aa5 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -273,31 +273,39 @@
 }
 
 requires_all_configs_enabled() {
-    if ! $P_QUERY -all $* 2>&1 > /dev/null
-    then
-        SKIP_NEXT="YES"
-    fi
+    for x in "$@"; do
+        if ! is_config_enabled "$x"; then
+            SKIP_NEXT="YES"
+            return
+        fi
+    done
 }
 
 requires_all_configs_disabled() {
-    if $P_QUERY -any $* 2>&1 > /dev/null
-    then
-        SKIP_NEXT="YES"
-    fi
+    for x in "$@"; do
+        if is_config_enabled "$x"; then
+            SKIP_NEXT="YES"
+            return
+        fi
+    done
 }
 
 requires_any_configs_enabled() {
-    if ! $P_QUERY -any $* 2>&1 > /dev/null
-    then
-        SKIP_NEXT="YES"
-    fi
+    for x in "$@"; do
+        if is_config_enabled "$x"; then
+            return
+        fi
+    done
+    SKIP_NEXT="YES"
 }
 
 requires_any_configs_disabled() {
-    if $P_QUERY -all $* 2>&1 > /dev/null
-    then
-        SKIP_NEXT="YES"
-    fi
+    for x in "$@"; do
+        if ! is_config_enabled "$x"; then
+            return
+        fi
+    done
+    SKIP_NEXT="YES"
 }
 
 TLS1_2_KEY_EXCHANGES_WITH_CERT="MBEDTLS_KEY_EXCHANGE_RSA_ENABLED \
@@ -317,13 +325,14 @@
                                        MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED \
                                        MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled() {
-    if $P_QUERY -all MBEDTLS_SSL_PROTO_TLS1_2
+requires_certificate_authentication () {
+    if is_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
     then
+        # TLS 1.3 is negotiated by default, so check whether it supports
+        # certificate-based authentication.
+        requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
+    else # Only TLS 1.2 is enabled.
         requires_any_configs_enabled $TLS1_2_KEY_EXCHANGES_WITH_CERT
-    elif ! $P_QUERY -all MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
-    then
-        SKIP_NEXT="YES"
     fi
 }
 
@@ -475,10 +484,19 @@
             requires_config_enabled MBEDTLS_SSL_ALPN;;
     esac
 
+    case " $CMD_LINE " in
+         *\ auth_mode=*|*[-_\ =]crt[_=]*)
+            # The test case involves certificates (crt), or a relevant
+            # aspect of it is the (certificate-based) authentication mode.
+            requires_certificate_authentication;;
+    esac
+
     case "$CMD_LINE" in
+        *[-_\ =]psk*|*[-_\ =]PSK*) :;; # No certificate requirement with PSK
         */server5*|\
         */server7*|\
         */dir-maxpath*)
+            requires_certificate_authentication
             if [ "$TLS_VERSION" = "TLS13" ]; then
                 # In case of TLS13 the support for ECDSA is enough
                 requires_pk_alg "ECDSA"
@@ -510,9 +528,11 @@
     esac
 
     case "$CMD_LINE" in
+        *[-_\ =]psk*|*[-_\ =]PSK*) :;; # No certificate requirement with PSK
         */server1*|\
         */server2*|\
         */server7*)
+            requires_certificate_authentication
             # Certificates with an RSA key. The algorithm requirement is
             # some subset of {PKCS#1v1.5 encryption, PKCS#1v1.5 signature,
             # PSS signature}. We can't easily tell which subset works, and
@@ -525,17 +545,12 @@
     unset tmp
 }
 
-requires_certificate_authentication () {
-    if [ "$PSK_ONLY" = "YES" ]; then
-        SKIP_NEXT="YES"
-    fi
-}
-
 adapt_cmd_for_psk () {
     case "$2" in
         *openssl*s_server*) s='-psk 73776f726466697368 -nocert';;
         *openssl*) s='-psk 73776f726466697368';;
-        *gnutls-*) s='--pskusername=Client_identity --pskkey=73776f726466697368';;
+        *gnutls-cli*) s='--pskusername=Client_identity --pskkey=73776f726466697368';;
+        *gnutls-serv*) s='--pskpasswd=../framework/data_files/simplepass.psk';;
         *) s='psk=73776f726466697368';;
     esac
     eval $1='"$2 $s"'
@@ -586,14 +601,28 @@
     adapt_cmd_for_psk SRV_CMD "$SRV_CMD"
 }
 
-case " $CONFIGS_ENABLED " in
-    *\ MBEDTLS_KEY_EXCHANGE_[^P]*) PSK_ONLY="NO";;
-    *\ MBEDTLS_KEY_EXCHANGE_P[^S]*) PSK_ONLY="NO";;
-    *\ MBEDTLS_KEY_EXCHANGE_PS[^K]*) PSK_ONLY="NO";;
-    *\ MBEDTLS_KEY_EXCHANGE_PSK[^_]*) PSK_ONLY="NO";;
-    *\ MBEDTLS_KEY_EXCHANGE_PSK_ENABLED\ *) PSK_ONLY="YES";;
-    *) PSK_ONLY="NO";;
-esac
+# PSK_PRESENT="YES" if at least one protocol versions supports at least
+# one PSK key exchange mode.
+PSK_PRESENT="NO"
+# PSK_ONLY="YES" if all the available key exchange modes are PSK-based
+# (pure-PSK or PSK-ephemeral, possibly both).
+PSK_ONLY=""
+for c in $CONFIGS_ENABLED; do
+    case $c in
+        MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) PSK_PRESENT="YES";;
+        MBEDTLS_KEY_EXCHANGE_*_PSK_ENABLED) PSK_PRESENT="YES";;
+        MBEDTLS_KEY_EXCHANGE_*_ENABLED) PSK_ONLY="NO";;
+        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) PSK_PRESENT="YES";;
+        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_*_ENABLED) PSK_PRESENT="YES";;
+        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_*_ENABLED) PSK_ONLY="NO";;
+    esac
+done
+# At this stage, $PSK_ONLY is empty if we haven't detected a non-PSK
+# key exchange, i.e. if we're in a PSK-only build or a build with no
+# key exchanges at all. We avoid triggering PSK-only adaptation code in
+# the edge case of no key exchanges.
+: ${PSK_ONLY:=$PSK_PRESENT}
+unset c
 
 HAS_ALG_MD5="NO"
 HAS_ALG_SHA_1="NO"
@@ -795,6 +824,14 @@
     fi
 }
 
+# OpenSSL servers forbid client renegotiation by default since OpenSSL 3.0.
+# Older versions always allow it and have no command-line option.
+OPENSSL_S_SERVER_CLIENT_RENEGOTIATION=
+case $($OPENSSL s_server -help 2>&1) in
+    *-client_renegotiation*)
+        OPENSSL_S_SERVER_CLIENT_RENEGOTIATION=-client_renegotiation;;
+esac
+
 # skip next test if tls1_3 is not available
 requires_gnutls_tls1_3() {
     requires_gnutls_next
@@ -1645,7 +1682,7 @@
     esac
     # Third if the version is not forced, if TLS 1.3 is enabled then the test
     # is aimed to run a TLS 1.3 handshake.
-    if $P_QUERY -all MBEDTLS_SSL_PROTO_TLS1_3
+    if is_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
     then
         echo "TLS13"
     else
@@ -1731,14 +1768,14 @@
         TLS_VERSION="TLS12"
     fi
 
+    # If we're in a PSK-only build and the test can be adapted to PSK, do that.
+    maybe_adapt_for_psk "$@"
+
     # If the client or server requires certain features that can be detected
     # from their command-line arguments, check whether they're enabled.
     detect_required_features "$SRV_CMD" "server" "$TLS_VERSION" "$EXT_WO_ECDH" "$@"
     detect_required_features "$CLI_CMD" "client" "$TLS_VERSION" "$EXT_WO_ECDH" "$@"
 
-    # If we're in a PSK-only build and the test can be adapted to PSK, do that.
-    maybe_adapt_for_psk "$@"
-
     # should we skip?
     if [ "X$SKIP_NEXT" = "XYES" ]; then
         SKIP_NEXT="NO"
@@ -2070,8 +2107,8 @@
 # - the expected parameters are selected
 requires_ciphersuite_enabled TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256
 requires_hash_alg SHA_512 # "signature_algorithm ext: 6"
-requires_any_configs_enabled "MBEDTLS_ECP_DP_CURVE25519_ENABLED \
-                              PSA_WANT_ECC_MONTGOMERY_255"
+requires_any_configs_enabled MBEDTLS_ECP_DP_CURVE25519_ENABLED \
+                             PSA_WANT_ECC_MONTGOMERY_255
 run_test    "Default, TLS 1.2" \
             "$P_SRV debug_level=3" \
             "$P_CLI force_version=tls12" \
@@ -2092,7 +2129,6 @@
             -s "Protocol is DTLSv1.2" \
             -s "Ciphersuite is TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "TLS client auth: required" \
             "$P_SRV auth_mode=required" \
             "$P_CLI" \
@@ -2696,8 +2732,8 @@
             -U "IV used"
 
 # Test for correctness of sent single supported algorithm
-requires_any_configs_enabled "MBEDTLS_ECP_DP_SECP256R1_ENABLED \
-                              PSA_WANT_ECC_SECP_R1_256"
+requires_any_configs_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED \
+                             PSA_WANT_ECC_SECP_R1_256
 requires_config_enabled MBEDTLS_DEBUG_C
 requires_config_enabled MBEDTLS_SSL_CLI_C
 requires_config_enabled MBEDTLS_SSL_SRV_C
@@ -2712,8 +2748,8 @@
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_SSL_SRV_C
-requires_any_configs_enabled "MBEDTLS_ECP_DP_SECP256R1_ENABLED \
-                              PSA_WANT_ECC_SECP_R1_256"
+requires_any_configs_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED \
+                             PSA_WANT_ECC_SECP_R1_256
 requires_hash_alg SHA_256
 run_test    "Single supported algorithm sending: openssl client" \
             "$P_SRV sig_algs=ecdsa_secp256r1_sha256 auth_mode=required" \
@@ -2722,7 +2758,6 @@
             0
 
 # Tests for certificate verification callback
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Configuration-specific CRT verification callback" \
             "$P_SRV debug_level=3" \
             "$P_CLI context_crt_cb=0 debug_level=3" \
@@ -2733,7 +2768,6 @@
             -C "Use context-specific verification callback" \
             -C "error"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Context-specific CRT verification callback" \
             "$P_SRV debug_level=3" \
             "$P_CLI context_crt_cb=1 debug_level=3" \
@@ -5550,7 +5584,7 @@
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "Renegotiation: openssl server, client-initiated" \
-            "$O_SRV -www -tls1_2" \
+            "$O_SRV -www $OPENSSL_S_SERVER_CLIENT_RENEGOTIATION -tls1_2" \
             "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \
             0 \
             -c "client hello, adding renegotiation extension" \
@@ -5812,7 +5846,6 @@
 # When updating these tests, modify the matching authentication tests accordingly
 
 # The next 4 cases test the 3 auth modes with a badly signed server cert.
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: server badcert, client required" \
             "$P_SRV crt_file=$DATA_FILES_PATH/server5-badsign.crt \
              key_file=$DATA_FILES_PATH/server5.key" \
@@ -5884,7 +5917,6 @@
             -C "send alert level=2 message=48" \
             -C "X509 - Certificate verification failed"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: server goodcert, client required, no trusted CA" \
             "$P_SRV" \
             "$P_CLI debug_level=3 auth_mode=required ca_file=none ca_path=none" \
@@ -5906,7 +5938,6 @@
             -c "! mbedtls_ssl_handshake returned" \
             -c "SSL - No CA Chain is set, but required to operate"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: server goodcert, client optional, no trusted CA" \
             "$P_SRV" \
             "$P_CLI debug_level=3 auth_mode=optional ca_file=none ca_path=none" \
@@ -5930,7 +5961,6 @@
             -C "X509 - Certificate verification failed" \
             -C "SSL - No CA Chain is set, but required to operate"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: server goodcert, client none, no trusted CA" \
             "$P_SRV" \
             "$P_CLI debug_level=3 auth_mode=none ca_file=none ca_path=none" \
@@ -5999,7 +6029,6 @@
             -c "Supported Signature Algorithm found: 04 " \
             -c "Supported Signature Algorithm found: 05 "
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client has no cert, server required (TLS)" \
             "$P_SRV debug_level=3 auth_mode=required" \
             "$P_CLI debug_level=3 crt_file=none \
@@ -6015,7 +6044,6 @@
             -s "! mbedtls_ssl_handshake returned" \
             -s "No client certification received from the client, but required by the authentication mode"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client badcert, server required" \
             "$P_SRV debug_level=3 auth_mode=required" \
             "$P_CLI debug_level=3 crt_file=$DATA_FILES_PATH/server5-badsign.crt \
@@ -6036,7 +6064,6 @@
 # detect that its write end of the connection is closed and abort
 # before reading the alert message.
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client cert self-signed and trusted, server required" \
             "$P_SRV debug_level=3 auth_mode=required ca_file=$DATA_FILES_PATH/server5-selfsigned.crt" \
             "$P_CLI debug_level=3 crt_file=$DATA_FILES_PATH/server5-selfsigned.crt \
@@ -6052,7 +6079,6 @@
             -S "! The certificate is not correctly signed" \
             -S "X509 - Certificate verification failed"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client cert not trusted, server required" \
             "$P_SRV debug_level=3 auth_mode=required" \
             "$P_CLI debug_level=3 crt_file=$DATA_FILES_PATH/server5-selfsigned.crt \
@@ -6069,7 +6095,6 @@
             -s "! mbedtls_ssl_handshake returned" \
             -s "X509 - Certificate verification failed"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client badcert, server optional" \
             "$P_SRV debug_level=3 auth_mode=optional" \
             "$P_CLI debug_level=3 crt_file=$DATA_FILES_PATH/server5-badsign.crt \
@@ -6087,7 +6112,6 @@
             -C "! mbedtls_ssl_handshake returned" \
             -S "X509 - Certificate verification failed"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client badcert, server none" \
             "$P_SRV debug_level=3 auth_mode=none" \
             "$P_CLI debug_level=3 crt_file=$DATA_FILES_PATH/server5-badsign.crt \
@@ -6105,7 +6129,6 @@
             -C "! mbedtls_ssl_handshake returned" \
             -S "X509 - Certificate verification failed"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client no cert, server optional" \
             "$P_SRV debug_level=3 auth_mode=optional" \
             "$P_CLI debug_level=3 crt_file=none key_file=none" \
@@ -6123,7 +6146,6 @@
             -S "X509 - Certificate verification failed"
 
 requires_openssl_tls1_3_with_compatible_ephemeral
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: openssl client no cert, server optional" \
             "$P_SRV debug_level=3 auth_mode=optional" \
             "$O_NEXT_CLI_NO_CERT -no_middlebox" \
@@ -6537,7 +6559,6 @@
 # tests for SNI
 
 requires_config_disabled MBEDTLS_X509_REMOVE_INFO
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: no SNI callback" \
             "$P_SRV debug_level=3 \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key" \
@@ -6547,7 +6568,6 @@
             -c "subject name *: C=NL, O=PolarSSL, CN=localhost"
 
 requires_config_disabled MBEDTLS_X509_REMOVE_INFO
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: matching cert 1" \
             "$P_SRV debug_level=3 \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6559,7 +6579,6 @@
             -c "subject name *: C=NL, O=PolarSSL, CN=localhost"
 
 requires_config_disabled MBEDTLS_X509_REMOVE_INFO
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: matching cert 2" \
             "$P_SRV debug_level=3 \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6571,7 +6590,6 @@
             -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example"
 
 requires_config_disabled MBEDTLS_X509_REMOVE_INFO
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: no matching cert" \
             "$P_SRV debug_level=3 \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6584,7 +6602,6 @@
             -c "mbedtls_ssl_handshake returned" \
             -c "SSL - A fatal alert message was received from our peer"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: client auth no override: optional" \
             "$P_SRV debug_level=3 auth_mode=optional \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6598,7 +6615,6 @@
             -C "skip write certificate verify" \
             -S "skip parse certificate verify"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: client auth override: none -> optional" \
             "$P_SRV debug_level=3 auth_mode=none \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6612,7 +6628,6 @@
             -C "skip write certificate verify" \
             -S "skip parse certificate verify"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: client auth override: optional -> none" \
             "$P_SRV debug_level=3 auth_mode=optional \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6624,7 +6639,6 @@
             -c "got no certificate request" \
             -c "skip write certificate"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: CA no override" \
             "$P_SRV debug_level=3 auth_mode=optional \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6643,7 +6657,6 @@
             -s "! The certificate is not correctly signed by the trusted CA" \
             -S "The certificate has been revoked (is on a CRL)"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: CA override" \
             "$P_SRV debug_level=3 auth_mode=optional \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6662,7 +6675,6 @@
             -S "! The certificate is not correctly signed by the trusted CA" \
             -S "The certificate has been revoked (is on a CRL)"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "SNI: CA override with CRL" \
             "$P_SRV debug_level=3 auth_mode=optional \
              crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
@@ -6835,7 +6847,6 @@
 
 # Tests for non-blocking I/O: exercise a variety of handshake flows
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Non-blocking I/O: basic handshake" \
             "$P_SRV nbio=2 tickets=0 auth_mode=none" \
             "$P_CLI nbio=2 tickets=0" \
@@ -6844,7 +6855,6 @@
             -C "mbedtls_ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Non-blocking I/O: client auth" \
             "$P_SRV nbio=2 tickets=0 auth_mode=required" \
             "$P_CLI nbio=2 tickets=0" \
@@ -6853,7 +6863,6 @@
             -C "mbedtls_ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
 run_test    "Non-blocking I/O: ticket" \
             "$P_SRV nbio=2 tickets=1 auth_mode=none" \
@@ -6863,7 +6872,6 @@
             -C "mbedtls_ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
 run_test    "Non-blocking I/O: ticket + client auth" \
             "$P_SRV nbio=2 tickets=1 auth_mode=required" \
@@ -6928,7 +6936,6 @@
 
 # Tests for event-driven I/O: exercise a variety of handshake flows
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Event-driven I/O: basic handshake" \
             "$P_SRV event=1 tickets=0 auth_mode=none" \
             "$P_CLI event=1 tickets=0" \
@@ -6937,7 +6944,6 @@
             -C "mbedtls_ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Event-driven I/O: client auth" \
             "$P_SRV event=1 tickets=0 auth_mode=required" \
             "$P_CLI event=1 tickets=0" \
@@ -6946,7 +6952,6 @@
             -C "mbedtls_ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
 run_test    "Event-driven I/O: ticket" \
             "$P_SRV event=1 tickets=1 auth_mode=none" \
@@ -6956,7 +6961,6 @@
             -C "mbedtls_ssl_handshake returned" \
             -c "Read from server: .* bytes read"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
 run_test    "Event-driven I/O: ticket + client auth" \
             "$P_SRV event=1 tickets=1 auth_mode=required" \
@@ -7651,7 +7655,6 @@
 
 # Tests for ALPN extension
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: none" \
             "$P_SRV debug_level=3" \
             "$P_CLI debug_level=3" \
@@ -7664,7 +7667,6 @@
             -C "Application Layer Protocol is" \
             -S "Application Layer Protocol is"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: client only" \
             "$P_SRV debug_level=3" \
             "$P_CLI debug_level=3 alpn=abc,1234" \
@@ -7677,7 +7679,6 @@
             -c "Application Layer Protocol is (none)" \
             -S "Application Layer Protocol is"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: server only" \
             "$P_SRV debug_level=3 alpn=abc,1234" \
             "$P_CLI debug_level=3" \
@@ -7690,7 +7691,6 @@
             -C "Application Layer Protocol is" \
             -s "Application Layer Protocol is (none)"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: both, common cli1-srv1" \
             "$P_SRV debug_level=3 alpn=abc,1234" \
             "$P_CLI debug_level=3 alpn=abc,1234" \
@@ -7703,7 +7703,6 @@
             -c "Application Layer Protocol is abc" \
             -s "Application Layer Protocol is abc"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: both, common cli2-srv1" \
             "$P_SRV debug_level=3 alpn=abc,1234" \
             "$P_CLI debug_level=3 alpn=1234,abc" \
@@ -7716,7 +7715,6 @@
             -c "Application Layer Protocol is abc" \
             -s "Application Layer Protocol is abc"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: both, common cli1-srv2" \
             "$P_SRV debug_level=3 alpn=abc,1234" \
             "$P_CLI debug_level=3 alpn=1234,abcde" \
@@ -7729,7 +7727,6 @@
             -c "Application Layer Protocol is 1234" \
             -s "Application Layer Protocol is 1234"
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "ALPN: both, no common" \
             "$P_SRV debug_level=3 alpn=abc,123" \
             "$P_CLI debug_level=3 alpn=1234,abcde" \
@@ -8161,28 +8158,24 @@
 
 # Tests for extendedKeyUsage, part 1: server-side certificate/suite selection
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "extKeyUsage srv: serverAuth -> OK" \
             "$P_SRV key_file=$DATA_FILES_PATH/server5.key \
              crt_file=$DATA_FILES_PATH/server5.eku-srv.crt" \
             "$P_CLI" \
             0
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "extKeyUsage srv: serverAuth,clientAuth -> OK" \
             "$P_SRV key_file=$DATA_FILES_PATH/server5.key \
              crt_file=$DATA_FILES_PATH/server5.eku-srv.crt" \
             "$P_CLI" \
             0
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "extKeyUsage srv: codeSign,anyEKU -> OK" \
             "$P_SRV key_file=$DATA_FILES_PATH/server5.key \
              crt_file=$DATA_FILES_PATH/server5.eku-cs_any.crt" \
             "$P_CLI" \
             0
 
-requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "extKeyUsage srv: codeSign -> fail" \
             "$P_SRV key_file=$DATA_FILES_PATH/server5.key \
              crt_file=$DATA_FILES_PATH/server5.eku-cli.crt" \
@@ -12262,7 +12255,7 @@
 client_needs_more_time 2
 run_test    "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \
+            "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 \
              psk=73776f726466697368" \
             "$P_CLI dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 psk=73776f726466697368 \
              force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/bignum.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/bignum.h
index 71d7b97..8367cd3 100644
--- a/tf-psa-crypto/drivers/builtin/include/mbedtls/bignum.h
+++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/bignum.h
@@ -880,7 +880,7 @@
                         mbedtls_mpi_sint b);
 
 /**
- * \brief          Perform a sliding-window exponentiation: X = A^E mod N
+ * \brief          Perform a modular exponentiation: X = A^E mod N
  *
  * \param X        The destination MPI. This must point to an initialized MPI.
  *                 This must not alias E or N.
diff --git a/tf-psa-crypto/drivers/builtin/src/bignum.c b/tf-psa-crypto/drivers/builtin/src/bignum.c
index c45fd5b..4244909 100644
--- a/tf-psa-crypto/drivers/builtin/src/bignum.c
+++ b/tf-psa-crypto/drivers/builtin/src/bignum.c
@@ -27,6 +27,7 @@
 
 #include "mbedtls/bignum.h"
 #include "bignum_core.h"
+#include "bignum_internal.h"
 #include "bn_mul.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
@@ -1610,9 +1611,13 @@
     return 0;
 }
 
-int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
-                        const mbedtls_mpi *E, const mbedtls_mpi *N,
-                        mbedtls_mpi *prec_RR)
+/*
+ * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
+ * this function is not constant time with respect to the exponent (parameter E).
+ */
+static int mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi *X, const mbedtls_mpi *A,
+                                               const mbedtls_mpi *E, int E_public,
+                                               const mbedtls_mpi *N, mbedtls_mpi *prec_RR)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
@@ -1695,7 +1700,11 @@
     {
         mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p);
         mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T);
-        mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
+        if (E_public == MBEDTLS_MPI_IS_PUBLIC) {
+            mbedtls_mpi_core_exp_mod_unsafe(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
+        } else {
+            mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T);
+        }
         mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T);
     }
 
@@ -1720,6 +1729,20 @@
     return ret;
 }
 
+int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
+                        const mbedtls_mpi *E, const mbedtls_mpi *N,
+                        mbedtls_mpi *prec_RR)
+{
+    return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_SECRET, N, prec_RR);
+}
+
+int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A,
+                               const mbedtls_mpi *E, const mbedtls_mpi *N,
+                               mbedtls_mpi *prec_RR)
+{
+    return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_PUBLIC, N, prec_RR);
+}
+
 /*
  * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
  */
diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_core.c b/tf-psa-crypto/drivers/builtin/src/bignum_core.c
index 39ab6e9..60f48f9 100644
--- a/tf-psa-crypto/drivers/builtin/src/bignum_core.c
+++ b/tf-psa-crypto/drivers/builtin/src/bignum_core.c
@@ -747,8 +747,96 @@
     }
 }
 
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+void (*mbedtls_safe_codepath_hook)(void) = NULL;
+void (*mbedtls_unsafe_codepath_hook)(void) = NULL;
+#endif
+
+/*
+ * This function calculates the indices of the exponent where the exponentiation algorithm should
+ * start processing.
+ *
+ * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
+ * this function is not constant time with respect to the exponent (parameter E).
+ */
+static inline void exp_mod_calc_first_bit_optionally_safe(const mbedtls_mpi_uint *E,
+                                                          size_t E_limbs,
+                                                          int E_public,
+                                                          size_t *E_limb_index,
+                                                          size_t *E_bit_index)
+{
+    if (E_public == MBEDTLS_MPI_IS_PUBLIC) {
+        /*
+         * Skip leading zero bits.
+         */
+        size_t E_bits = mbedtls_mpi_core_bitlen(E, E_limbs);
+        if (E_bits == 0) {
+            /*
+             * If E is 0 mbedtls_mpi_core_bitlen() returns 0. Even if that is the case, we will want
+             * to represent it as a single 0 bit and as such the bitlength will be 1.
+             */
+            E_bits = 1;
+        }
+
+        *E_limb_index = E_bits / biL;
+        *E_bit_index = E_bits % biL;
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+        if (mbedtls_unsafe_codepath_hook != NULL) {
+            mbedtls_unsafe_codepath_hook();
+        }
+#endif
+    } else {
+        /*
+         * Here we need to be constant time with respect to E and can't do anything better than
+         * start at the first allocated bit.
+         */
+        *E_limb_index = E_limbs;
+        *E_bit_index = 0;
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+        if (mbedtls_safe_codepath_hook != NULL) {
+            mbedtls_safe_codepath_hook();
+        }
+#endif
+    }
+}
+
+/*
+ * Warning! If the parameter window_public has MBEDTLS_MPI_IS_PUBLIC as its value, this function is
+ * not constant time with respect to the window parameter and consequently the exponent of the
+ * exponentiation (parameter E of mbedtls_mpi_core_exp_mod_optionally_safe).
+ */
+static inline void exp_mod_table_lookup_optionally_safe(mbedtls_mpi_uint *Wselect,
+                                                        mbedtls_mpi_uint *Wtable,
+                                                        size_t AN_limbs, size_t welem,
+                                                        mbedtls_mpi_uint window,
+                                                        int window_public)
+{
+    if (window_public == MBEDTLS_MPI_IS_PUBLIC) {
+        memcpy(Wselect, Wtable + window * AN_limbs, AN_limbs * ciL);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+        if (mbedtls_unsafe_codepath_hook != NULL) {
+            mbedtls_unsafe_codepath_hook();
+        }
+#endif
+    } else {
+        /* Select Wtable[window] without leaking window through
+         * memory access patterns. */
+        mbedtls_mpi_core_ct_uint_table_lookup(Wselect, Wtable,
+                                              AN_limbs, welem, window);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+        if (mbedtls_safe_codepath_hook != NULL) {
+            mbedtls_safe_codepath_hook();
+        }
+#endif
+    }
+}
+
 /* Exponentiation: X := A^E mod N.
  *
+ * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value,
+ * this function is not constant time with respect to the exponent (parameter E).
+ *
  * A must already be in Montgomery form.
  *
  * As in other bignum functions, assume that AN_limbs and E_limbs are nonzero.
@@ -759,16 +847,25 @@
  * (The difference is that the body in our loop processes a single bit instead
  * of a full window.)
  */
-void mbedtls_mpi_core_exp_mod(mbedtls_mpi_uint *X,
-                              const mbedtls_mpi_uint *A,
-                              const mbedtls_mpi_uint *N,
-                              size_t AN_limbs,
-                              const mbedtls_mpi_uint *E,
-                              size_t E_limbs,
-                              const mbedtls_mpi_uint *RR,
-                              mbedtls_mpi_uint *T)
+static void mbedtls_mpi_core_exp_mod_optionally_safe(mbedtls_mpi_uint *X,
+                                                     const mbedtls_mpi_uint *A,
+                                                     const mbedtls_mpi_uint *N,
+                                                     size_t AN_limbs,
+                                                     const mbedtls_mpi_uint *E,
+                                                     size_t E_limbs,
+                                                     int E_public,
+                                                     const mbedtls_mpi_uint *RR,
+                                                     mbedtls_mpi_uint *T)
 {
-    const size_t wsize = exp_mod_get_window_size(E_limbs * biL);
+    /* We'll process the bits of E from most significant
+     * (limb_index=E_limbs-1, E_bit_index=biL-1) to least significant
+     * (limb_index=0, E_bit_index=0). */
+    size_t E_limb_index = E_limbs;
+    size_t E_bit_index = 0;
+    exp_mod_calc_first_bit_optionally_safe(E, E_limbs, E_public,
+                                           &E_limb_index, &E_bit_index);
+
+    const size_t wsize = exp_mod_get_window_size(E_limb_index * biL);
     const size_t welem = ((size_t) 1) << wsize;
 
     /* This is how we will use the temporary storage T, which must have space
@@ -787,7 +884,7 @@
 
     const mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N);
 
-    /* Set Wtable[i] = A^(2^i) (in Montgomery representation) */
+    /* Set Wtable[i] = A^i (in Montgomery representation) */
     exp_mod_precompute_window(A, N, AN_limbs,
                               mm, RR,
                               welem, Wtable, temp);
@@ -799,11 +896,6 @@
     /* X = 1 (in Montgomery presentation) initially */
     memcpy(X, Wtable, AN_limbs * ciL);
 
-    /* We'll process the bits of E from most significant
-     * (limb_index=E_limbs-1, E_bit_index=biL-1) to least significant
-     * (limb_index=0, E_bit_index=0). */
-    size_t E_limb_index = E_limbs;
-    size_t E_bit_index = 0;
     /* At any given time, window contains window_bits bits from E.
      * window_bits can go up to wsize. */
     size_t window_bits = 0;
@@ -829,10 +921,9 @@
          * when we've finished processing the exponent. */
         if (window_bits == wsize ||
             (E_bit_index == 0 && E_limb_index == 0)) {
-            /* Select Wtable[window] without leaking window through
-             * memory access patterns. */
-            mbedtls_mpi_core_ct_uint_table_lookup(Wselect, Wtable,
-                                                  AN_limbs, welem, window);
+
+            exp_mod_table_lookup_optionally_safe(Wselect, Wtable, AN_limbs, welem,
+                                                 window, E_public);
             /* Multiply X by the selected element. */
             mbedtls_mpi_core_montmul(X, X, Wselect, AN_limbs, N, AN_limbs, mm,
                                      temp);
@@ -842,6 +933,42 @@
     } while (!(E_bit_index == 0 && E_limb_index == 0));
 }
 
+void mbedtls_mpi_core_exp_mod(mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *N, size_t AN_limbs,
+                              const mbedtls_mpi_uint *E, size_t E_limbs,
+                              const mbedtls_mpi_uint *RR,
+                              mbedtls_mpi_uint *T)
+{
+    mbedtls_mpi_core_exp_mod_optionally_safe(X,
+                                             A,
+                                             N,
+                                             AN_limbs,
+                                             E,
+                                             E_limbs,
+                                             MBEDTLS_MPI_IS_SECRET,
+                                             RR,
+                                             T);
+}
+
+void mbedtls_mpi_core_exp_mod_unsafe(mbedtls_mpi_uint *X,
+                                     const mbedtls_mpi_uint *A,
+                                     const mbedtls_mpi_uint *N, size_t AN_limbs,
+                                     const mbedtls_mpi_uint *E, size_t E_limbs,
+                                     const mbedtls_mpi_uint *RR,
+                                     mbedtls_mpi_uint *T)
+{
+    mbedtls_mpi_core_exp_mod_optionally_safe(X,
+                                             A,
+                                             N,
+                                             AN_limbs,
+                                             E,
+                                             E_limbs,
+                                             MBEDTLS_MPI_IS_PUBLIC,
+                                             RR,
+                                             T);
+}
+
 mbedtls_mpi_uint mbedtls_mpi_core_sub_int(mbedtls_mpi_uint *X,
                                           const mbedtls_mpi_uint *A,
                                           mbedtls_mpi_uint c,  /* doubles as carry */
diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_core.h b/tf-psa-crypto/drivers/builtin/src/bignum_core.h
index 51ecca5..484fa8c 100644
--- a/tf-psa-crypto/drivers/builtin/src/bignum_core.h
+++ b/tf-psa-crypto/drivers/builtin/src/bignum_core.h
@@ -70,9 +70,7 @@
 
 #include "common.h"
 
-#if defined(MBEDTLS_BIGNUM_C)
 #include "mbedtls/bignum.h"
-#endif
 
 #include "constant_time_internal.h"
 
@@ -90,6 +88,34 @@
 #define GET_BYTE(X, i)                                \
     (((X)[(i) / ciL] >> (((i) % ciL) * 8)) & 0xff)
 
+/* Constants to identify whether a value is public or secret. If a parameter is marked as secret by
+ * this constant, the function must be constant time with respect to the parameter.
+ *
+ * This is only needed for functions with the _optionally_safe postfix. All other functions have
+ * fixed behavior that can't be changed at runtime and are constant time with respect to their
+ * parameters as prescribed by their documentation or by conventions in their module's documentation.
+ *
+ * Parameters should be named X_public where X is the name of the
+ * corresponding input parameter.
+ *
+ * Implementation should always check using
+ *  if (X_public == MBEDTLS_MPI_IS_PUBLIC) {
+ *      // unsafe path
+ *  } else {
+ *      // safe path
+ *  }
+ * not the other way round, in order to prevent misuse. (That is, if a value
+ * other than the two below is passed, default to the safe path.)
+ *
+ * The value of MBEDTLS_MPI_IS_PUBLIC is chosen in a way that is unlikely to happen by accident, but
+ * which can be used as an immediate value in a Thumb2 comparison (for code size). */
+#define MBEDTLS_MPI_IS_PUBLIC  0x2a2a2a2a
+#define MBEDTLS_MPI_IS_SECRET  0
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+// Default value for testing that is neither MBEDTLS_MPI_IS_PUBLIC nor MBEDTLS_MPI_IS_SECRET
+#define MBEDTLS_MPI_IS_TEST  1
+#endif
+
 /** Count leading zero bits in a given integer.
  *
  * \warning     The result is undefined if \p a == 0
@@ -615,6 +641,42 @@
 size_t mbedtls_mpi_core_exp_mod_working_limbs(size_t AN_limbs, size_t E_limbs);
 
 /**
+ * \brief            Perform a modular exponentiation with public or secret exponent:
+ *                   X = A^E mod N, where \p A is already in Montgomery form.
+ *
+ * \warning          This function is not constant time with respect to \p E (the exponent).
+ *
+ * \p X may be aliased to \p A, but not to \p RR or \p E, even if \p E_limbs ==
+ * \p AN_limbs.
+ *
+ * \param[out] X     The destination MPI, as a little endian array of length
+ *                   \p AN_limbs.
+ * \param[in] A      The base MPI, as a little endian array of length \p AN_limbs.
+ *                   Must be in Montgomery form.
+ * \param[in] N      The modulus, as a little endian array of length \p AN_limbs.
+ * \param AN_limbs   The number of limbs in \p X, \p A, \p N, \p RR.
+ * \param[in] E      The exponent, as a little endian array of length \p E_limbs.
+ * \param E_limbs    The number of limbs in \p E.
+ * \param[in] RR     The precomputed residue of 2^{2*biL} modulo N, as a little
+ *                   endian array of length \p AN_limbs.
+ * \param[in,out] T  Temporary storage of at least the number of limbs returned
+ *                   by `mbedtls_mpi_core_exp_mod_working_limbs()`.
+ *                   Its initial content is unused and its final content is
+ *                   indeterminate.
+ *                   It must not alias or otherwise overlap any of the other
+ *                   parameters.
+ *                   It is up to the caller to zeroize \p T when it is no
+ *                   longer needed, and before freeing it if it was dynamically
+ *                   allocated.
+ */
+void mbedtls_mpi_core_exp_mod_unsafe(mbedtls_mpi_uint *X,
+                                     const mbedtls_mpi_uint *A,
+                                     const mbedtls_mpi_uint *N, size_t AN_limbs,
+                                     const mbedtls_mpi_uint *E, size_t E_limbs,
+                                     const mbedtls_mpi_uint *RR,
+                                     mbedtls_mpi_uint *T);
+
+/**
  * \brief            Perform a modular exponentiation with secret exponent:
  *                   X = A^E mod N, where \p A is already in Montgomery form.
  *
diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_core_invasive.h b/tf-psa-crypto/drivers/builtin/src/bignum_core_invasive.h
new file mode 100644
index 0000000..167099d
--- /dev/null
+++ b/tf-psa-crypto/drivers/builtin/src/bignum_core_invasive.h
@@ -0,0 +1,23 @@
+/**
+ * \file bignum_core_invasive.h
+ *
+ * \brief Function declarations for invasive functions of bignum core.
+ */
+/**
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef MBEDTLS_BIGNUM_CORE_INVASIVE_H
+#define MBEDTLS_BIGNUM_CORE_INVASIVE_H
+
+#include "bignum_core.h"
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+
+extern void (*mbedtls_safe_codepath_hook)(void);
+extern void (*mbedtls_unsafe_codepath_hook)(void);
+
+#endif /* MBEDTLS_TEST_HOOKS && !MBEDTLS_THREADING_C */
+
+#endif /* MBEDTLS_BIGNUM_CORE_INVASIVE_H */
diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_internal.h b/tf-psa-crypto/drivers/builtin/src/bignum_internal.h
new file mode 100644
index 0000000..aceaf55
--- /dev/null
+++ b/tf-psa-crypto/drivers/builtin/src/bignum_internal.h
@@ -0,0 +1,50 @@
+/**
+ * \file bignum_internal.h
+ *
+ * \brief Internal-only bignum public-key cryptosystem API.
+ *
+ * This file declares bignum-related functions that are to be used
+ * only from within the Mbed TLS library itself.
+ *
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+#ifndef MBEDTLS_BIGNUM_INTERNAL_H
+#define MBEDTLS_BIGNUM_INTERNAL_H
+
+/**
+ * \brief          Perform a modular exponentiation: X = A^E mod N
+ *
+ * \warning        This function is not constant time with respect to \p E (the exponent).
+ *
+ * \param X        The destination MPI. This must point to an initialized MPI.
+ *                 This must not alias E or N.
+ * \param A        The base of the exponentiation.
+ *                 This must point to an initialized MPI.
+ * \param E        The exponent MPI. This must point to an initialized MPI.
+ * \param N        The base for the modular reduction. This must point to an
+ *                 initialized MPI.
+ * \param prec_RR  A helper MPI depending solely on \p N which can be used to
+ *                 speed-up multiple modular exponentiations for the same value
+ *                 of \p N. This may be \c NULL. If it is not \c NULL, it must
+ *                 point to an initialized MPI. If it hasn't been used after
+ *                 the call to mbedtls_mpi_init(), this function will compute
+ *                 the helper value and store it in \p prec_RR for reuse on
+ *                 subsequent calls to this function. Otherwise, the function
+ *                 will assume that \p prec_RR holds the helper value set by a
+ *                 previous call to mbedtls_mpi_exp_mod(), and reuse it.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed.
+ * \return         #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \c N is negative or
+ *                 even, or if \c E is negative.
+ * \return         Another negative error code on different kinds of failures.
+ *
+ */
+int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A,
+                               const mbedtls_mpi *E, const mbedtls_mpi *N,
+                               mbedtls_mpi *prec_RR);
+
+#endif /* bignum_internal.h */
diff --git a/tf-psa-crypto/drivers/builtin/src/ccm.c b/tf-psa-crypto/drivers/builtin/src/ccm.c
index 2503e9f..68af903 100644
--- a/tf-psa-crypto/drivers/builtin/src/ccm.c
+++ b/tf-psa-crypto/drivers/builtin/src/ccm.c
@@ -167,11 +167,12 @@
     }
 
     /* CCM expects non-empty tag.
-     * CCM* allows empty tag. For CCM* without tag, ignore plaintext length.
+     * CCM* allows empty tag. For CCM* without tag, the tag calculation is skipped.
      */
     if (ctx->tag_len == 0) {
         if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
             ctx->plaintext_len = 0;
+            return 0;
         } else {
             return MBEDTLS_ERR_CCM_BAD_INPUT;
         }
diff --git a/tf-psa-crypto/drivers/builtin/src/rsa.c b/tf-psa-crypto/drivers/builtin/src/rsa.c
index 5e7e762..33bb1d3 100644
--- a/tf-psa-crypto/drivers/builtin/src/rsa.c
+++ b/tf-psa-crypto/drivers/builtin/src/rsa.c
@@ -29,6 +29,7 @@
 
 #include "mbedtls/rsa.h"
 #include "bignum_core.h"
+#include "bignum_internal.h"
 #include "rsa_alt_helpers.h"
 #include "rsa_internal.h"
 #include "mbedtls/oid.h"
@@ -1257,7 +1258,7 @@
     }
 
     olen = ctx->len;
-    MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&T, &T, &ctx->E, &ctx->N, &ctx->RN));
+    MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod_unsafe(&T, &T, &ctx->E, &ctx->N, &ctx->RN));
     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&T, output, olen));
 
 cleanup:
diff --git a/tf-psa-crypto/scripts/project_name.txt b/tf-psa-crypto/scripts/project_name.txt
new file mode 100644
index 0000000..94a73fa
--- /dev/null
+++ b/tf-psa-crypto/scripts/project_name.txt
@@ -0,0 +1 @@
+TF-PSA-Crypto
diff --git a/tf-psa-crypto/tests/suites/test_suite_bignum.function b/tf-psa-crypto/tests/suites/test_suite_bignum.function
index 1830e5a..3d2b8a1 100644
--- a/tf-psa-crypto/tests/suites/test_suite_bignum.function
+++ b/tf-psa-crypto/tests/suites/test_suite_bignum.function
@@ -3,7 +3,9 @@
 #include "mbedtls/entropy.h"
 #include "constant_time_internal.h"
 #include "bignum_core.h"
+#include "bignum_internal.h"
 #include "test/constant_flow.h"
+#include "test/bignum_codepath_check.h"
 
 #if MBEDTLS_MPI_MAX_BITS > 792
 #define MPI_MAX_BITS_LARGER_THAN_792
@@ -988,7 +990,13 @@
      * against a smaller RR. */
     TEST_LE_U(RR.n, N.n - 1);
 
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
     res = mbedtls_mpi_exp_mod(&Z, &A, &E, &N, &RR);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_SECRET, res, E);
+#endif
     /* We know that exp_mod internally needs RR to be as large as N.
      * Validate that it is the case now, otherwise there was probably
      * a buffer overread. */
@@ -1021,7 +1029,26 @@
     TEST_ASSERT(mbedtls_test_read_mpi(&N, input_N) == 0);
     TEST_ASSERT(mbedtls_test_read_mpi(&X, input_X) == 0);
 
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
     res = mbedtls_mpi_exp_mod(&Z, &A, &E, &N, NULL);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_SECRET, res, E);
+#endif
+    TEST_ASSERT(res == exp_result);
+    if (res == 0) {
+        TEST_ASSERT(sign_is_valid(&Z));
+        TEST_ASSERT(mbedtls_mpi_cmp_mpi(&Z, &X) == 0);
+    }
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
+    res = mbedtls_mpi_exp_mod_unsafe(&Z, &A, &E, &N, NULL);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_PUBLIC, res, E);
+#endif
     TEST_ASSERT(res == exp_result);
     if (res == 0) {
         TEST_ASSERT(sign_is_valid(&Z));
@@ -1029,7 +1056,13 @@
     }
 
     /* Now test again with the speed-up parameter supplied as an output. */
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
     res = mbedtls_mpi_exp_mod(&Z, &A, &E, &N, &RR);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_SECRET, res, E);
+#endif
     TEST_ASSERT(res == exp_result);
     if (res == 0) {
         TEST_ASSERT(sign_is_valid(&Z));
@@ -1037,7 +1070,13 @@
     }
 
     /* Now test again with the speed-up parameter supplied in calculated form. */
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
     res = mbedtls_mpi_exp_mod(&Z, &A, &E, &N, &RR);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_SECRET, res, E);
+#endif
     TEST_ASSERT(res == exp_result);
     if (res == 0) {
         TEST_ASSERT(sign_is_valid(&Z));
@@ -1077,7 +1116,21 @@
         TEST_ASSERT(mbedtls_test_read_mpi(&RR, input_RR) == 0);
     }
 
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
     TEST_ASSERT(mbedtls_mpi_exp_mod(&Z, &A, &E, &N, &RR) == exp_result);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_SECRET, exp_result, E);
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
+    TEST_ASSERT(mbedtls_mpi_exp_mod_unsafe(&Z, &A, &E, &N, &RR) == exp_result);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_BIGNUM_CODEPATH(MBEDTLS_MPI_IS_PUBLIC, exp_result, E);
+#endif
 
 exit:
     mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N);
diff --git a/tf-psa-crypto/tests/suites/test_suite_bignum_core.function b/tf-psa-crypto/tests/suites/test_suite_bignum_core.function
index 6c0bd1e..c755287 100644
--- a/tf-psa-crypto/tests/suites/test_suite_bignum_core.function
+++ b/tf-psa-crypto/tests/suites/test_suite_bignum_core.function
@@ -4,6 +4,7 @@
 #include "bignum_core.h"
 #include "constant_time_internal.h"
 #include "test/constant_flow.h"
+#include "test/bignum_codepath_check.h"
 
 /** Verifies mbedtls_mpi_core_add().
  *
@@ -1246,6 +1247,7 @@
                       char *input_E, char *input_X)
 {
     mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *A_copy = NULL;
     mbedtls_mpi_uint *E = NULL;
     mbedtls_mpi_uint *N = NULL;
     mbedtls_mpi_uint *X = NULL;
@@ -1297,6 +1299,7 @@
 
     TEST_CALLOC(T, working_limbs);
 
+    /* Test the safe variant */
     TEST_CF_SECRET(A, A_limbs * sizeof(mbedtls_mpi_uint));
     TEST_CF_SECRET(N, N_limbs * sizeof(mbedtls_mpi_uint));
     TEST_CF_SECRET(E, E_limbs * sizeof(mbedtls_mpi_uint));
@@ -1304,22 +1307,48 @@
     mbedtls_mpi_core_exp_mod(Y, A, N, N_limbs, E, E_limbs, R2, T);
 
     TEST_CF_PUBLIC(Y, N_limbs * sizeof(mbedtls_mpi_uint));
+    TEST_EQUAL(0, memcmp(X, Y, N_limbs * sizeof(mbedtls_mpi_uint)));
+
+    /* Test the unsafe variant */
+    TEST_CF_PUBLIC(A, A_limbs * sizeof(mbedtls_mpi_uint));
+    TEST_CF_PUBLIC(N, N_limbs * sizeof(mbedtls_mpi_uint));
+    TEST_CF_PUBLIC(E, E_limbs * sizeof(mbedtls_mpi_uint));
+
+    mbedtls_mpi_core_exp_mod_unsafe(Y, A, N, N_limbs, E, E_limbs, R2, T);
 
     TEST_EQUAL(0, memcmp(X, Y, N_limbs * sizeof(mbedtls_mpi_uint)));
 
+    /*
+     * Check both with output aliased to input
+     */
+
+    TEST_CALLOC(A_copy, A_limbs);
+    memcpy(A_copy, A, sizeof(*A_copy) * A_limbs); // save A
+
+    /* Safe */
     TEST_CF_SECRET(A, A_limbs * sizeof(mbedtls_mpi_uint));
     TEST_CF_SECRET(N, N_limbs * sizeof(mbedtls_mpi_uint));
     TEST_CF_SECRET(E, E_limbs * sizeof(mbedtls_mpi_uint));
 
-    /* Check when output aliased to input */
     mbedtls_mpi_core_exp_mod(A, A, N, N_limbs, E, E_limbs, R2, T);
 
     TEST_CF_PUBLIC(A, A_limbs * sizeof(mbedtls_mpi_uint));
     TEST_EQUAL(0, memcmp(X, A, N_limbs * sizeof(mbedtls_mpi_uint)));
 
+    /* Unsafe */
+    memcpy(A, A_copy, sizeof(*A) * A_limbs); // restore A
+    TEST_CF_PUBLIC(A, A_limbs * sizeof(mbedtls_mpi_uint));
+    TEST_CF_PUBLIC(N, N_limbs * sizeof(mbedtls_mpi_uint));
+    TEST_CF_PUBLIC(E, E_limbs * sizeof(mbedtls_mpi_uint));
+
+    mbedtls_mpi_core_exp_mod_unsafe(A, A, N, N_limbs, E, E_limbs, R2, T);
+
+    TEST_EQUAL(0, memcmp(X, A, N_limbs * sizeof(mbedtls_mpi_uint)));
+
 exit:
     mbedtls_free(T);
     mbedtls_free(A);
+    mbedtls_free(A_copy);
     mbedtls_free(E);
     mbedtls_free(N);
     mbedtls_free(X);
diff --git a/tf-psa-crypto/tests/suites/test_suite_rsa.function b/tf-psa-crypto/tests/suites/test_suite_rsa.function
index e824529..98ea9ef 100644
--- a/tf-psa-crypto/tests/suites/test_suite_rsa.function
+++ b/tf-psa-crypto/tests/suites/test_suite_rsa.function
@@ -1,7 +1,9 @@
 /* BEGIN_HEADER */
 #include "mbedtls/rsa.h"
+#include "bignum_core.h"
 #include "rsa_alt_helpers.h"
 #include "rsa_internal.h"
+#include "test/bignum_codepath_check.h"
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -489,7 +491,13 @@
     TEST_EQUAL(mbedtls_rsa_get_bitlen(&ctx), (size_t) mod);
     TEST_ASSERT(mbedtls_rsa_check_pubkey(&ctx) == 0);
 
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    mbedtls_codepath_reset();
+#endif
     TEST_ASSERT(mbedtls_rsa_public(&ctx, message_str->x, output) == result);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+    ASSERT_RSA_CODEPATH(MBEDTLS_MPI_IS_PUBLIC, result);
+#endif
     if (result == 0) {
 
         TEST_ASSERT(mbedtls_test_hexcmp(output, result_str->x,
@@ -554,9 +562,15 @@
     /* repeat three times to test updating of blinding values */
     for (i = 0; i < 3; i++) {
         memset(output, 0x00, sizeof(output));
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+        mbedtls_codepath_reset();
+#endif
         TEST_ASSERT(mbedtls_rsa_private(&ctx, mbedtls_test_rnd_pseudo_rand,
                                         &rnd_info, message_str->x,
                                         output) == result);
+#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
+        ASSERT_RSA_CODEPATH(MBEDTLS_MPI_IS_SECRET, result);
+#endif
         if (result == 0) {
 
             TEST_ASSERT(mbedtls_test_hexcmp(output, result_str->x,
diff --git a/tf-psa-crypto/tests/suites/test_suite_version.data b/tf-psa-crypto/tests/suites/test_suite_version.data
index 0edee96..3a21f1b 100644
--- a/tf-psa-crypto/tests/suites/test_suite_version.data
+++ b/tf-psa-crypto/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compile time library version
-check_compiletime_version:"3.6.0"
+check_compiletime_version:"4.0.0"
 
 Check runtime library version
-check_runtime_version:"3.6.0"
+check_runtime_version:"4.0.0"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0